Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit a14bb65

Browse files
committed
2 parents 4178f97 + 80f14bc commit a14bb65

File tree

11 files changed

+43
-22
lines changed

11 files changed

+43
-22
lines changed

CriCodecsEx/crilayla.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ See also:
2222
#include <stdlib.h>
2323
#include <string.h>
2424

25+
unsigned fourCC(const char a, const char b, const char c, const char d) {
26+
return (a << 0) | (b << 8) | (c << 16) | (d << 24);
27+
};
28+
const unsigned CRILAYLA_LO = fourCC('C', 'R', 'I', 'L');
29+
const unsigned CRILAYLA_HI = fourCC('A', 'Y', 'L', 'A');
30+
const unsigned long long CRILAYLA_MAGIC = CRILAYLA_LO | (unsigned long long)CRILAYLA_HI << 32uLL;
31+
2532
struct crilayla_header{
2633
unsigned long long crilayla;
2734
unsigned int decompress_size;
@@ -186,7 +193,7 @@ unsigned int layla_comp(unsigned char *dest, int *destLen, unsigned char *src, i
186193
return 0; // Underflow
187194
*destLen = *destLen - m; dest += m;
188195
// CRIL AYLA srcLen-0x100 destLen
189-
int l[] = { 0x4c495243,0x414c5941,srcLen - 0x100,*destLen };
196+
int l[] = { (int)CRILAYLA_LO,(int)CRILAYLA_HI,srcLen - 0x100,*destLen };
190197
for (j = 0; j<4; j++)
191198
{
192199
for (i = 0; i<4; i++)
@@ -210,7 +217,7 @@ PyObject* CriLaylaDecompress(PyObject* self, PyObject* d){
210217
unsigned char *data = (unsigned char *)PyBytes_AsString(d);
211218
crilayla_header header = *(crilayla_header*)data;
212219

213-
if (header.crilayla != 0x414c59434152494cULL) {
220+
if (header.crilayla != CRILAYLA_MAGIC) {
214221
PyErr_SetString(PyExc_ValueError, "Invalid CRILAYLA header.");
215222
return NULL;
216223
}

PyCriCodecsEx/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.4"
1+
__version__ = "0.0.5"

PyCriCodecsEx/acb.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,17 @@ def awb(self) -> AWB:
197197
return AWB(awb_path.open('rb'))
198198

199199

200-
def get_waveforms(self) -> List[HCACodec | ADXCodec | Tuple[AcbEncodeTypes, int, int, int, bytes]]:
200+
def get_waveforms(self, **kwargs) -> List[HCACodec | ADXCodec | Tuple[AcbEncodeTypes, int, int, int, bytes]]:
201201
"""Returns a list of decoded waveforms.
202202
203203
Item may be a codec (if known), or a tuple of (Codec ID, Channel Count, Sample Count, Sample Rate, Raw data).
204+
205+
Additional keyword arguments are passed to the codec constructors. e.g. for encrypted HCA payloads,
206+
you may do the following:
207+
```python
208+
get_waveforms(key=..., subkey=...)
209+
```
210+
See also the respective docs (ADXCodec, HCACodec) for more details.
204211
"""
205212
CODEC_TABLE = {
206213
AcbEncodeTypes.ADX: ADXCodec,
@@ -213,7 +220,7 @@ def get_waveforms(self) -> List[HCACodec | ADXCodec | Tuple[AcbEncodeTypes, int,
213220
encode = AcbEncodeTypes(wav.EncodeType)
214221
codec = (CODEC_TABLE.get(encode, None))
215222
if codec:
216-
wavs.append(codec(awb.get_file_at(wav.MemoryAwbId)))
223+
wavs.append(codec(awb.get_file_at(wav.MemoryAwbId), **kwargs))
217224
else:
218225
wavs.append((encode, wav.NumChannels, wav.NumSamples, wav.SamplingRate, awb.get_file_at(wav.MemoryAwbId)))
219226
return wavs

PyCriCodecsEx/adx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __init__(self, stream: str | bytes, filename: str = "default.adx", bitdepth:
5757
5858
Args:
5959
stream (str | bytes): Path to the ADX or WAV file, or a BinaryIO stream. WAV files will be automatically encoded with the given settings first.
60-
filename (str, optional): Output filename. Defaults to "default.adx".
60+
filename (str, optional): Filename, used by USMBuilder. Defaults to "default.adx".
6161
bitdepth (int, optional): Audio bit depth within [2,15]. Defaults to 4.
6262
"""
6363
if type(stream) == str:

PyCriCodecsEx/hca.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def __init__(self, stream: str | bytes, filename: str = "default.hca", quality:
332332
333333
Args:
334334
stream (str | bytes): Path to the HCA or WAV file, or a BinaryIO stream. WAV files will be automatically encoded with the given settings first.
335-
filename (str, optional): USM filename. Defaults to "default.hca".
335+
filename (str, optional): Filename, used by USMBuilder. Defaults to "default.hca".
336336
quality (CriHcaQuality, optional): Encoding quality. Defaults to CriHcaQuality.High.
337337
key (int, optional): HCA key. Defaults to 0.
338338
subkey (int, optional): HCA subkey. Defaults to 0.

PyCriCodecsEx/usm.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@
1313
import tempfile
1414

1515
# Big thanks and credit for k0lb3 and 9th helping me write this specific code.
16-
# Also credit for the original C++ code from Nyagamon/bnnm.
17-
18-
# Apparently there is an older USM format called SofDec? This is for SofDec2 though.
19-
# Extraction working only for now, although check https://github.com/donmai-me/WannaCRI/
20-
# code for a complete breakdown of the USM format.
16+
# Also credit for the original C++ code from Nyagamon/bnnm and https://github.com/donmai-me/WannaCRI/
2117

2218
class USMCrypt:
2319
"""USM related crypto functions"""

Tests/CPK/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ default.cpk
77
88
└───subdir
99
niko-512.png
10-
```
10+
```
11+
### compressed.cpk
12+
```
13+
compressed.cpk
14+
niko.png
15+
```

Tests/CPK/compressed.cpk

10.1 KB
Binary file not shown.

Tests/test_CPK.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
from . import sample_file_path, temp_file_path
33
from PyCriCodecsEx.cpk import CPK, CPKBuilder
44

5-
def test_cpk_unpack():
5+
def cpk_unpack(fname):
66
# Extract CPK content
77
cpkdir = temp_file_path('cpk')
8-
cpk = CPK(sample_file_path('CPK/default.cpk'))
8+
cpk = CPK(sample_file_path(fname))
99
for f in cpk.files:
1010
dst = os.path.join(cpkdir, f.path)
1111
os.makedirs(os.path.dirname(dst), exist_ok=True)
@@ -29,5 +29,12 @@ def progress_callback(stage: str, current: int, total: int):
2929
cpk.save(temp_file_path('rebuild.cpk'))
3030
print('Repack done.')
3131

32+
def test_cpk_regular():
33+
cpk_unpack('CPK/default.cpk')
34+
35+
def test_cpk_compressed():
36+
cpk_unpack('CPK/compressed.cpk')
37+
3238
if __name__ == "__main__":
33-
test_cpk_unpack()
39+
test_cpk_regular()
40+
test_cpk_compressed()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# TODO: Fix CRILAYLA Compression
2+
# Decompression is tested in test_CPK.py
13
import os
24
from . import sample_file_path, temp_file_path
35
from CriCodecsEx import CriLaylaCompress, CriLaylaDecompress

0 commit comments

Comments
 (0)