mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
fix: read DepotDownloader's compressed protobuf depot.config
This commit is contained in:
1 parent
0cc187025f
commit
4cc117b45b
2 files changed
+66
-5
No files matched your search
@@ -11,6 +11,7 @@ import time
|
||||
import unicodedata
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import zlib
|
||||
|
||||
STATE = ".droiddeck-games.json"
|
||||
TRIED = ".droiddeck-import-tried.json"
|
||||
@@ -301,17 +302,62 @@ def installed_build(folder, appid, installdir):
|
||||
if not (folder / ".download_complete").is_file():
|
||||
return None
|
||||
try:
|
||||
ids = json.loads((folder / ".DepotDownloader/depot.config").read_text())["installedManifestIDs"]
|
||||
depots = sorted((int(depot), int(gid)) for depot, gid in ids.items())
|
||||
except FileNotFoundError:
|
||||
depots = config_depots((folder / ".DepotDownloader/depot.config").read_bytes())
|
||||
except OSError:
|
||||
depots = None
|
||||
if depots is None:
|
||||
depots = completed_depots(folder / ".DepotDownloader/completed")
|
||||
except (OSError, ValueError, KeyError, TypeError, AttributeError):
|
||||
return None
|
||||
if not depots or not all(0 < depot < 0x80000000 and 0 < gid < 0x7FFFFFFFFFFFFFFF for depot, gid in depots):
|
||||
return None
|
||||
return "".join(f' "{depot}"\n {{\n "manifest" "{gid}"\n }}\n' for depot, gid in depots)
|
||||
|
||||
|
||||
def varint(data, i):
|
||||
value = shift = 0
|
||||
while True:
|
||||
byte = data[i]
|
||||
i += 1
|
||||
value |= (byte & 0x7F) << shift
|
||||
shift += 7
|
||||
if byte < 0x80:
|
||||
return value, i
|
||||
|
||||
|
||||
def proto_fields(data):
|
||||
i = 0
|
||||
while i < len(data):
|
||||
key, i = varint(data, i)
|
||||
kind = key & 7
|
||||
if kind == 0:
|
||||
value, i = varint(data, i)
|
||||
elif kind == 2:
|
||||
size, i = varint(data, i)
|
||||
value, i = data[i:i + size], i + size
|
||||
elif kind in (1, 5):
|
||||
value, i = None, i + (8 if kind == 1 else 4)
|
||||
else:
|
||||
raise ValueError
|
||||
yield key >> 3, kind, value
|
||||
|
||||
|
||||
def config_depots(data):
|
||||
try:
|
||||
ids = json.loads(data.decode())["installedManifestIDs"]
|
||||
return sorted((int(depot), int(gid)) for depot, gid in ids.items())
|
||||
except (ValueError, KeyError, TypeError, AttributeError):
|
||||
pass
|
||||
try:
|
||||
depots = {}
|
||||
for number, kind, entry in proto_fields(zlib.decompress(data, -15)):
|
||||
if number == 1 and kind == 2:
|
||||
fields = {n: v for n, k, v in proto_fields(entry) if k == 0}
|
||||
if 1 in fields and 2 in fields:
|
||||
depots[fields[1]] = fields[2]
|
||||
return sorted(depots.items()) or None
|
||||
except (zlib.error, ValueError, IndexError):
|
||||
return None
|
||||
|
||||
|
||||
def completed_depots(completed):
|
||||
newest = {}
|
||||
try:
|
||||
|
||||
@@ -6,6 +6,7 @@ from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
import zlib
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
BIN = Path(__file__).resolve().parents[1] / 'linuxfs/overlay/usr/local/bin'
|
||||
@@ -247,6 +248,20 @@ class ImportsTest(unittest.TestCase):
|
||||
config.write_text(json.dumps({'installedManifestIDs': {'43': 0x7FFFFFFFFFFFFFFF}}))
|
||||
self.assertIsNone(imports.installed_build(self.folder, 42, 'DroidDeck-42'))
|
||||
|
||||
def test_compressed_protobuf_depot_config_records_installed_depots(self):
|
||||
config = self.folder / '.DepotDownloader/depot.config'
|
||||
config.parent.mkdir()
|
||||
(self.folder / '.download_complete').touch()
|
||||
entry = bytes([0x08, 43, 0x10, 99])
|
||||
packed = zlib.compressobj(wbits=-15)
|
||||
config.write_bytes(packed.compress(bytes([0x0A, len(entry)]) + entry) + packed.flush())
|
||||
self.assertIn('"43"\n {\n "manifest" "99"', imports.installed_build(self.folder, 42, 'DroidDeck-42'))
|
||||
config.write_bytes(b'not a config')
|
||||
self.assertIsNone(imports.installed_build(self.folder, 42, 'DroidDeck-42'))
|
||||
(config.parent / 'completed').mkdir()
|
||||
(config.parent / 'completed/43_98.manifest').write_bytes(b'x')
|
||||
self.assertIn('"manifest" "98"', imports.installed_build(self.folder, 42, 'DroidDeck-42'))
|
||||
|
||||
def test_completed_manifests_record_installed_depots(self):
|
||||
completed = self.folder / '.DepotDownloader/completed'
|
||||
completed.mkdir(parents=True)
|
||||
|
||||
Reference in new issue
Block a user