Skip to content

Commit 03ad02d

Browse files
Merge pull request #5 from xcoder-tool/new-container-version
feat: new container version (6) added
2 parents 094aae4 + fb35266 commit 03ad02d

File tree

15 files changed

+160
-151
lines changed

15 files changed

+160
-151
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A module for compression like in Supercell games.
44

5-
![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/Vorono4ka/sc-compression?include_prereleases)
5+
![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/xcoder-tool/sc-compression?include_prereleases)
66
-
77

88
TestPyPi - https://test.pypi.org/project/sc-compression/ <br>

build.bat

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@ECHO off
2+
SET FOLDER="dist"
3+
DEL /F/Q/S "%FOLDER%" > NUL
4+
RMDIR /Q/S "%FOLDER%"
5+
6+
python setup.py sdist bdist_wheel

sc_compression/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ def get_extension(file_path: str) -> str:
8080
return os.path.splitext(file_path)[1][1:]
8181

8282

83-
def join_filename(*parts, divider: str = ".") -> str:
84-
return divider.join(part for part in parts if type(part) is str and len(part) > 0)
83+
def join_filename(*parts: str, divider: str = ".") -> str:
84+
return divider.join(part for part in parts if len(part) > 0)
8585

8686

8787
def process_files(files: list[str], action: Callable[[bytes], bytes], suffix: str):

sc_compression/compressor.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from hashlib import md5
33

44
from sc_compression.signatures import Signatures
5-
from sc_compression.utils.writer import Writer
5+
from sc_compression.utils import ByteWriter
66

77
try:
88
import lzham
@@ -35,7 +35,11 @@ class Compressor:
3535
]
3636

3737
def compress(
38-
self, data: bytes, signature: Signatures, file_version: int = None
38+
self,
39+
data: bytes,
40+
signature: Signatures,
41+
file_version: int = None,
42+
metadata: bytes | None = None,
3943
) -> bytes:
4044
uncompressed_size = len(data)
4145

@@ -50,7 +54,7 @@ def compress(
5054
):
5155
signature = Signatures.SC
5256

