Skip to content

Commit 47d9136

Browse files
Merge pull request #3 from danila-schelkov/sc2-support
refactor: inheritance removed, added support for the fifth version
2 parents 74e3ad8 + 3226ba0 commit 47d9136

File tree

12 files changed

+293
-345
lines changed

12 files changed

+293
-345
lines changed

examples/compressor/main.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
from sc_compression.signatures import Signatures
44
from sc_compression import compress
55

6-
if not os.path.exists('in'):
7-
os.mkdir('in')
8-
9-
if not os.path.exists('out'):
10-
os.mkdir('out')
6+
if not os.path.exists("in"):
7+
os.mkdir("in")
118

9+
if not os.path.exists("out"):
10+
os.mkdir("out")
1211

13-
for filename in os.listdir('in'):
14-
with open('in/' + filename, 'rb') as f:
15-
file_data = f.read()
16-
f.close()
17-
with open('out/' + filename, 'wb') as f:
18-
f.write(compress(file_data, Signatures.SC, 3))
19-
f.close()
12+
13+
for filename in os.listdir("in"):
14+
with open("in/" + filename, "rb") as f:
15+
file_data = f.read()
16+
f.close()
17+
with open("out/" + filename, "wb") as f:
18+
f.write(compress(file_data, Signatures.SC, 3))
19+
f.close()

examples/decompressor/main.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
from sc_compression import decompress
44

5-
if not os.path.exists('in'):
6-
os.mkdir('in')
7-
8-
if not os.path.exists('out'):
9-
os.mkdir('out')
5+
if not os.path.exists("in"):
6+
os.mkdir("in")
107

8+
if not os.path.exists("out"):
9+
os.mkdir("out")
1110

12-
for filename in os.listdir('in'):
13-
with open('in/' + filename, 'rb') as f:
14-
file_data = f.read()
15-
f.close()
16-
with open('out/' + filename, 'wb') as f:
17-
f.write(decompress(file_data)[0])
18-
f.close()
11+
12+
for filename in os.listdir("in"):
13+
with open("in/" + filename, "rb") as f:
14+
file_data = f.read()
15+
f.close()
16+
with open("out/" + filename, "wb") as f:
17+
f.write(decompress(file_data)[0])
18+
f.close()

sc_compression/__init__.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,15 @@
22
from .decompressor import Decompressor
33
from .signatures import Signatures
44

5-
6-
__all__ = [
7-
'Decompressor',
8-
'Compressor',
9-
'Signatures',
10-
11-
'decompress',
12-
'compress'
13-
]
5+
__all__ = ["Decompressor", "Compressor", "Signatures", "decompress", "compress"]
146

157

168
def compress(buffer: bytes, signature: Signatures, file_version: int = None) -> bytes:
179
return Compressor().compress(buffer, signature, file_version)
1810

1911

20-
def decompress(buffer: bytes) -> (bytes, int):
12+
def decompress(buffer: bytes) -> tuple[bytes, Signatures, int]:
2113
_decompressor = Decompressor()
2214
decompressed = _decompressor.decompress(buffer)
2315

24-
return decompressed, _decompressor.signature
16+
return decompressed, _decompressor.signature, _decompressor.file_version

sc_compression/__main__.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,53 @@
77

88

99
def main() -> int:
10-
argument_parser = argparse.ArgumentParser(description='A module for compression like in Supercell games.')
11-
argument_parser.add_argument('-d', '--decompress', help='Decompress all files.', action='store_true')
12-
argument_parser.add_argument('-c', '--compress', help='Compress all files.', action='store_true')
10+
argument_parser = argparse.ArgumentParser(
11+
description="A module for compression like in Supercell games."
12+
)
13+
argument_parser.add_argument(
14+
"-d", "--decompress", help="Decompress all files", action="store_true"
15+
)
1316
argument_parser.add_argument(
14-
'-s', '--signature',
17+
"-c", "--compress", help="Compress all files", action="store_true"
18+
)
19+
argument_parser.add_argument(
20+
"-s",
21+
"--signature",
1522
choices=[signature.name for signature in Signatures],
23+
help="Required signature name",
24+
type=str,
25+
default=Signatures.SC.name,
26+
)
27+
argument_parser.add_argument(
28+
"-f",
29+
"--files",
30+
help="Files to be processed",
31+
type=str,
32+
nargs="+",
33+
required=True,
34+
)
35+
argument_parser.add_argument(
36+
"-S",
37+
"--suffix",
38+
help="Suffix for processed files",
1639
type=str,
17-
default='SC'
40+
default=None,
1841
)
19-
argument_parser.add_argument('-f', '--files', help='Files to be processed.', type=str, nargs='+', required=True)
2042

2143
args = argument_parser.parse_args()
2244
if args.decompress:
2345
process_files(
2446
args.files,
2547
lambda data: decompress(data)[0],
26-
'decomp'
48+
args.suffix or "decompressed",
2749
)
2850
elif args.compress:
2951
signature = Signatures[args.signature]
3052

3153
process_files(
3254
args.files,
3355
lambda data: compress(data, signature, 1),
34-
'comp'
56+
args.suffix or "compressed",
3557
)
3658
else:
3759
argument_parser.print_help()
@@ -58,25 +80,25 @@ def get_extension(file_path: str) -> str:
5880
return os.path.splitext(file_path)[1][1:]
5981

6082

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

6486

65-
def process_files(files: str, action: Callable[[bytes], bytes], suffix: str):
87+
def process_files(files: list[str], action: Callable[[bytes], bytes], suffix: str):
6688
for filename in files:
6789
path = get_absolute_file_path(filename)
6890
directory = get_directory(path)
6991
base_name = get_base_name(path)
7092
extension = get_extension(path)
7193

