hacktools 0.33.1__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.
- {hacktools-0.33.1 → hacktools-0.34.0}/LICENSE +1 -1
- {hacktools-0.33.1/hacktools.egg-info → hacktools-0.34.0}/PKG-INFO +2 -2
- {hacktools-0.33.1 → hacktools-0.34.0}/README.md +1 -1
- hacktools-0.34.0/hacktools/__init__.py +1 -0
- hacktools-0.34.0/hacktools/c_ext/cmp_racjin.c +227 -0
- {hacktools-0.33.1 → hacktools-0.34.0/hacktools.egg-info}/PKG-INFO +2 -2
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools.egg-info/SOURCES.txt +1 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/setup.py +1 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/tests/test_cmp.py +8 -1
- hacktools-0.33.1/hacktools/__init__.py +0 -1
- {hacktools-0.33.1 → hacktools-0.34.0}/MANIFEST.in +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/arch.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/assets/icon.png +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/c_ext/cmp_cri.c +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/c_ext/cmp_lzss.c +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/c_ext/cmp_misc.c +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/c_ext/inc.h +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/common.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/compression.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/cpk.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/gb.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/gui.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/nasm.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/nds.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/nitro.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/psp.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/psx.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/wii.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools/ws.py +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools.egg-info/dependency_links.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools.egg-info/requires.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/hacktools.egg-info/top_level.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.34.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hacktools
|
|
3
|
-
Version: 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
|
|
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
|
|
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
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hacktools
|
|
3
|
-
Version: 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
|
|
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
|
|
@@ -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.1"
|
|
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
|
|
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
|
|
File without changes
|