hacktools 0.33.1__tar.gz → 0.35.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.35.0}/LICENSE +1 -1
- {hacktools-0.33.1/hacktools.egg-info → hacktools-0.35.0}/PKG-INFO +2 -2
- {hacktools-0.33.1 → hacktools-0.35.0}/README.md +1 -1
- hacktools-0.35.0/hacktools/__init__.py +1 -0
- hacktools-0.35.0/hacktools/c_ext/cmp_racjin.c +227 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/common.py +13 -3
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/nds.py +10 -4
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/psp.py +2 -2
- {hacktools-0.33.1 → hacktools-0.35.0/hacktools.egg-info}/PKG-INFO +2 -2
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools.egg-info/SOURCES.txt +1 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/setup.py +1 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/tests/test_cmp.py +8 -1
- hacktools-0.33.1/hacktools/__init__.py +0 -1
- {hacktools-0.33.1 → hacktools-0.35.0}/MANIFEST.in +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/arch.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/assets/icon.png +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/c_ext/cmp_cri.c +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/c_ext/cmp_lzss.c +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/c_ext/cmp_misc.c +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/c_ext/inc.h +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/compression.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/cpk.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/gb.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/gui.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/nasm.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/nitro.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/psx.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/wii.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools/ws.py +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools.egg-info/dependency_links.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools.egg-info/requires.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.35.0}/hacktools.egg-info/top_level.txt +0 -0
- {hacktools-0.33.1 → hacktools-0.35.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.35.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.35.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 * 2);
|
|
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
|
+
}
|
|
@@ -756,7 +756,7 @@ class TranslationFile:
|
|
|
756
756
|
note = ET.SubElement(unit, "note")
|
|
757
757
|
note.text = comment
|
|
758
758
|
|
|
759
|
-
def preloadLookup(self):
|
|
759
|
+
def preloadLookup(self, comments="#"):
|
|
760
760
|
self.lookup = {}
|
|
761
761
|
self.chartot = 0
|
|
762
762
|
self.transtot = 0
|
|
@@ -764,6 +764,8 @@ class TranslationFile:
|
|
|
764
764
|
for unit in self.files[file][0]:
|
|
765
765
|
self.chartot += len(unit[0].text)
|
|
766
766
|
if unit[1].text is not None and unit[1].text != "":
|
|
767
|
+
if comments in unit[1].text:
|
|
768
|
+
unit[1].text = unit[1].text.split(comments)[0]
|
|
767
769
|
self.lookup[unit[0].text] = unit[1].text
|
|
768
770
|
self.transtot += len(unit[0].text)
|
|
769
771
|
|
|
@@ -1030,7 +1032,7 @@ class BinaryPointer:
|
|
|
1030
1032
|
self.str = str
|
|
1031
1033
|
|
|
1032
1034
|
|
|
1033
|
-
def repackBinaryStrings(section, infile, outfile, binranges, freeranges=None, readfunc=detectEncodedString, writefunc=writeEncodedString, encoding="shift_jis", pointerstart=0, injectstart=0, fallbackf=None, injectfallback=0, sectionname="bin"):
|
|
1035
|
+
def repackBinaryStrings(section, infile, outfile, binranges, freeranges=None, readfunc=detectEncodedString, writefunc=writeEncodedString, encoding="shift_jis", pointerstart=0, injectstart=0, fallbackf=None, injectfallback=0, sectionname="bin", preformat=None, postformat=None):
|
|
1034
1036
|
insize = os.path.getsize(infile)
|
|
1035
1037
|
notfound = []
|
|
1036
1038
|
with Stream(infile, "rb") as fi:
|
|
@@ -1045,6 +1047,9 @@ def repackBinaryStrings(section, infile, outfile, binranges, freeranges=None, re
|
|
|
1045
1047
|
pos = fi.tell()
|
|
1046
1048
|
check = readfunc(fi, encoding)
|
|
1047
1049
|
if check != "":
|
|
1050
|
+
pre = post = ""
|
|
1051
|
+
if preformat != None:
|
|
1052
|
+
check, pre, post = preformat(check)
|
|
1048
1053
|
if isinstance(section, TranslationFile):
|
|
1049
1054
|
newsjis = section.getEntry(check, sectionname, pos)
|
|
1050
1055
|
else:
|
|
@@ -1055,6 +1060,8 @@ def repackBinaryStrings(section, infile, outfile, binranges, freeranges=None, re
|
|
|
1055
1060
|
if newsjis != "":
|
|
1056
1061
|
if newsjis == "!":
|
|
1057
1062
|
newsjis = ""
|
|
1063
|
+
if postformat != None:
|
|
1064
|
+
newsjis = postformat(newsjis, pre, post)
|
|
1058
1065
|
newsjislog = newsjis.encode("ascii", "ignore")
|
|
1059
1066
|
logDebug("Replacing string at", toHex(pos), "with", newsjislog)
|
|
1060
1067
|
fo.seek(pos)
|
|
@@ -1104,7 +1111,10 @@ def repackBinaryStrings(section, infile, outfile, binranges, freeranges=None, re
|
|
|
1104
1111
|
newpointer = range[0]
|
|
1105
1112
|
# For the injected range, add injectstart, otherwise add pointerstart
|
|
1106
1113
|
if (len(range) == 3):
|
|
1107
|
-
|
|
1114
|
+
if isinstance(range[2], bool):
|
|
1115
|
+
newpointer += injectstart
|
|
1116
|
+
else:
|
|
1117
|
+
newpointer += int(range[2])
|
|
1108
1118
|
else:
|
|
1109
1119
|
newpointer += pointerstart
|
|
1110
1120
|
range[0] = fo.tell()
|
|
@@ -134,7 +134,7 @@ def extractBIN(binrange, readfunc=common.detectEncodedString, encoding="shift_ji
|
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
def repackBIN(binrange, freeranges=[], readfunc=common.detectEncodedString, writefunc=common.writeEncodedString, encoding="shift_jis", comments="#",
|
|
137
|
-
binin="data/extract/arm9.bin", binout="data/repack/arm9.bin", binfile="data/bin_input.txt", fixchars=[], pointerstart=0x02000000, injectstart=0x02000000, fallbackf=None, injectfallback=0, nocopy=False, sectionname="bin"):
|
|
137
|
+
binin="data/extract/arm9.bin", binout="data/repack/arm9.bin", binfile="data/bin_input.txt", fixchars=[], pointerstart=0x02000000, injectstart=0x02000000, fallbackf=None, injectfallback=0, nocopy=False, sectionname="bin", preformat=None, postformat=None):
|
|
138
138
|
if not os.path.isfile(binfile):
|
|
139
139
|
common.logError("Input file", binfile, "not found")
|
|
140
140
|
return False
|
|
@@ -152,7 +152,7 @@ def repackBIN(binrange, freeranges=[], readfunc=common.detectEncodedString, writ
|
|
|
152
152
|
section.preloadLookup()
|
|
153
153
|
if type(binrange) == tuple:
|
|
154
154
|
binrange = [binrange]
|
|
155
|
-
notfound = common.repackBinaryStrings(section, binin, binout, binrange, freeranges, readfunc, writefunc, encoding, pointerstart, injectstart, fallbackf, injectfallback, sectionname)
|
|
155
|
+
notfound = common.repackBinaryStrings(section, binin, binout, binrange, freeranges, readfunc, writefunc, encoding, pointerstart, injectstart, fallbackf, injectfallback, sectionname, preformat, postformat)
|
|
156
156
|
for pointer in notfound:
|
|
157
157
|
common.logError("Pointer", common.toHex(pointer.old), "->", common.toHex(pointer.new), "not found for string", pointer.str)
|
|
158
158
|
if binfile.endswith(".txt"):
|
|
@@ -176,13 +176,17 @@ class BINSection:
|
|
|
176
176
|
self.data = bytearray(ramlen)
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
def expandBIN(binin, binout, headerin, headerout,
|
|
179
|
+
def expandBIN(binin, binout, headerin, headerout, newlengths, injectpos):
|
|
180
180
|
if not os.path.isfile(binin):
|
|
181
181
|
common.logError("Input file", binin, "not found")
|
|
182
182
|
return False
|
|
183
183
|
if not os.path.isfile(headerin):
|
|
184
184
|
common.logError("Header file", headerin, "not found")
|
|
185
185
|
return False
|
|
186
|
+
if not isinstance(newlengths, list):
|
|
187
|
+
newlengths = [newlengths]
|
|
188
|
+
if not isinstance(injectpos, list):
|
|
189
|
+
injectpos = [injectpos]
|
|
186
190
|
codesettings = -1
|
|
187
191
|
with common.Stream(headerin, "rb") as fin:
|
|
188
192
|
fin.seek(0x20)
|
|
@@ -225,13 +229,15 @@ def expandBIN(binin, binout, headerin, headerout, newlength, injectpos):
|
|
|
225
229
|
sections.append(BINSection(fin, start, size, datastart, bsssize))
|
|
226
230
|
datastart += size
|
|
227
231
|
# Write the new extended arm9.bin
|
|
228
|
-
|
|
232
|
+
for i in range(len(newlengths)):
|
|
233
|
+
sections.append(BINSection(None, injectpos[i], newlengths[i], 0, 0, True if i < len(newlengths) - 1 else False))
|
|
229
234
|
with common.Stream(binout, "wb") as f:
|
|
230
235
|
# Write the section data first
|
|
231
236
|
f.write(sections[0].data)
|
|
232
237
|
datastart = f.tell()
|
|
233
238
|
for i in range(1, len(sections)):
|
|
234
239
|
sections[i].offset = f.tell()
|
|
240
|
+
common.logDebug("Section", i, "offset:", common.toHex(f.tell()))
|
|
235
241
|
f.write(sections[i].data)
|
|
236
242
|
# Write the new copytable
|
|
237
243
|
copytablestart = f.tell()
|
|
@@ -31,7 +31,7 @@ def extractIso(isofile, extractfolder, workfolder="", fixfilename=False):
|
|
|
31
31
|
common.logMessage("Done!")
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def repackIso(isofile, isopatch, workfolder, patchfile=""):
|
|
34
|
+
def repackIso(isofile, isopatch, workfolder, patchfile="", fixfilename=False):
|
|
35
35
|
try:
|
|
36
36
|
import pycdlib
|
|
37
37
|
except ImportError:
|
|
@@ -45,7 +45,7 @@ def repackIso(isofile, isopatch, workfolder, patchfile=""):
|
|
|
45
45
|
for file in common.showProgress(files):
|
|
46
46
|
filelen = os.path.getsize(workfolder + file)
|
|
47
47
|
with open(workfolder + file, "rb") as f:
|
|
48
|
-
iso.modify_file_in_place(f, filelen, "/" + file)
|
|
48
|
+
iso.modify_file_in_place(f, filelen, "/" + file + (";1" if fixfilename and not file.endswith(".") else ""))
|
|
49
49
|
iso.close()
|
|
50
50
|
common.logMessage("Done!")
|
|
51
51
|
# Create xdelta patch
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hacktools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.35.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
|