diff --git a/UnityPy/environment.py b/UnityPy/environment.py index bfec2fbc..ff790d33 100644 --- a/UnityPy/environment.py +++ b/UnityPy/environment.py @@ -107,6 +107,16 @@ def load_file( file = b"".join(file) else: name = file + if not os.path.exists(file): + # relative paths are in the asset directory, not the cwd + if not os.path.isabs(file): + file = os.path.join(self.path, file) + # Unity paths are case insensitive, so we need to find "Resources/Foo.asset" when the record says "resources/foo.asset" + if not os.path.exists(file): + file = ImportHelper.find_sensitive_path(self.path, file) + # nonexistent files might be packaging errors or references to Unity's global Library/ + if file is None: + return file = self.fs.open(file, "rb") typ, reader = ImportHelper.check_file_type(file) @@ -155,7 +165,7 @@ def save(self, pack="none", out_path="output"): for fname, fitem in self.files.items(): if getattr(fitem, "is_changed", False): with open( - self.fs.sep.join([out_path, ntpath.basename(f)]), "wb" + self.fs.sep.join([out_path, ntpath.basename(fname)]), "wb" ) as out: out.write(fitem.save(packer=pack)) diff --git a/UnityPy/helpers/ImportHelper.py b/UnityPy/helpers/ImportHelper.py index 53599ef5..e931daae 100644 --- a/UnityPy/helpers/ImportHelper.py +++ b/UnityPy/helpers/ImportHelper.py @@ -1,4 +1,5 @@ -import os +from __future__ import annotations +import os from typing import Union, List from .CompressionHelper import BROTLI_MAGIC, GZIP_MAGIC from ..enums import FileType @@ -127,7 +128,7 @@ def parse_file( name: str, typ: FileType = None, is_dependency=False, -): +) -> Union[files.File, EndianBinaryReader]: if typ is None: typ, _ = check_file_type(reader) if typ == FileType.AssetsFile and not name.endswith( @@ -141,3 +142,20 @@ def parse_file( else: f = reader return f + + +def find_sensitive_path(dir: str, insensitive_path: str) -> Union[str, None]: + parts = os.path.split(insensitive_path.strip(os.path.sep)) + + senstive_path = dir + for part in parts: + part_lower = part.lower() + part = next( + (name for name in os.listdir(senstive_path) if name.lower() == part_lower), + None, + ) + if next is None: + return None + senstive_path = os.path.join(senstive_path, part) + + return senstive_path