Skip to content

Commit

Permalink
escape | char for filepaths
Browse files Browse the repository at this point in the history
  • Loading branch information
HENDRIX-ZT2 committed Dec 17, 2024
1 parent bb84697 commit aec9ee6
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 128 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Frontier's Cobra Engine Formats",
"author": "Harlequinz Ego, HENDRIX et al.",
"blender": (4, 0, 0),
"version": (2024, 12, 9),
"version": (2024, 12, 11),
"location": "File > Import-Export",
"description": "Import-Export models, skeletons and animations",
"warning": "",
Expand Down
6 changes: 3 additions & 3 deletions __version__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# this file is auto-generated by the pre-commit hook increment_version.py
VERSION = "2024.12.09"
COMMIT_HASH = "99725876b"
COMMIT_TIME = "Mon Dec 9 18:44:57 2024 +0100"
VERSION = "2024.12.11"
COMMIT_HASH = "bb84697db"
COMMIT_TIME = "Wed Dec 11 23:07:58 2024 +0100"
12 changes: 3 additions & 9 deletions generated/formats/ovl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
from generated.formats.ovl.versions import *
from generated.formats.ovl_base.enums.Compression import Compression
from modules.formats.formats_dict import FormatDict
from modules.formats.shared import djb2, DummyReporter, walk_type
from ovl_util.shared import hex_dump
from modules.formats.shared import djb2, DummyReporter, walk_type, escape_path, unescape_path

try:
from ovl_util.oodle.oodle import oodle_compressor, OodleDecompressEnum, INPUT_CHUNK_SIZE, OODLE_CODEC
Expand Down Expand Up @@ -658,7 +657,7 @@ def extract(self, out_dir, only_names=(), only_types=()):

def out_dir_func(n):
"""Helper function to generate temporary output file name"""
out_path = os.path.normpath(os.path.join(out_dir, n))
out_path = os.path.normpath(os.path.join(out_dir, escape_path(n)))
# create output dir
os.makedirs(os.path.dirname(out_path), exist_ok=True)
return out_path
Expand Down Expand Up @@ -692,7 +691,7 @@ def out_dir_func(n):
def create_file(self, file_path, file_name, ovs_name="STATIC"):
"""Create a loader from a file path"""
file_path = os.path.normpath(file_path)
file_name = file_name.lower()
file_name = unescape_path(file_name.lower())
_, ext = os.path.splitext(file_name)
logging.info(f"Creating {file_name} in {ovs_name}")
try:
Expand Down Expand Up @@ -1487,8 +1486,3 @@ def save(self, filepath, use_threads=True):

if __name__ == "__main__":
ovl = OvlFile()
#ovl.load_hash_table()
#ovl.load("C:/Users/arnfi/Desktop/Coding/ovl/OVLs/Parrot.ovl")
#ovl.extract('C:/Users/ilo/Documents/GitHub/cobra-tools/', ['database.contentpdlc2luadatabase.lua'])
#ovl.add_files( ['C:/Users/ilo/Documents/GitHub/cobra-tools/version.txt'] )
#ovl.save("C:/Users/arnfi/Desktop/Coding/ovl/OVLs/Parrot1.ovl", use_threads=False)
4 changes: 4 additions & 0 deletions generated/formats/trackstation/compounds/TrackOnly.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from generated.formats.trackstation.compounds.CommonChunk import CommonChunk
from generated.formats.trackstation.imports import name_type_map


class TrackOnly(CommonChunk):
Expand All @@ -12,13 +13,16 @@ class TrackOnly(CommonChunk):

def __init__(self, context, arg=0, template=None, set_default=True):
super().__init__(context, arg, template, set_default=False)
self.zero_2 = name_type_map['Uint64'](self.context, 0, None)
if set_default:
self.set_defaults()

@classmethod
def _get_attribute_list(cls):
yield from super()._get_attribute_list()
yield 'zero_2', name_type_map['Uint64'], (0, None), (False, None), (None, None)

@classmethod
def _get_filtered_attribute_list(cls, instance, include_abstract=True):
yield from super()._get_filtered_attribute_list(instance, include_abstract)
yield 'zero_2', name_type_map['Uint64'], (0, None), (False, None)
2 changes: 1 addition & 1 deletion generated/formats/trackstation/trackstation.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@

<compound name="TrackOnly" inherit="CommonChunk">
PZ and PC: 112 bytes
<!--<add name="zero2" type="uint64"/>-->
<add name="zero2" type="uint64"/>
</compound>

<compound name="CornerEdgeTrack" inherit="MemStruct">
Expand Down
1 change: 0 additions & 1 deletion modules/formats/BaseFormat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import contextlib
import io
import logging
import os
import struct
Expand Down
223 changes: 120 additions & 103 deletions modules/formats/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,132 +7,149 @@


