hacktools 0.33.0__tar.gz → 0.34.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {hacktools-0.33.0 → hacktools-0.34.0}/LICENSE +1 -1
  2. {hacktools-0.33.0/hacktools.egg-info → hacktools-0.34.0}/PKG-INFO +2 -2
  3. {hacktools-0.33.0 → hacktools-0.34.0}/README.md +1 -1
  4. hacktools-0.34.0/hacktools/__init__.py +1 -0
  5. hacktools-0.34.0/hacktools/c_ext/cmp_racjin.c +227 -0
  6. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/common.py +4 -2
  7. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/psp.py +5 -2
  8. {hacktools-0.33.0 → hacktools-0.34.0/hacktools.egg-info}/PKG-INFO +2 -2
  9. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools.egg-info/SOURCES.txt +1 -0
  10. {hacktools-0.33.0 → hacktools-0.34.0}/setup.py +1 -0
  11. {hacktools-0.33.0 → hacktools-0.34.0}/tests/test_cmp.py +8 -1
  12. hacktools-0.33.0/hacktools/__init__.py +0 -1
  13. {hacktools-0.33.0 → hacktools-0.34.0}/MANIFEST.in +0 -0
  14. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/arch.py +0 -0
  15. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/assets/icon.png +0 -0
  16. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/c_ext/cmp_cri.c +0 -0
  17. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/c_ext/cmp_lzss.c +0 -0
  18. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/c_ext/cmp_misc.c +0 -0
  19. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/c_ext/inc.h +0 -0
  20. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/compression.py +0 -0
  21. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/cpk.py +0 -0
  22. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/gb.py +0 -0
  23. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/gui.py +0 -0
  24. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/nasm.py +0 -0
  25. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/nds.py +0 -0
  26. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/nitro.py +0 -0
  27. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/psx.py +0 -0
  28. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/wii.py +0 -0
  29. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools/ws.py +0 -0
  30. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools.egg-info/dependency_links.txt +0 -0
  31. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools.egg-info/requires.txt +0 -0
  32. {hacktools-0.33.0 → hacktools-0.34.0}/hacktools.egg-info/top_level.txt +0 -0
  33. {hacktools-0.33.0 → hacktools-0.34.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020-2023 Illidan
3
+ Copyright (c) 2020-2024 Illidan
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hacktools
3
- Version: 0.33.0
3
+ Version: 0.34.0
4
4
  Summary: A set of utilities and tools for rom hacking and translations.
5
5
  Home-page: https://github.com/Illidanz/hacktools
6
6
  Author: Illidan
@@ -96,7 +96,7 @@ External dependencies not included are marked as `(through *dependency*)`
96
96
  ### Other / Generic
97
97
  - CPK archives
98
98
  - ARCH archives
99
- - LZ10, LZ11, Huffman and CRILAYLA compression/decompression
99
+ - LZ10, LZ11, Huffman, CRILAYLA and RACJIN compression/decompression
100
100
  - ARM/MIPS binary patching
101
101
  - xdelta patch creation
102
102
  - IPS patch creation
@@ -47,7 +47,7 @@ External dependencies not included are marked as `(through *dependency*)`
47
47
  ### Other / Generic
48
48
  - CPK archives
49
49
  - ARCH archives
50
- - LZ10, LZ11, Huffman and CRILAYLA compression/decompression
50
+ - LZ10, LZ11, Huffman, CRILAYLA and RACJIN compression/decompression
51
51
  - ARM/MIPS binary patching
52
52
  - xdelta patch creation
53
53
  - IPS patch creation
@@ -0,0 +1 @@
1
+ __version__ = "0.34.0"
@@ -0,0 +1,227 @@
1
+ #include "inc.h"
2
+
3
+ // https://github.com/Raw-man/Racjin-de-compression/blob/master/src/encode.cpp
4
+ static PyObject* compressRACJIN(PyObject* module, PyObject* args, PyObject* kwargs)
5
+ {
6
+ static char *kwlist[] = { "indata", NULL };
7
+
8
+ unsigned char* src;
9
+ size_t srclen;
10
+
11
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#", kwlist, &src, &srclen))
12
+ return NULL;
13
+
14
+ unsigned char* compressed_buffer = PyMem_Malloc(srclen);
15
+ MALLOC_CHECK(compressed_buffer);
16
+ unsigned int destlen = 0;
17
+
18
+ unsigned int index = 0; //position of an element from the input buffer
19
+ unsigned char last_enc_byte = 0;//last encoded byte
20
+ unsigned char bit_shift = 0; //shift by bitShift (used to fold codes)
21
+ unsigned char* frequencies = PyMem_Calloc(256, sizeof(unsigned char));
22
+ MALLOC_CHECK(frequencies);
23
+ for (int i = 0; i < 256; ++i)
24
+ frequencies[i] = 0;
25
+ unsigned int* seq_indices = PyMem_Calloc(8192, sizeof(unsigned int));
26
+ MALLOC_CHECK(seq_indices);
27
+ for (int i = 0; i < 8192; ++i)
28
+ seq_indices[i] = 0;
29
+ unsigned short* codes = PyMem_Calloc(srclen, sizeof(unsigned short));
30
+ MALLOC_CHECK(codes);
31
+ for (int i = 0; i < srclen; ++i)
32
+ codes[i] = 0;
33
+ unsigned int codeslen = 0;
34
+
35
+ while (index < srclen)
36
+ {
37
+ unsigned char best_freq = 0;
38
+ unsigned char best_match = 0;
39
+
40
+ // To get the exact same compression for CDDATA.DIG files uncomment the following:
41
+ if (frequencies[last_enc_byte] == 256)
42
+ frequencies[last_enc_byte] = 0x00;
43
+
44
+ unsigned char positions_to_check = frequencies[last_enc_byte] < 32 ? (frequencies[last_enc_byte] & 0x1F) : 32;
45
+ unsigned int seq_index = index;
46
+
47
+ for (unsigned char freq = 0; freq < positions_to_check; freq++)
48
+ {
49
+ unsigned short key = freq + last_enc_byte * 32; //0x1F + 0xFF*32 = 8191
50
+ unsigned int src_index = seq_indices[key];
51
+ unsigned char matched = 0;
52
+ unsigned char max_length = index + 8 < srclen ? 8 : srclen - index;
53
+
54
+ for (unsigned char offset = 0; offset < max_length; ++offset)
55
+ {
56
+ if (src[src_index + offset] == src[index + offset])
57
+ ++matched;
58
+ else
59
+ break;
60
+ }
61
+
62
+ if (matched > best_match)
63
+ {
64
+ best_freq = freq;
65
+ best_match = matched;
66
+ }
67
+ }
68
+
69
+ unsigned short code = 0x00;
70
+ if (best_match > 0) //found a better match?
71
+ {
72
+ code = code | (best_freq << 3); //f|ooooolll //f=0 (flag), o - occurrences/frequency, l -length
73
+ code = code | (best_match - 1); //encode a reference
74
+ index += best_match;
75
+ }
76
+ else //encode byte literal
77
+ {
78
+ code = 0x100 | src[index]; //f|bbbbbbbb //f=1
79
+ ++index;
80
+ }
81
+
82
+ code = code << bit_shift; //prepare for folding
83
+ codes[codeslen] = code;
84
+ codeslen++;
85
+
86
+ ++bit_shift;
87
+ if (bit_shift == 8)
88
+ bit_shift = 0;
89
+
90
+ unsigned int key = (frequencies[last_enc_byte] & 0x1F) + last_enc_byte * 32; //0x1F + 0xFF*32 = 8191
91
+ seq_indices[key] = seq_index;
92
+ frequencies[last_enc_byte] = frequencies[last_enc_byte] + 1; //increase by 1 (up to 31)
93
+ last_enc_byte = src[index - 1];
94
+ }
95
+ //Fold codes (8 codes, 16 bytes -> 8 codes, 9 bytes)
96
+ for (unsigned int i = 0; i < codeslen; i = i + 8)
97
+ {
98
+ unsigned char group_size = i + 8 < codeslen ? 8 : codeslen - i;
99
+ for (unsigned char s = 0; s <= group_size; s += 2)
100
+ {
101
+ unsigned short first = s > 0 ? codes[s + i - 1] : 0x00;
102
+ unsigned short middle = s < group_size ? codes[s + i] : 0x00;
103
+ unsigned short last = s < group_size - 1 ? codes[s + i + 1] : 0x00;
104
+ unsigned short result = middle | (first >> 8) | (last << 8);
105
+ compressed_buffer[destlen] = result & 0xFF;
106
+ ++destlen;
107
+ if (s < group_size)
108
+ {
109
+ compressed_buffer[destlen] = result >> 8;
110
+ ++destlen;
111
+ }
112
+ }
113
+ }
114
+
115
+ PyObject *output = PyBytes_FromStringAndSize(compressed_buffer, destlen);
116
+ PyMem_Free(compressed_buffer);
117
+ PyMem_Free(frequencies);
118
+ PyMem_Free(seq_indices);
119
+ PyMem_Free(codes);
120
+ return output;
121
+ }
122
+
123
+ // https://github.com/Raw-man/Racjin-de-compression/blob/master/src/decode.cpp
124
+ static PyObject* decompressRACJIN(PyObject* m, PyObject* args, PyObject* kwargs)
125
+ {
126
+ static char *kwlist[] = { "indata", "decomplength", NULL };
127
+
128
+ unsigned char* input_buffer;
129
+ size_t input_size;
130
+ unsigned int decomplength;
131
+
132
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#I", kwlist, &input_buffer, &input_size, &decomplength))
133
+ return NULL;
134
+
135
+ unsigned int index = 0; //position of a byte from the input buffer
136
+ unsigned int dest_index = 0; //position (destination) of a decoded byte in the output buffer
137
+ unsigned char last_dec_byte = 0; //last decoded byte of the previus decoding iteration
138
+ unsigned char bit_shift = 0; //shift right by bitShift
139
+
140
+ // Allocate buffers
141
+ unsigned char* frequencies = PyMem_Malloc(256);
142
+ MALLOC_CHECK(frequencies);
143
+ for (int i = 0; i < 256; ++i)
144
+ frequencies[i] = 0;
145
+ unsigned int* seq_indices = PyMem_Calloc(8192, sizeof(unsigned int));
146
+ MALLOC_CHECK(seq_indices);
147
+ for (int i = 0; i < 8192; ++i)
148
+ seq_indices[i] = 0;
149
+ unsigned char* decompressed_buffer = PyMem_Malloc(decomplength);
150
+ MALLOC_CHECK(decompressed_buffer);
151
+
152
+ while (index < input_size)
153
+ {
154
+ unsigned short next_code = input_buffer[index + 1]; //next pair of bytes to decode from the input buffer
155
+ next_code = next_code << 8;
156
+ next_code = next_code | input_buffer[index];
157
+ next_code = next_code >> bit_shift; //unfold 9 bit token
158
+
159
+ //The result can be interpreted as follows:
160
+ // iiiiiiif|ooooolll //f=0
161
+ // iiiiiiif|bbbbbbbb //f=1
162
+ //i - ignore
163
+ //f - flag (is literal or offset/length pair)
164
+ //l - length (add 1 to get the real length)
165
+ //o - occurrences/frequency
166
+ //b - byte literal
167
+
168
+ ++bit_shift;
169
+ ++index;
170
+
171
+ if (bit_shift == 8)
172
+ {
173
+ bit_shift = 0;
174
+ ++index;
175
+ }
176
+
177
+ unsigned int seq_index = dest_index; //start of a byte sequence
178
+ if ((next_code & 0x100) != 0) // bit flag: is nextToken a literal or a reference?
179
+ {
180
+ decompressed_buffer[dest_index] = (unsigned char)(next_code & 0xFF); //store the literal
181
+ ++dest_index;
182
+ }
183
+ else
184
+ {
185
+ unsigned int key = ((next_code >> 3) & 0x1F) + last_dec_byte * 32; //0x1F + 0xFF*32 = 8191
186
+ unsigned int src_index = seq_indices[key]; //get a reference to a previously decoded sequence
187
+
188
+ for (unsigned char length = 0; length < (next_code & 0x07) + 1; ++length, ++dest_index, ++src_index)
189
+ {
190
+ decompressed_buffer[dest_index] = decompressed_buffer[src_index]; //copy a previously decoded byte sequence (up to 8)
191
+ }
192
+ }
193
+
194
+ if (dest_index >= decomplength)
195
+ break;
196
+
197
+ unsigned int key = frequencies[last_dec_byte] + last_dec_byte * 32; //0x1F + 0xFF*32 = 8191
198
+ seq_indices[key] = seq_index;
199
+ frequencies[last_dec_byte] = (unsigned char)((frequencies[last_dec_byte] + 1) & 0x1F); //increase by 1 (up to 31)
200
+ last_dec_byte = decompressed_buffer[dest_index - 1];
201
+ }
202
+
203
+ PyObject *output = PyBytes_FromStringAndSize(decompressed_buffer, decomplength);
204
+ PyMem_Free(frequencies);
205
+ PyMem_Free(seq_indices);
206
+ PyMem_Free(decompressed_buffer);
207
+ return output;
208
+ }
209
+
210
+ static PyMethodDef Cmp_racjinMethods[] = {
211
+ {"compressRACJIN", (PyCFunction)compressRACJIN, METH_VARARGS | METH_KEYWORDS, "Compress RACJIN data."},
212
+ {"decompressRACJIN", (PyCFunction)decompressRACJIN, METH_VARARGS | METH_KEYWORDS, "Decompress RACJIN data."},
213
+ {NULL, NULL, 0, NULL}
214
+ };
215
+
216
+ static struct PyModuleDef cmp_racjinmodule = {
217
+ PyModuleDef_HEAD_INIT,
218
+ "cmp_racjin",
219
+ "RACJIN functions.",
220
+ -1,
221
+ Cmp_racjinMethods
222
+ };
223
+
224
+ PyMODINIT_FUNC PyInit_cmp_racjin(void)
225
+ {
226
+ return PyModule_Create(&cmp_racjinmodule);
227
+ }
@@ -193,12 +193,14 @@ class Stream(object):
193
193
  self.seek(current)
194
194
  return ret
195
195
 
196
- def readHalf(self):
196
+ def readHalf(self, big=False):
197
197
  if self.half is None:
198
198
  self.half = self.readByte()
199
+ if big:
200
+ return self.half >> 4
199
201
  return self.half & 0x0f
200
202
  else:
201
- ret = self.half >> 4
203
+ ret = self.half >> 4 if not big else self.half & 0x0f
202
204
  self.half = None
203
205
  return ret
204
206
 
@@ -7,7 +7,7 @@ import struct
7
7
  from hacktools import common
8
8
 
9
9
 
10
- def extractIso(isofile, extractfolder, workfolder=""):
10
+ def extractIso(isofile, extractfolder, workfolder="", fixfilename=False):
11
11
  try:
12
12
  import pycdlib
13
13
  except ImportError:
@@ -20,7 +20,10 @@ def extractIso(isofile, extractfolder, workfolder=""):
20
20
  for dirname, dirlist, filelist in iso.walk(iso_path="/"):
21
21
  common.makeFolders(extractfolder + dirname[1:])
22
22
  for file in filelist:
23
- with open(extractfolder + dirname[1:] + "/" + file, "wb") as f:
23
+ extractname = file
24
+ if fixfilename:
25
+ extractname = extractname.replace(";1", "")
26
+ with open(extractfolder + dirname[1:] + "/" + extractname, "wb") as f:
24
27
  iso.get_file_from_iso_fp(f, iso_path=dirname + "/" + file)
25
28
  iso.close()
26
29
  if workfolder != "":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hacktools
3
- Version: 0.33.0
3
+ Version: 0.34.0
4
4
  Summary: A set of utilities and tools for rom hacking and translations.
5
5
  Home-page: https://github.com/Illidanz/hacktools
6
6
  Author: Illidan
@@ -96,7 +96,7 @@ External dependencies not included are marked as `(through *dependency*)`
96
96
  ### Other / Generic
97
97
  - CPK archives
98
98
  - ARCH archives
99
- - LZ10, LZ11, Huffman and CRILAYLA compression/decompression
99
+ - LZ10, LZ11, Huffman, CRILAYLA and RACJIN compression/decompression
100
100
  - ARM/MIPS binary patching
101
101
  - xdelta patch creation
102
102
  - IPS patch creation
@@ -25,5 +25,6 @@ hacktools/assets/icon.png
25
25
  hacktools/c_ext/cmp_cri.c
26
26
  hacktools/c_ext/cmp_lzss.c
27
27
  hacktools/c_ext/cmp_misc.c
28
+ hacktools/c_ext/cmp_racjin.c
28
29
  hacktools/c_ext/inc.h
29
30
  tests/test_cmp.py
@@ -41,6 +41,7 @@ setup(
41
41
  Extension("hacktools.cmp_lzss", sources=["hacktools/c_ext/cmp_lzss.c"]),
42
42
  Extension("hacktools.cmp_cri", sources=["hacktools/c_ext/cmp_cri.c"]),
43
43
  Extension("hacktools.cmp_misc", sources=["hacktools/c_ext/cmp_misc.c"]),
44
+ Extension("hacktools.cmp_racjin", sources=["hacktools/c_ext/cmp_racjin.c"]),
44
45
  ],
45
46
  classifiers=[
46
47
  "Programming Language :: Python :: 3.7",
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
  import os.path
3
- from hacktools import cmp_lzss, cmp_cri
3
+ from hacktools import cmp_lzss, cmp_cri, cmp_racjin
4
4
 
5
5
  @pytest.fixture
6
6
  def data():
@@ -28,3 +28,10 @@ def test_cmp_cri(data):
28
28
  decmp = cmp_cri.decompressCRILAYLA(cmp)
29
29
  assert len(data) == len(decmp)
30
30
  assert data == decmp
31
+
32
+
33
+ def test_cmp_racjin(data):
34
+ cmp = cmp_racjin.compressRACJIN(data)
35
+ decmp = cmp_racjin.decompressRACJIN(cmp, len(data))
36
+ assert len(data) == len(decmp)
37
+ assert data == decmp
@@ -1 +0,0 @@
1
- __version__ = "0.33.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes