1- /*
2- CRI layla decompression.
3- written by tpu. (https://forum.xentax.com/viewtopic.php?f=21&t=5137&p=44220&hilit=CRILAYLA#p44220)
4- Python wrapper by me (and modification).
1+ /* CRILAYLA Encoder/Decoder
52
6- CRIcompress method by KenTse
7- Taken from wmltogether's fork of CriPakTools.
8- Python wrapper by me.
93
10- Note: I have no idea how this compression technique works. I just made the wrapper.
4+ CRI layla decompression.
5+ written by tpu. (https://forum.xentax.com/viewtopic.php?f=21&t=5137&p=44220&hilit=CRILAYLA#p44220)
6+ Python wrapper by https://github.com/Youjose/PyCriCodecs (and modification).
7+
8+ CRIcompress method by KenTse
9+ Taken from wmltogether's fork of CriPakTools.
10+ Python wrapper by https://github.com/Youjose/PyCriCodecs.
11+ TODO: This implementation may produce larger output - which shouldn't be
12+ possible with LZ-based compression. Investigate and fix.
13+ For now, if compression fails, the original data is returned.
14+ See also:
15+ - https://github.com/FanTranslatorsInternational/Kuriimu2/blob/imgui/src/lib/Kompression/Encoder/CrilaylaEncoder.cs
16+ - https://glinscott.github.io/lz/index.html
1117*/
1218#define PY_SSIZE_T_CLEAN
1319#pragma once
@@ -22,32 +28,30 @@ struct crilayla_header{
2228 unsigned int compressed_size;
2329};
2430
25-
26- unsigned char *sbuf;
27- unsigned int bitcnt;
28- unsigned int bitdat;
29- unsigned int get_bits (unsigned int n){
30- unsigned int data, mask;
31-
32- if (bitcnt<n){
33- data = ((24 -bitcnt)>>3 )+1 ;
34- bitcnt += data*8 ;
35- while (data) {
36- bitdat = (bitdat<<8 ) | (*sbuf--);
37- data--;
38- }
39- }
40-
41- data = bitdat>>(bitcnt-n);
42- bitcnt -= n;
43- mask = (1 <<n)-1 ;
44- data &= mask;
45- return data;
46- }
47-
4831unsigned int llcp_dec (unsigned char *src, unsigned int src_len, unsigned char *dst, unsigned int dst_len){
49- unsigned char *dbuf, *pbuf;
32+ unsigned char *dbuf, *pbuf;
5033 unsigned int plen, poffset, byte;
34+ unsigned char *sbuf;
35+ unsigned int bitcnt;
36+ unsigned int bitdat;
37+ auto get_bits = [&](unsigned int n){
38+ unsigned int data, mask;
39+
40+ if (bitcnt<n){
41+ data = ((24 -bitcnt)>>3 )+1 ;
42+ bitcnt += data*8 ;
43+ while (data) {
44+ bitdat = (bitdat<<8 ) | (*sbuf--);
45+ data--;
46+ }
47+ }
48+
49+ data = bitdat>>(bitcnt-n);
50+ bitcnt -= n;
51+ mask = (1 <<n)-1 ;
52+ data &= mask;
53+ return data;
54+ };
5155
5256 sbuf = src+src_len-1 ;
5357 dbuf = dst+dst_len-1 ;
@@ -108,40 +112,41 @@ unsigned char* layla_decomp(unsigned char* data, crilayla_header header){
108112 return dst;
109113}
110114
111- unsigned int layla_comp (unsigned char * dest, unsigned int * destLen, unsigned char * src, unsigned int srcLen){
112- unsigned int n = srcLen - 1 , m = *destLen - 0x1 , T = 0 , d = 0 , p, q, i, j, k;
113- unsigned char * odest = dest;
115+ unsigned int layla_comp (unsigned char *dest, int *destLen, unsigned char *src, int srcLen)
116+ {
117+ int n = srcLen - 1 , m = *destLen - 0x1 , T = 0 , d = 0 , p, q, i, j, k;
118+ unsigned char *odest = dest;
114119 for (; n >= 0x100 ;)
115120 {
116121 j = n + 3 + 0x2000 ;
117- if (j > srcLen) j = srcLen;
118- for (i = n + 3 , p = 0 ; i < j; i++)
122+ if (j> srcLen) j = srcLen;
123+ for (i = n + 3 , p = 0 ; i< j; i++)
119124 {
120125 for (k = 0 ; k <= n - 0x100 ; k++)
121126 {
122127 if (*(src + n - k) != *(src + i - k)) break ;
123128 }
124- if (k > p)
129+ if (k> p)
125130 {
126131 q = i - n - 3 ; p = k;
127132 }
128133 }
129- if (p < 3 )
134+ if (p< 3 )
130135 {
131136 d = (d << 9 ) | (*(src + n--)); T += 9 ;
132137 }
133138 else
134139 {
135140 d = (((d << 1 ) | 1 ) << 13 ) | q; T += 14 ; n -= p;
136- if (p < 6 )
141+ if (p< 6 )
137142 {
138143 d = (d << 2 ) | (p - 3 ); T += 2 ;
139144 }
140- else if (p < 13 )
145+ else if (p< 13 )
141146 {
142147 d = (((d << 2 ) | 3 ) << 3 ) | (p - 6 ); T += 5 ;
143148 }
144- else if (p < 44 )
149+ else if (p< 44 )
145150 {
146151 d = (((d << 5 ) | 0x1f ) << 5 ) | (p - 13 ); T += 10 ;
147152 }
@@ -150,45 +155,50 @@ unsigned int layla_comp(unsigned char* dest, unsigned int* destLen, unsigned cha
150155 d = ((d << 10 ) | 0x3ff ); T += 10 ; p -= 44 ;
151156 for (;;)
152157 {
153- for (; T >= 8 ;)
158+ for (; m > 0 && T >= 8 ;)
154159 {
155- *(dest + m--) = (d >> (T - 8 )) & 0xff ; T -= 8 ; d = d & ((1 << T) - 1 );
160+ *(dest + m--) = (d >> (T - 8 )) & 0xff ; T -= 8 ; d = d& ((1 << T) - 1 );
156161 }
157- if (p < 255 ) break ;
162+ if (p< 255 ) break ;
158163 d = (d << 8 ) | 0xff ; T += 8 ; p = p - 0xff ;
159164 }
160165 d = (d << 8 ) | p; T += 8 ;
161166 }
162167 }
163- for (; T >= 8 ;)
168+ for (; m > 0 && T >= 8 ;)
164169 {
165- *(dest + m--) = (d >> (T - 8 )) & 0xff ; T -= 8 ; d = d & ((1 << T) - 1 );
170+ *(dest + m--) = (d >> (T - 8 )) & 0xff ; T -= 8 ; d = d& ((1 << T) - 1 );
166171 }
167172 }
168- if (T != 0 )
173+ if (m > 0 && T != 0 )
169174 {
170175 *(dest + m--) = d << (8 - T);
171176 }
172- *(dest + m--) = 0 ; *(dest + m) = 0 ;
173- for (;;)
174- {
175- if (((*destLen - m) & 3 ) == 0 ) break ;
176- *(dest + m--) = 0 ;
177+ if (m > 0 ) {
178+ *(dest + m--) = 0 ; *(dest + m) = 0 ;
179+ for (;;)
180+ {
181+ if (((*destLen - m) & 3 ) == 0 ) break ;
182+ *(dest + m--) = 0 ;
183+ }
177184 }
185+ if (m <= 0 )
186+ return 0 ; // Underflow
178187 *destLen = *destLen - m; dest += m;
179- unsigned int l[] = { 0x4c495243 ,0x414c5941 ,srcLen - 0x100 ,*destLen };
180- for (j = 0 ; j < 4 ; j++)
188+ // CRIL AYLA srcLen-0x100 destLen
189+ int l[] = { 0x4c495243 ,0x414c5941 ,srcLen - 0x100 ,*destLen };
190+ for (j = 0 ; j<4 ; j++)
181191 {
182- for (i = 0 ; i < 4 ; i++)
192+ for (i = 0 ; i< 4 ; i++)
183193 {
184194 *(odest + i + j * 4 ) = l[j] & 0xff ; l[j] >>= 8 ;
185195 }
186196 }
187- for (j = 0 , odest += 0x10 ; j < *destLen; j++)
197+ for (j = 0 , odest += 0x10 ; j< *destLen; j++)
188198 {
189199 *(odest++) = *(dest + j);
190200 }
191- for (j = 0 ; j < 0x100 ; j++)
201+ for (j = 0 ; j< 0x100 ; j++)
192202 {
193203 *(odest++) = *(src + j);
194204 }
@@ -200,6 +210,11 @@ PyObject* CriLaylaDecompress(PyObject* self, PyObject* d){
200210 unsigned char *data = (unsigned char *)PyBytes_AsString (d);
201211 crilayla_header header = *(crilayla_header*)data;
202212
213+ if (header.crilayla != 0x414c59434152494cULL ) {
214+ PyErr_SetString (PyExc_ValueError, " Invalid CRILAYLA header." );
215+ return NULL ;
216+ }
217+
203218 unsigned char *out;
204219 Py_BEGIN_ALLOW_THREADS
205220 out = layla_decomp ((data+16 ), header);
@@ -218,18 +233,26 @@ unsigned char* CriLaylaDecompress(unsigned char* d){
218233
219234PyObject* CriLaylaCompress (PyObject* self, PyObject* args){
220235 unsigned char *data;
221- unsigned int data_size;
236+ Py_ssize_t data_size;
222237 if (!PyArg_ParseTuple (args, " y#" , &data, &data_size)){
223238 return NULL ;
224239 }
225- unsigned char *buf = new unsigned char [data_size];
226- memset (buf, 0 , data_size);
227240
241+ unsigned char *buf = new unsigned char [data_size + 0x200 ];
242+
243+ int compressed_size = data_size;
244+ int res = 0 ;
228245 Py_BEGIN_ALLOW_THREADS
229- layla_comp (buf, &data_size , data, data_size );
246+ res = layla_comp (buf, &compressed_size , data, compressed_size );
230247 Py_END_ALLOW_THREADS
231-
232- PyObject* bufObj = Py_BuildValue (" y#" , buf, data_size);
248+ PyObject* bufObj;
249+ if (res && res < data_size) {
250+ bufObj = Py_BuildValue (" y#" , buf, compressed_size);
251+ } else {
252+ // FIXME
253+ PyErr_SetString (PyExc_RuntimeError, " Compression failure." );
254+ return NULL ;
255+ }
233256 delete[] buf;
234257 return bufObj;
235258}
0 commit comments