def get_padding_size(size, alignment=16):
mod = size % alignment
if mod:
return alignment - mod
return 0
mod = size % alignment
if mod:
return alignment - mod
return 0


def get_padding(size, alignment=16):
if alignment:
# create the new blank padding
return b"\x00" * get_padding_size(size, alignment=alignment)
return b""
if alignment:
# create the new blank padding
return b"\x00" * get_padding_size(size, alignment=alignment)
return b""


def djb2(s: str):
"""calculates djb2 hash for string s"""
# from https://gist.github.com/mengzhuo/180cd6be8ba9e2743753#file-hash_djb2-py
n = 5381
for x in s:
n = ((n << 5) + n) + ord(x)
return n & 0xFFFFFFFF
"""calculates djb2 hash for string s"""
# from https://gist.github.com/mengzhuo/180cd6be8ba9e2743753#file-hash_djb2-py
n = 5381
for x in s:
n = ((n << 5) + n) + ord(x)
return n & 0xFFFFFFFF


def fnv64(b: bytes):
"""calculates fnv64 hash for bytes b"""
n = 0xcbf29ce484222325
for b in b:
n *= 0x100000001b3
n &= 0xffffffffffffffff
n ^= b
return n
"""calculates fnv64 hash for bytes b"""
n = 0xcbf29ce484222325
for b in b:
n *= 0x100000001b3
n &= 0xffffffffffffffff
n ^= b
return n