7294
if os.path.isfile(path):
73-
with open(path, 'rb') as file:
95+
with open(path, "rb") as file:
7496
data = action(file.read())
7597

7698
processed_filename = join_filename(base_name, suffix, extension)
77-
with open(os.path.join(directory, processed_filename), 'wb') as file:
99+
with open(os.path.join(directory, processed_filename), "wb") as file:
78100
file.write(data)
79101

80102

81-
if __name__ == '__main__':
103+
if __name__ == "__main__":
82104
exit(main())

sc_compression/compressor.py

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from platform import system as get_system_name
1111

1212
lzham = None
13-
if get_system_name() == 'Windows':
13+
if get_system_name() == "Windows":
1414
from sc_compression.support.lzham import LZHAM
1515

1616
lzham = LZHAM
@@ -21,76 +21,90 @@
2121
zstandard = None
2222

2323

24-
class Compressor(Writer):
25-
lzham_filters = {
26-
'dict_size_log2': 18
27-
}
24+
class Compressor:
25+
lzham_filters = {"dict_size_log2": 18}
2826
lzma_filters = [
2927
{
3028
"id": lzma.FILTER_LZMA1,
3129
"dict_size": 256 * 1024,
3230
"lc": 3,
3331
"lp": 0,
3432
"pb": 2,
35-
"mode": lzma.MODE_NORMAL
33+
"mode": lzma.MODE_NORMAL,
3634
},
3735
]
3836

39-
def __init__(self):
40-
super().__init__('little')
41-
42-
def compress(self, data, signature: Signatures, file_version: int = None) -> bytes:
37+
def compress(
38+
self, data: bytes, signature: Signatures, file_version: int = None
39+
) -> bytes:
4340
uncompressed_size = len(data)
4441

4542
if file_version is None:
4643
file_version = 3 if zstandard and signature != Signatures.SCLZ else 1
4744

48-
if signature == Signatures.ZSTD and not zstandard or \
49-
signature == Signatures.SCLZ and not lzham:
45+
if (
46+
signature == Signatures.ZSTD
47+
and not zstandard
48+
or signature == Signatures.SCLZ
49+
and not lzham
50+
):
5051
signature = Signatures.SC
5152

52-
super().__init__('little')
53+
writer = Writer("little")
5354
if signature is Signatures.NONE:
5455
return data
55-
elif signature in (Signatures.LZMA, Signatures.SIG) or (signature == Signatures.SC and file_version != 3):
56-
compressed = lzma.compress(data, format=lzma.FORMAT_ALONE, filters=self.lzma_filters)
56+
elif signature in (Signatures.LZMA, Signatures.SIG) or (
57+
signature == Signatures.SC and file_version != 3
58+
):
59+
compressed = lzma.compress(
60+
data, format=lzma.FORMAT_ALONE, filters=self.lzma_filters
61+
)
5762

58-
self.write(compressed[:5])
63+
writer.write(compressed[:5])
5964

60-
self.writeInt32(uncompressed_size)
65+
writer.write_int32(uncompressed_size)
6166

62-
self.write(compressed[13:])
67+
writer.write(compressed[13:])
6368

64-
compressed = self.buffer
69+
compressed = writer.buffer
6570
elif signature == Signatures.SCLZ and lzham:
6671
compressed = lzham.compress(data, filters=self.lzham_filters)
6772

68-
self.write(b'SCLZ')
69-
self.writeUByte(self.lzham_filters['dict_size_log2'])
70-
self.writeInt32(uncompressed_size)
71-
self.write(compressed)
73+
writer.write(b"SCLZ")
74+
writer.write_u_int8(self.lzham_filters["dict_size_log2"])
75+
writer.write_int32(uncompressed_size)
76+
writer.write(compressed)
7277

73-
compressed = self.buffer
74-
elif signature in (Signatures.SC, Signatures.ZSTD) and file_version == 3:
78+
compressed = writer.buffer
79+
elif signature in (Signatures.SC, Signatures.ZSTD) and zstandard is not None:
7580
compressor = zstandard.ZstdCompressor()
7681
compressed = compressor.compress(data)
7782
else:
78-
raise TypeError('Unknown Signature!')
83+
raise TypeError("Unknown Signature!")
84+
85+
compressed = self._write_header(compressed, data, file_version, signature)
86+
87+
return compressed
7988

80-
super().__init__('big')
89+
@staticmethod
90+
def _write_header(
91+
compressed: bytes, data: bytes, file_version: int, signature: Signatures
92+
) -> bytes:
8193
if signature in (Signatures.SC, Signatures.SCLZ):
8294
data_hash = md5(data).digest()
8395

84-
self.write(b'SC')
85-
self.writeInt32(file_version)
96+
writer = Writer("big")
97+
writer.write(b"SC")
98+
writer.write_int32(file_version)
8699
if file_version == 4:
87-
self.writeInt32(1)
88-
self.writeInt32(len(data_hash))
89-
self.write(data_hash)
90-
compressed = self.buffer + compressed
100+
writer.write_int32(1)
101+
writer.write_int32(len(data_hash))
102+
writer.write(data_hash)
103+
return writer.buffer + compressed
91104
elif signature == Signatures.SIG:
92-
self.write(b'Sig:')
93-
self.write(b'\x00' * 64) # sha64
94-
compressed = self.buffer + compressed
105+
writer = Writer("big")
106+
writer.write(b"Sig:")
107+
writer.write(b"\x00" * 64) # sha64
108+
return writer.buffer + compressed
95109

96110
return compressed

0 commit comments

Comments
 (0)