-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathslimscbindings.c
More file actions
89 lines (72 loc) · 2.44 KB
/
slimscbindings.c
File metadata and controls
89 lines (72 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
Python C extensions for Slim's Editor.
Checksum method copied from https://github.com/stiantoften/RC-checksum/
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
// Read a little endian unsigned int from a byte buffer
uint32_t readInt(const uint8_t *buffer, const uint32_t seek) {
return ((buffer[seek + 3u] & 0xFFu) << 24u
| (buffer[seek + 2u] & 0xFFu) << 16u
| (buffer[seek + 1u] & 0xFFu) << 8u
| (buffer[seek] & 0xFFu));
}
// Write a little endian unsigned int to a byte buffer
void writeInt(uint8_t *buffer, const uint32_t seek, const uint32_t value) {
buffer[seek] = value;
buffer[seek+1] = value >> 8;
buffer[seek+2] = value >> 16;
buffer[seek+3] = value >> 24;
}
static PyObject * slimscbindings_calculate_checksum(PyObject *self, PyObject *args)
{
PyByteArrayObject* data = NULL;
if (!PyArg_ParseTuple(args, "Y", &data)) {
return Py_None;
}
long filesize = PyByteArray_Size(data);
char* buffer = PyByteArray_AsString(data);
uint32_t pos = 0x08;
while (pos < filesize) {
uint32_t bytecount = readInt(buffer, pos);
uint32_t prevchecksum = readInt(buffer, pos + 4);
pos += 0x08;
uint32_t prevpos = pos;
// Exit if the section length seems incorrect
if (bytecount <= 0x20 || bytecount > 0xFFFF) {
return Py_None;
}
// Calculate checksum of the section
uint32_t checksum = 0x8320;
while (pos < prevpos + bytecount) {
checksum ^= ((buffer[pos++] & 0xFFu) << 8u);
for (int i = 0; i < 8; i++) {
checksum = checksum & 0x8000u ? (checksum << 1u) ^ 0x1F45u : checksum << 1u;
}
}
// The calculated checksum is 4 bytes, but the save only uses the lower 2
checksum &= 0xFFFFu;
// Write the new checksum
if (checksum != prevchecksum) {
writeInt(buffer, prevpos - 4, checksum);
}
}
return PyByteArray_FromStringAndSize(buffer, filesize);
}
static PyMethodDef SlimsCBindingsMethods[] = {
{"calculate_checksum",
slimscbindings_calculate_checksum,
METH_VARARGS,
"Calculate checksum for OG trilogy games."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef slimscbindings = {
PyModuleDef_HEAD_INIT,
"slimscbindings",
NULL,
-1,
SlimsCBindingsMethods
};
PyMODINIT_FUNC PyInit_slimscbindings(void) {
return PyModule_Create(&slimscbindings);
}