def encode_int64_base32(integer: int, charset: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"):
"""Encodes a 64-bit integer into a base32 string with a custom charset."""
encoded = ""
for _ in range(13):
index = integer & 0x1F
encoded += charset[index]
integer >>= 5
return encoded
"""Encodes a 64-bit integer into a base32 string with a custom charset."""
encoded = ""
for _ in range(13):
index = integer & 0x1F
encoded += charset[index]
integer >>= 5
return encoded


def fmt_hash(id_hash):
return "".join([f"{b:02X}" for b in struct.pack("<I", id_hash)])
return "".join([f"{b:02X}" for b in struct.pack("<I", id_hash)])


class DummySignal:

def emit(self, val):
pass
# logging.debug(f"Emitted {val}")
def emit(self, val):
pass
# logging.debug(f"Emitted {val}")

def connect(self, func):
pass
def connect(self, func):
pass


class DummyReporter:
"""A class wrapping the interaction between OvlFile and the UI"""
warning_msg = DummySignal() # type: ignore
success_msg = DummySignal() # type: ignore
files_list = DummySignal() # type: ignore
included_ovls_list = DummySignal() # type: ignore
progress_percentage = DummySignal() # type: ignore
progress_total = DummySignal() # type: ignore
current_action = DummySignal() # type: ignore

def iter_progress(self, iterable, message, cond=True):
if cond:
self.current_action.emit(message)
self._percentage = -1
if len(iterable) > 1:
self.progress_total.emit(100)
else:
self.progress_total.emit(0)
for i, item in enumerate(iterable):
p = round(i / len(iterable) * 100)
if p != self._percentage:
self.progress_percentage.emit(p)
self._percentage = p
yield item
# clear both to also make indeterminate processes appear complete
self.progress_percentage.emit(100)
self.progress_total.emit(100)
msg = f"Finished {message}"
self.current_action.emit(msg)
# logging.success(msg)
else:
for item in iterable:
yield item

@contextlib.contextmanager
def report_error_files(self, operation):
error_files = []
yield error_files
if error_files:
self.warning_msg.emit(
(f"{operation} {len(error_files)} files failed - please check 'Show Details' or the log.",
"\n".join(error_files)))
else:
msg = f"{operation} succeeded"
logging.success(msg)
self.success_msg.emit(msg)

def show_success(self, msg):
logging.success(msg)
self.success_msg.emit(msg)

def show_error(self, msg, files=()):
self.warning_msg.emit((msg, "\n".join(files)))

@contextlib.contextmanager
def log_duration(self, operation):
logging.info(operation)
start_time = time.time()
yield
duration = time.time() - start_time
logging.debug(f"{operation} took {duration:.2f} seconds")
"""A class wrapping the interaction between OvlFile and the UI"""
warning_msg = DummySignal() # type: ignore
success_msg = DummySignal() # type: ignore
files_list = DummySignal() # type: ignore
included_ovls_list = DummySignal() # type: ignore
progress_percentage = DummySignal() # type: ignore
progress_total = DummySignal() # type: ignore
current_action = DummySignal() # type: ignore

def iter_progress(self, iterable, message, cond=True):
if cond:
self.current_action.emit(message)
self._percentage = -1
if len(iterable) > 1:
self.progress_total.emit(100)
else:
self.progress_total.emit(0)
for i, item in enumerate(iterable):
p = round(i / len(iterable) * 100)
if p != self._percentage:
self.progress_percentage.emit(p)
self._percentage = p
yield item
# clear both to also make indeterminate processes appear complete
self.progress_percentage.emit(100)
self.progress_total.emit(100)
msg = f"Finished {message}"
self.current_action.emit(msg)
# logging.success(msg)
else:
for item in iterable:
yield item

@contextlib.contextmanager
def report_error_files(self, operation):
error_files = []
yield error_files
if error_files:
self.warning_msg.emit(
(f"{operation} {len(error_files)} files failed - please check 'Show Details' or the log.",
"\n".join(error_files)))
else:
msg = f"{operation} succeeded"
logging.success(msg)
self.success_msg.emit(msg)

def show_success(self, msg):
logging.success(msg)
self.success_msg.emit(msg)

def show_error(self, msg, files=()):
self.warning_msg.emit((msg, "\n".join(files)))

@contextlib.contextmanager
def log_duration(self, operation):
logging.info(operation)
start_time = time.time()
yield
duration = time.time() - start_time
logging.debug(f"{operation} took {duration:.2f} seconds")


def walk_type(start_dir, extension=".ovl"):
logging.info(f"Scanning {Path(start_dir)} for {extension} files")
ret = []
for root, dirs, files in os.walk(start_dir, topdown=False):
for name in files:
if extension and not name.lower().endswith(extension):
continue
ret.append(os.path.join(root, name))
logging.info(ret)
return ret
logging.info(f"Scanning {Path(start_dir)} for {extension} files")
ret = []
for root, dirs, files in os.walk(start_dir, topdown=False):
for name in files:
if extension and not name.lower().endswith(extension):
continue
ret.append(os.path.join(root, name))
logging.info(ret)
return ret


filepath_escapes = {
"|": "&#124;",
}


def escape_path(filepath):
for k, v in filepath_escapes.items():
filepath = filepath.replace(k, v)
return filepath


def unescape_path(filepath):
for k, v in filepath_escapes.items():
filepath = filepath.replace(v, k)
return filepath
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "cobra-tools"
version = "2024.12.09"
version = "2024.12.11"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = "==3.11.*"
Expand Down
12 changes: 3 additions & 9 deletions source/formats/ovl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
from generated.formats.ovl.versions import *
from generated.formats.ovl_base.enums.Compression import Compression
from modules.formats.formats_dict import FormatDict
from modules.formats.shared import djb2, DummyReporter, walk_type
from ovl_util.shared import hex_dump
from modules.formats.shared import djb2, DummyReporter, walk_type, escape_path, unescape_path

try:
from ovl_util.oodle.oodle import oodle_compressor, OodleDecompressEnum, INPUT_CHUNK_SIZE, OODLE_CODEC
Expand Down Expand Up @@ -657,7 +656,7 @@ def extract(self, out_dir, only_names=(), only_types=()):

def out_dir_func(n):
"""Helper function to generate temporary output file name"""
out_path = os.path.normpath(os.path.join(out_dir, n))
out_path = os.path.normpath(os.path.join(out_dir, escape_path(n)))
# create output dir
os.makedirs(os.path.dirname(out_path), exist_ok=True)
return out_path
Expand Down Expand Up @@ -691,7 +690,7 @@ def out_dir_func(n):
def create_file(self, file_path, file_name, ovs_name="STATIC"):
"""Create a loader from a file path"""
file_path = os.path.normpath(file_path)
file_name = file_name.lower()
file_name = unescape_path(file_name.lower())
_, ext = os.path.splitext(file_name)
logging.info(f"Creating {file_name} in {ovs_name}")
try:
Expand Down Expand Up @@ -1486,8 +1485,3 @@ def save(self, filepath, use_threads=True):

if __name__ == "__main__":
ovl = OvlFile()
#ovl.load_hash_table()
#ovl.load("C:/Users/arnfi/Desktop/Coding/ovl/OVLs/Parrot.ovl")
#ovl.extract('C:/Users/ilo/Documents/GitHub/cobra-tools/', ['database.contentpdlc2luadatabase.lua'])
#ovl.add_files( ['C:/Users/ilo/Documents/GitHub/cobra-tools/version.txt'] )
#ovl.save("C:/Users/arnfi/Desktop/Coding/ovl/OVLs/Parrot1.ovl", use_threads=False)

0 comments on commit aec9ee6

Please sign in to comment.