53-
writer = Writer("little")
57+
writer = ByteWriter("little")
5458
if signature is Signatures.NONE:
5559
return data
5660
elif signature in (Signatures.LZMA, Signatures.SIG) or (
@@ -82,27 +86,45 @@ def compress(
8286
else:
8387
raise TypeError("Unknown Signature!")
8488

85-
compressed = self._write_header(compressed, data, file_version, signature)
89+
compressed = self._write_header(
90+
compressed, data, file_version, signature, metadata
91+
)
8692

8793
return compressed
8894

8995
@staticmethod
9096
def _write_header(
91-
compressed: bytes, data: bytes, file_version: int, signature: Signatures
97+
compressed: bytes,
98+
data: bytes,
99+
file_version: int,
100+
signature: Signatures,
101+
metadata: bytes | None,
92102
) -> bytes:
93103
if signature in (Signatures.SC, Signatures.SCLZ):
94-
data_hash = md5(data).digest()
95-
96-
writer = Writer("big")
104+
writer = ByteWriter("big")
97105
writer.write(b"SC")
98-
writer.write_int32(file_version)
99-
if file_version == 4:
100-
writer.write_int32(1)
101-
writer.write_int32(len(data_hash))
102-
writer.write(data_hash)
106+
if file_version <= 4:
107+
writer.write_int32(file_version)
108+
if file_version == 4:
109+
writer.write_int32(1)
110+
111+
data_hash = md5(data).digest()
112+
113+
writer.write_int32(len(data_hash))
114+
writer.write(data_hash)
115+
else:
116+
writer.set_endian("little")
117+
writer.write_int32(file_version)
118+
119+
if metadata is None:
120+
metadata = b""
121+
122+
writer.write_int32(len(metadata))
123+
writer.write(metadata)
124+
103125
return writer.buffer + compressed
104126
elif signature == Signatures.SIG:
105-
writer = Writer("big")
127+
writer = ByteWriter("big")
106128
writer.write(b"Sig:")
107129
writer.write(b"\x00" * 64) # sha64
108130
return writer.buffer + compressed

sc_compression/decompressor.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import lzma
22

33
from sc_compression.exceptions import UnknownFileMagicException
4-
from sc_compression.signatures import Signatures, get_signature, MAGIC_SC, MAGIC_ZSTD, MAGIC_SCLZ
5-
from sc_compression.utils.reader import Reader
4+
from sc_compression.signatures import (
5+
Signatures,
6+
get_signature,
7+
MAGIC_SC,
8+
MAGIC_ZSTD,
9+
MAGIC_SCLZ,
10+
)
11+
from sc_compression.utils import ByteReader
612

713
try:
814
import lzham
@@ -33,38 +39,39 @@ def decompress(self, buffer: bytes) -> bytes:
3339
return buffer
3440

3541
if self.signature == Signatures.SC:
36-
reader = Reader(buffer, "big")
42+
reader = ByteReader(buffer, "big")
3743

3844
self.check_magic(MAGIC_SC, reader=reader)
3945

4046
self.file_version = reader.read_int32()
4147
if self.file_version == 4:
4248
self.file_version = reader.read_int32()
4349

44-
if self.file_version == 0x05000000:
45-
reader.endian = "little"
50+
if self.file_version == 0x05000000 or self.file_version == 0x06000000:
51+
reader.set_endian("little")
52+
53+
if self.file_version == 0x06000000:
54+
reader.read_int16()
4655

4756
metadata_table_offset = reader.read_int32() # offset to metadata vtable
4857
reader.read(metadata_table_offset) # metadata
4958
else:
5059
hash_length = reader.read_int32()
5160
self.hash = reader.read(hash_length)
5261

53-
return self.decompress(buffer[reader.tell() :])
62+
return self.decompress(reader.read_all_bytes())
5463
elif self.signature == Signatures.SIG:
5564
return self.decompress(buffer[68:])
5665
elif self.signature == Signatures.SCLZ and lzham is not None:
57-
reader = Reader(buffer, "little")
66+
reader = ByteReader(buffer, "little")
5867

5968
self.check_magic(MAGIC_SCLZ, reader=reader)
6069

6170
dict_size_log2 = reader.read_u_int8()
6271
uncompressed_size = reader.read_int32()
6372

6473
filters = {"dict_size_log2": dict_size_log2}
65-
return lzham.decompress(
66-
reader.buffer[reader.tell() :], uncompressed_size, filters
67-
)
74+
return lzham.decompress(reader.read_all_bytes(), uncompressed_size, filters)
6875
elif self.signature == Signatures.LZMA:
6976
decompressor = lzma.LZMADecompressor()
7077
compressed = buffer[:5] + b"\xff" * 8 + buffer[9:]
@@ -78,11 +85,15 @@ def decompress(self, buffer: bytes) -> bytes:
7885
raise TypeError(self.signature)
7986

8087
@staticmethod
81-
def check_magic(expected_magic: bytes, reader: Reader | None = None, buffer: bytes | None = None) -> None:
88+
def check_magic(
89+
expected_magic: bytes,
90+
reader: ByteReader | None = None,
91+
buffer: bytes | None = None,
92+
) -> None:
8293
if reader is not None:
8394
magic = reader.read(len(expected_magic))
8495
elif buffer is not None:
85-
magic = buffer[:len(expected_magic)]
96+
magic = buffer[: len(expected_magic)]
8697
else:
8798
raise Exception("Cannot find buffer to get magic from.")
8899

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
class UnknownFileMagicException(Exception):
22
def __init__(self, magic: bytes, expected_magic: bytes, *args):
3-
super().__init__(f"Unknown file magic: {magic.hex()}, while expected was {expected_magic.hex()}", *args)
3+
super().__init__(
4+
f"Unknown file magic: {magic.hex()}, while expected was {expected_magic.hex()}",
5+
*args,
6+
)

sc_compression/signatures.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import enum
12
import re
2-
from enum import Enum
3+
from enum import IntEnum
34

4-
MAGIC_SC = b"SC"
5-
MAGIC_SCLZ = b"SCLZ"
6-
MAGIC_SIG = b"Sig:"
7-
MAGIC_ZSTD = b"\x28\xb5\x2f\xfd"
5+
MAGIC_SC: bytes = b"SC"
6+
MAGIC_SCLZ: bytes = b"SCLZ"
7+
MAGIC_SIG: bytes = b"Sig:"
8+
MAGIC_ZSTD: bytes = b"\x28\xb5\x2f\xfd"
89

910

10-
class Signatures(Enum):
11+
@enum.unique
12+
class Signatures(IntEnum):
1113
NONE = 0
1214
LZMA = 1
1315
SC = 2

sc_compression/support/lzham.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def decompress(data, uncompressed_size, filters):
2020
decompressed_path = mktemp(".lzham")
2121
if system(
2222
f"{path.dirname(__file__)}/lzham.exe "
23-
f'-c -d{filters["dict_size_log2"]} '
23+
f"-c -d{filters['dict_size_log2']} "
2424
f"d {temp_file_path} {decompressed_path} > nul 2>&1"
2525
):
2626
remove(temp_file_path)
@@ -43,7 +43,7 @@ def compress(data, filters):
4343
compressed_path = mktemp(".lzham")
4444
if system(
4545
f"{path.dirname(__file__)}/lzham.exe "
46-
f'-c -d{filters["dict_size_log2"]} '
46+
f"-c -d{filters['dict_size_log2']} "
4747
f"c {temp_file_path} {compressed_path} > nul 2>&1"
4848
):
4949
remove(temp_file_path)

sc_compression/utils/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
__all__ = ["reader", "writer"]
1+
from .reader import ByteReader
2+
from .writer import ByteWriter
3+
4+
__all__ = ["ByteWriter", "ByteReader"]

sc_compression/utils/common.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from typing import Literal
2+
3+
from typing_extensions import TypeAlias
4+
5+
Endian: TypeAlias = Literal["big", "little"]
6+
7+
8+
def get_endian_sign(endian: Literal["big", "little"]) -> Literal[">", "<"]:
9+
if endian == "big":
10+
return ">"
11+
elif endian == "little":
12+
return "<"
13+
14+
raise NotImplementedError(f"Unknown endian requested: {endian}")

0 commit comments

Comments
 (0)