diff --git a/src/coding/coding.h b/src/coding/coding.h
index 3d05f987..32fea8f3 100644
--- a/src/coding/coding.h
+++ b/src/coding/coding.h
@@ -324,9 +324,21 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_hca(hca_codec_data* data);
void loop_hca(hca_codec_data* data, int32_t num_sample);
void free_hca(hca_codec_data* data);
-int test_hca_key(hca_codec_data* data, unsigned long long keycode);
-void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode);
clHCA_stInfo* hca_get_info(hca_codec_data* data);
+
+typedef struct {
+ /* config + output */
+ uint64_t key;
+ uint16_t subkey;
+ uint64_t best_key;
+ int best_score;
+ /* internals */
+ uint32_t start_offset;
+} hca_keytest_t;
+
+void test_hca_key(hca_codec_data* data, hca_keytest_t* hk);
+void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode);
+
STREAMFILE* hca_get_streamfile(hca_codec_data* data);
diff --git a/src/coding/hca_decoder.c b/src/coding/hca_decoder.c
index d4183b62..1f1de3a5 100644
--- a/src/coding/hca_decoder.c
+++ b/src/coding/hca_decoder.c
@@ -3,7 +3,7 @@
struct hca_codec_data {
- STREAMFILE* streamfile;
+ STREAMFILE* sf;
clHCA_stInfo info;
signed short* sample_buffer;
@@ -58,8 +58,8 @@ hca_codec_data* init_hca(STREAMFILE* sf) {
if (!data->sample_buffer) goto fail;
/* load streamfile for reads */
- data->streamfile = reopen_streamfile(sf, 0);
- if (!data->streamfile) goto fail;
+ data->sf = reopen_streamfile(sf, 0);
+ if (!data->sf) goto fail;
/* set initial values */
reset_hca(data);
@@ -115,7 +115,7 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
}
/* read frame */
- bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile);
+ bytes = read_streamfile(data->data_buffer, offset, blockSize, data->sf);
if (bytes != blockSize) {
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset);
break;
@@ -171,7 +171,7 @@ void loop_hca(hca_codec_data* data, int32_t num_sample) {
void free_hca(hca_codec_data* data) {
if (!data) return;
- close_streamfile(data->streamfile);
+ close_streamfile(data->sf);
clHCA_done(data->handle);
free(data->handle);
free(data->data_buffer);
@@ -179,6 +179,14 @@ void free_hca(hca_codec_data* data) {
free(data);
}
+clHCA_stInfo* hca_get_info(hca_codec_data* data) {
+ return &data->info;
+}
+
+STREAMFILE* hca_get_streamfile(hca_codec_data* data) {
+ if (!data) return NULL;
+ return data->sf;
+}
/* ************************************************************************* */
@@ -192,19 +200,25 @@ void free_hca(hca_codec_data* data) {
/* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */
#define HCA_KEY_MAX_SKIP_BLANKS 1200
/* 5~15 should be enough, but almost silent or badly mastered files may need tweaks
- * (ex. newer Tales of the Rays files clip a lot and need +6 as some keys give almost-ok results) */
-#define HCA_KEY_MIN_TEST_FRAMES 7
-#define HCA_KEY_MAX_TEST_FRAMES 12
+ * (ex. newer Tales of the Rays files clip a lot) */
+#define HCA_KEY_MIN_TEST_FRAMES 3 //7
+#define HCA_KEY_MAX_TEST_FRAMES 7 //12
/* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely */
#define HCA_KEY_MAX_FRAME_SCORE 150
#define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE)
/* Test a number of frames if key decrypts correctly.
* Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */
-int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
+static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk, unsigned long long keycode) {
size_t test_frames = 0, current_frame = 0, blank_frames = 0;
- int total_score = 0, found_regular_frame = 0;
- const unsigned int blockSize = data->info.blockSize;
+ int total_score = 0;
+ const unsigned int block_size = data->info.blockSize;
+ uint32_t offset = hk->start_offset;
+
+ if (!offset)
+ offset = data->info.headerSize;
+
+//VGM_LOG("test=k\n");
/* Due to the potentially large number of keys this must be tuned for speed.
* Buffered IO seems fast enough (not very different reading a large block once vs frame by frame).
@@ -216,19 +230,25 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
/* A final score of 0 (=silent) is only possible for short files with all blank frames */
while (test_frames < HCA_KEY_MAX_TEST_FRAMES && current_frame < data->info.blockCount) {
- off_t offset = data->info.headerSize + current_frame * blockSize;
int score;
size_t bytes;
-
+//VGM_LOG(" *frame\n");
/* read and test frame */
- bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile);
- if (bytes != blockSize) {
+ bytes = read_streamfile(data->data_buffer, offset, block_size, data->sf);
+ if (bytes != block_size) {
/* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */
//total_score = -1;
break;
}
- score = clHCA_TestBlock(data->handle, (void*)(data->data_buffer), blockSize);
+ score = clHCA_TestBlock(data->handle, data->data_buffer, block_size);
+
+ /* get first non-blank frame */
+ if (!hk->start_offset && score != 0) {
+ hk->start_offset = offset;
+ }
+ offset += bytes;
+
if (score < 0 || score > HCA_KEY_MAX_FRAME_SCORE) {
total_score = -1;
break;
@@ -236,13 +256,12 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
current_frame++;
- /* ignore silent frames at the beginning, up to a point */
- if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !found_regular_frame) {
+ /* ignore silent frames at the beginning, up to a point and first non-blank */
+ if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !hk->start_offset) {
blank_frames++;
continue;
}
- found_regular_frame = 1;
test_frames++;
/* scale values to make scores of perfect frames more detectable */
@@ -254,7 +273,6 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
total_score += score;
-
/* don't bother checking more frames, other keys will get better scores */
if (total_score > HCA_KEY_MAX_TOTAL_SCORE)
break;
@@ -265,20 +283,42 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
if (test_frames > HCA_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) {
total_score = 1;
}
-
+//VGM_LOG("test=%i\n", total_score);
clHCA_DecodeReset(data->handle);
return total_score;
}
+void test_hca_key(hca_codec_data* data, hca_keytest_t* hk) {
+ int score;
+ uint64_t key = hk->key;
+ uint16_t subkey = hk->subkey;
+
+ //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x\n",
+ // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey);
+
+ if (subkey) {
+ key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
+ }
+
+ score = test_hca_score(data, hk, (unsigned long long)key);
+
+ //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n",
+ // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score);
+
+ /* wrong key */
+ if (score < 0)
+ return;
+
+ //;VGM_LOG("HCA: ok key=%08x%08x, subkey=%04x, score=%i\n",
+ // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score);
+
+ /* update if something better is found */
+ if (hk->best_score <= 0 || (score < hk->best_score && score > 0)) {
+ hk->best_score = score;
+ hk->best_key = key;
+ }
+}
+
void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode) {
clHCA_SetKey(data->handle, (unsigned long long)keycode);
}
-
-clHCA_stInfo* hca_get_info(hca_codec_data* data) {
- return &data->info;
-}
-
-STREAMFILE* hca_get_streamfile(hca_codec_data* data) {
- if (!data) return NULL;
- return data->streamfile;
-}
diff --git a/src/coding/hca_decoder_clhca.c b/src/coding/hca_decoder_clhca.c
index 09294066..4a999979 100644
--- a/src/coding/hca_decoder_clhca.c
+++ b/src/coding/hca_decoder_clhca.c
@@ -57,9 +57,9 @@
#define HCA_MAX_FRAME_SIZE 0xFFFF /* lib max */
#define HCA_MASK 0x7F7F7F7F /* chunk obfuscation when the HCA is encrypted with key */
-#define HCA_SUBFRAMES_PER_FRAME 8
+#define HCA_SUBFRAMES 8
#define HCA_SAMPLES_PER_SUBFRAME 128 /* also spectrum points/etc */
-#define HCA_SAMPLES_PER_FRAME (HCA_SUBFRAMES_PER_FRAME*HCA_SAMPLES_PER_SUBFRAME)
+#define HCA_SAMPLES_PER_FRAME (HCA_SUBFRAMES*HCA_SAMPLES_PER_SUBFRAME)
#define HCA_MDCT_BITS 7 /* (1<<7) = 128 */
#define HCA_MIN_CHANNELS 1
@@ -88,7 +88,7 @@ typedef struct stChannel {
unsigned int coded_count; /* encoded scales/resolutions/coefs */
/* subframe state */
- unsigned char intensity[HCA_SUBFRAMES_PER_FRAME]; /* intensity indexes for joins stereo (value max: 15 / 4b) */
+ unsigned char intensity[HCA_SUBFRAMES]; /* intensity indexes for joins stereo (value max: 15 / 4b) */
unsigned char scalefactors[HCA_SAMPLES_PER_SUBFRAME]; /* scale indexes (value max: 64 / 6b)*/
unsigned char resolution[HCA_SAMPLES_PER_SUBFRAME]; /* resolution indexes (value max: 15 / 4b) */
unsigned char noises[HCA_SAMPLES_PER_SUBFRAME]; /* indexes to coefs that need noise fill + coefs that don't (value max: 128 / 8b) */
@@ -96,13 +96,14 @@ typedef struct stChannel {
unsigned int valid_count; /* resolutions with valid values saved in 'noises' */
float gain[HCA_SAMPLES_PER_SUBFRAME]; /* gain to apply to quantized spectral data */
- float spectra[HCA_SAMPLES_PER_SUBFRAME]; /* resulting dequantized data */
+ float spectra[HCA_SUBFRAMES][HCA_SAMPLES_PER_SUBFRAME]; /* resulting dequantized data */
+
float temp[HCA_SAMPLES_PER_SUBFRAME]; /* temp for DCT-IV */
float dct[HCA_SAMPLES_PER_SUBFRAME]; /* result of DCT-IV */
float imdct_previous[HCA_SAMPLES_PER_SUBFRAME]; /* IMDCT */
/* frame state */
- float wave[HCA_SUBFRAMES_PER_FRAME][HCA_SAMPLES_PER_SUBFRAME]; /* resulting samples */
+ float wave[HCA_SUBFRAMES][HCA_SAMPLES_PER_SUBFRAME]; /* resulting samples */
} stChannel;
typedef struct clHCA {
@@ -333,7 +334,7 @@ void clHCA_ReadSamples16(clHCA* hca, signed short *samples) {
unsigned int i, j, k;
/* PCM output is generally unused, but lib functions seem to use SIMD for f32 to s32 + round to zero */
- for (i = 0; i < HCA_SUBFRAMES_PER_FRAME; i++) {
+ for (i = 0; i < HCA_SUBFRAMES; i++) {
for (j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (k = 0; k < hca->channels; k++) {
f = hca->channel[k].wave[i][j];
@@ -989,8 +990,12 @@ void clHCA_SetKey(clHCA* hca, unsigned long long keycode) {
}
}
+static int clHCA_DecodeBlock_unpack(clHCA* hca, void *data, unsigned int size);
+static void clHCA_DecodeBlock_transform(clHCA* hca);
+
+
int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) {
- const int frame_samples = HCA_SUBFRAMES_PER_FRAME * HCA_SAMPLES_PER_SUBFRAME;
+ const int frame_samples = HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME;
const float scale = 32768.0f;
unsigned int i, ch, sf, s;
int status;
@@ -1014,7 +1019,7 @@ int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) {
}
/* return if decode fails (happens often with wrong keys due to bad bitstream values) */
- status = clHCA_DecodeBlock(hca, data, size);
+ status = clHCA_DecodeBlock_unpack(hca, data, size);
if (status < 0)
return -1;
@@ -1042,8 +1047,9 @@ int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) {
}
/* check decode results as (rarely) bad keys may still get here */
+ clHCA_DecodeBlock_transform(hca);
for (ch = 0; ch < hca->channels; ch++) {
- for (sf = 0; sf < HCA_SUBFRAMES_PER_FRAME; sf++) {
+ for (sf = 0; sf < HCA_SUBFRAMES; sf++) {
for (s = 0; s < HCA_SAMPLES_PER_SUBFRAME; s++) {
float fsample = hca->channel[ch].wave[sf][s];
@@ -1095,15 +1101,15 @@ void clHCA_DecodeReset(clHCA * hca) {
stChannel* ch = &hca->channel[i];
/* most values get overwritten during decode */
- //memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME);
+ //memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES);
//memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME);
- //memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME);
+ //memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->imdct_previous, 0, sizeof(ch->imdct_previous[0]) * HCA_SAMPLES_PER_SUBFRAME);
- //memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME);
+ //memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES * HCA_SUBFRAMES);
}
}
@@ -1119,23 +1125,21 @@ static void calculate_resolution(stChannel* ch, unsigned int packed_noise_level,
static void calculate_gain(stChannel* ch);
-static void dequantize_coefficients(stChannel* ch, clData* br);
+static void dequantize_coefficients(stChannel* ch, clData* br, int subframe);
-static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p);
+static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p, int subframe);
static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_count, unsigned int bands_per_hfr_group,
- unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version);
+ unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version, int subframe);
static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned int base_band_count, unsigned int total_band_count);
-static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count);
+static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count, int subframe);
static void imdct_transform(stChannel* ch, int subframe);
-/* takes HCA data and decodes all of a frame's samples */
-//hcadecoder_decode_block
-int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) {
+static int clHCA_DecodeBlock_unpack(clHCA* hca, void *data, unsigned int size) {
clData br;
unsigned short sync;
unsigned int subframe, ch;
@@ -1180,19 +1184,29 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) {
}
/* lib seems to use a state value to skip parts (unpacking/subframe N/etc) as needed */
- for (subframe = 0; subframe < HCA_SUBFRAMES_PER_FRAME; subframe++) {
+ for (subframe = 0; subframe < HCA_SUBFRAMES; subframe++) {
/* unpack channel data and get dequantized spectra */
for (ch = 0; ch < hca->channels; ch++){
- dequantize_coefficients(&hca->channel[ch], &br);
+ dequantize_coefficients(&hca->channel[ch], &br, subframe);
}
+ /* original code transforms subframe here, but we have it for later */
+ }
+
+ return br.bit; /* numbers of read bits for validations */
+}
+
+static void clHCA_DecodeBlock_transform(clHCA* hca) {
+ unsigned int subframe, ch;
+
+ for (subframe = 0; subframe < HCA_SUBFRAMES; subframe++) {
/* restore missing bands from spectra */
for (ch = 0; ch < hca->channels; ch++) {
- reconstruct_noise(&hca->channel[ch], hca->min_resolution, hca->ms_stereo, &hca->random);
+ reconstruct_noise(&hca->channel[ch], hca->min_resolution, hca->ms_stereo, &hca->random, subframe);
reconstruct_high_frequency(&hca->channel[ch], hca->hfr_group_count, hca->bands_per_hfr_group,
- hca->stereo_band_count, hca->base_band_count, hca->total_band_count, hca->version);
+ hca->stereo_band_count, hca->base_band_count, hca->total_band_count, hca->version, subframe);
}
/* restore missing joint stereo bands */
@@ -1200,7 +1214,7 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) {
for (ch = 0; ch < hca->channels - 1; ch++) {
apply_intensity_stereo(&hca->channel[ch], subframe, hca->base_band_count, hca->total_band_count);
- apply_ms_stereo(&hca->channel[ch], hca->ms_stereo, hca->base_band_count, hca->total_band_count);
+ apply_ms_stereo(&hca->channel[ch], hca->ms_stereo, hca->base_band_count, hca->total_band_count, subframe);
}
}
@@ -1209,9 +1223,27 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) {
imdct_transform(&hca->channel[ch], subframe);
}
}
+}
- return br.bit; /* numbers of read bits for validations */
+/* takes HCA data and decodes all of a frame's samples */
+//hcadecoder_decode_block
+int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) {
+ int res;
+
+ /* Original HCA code doesn't separate unpack + transform (unpacks most data,
+ * reads a subframe's spectra, transforms that subframe.
+ *
+ * Unpacking first takes a bit more memory (1 spectra per subframe) but test keys faster
+ * (since unpack may fail with bad keys we can skip transform). For regular decoding, this
+ * way somehow is slightly faster? (~3-5%, extra compiler optimizations with reduced scope?) */
+
+ res = clHCA_DecodeBlock_unpack(hca, data, size);
+ if (res < 0)
+ return res;
+ clHCA_DecodeBlock_transform(hca);
+
+ return res;
}
//--------------------------------------------------
@@ -1330,7 +1362,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co
ch->intensity[0] = value;
if (value < 15) {
bitreader_skip(br, 4);
- for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) {
+ for (i = 1; i < HCA_SUBFRAMES; i++) {
ch->intensity[i] = bitreader_read(br, 4);
}
}
@@ -1352,7 +1384,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co
ch->intensity[0] = value;
if (delta_bits == 3) { /* 3+1 = 4b */
/* fixed intensities */
- for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) {
+ for (i = 1; i < HCA_SUBFRAMES; i++) {
ch->intensity[i] = bitreader_read(br, 4);
}
}
@@ -1361,7 +1393,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co
unsigned char bmax = (2 << delta_bits) - 1;
unsigned char bits = delta_bits + 1;
- for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) {
+ for (i = 1; i < HCA_SUBFRAMES; i++) {
unsigned char delta = bitreader_read(br, bits);
if (delta == bmax) {
value = bitreader_read(br, 4); /* encoded */
@@ -1378,7 +1410,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co
}
else {
bitreader_skip(br, 4);
- for (i = 0; i < HCA_SUBFRAMES_PER_FRAME; i++) {
+ for (i = 0; i < HCA_SUBFRAMES; i++) {
ch->intensity[i] = 7;
}
}
@@ -1498,7 +1530,7 @@ static const float hcatbdecoder_read_val_table[128] = {
};
/* read spectral coefficients in the bitstream */
-static void dequantize_coefficients(stChannel* ch, clData* br) {
+static void dequantize_coefficients(stChannel* ch, clData* br, int subframe) {
int i;
unsigned int cc_count = ch->coded_count;
@@ -1524,11 +1556,11 @@ static void dequantize_coefficients(stChannel* ch, clData* br) {
}
/* dequantize coef with gain */
- ch->spectra[i] = ch->gain[i] * qc;
+ ch->spectra[subframe][i] = ch->gain[i] * qc;
}
/* clean rest of spectra */
- memset(&ch->spectra[cc_count], 0, sizeof(ch->spectra[0]) * (HCA_SAMPLES_PER_SUBFRAME - cc_count));
+ memset(&ch->spectra[subframe][cc_count], 0, sizeof(ch->spectra[subframe][0]) * (HCA_SAMPLES_PER_SUBFRAME - cc_count));
}
@@ -1560,7 +1592,7 @@ static const float* hcadecoder_scale_conversion_table = (const float*)hcadecoder
/* recreate resolution 0 coefs (not encoded) with pseudo-random noise based on
* other coefs/scales (probably similar to AAC's perceptual noise substitution) */
-static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p) {
+static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p, int subframe) {
if (min_resolution > 0) /* added in v3.0 */
return;
if (ch->valid_count <= 0 || ch->noise_count <= 0)
@@ -1587,7 +1619,8 @@ static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsign
sf_valid = ch->scalefactors[valid_index];
sc_index = (sf_noise - sf_valid + 62) & ~((sf_noise - sf_valid + 62) >> 31);
- ch->spectra[noise_index] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[valid_index];
+ ch->spectra[subframe][noise_index] =
+ hcadecoder_scale_conversion_table[sc_index] * ch->spectra[subframe][valid_index];
}
*random_p = random; /* lib saves this in the bitreader, maybe for simplified passing around */
@@ -1596,7 +1629,7 @@ static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsign
/* recreate missing coefs in high bands based on lower bands (probably similar to AAC's spectral band replication) */
static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_count, unsigned int bands_per_hfr_group,
- unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version) {
+ unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version, int subframe) {
if (bands_per_hfr_group == 0) /* added in v2.0, skipped in v2.0 files with 0 bands too */
return;
if (ch->type == STEREO_SECONDARY)
@@ -1630,7 +1663,7 @@ static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_cou
sc_index = hfr_scales[group] - ch->scalefactors[lowband] + 63;
sc_index = sc_index & ~(sc_index >> 31); /* clamped in v3.0 lib (in theory 6b sf are 0..128) */
- ch->spectra[highband] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[lowband];
+ ch->spectra[subframe][highband] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[subframe][lowband];
highband += 1;
lowband -= lowband_sub;
@@ -1638,7 +1671,7 @@ static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_cou
}
/* last spectrum coefficient is 0 (normally highband = 128, but perhaps could 'break' before) */
- ch->spectra[highband - 1] = 0.0f;
+ ch->spectra[subframe][highband - 1] = 0.0f;
}
}
@@ -1661,8 +1694,8 @@ static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned in
int band;
float ratio_l = hcadecoder_intensity_ratio_table[ ch_pair[1].intensity[subframe] ];
float ratio_r = 2.0f - ratio_l; /* correct, though other decoders substract 2.0 (it does use 'fsubr 2.0' and such) */
- float* sp_l = ch_pair[0].spectra;
- float* sp_r = ch_pair[1].spectra;
+ float* sp_l = &ch_pair[0].spectra[subframe][0];
+ float* sp_r = &ch_pair[1].spectra[subframe][0];
for (band = base_band_count; band < total_band_count; band++) {
float coef_l = sp_l[band] * ratio_l;
@@ -1674,7 +1707,7 @@ static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned in
}
/* restore L/R bands based on mid channel + side differences */
-static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count) {
+static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count, int subframe) {
if (!ms_stereo) /* added in v3.0 */
return;
if (ch_pair[0].type != STEREO_PRIMARY)
@@ -1683,8 +1716,8 @@ static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned
{
int band;
const float ratio = 0.70710676908493; /* 0x3F3504F3 */
- float* sp_l = ch_pair[0].spectra;
- float* sp_r = ch_pair[1].spectra;
+ float* sp_l = &ch_pair[0].spectra[subframe][0];
+ float* sp_r = &ch_pair[1].spectra[subframe][0];
for (band = base_band_count; band < total_band_count; band++) {
float coef_l = (sp_l[band] + sp_r[band]) * ratio;
@@ -1867,8 +1900,8 @@ static void imdct_transform(stChannel* ch, int subframe) {
{
unsigned int count1 = 1;
unsigned int count2 = half;
- float* temp1 = ch->spectra;
- float* temp2 = ch->temp;
+ float* temp1 = &ch->spectra[subframe][0];
+ float* temp2 = &ch->temp[0];
for (i = 0; i < mdct_bits; i++) {
float* swap;
@@ -1897,8 +1930,8 @@ static void imdct_transform(stChannel* ch, int subframe) {
{
unsigned int count1 = half;
unsigned int count2 = 1;
- float* temp1 = ch->temp;
- float* temp2 = ch->spectra;
+ float* temp1 = &ch->temp[0];
+ float* temp2 = &ch->spectra[subframe][0];
for (i = 0; i < mdct_bits; i++) {
const float* sin_table = (const float*) sin_tables_hex[i];//todo cleanup
@@ -1934,15 +1967,15 @@ static void imdct_transform(stChannel* ch, int subframe) {
/* copy dct */
/* (with the above optimization spectra is already modified, so this is redundant) */
for (i = 0; i < size; i++) {
- ch->dct[i] = ch->spectra[i];
+ ch->dct[i] = ch->spectra[subframe][i];
}
#endif
}
/* update output/imdct with overlapped window (lib fuses this with the above) */
{
- const float* dct = ch->spectra; //ch->dct;
- const float* prev = ch->imdct_previous;
+ const float* dct = &ch->spectra[subframe][0]; //ch->dct;
+ const float* prev = &ch->imdct_previous[0];
for (i = 0; i < half; i++) {
ch->wave[subframe][i] = hcaimdct_window_float[i] * dct[i + half] + prev[i];
diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj
index 93e46652..0ed715e9 100644
--- a/src/libvgmstream.vcxproj
+++ b/src/libvgmstream.vcxproj
@@ -145,6 +145,7 @@
+
diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters
index 65f965fb..89389ef0 100644
--- a/src/libvgmstream.vcxproj.filters
+++ b/src/libvgmstream.vcxproj.filters
@@ -197,6 +197,9 @@
meta\Header Files
+
+ meta\Header Files
+
meta\Header Files
diff --git a/src/meta/hca.c b/src/meta/hca.c
index 9e176525..37e58d29 100644
--- a/src/meta/hca.c
+++ b/src/meta/hca.c
@@ -4,12 +4,12 @@
#include "../coding/hca_decoder_clhca.h"
#ifdef VGM_DEBUG_OUTPUT
-//#define HCA_BRUTEFORCE
+ //#define HCA_BRUTEFORCE
+ #ifdef HCA_BRUTEFORCE
+ #include "hca_bf.h"
+ #endif
#endif
-#ifdef HCA_BRUTEFORCE
-static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey);
-#endif
static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey);
@@ -128,60 +128,32 @@ fail:
}
-static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t subkey, int* best_score, uint64_t* best_keycode) {
- int score;
-
- //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x\n",
- // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey);
-
- if (subkey) {
- key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
- }
-
- score = test_hca_key(hca_data, (unsigned long long)key);
-
- //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n",
- // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score);
-
- /* wrong key */
- if (score < 0)
- return;
-
- //;VGM_LOG("HCA: ok key=%08x%08x, subkey=%04x, score=%i\n",
- // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score);
-
- /* update if something better is found */
- if (*best_score <= 0 || (score < *best_score && score > 0)) {
- *best_score = score;
- *best_keycode = key;
- }
-}
-
-/* try to find the decryption key from a list. */
+/* try to find the decryption key from a list */
static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) {
- const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info);
- int best_score = -1;
+ const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_list[0]);
int i;
+ hca_keytest_t hk = {0};
- *p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
+ hk.best_key = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
+ hk.subkey = subkey;
for (i = 0; i < keys_length; i++) {
- uint64_t key = hcakey_list[i].key;
+ hk.key = hcakey_list[i].key;
- test_key(hca_data, key, subkey, &best_score, p_keycode);
- if (best_score == 1)
+ test_hca_key(hca_data, &hk);
+ if (hk.best_score == 1)
goto done;
#if 0
{
int j;
-
size_t subkeys_size = hcakey_list[i].subkeys_size;
- const uint16_t *subkeys = hcakey_list[i].subkeys;
+ const uint16_t* subkeys = hcakey_list[i].subkeys;
if (subkeys_size > 0 && subkey == 0) {
for (j = 0; j < subkeys_size; j++) {
- test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
- if (best_score == 1)
+ hk.subkey = subkeys[j];
+ test_hca_key(hca_data, &hk);
+ if (hk.best_score == 1)
goto done;
}
}
@@ -190,219 +162,9 @@ static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
}
done:
- VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
- (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
- vgm_asserti(best_score < 0, "HCA: decryption key not found\n");
- return best_score > 0;
+ *p_keycode = hk.best_key;
+ VGM_ASSERT(hk.best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
+ (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk.best_score);
+ vgm_asserti(hk.best_score <= 0, "HCA: decryption key not found\n");
+ return hk.best_score > 0;
}
-
-#ifdef HCA_BRUTEFORCE
-typedef enum {
- HBF_TYPE_64LE_1,
- HBF_TYPE_64BE_1,
- HBF_TYPE_32LE_1,
- HBF_TYPE_32BE_1,
- HBF_TYPE_64LE_4,
- HBF_TYPE_64BE_4,
- HBF_TYPE_32LE_4,
- HBF_TYPE_32BE_4,
-} HBF_type_t;
-
-/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
- * Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys
- * in plaintext (inside levelX or other base files) instead though. */
-static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) {
- STREAMFILE* sf_keys = NULL;
- uint8_t* buf = NULL;
- int best_score = 0xFFFFFF, cur_score;
- off_t keys_size, bytes;
- int pos, step;
- uint64_t old_key = 0;
- uint64_t key = 0;
- uint64_t best_key = 0;
-
-
- /* load whole file in memory for performance (exes with keys shouldn't be too big) */
- sf_keys = open_streamfile_by_filename(sf, "keys.bin");
- if (!sf_keys) return;
-
- VGM_LOG("HCA BF: test keys.bin (type %i)\n", type);
- *p_keycode = 0;
-
- keys_size = get_streamfile_size(sf_keys);
-
- buf = malloc(keys_size);
- if (!buf) goto done;
-
- bytes = read_streamfile(buf, 0, keys_size, sf_keys);
- if (bytes != keys_size) goto done;
-
- VGM_LOG("HCA BF: start .bin\n");
-
- switch(type) {
- case HBF_TYPE_64LE_1:
- case HBF_TYPE_64BE_1:
- case HBF_TYPE_32LE_1:
- case HBF_TYPE_32BE_1: step = 0x01; break;
- case HBF_TYPE_64LE_4:
- case HBF_TYPE_64BE_4:
- case HBF_TYPE_32LE_4:
- case HBF_TYPE_32BE_4: step = 0x04; break;
- default: goto done;
- }
-
- pos = 0;
- while (pos < keys_size - 8) {
- VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos);
-
- /* keys are usually u64le but other orders may exist */
- switch(type) {
- case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); break;
- case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); break;
- case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); break;
- case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); break;
- case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break;
- case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break;
- case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break;
- case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break;
- default: goto done;
- }
- pos += step;
-
- if (key == 0 || key == old_key)
- continue;
- old_key = key;
-
- cur_score = 0;
- test_key(hca_data, key, subkey, &cur_score, p_keycode);
- if (cur_score == 1) {
- best_key = key;
- best_score = cur_score;
- goto done;
- }
-
- if (cur_score > 0 && cur_score <= 500) {
- VGM_LOG("HCA BF: possible key=%08x%08x (score=%i) at offset %x\n",
- (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), cur_score, pos - step);
- if (best_score > cur_score) {
- best_key = key;
- best_score = cur_score;
- }
- }
- }
-
-done:
- if (best_score < 0 || best_score > 10000) {
- *p_keycode = 0;
- VGM_LOG("HCA BF: no good key found\n");
- }
- else {
- /* print best_key as p_keycode includes subkey */
- VGM_LOG("HCA BF: best key=%08x%08x (score=%i)\n",
- (uint32_t)((best_key >> 32) & 0xFFFFFFFF), (uint32_t)(best_key & 0xFFFFFFFF), best_score);
- }
-
- close_streamfile(sf_keys);
- free(buf);
-}
-
-static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1);
-/*
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1);
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
-
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4);
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4);
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4);
- bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4);
-*/
-}
-
-
-#include
-//#include
-
-/* same as the above but for txt lines. */
-static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
- STREAMFILE* sf_keys = NULL;
- uint8_t* buf = NULL;
- int best_score = 0xFFFFFF, cur_score;
- off_t keys_size, bytes;
- int i = 0, pos;
- char line[1024];
-
-
-
- /* load whole file in memory for performance (exes with keys shouldn't be too big) */
- sf_keys = open_streamfile_by_filename(sf, "keys.txt");
- if (!sf_keys) return;
-
- VGM_LOG("HCA BF: test keys.txt\n");
- *p_keycode = 0;
-
- keys_size = get_streamfile_size(sf_keys);
-
- buf = malloc(keys_size);
- if (!buf) goto done;
-
- bytes = read_streamfile(buf, 0, keys_size, sf_keys);
- if (bytes != keys_size) goto done;
-
- VGM_LOG("HCA BF: start .txt\n");
-
- pos = 0;
- while (pos < keys_size) {
- int bytes_read, line_ok, count;
- uint64_t key = 0;
-
- bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
- pos += bytes_read;
- if (!line_ok) continue; /* line too long */
-
- count = sscanf(line, "%" SCNd64, &key);
- if (count != 1) continue;
-
- VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i);
-
- if (key == 0)
- continue;
- i++;
-
- cur_score = 0;
- test_key(hca_data, key, subkey, &cur_score, p_keycode);
- if (cur_score == 1)
- goto done;
-
- if (cur_score > 0 && cur_score <= 500) {
- VGM_LOG("HCA BF: possible key=%08x%08x (score=%i) at %x\n",
- (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), cur_score, pos - bytes_read);
- if (best_score > cur_score)
- best_score = cur_score;
- }
- }
-
-done:
- VGM_LOG("HCA BF: done %i keys.txt\n", i);
- VGM_ASSERT(best_score > 0, "HCA BF: best key=%08x%08x (score=%i)\n",
- (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
- VGM_ASSERT(best_score < 0, "HCA BF: no good key found\n");
- if (best_score < 0 || best_score > 10000)
- *p_keycode = 0;
-
- close_streamfile(sf_keys);
- free(buf);
-}
-
-static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
- bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey);
- if (*p_keycode != 0)
- return;
-
- bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey);
- if (*p_keycode != 0)
- return;
-}
-
-#endif
diff --git a/src/meta/hca_bf.h b/src/meta/hca_bf.h
new file mode 100644
index 00000000..8d43460a
--- /dev/null
+++ b/src/meta/hca_bf.h
@@ -0,0 +1,257 @@
+#ifndef _HCA_BF_
+#define _HCA_BF_
+
+#include "meta.h"
+#include "../coding/coding.h"
+
+#ifdef HCA_BRUTEFORCE
+
+static void bruteforce_process_result(hca_keytest_t* hk, unsigned long long* p_keycode) {
+ *p_keycode = hk->best_key;
+ if (hk->best_score < 0 || hk->best_score > 10000) {
+ VGM_LOG("HCA BF: no good key found\n");
+ }
+ else {
+ VGM_LOG("HCA BF: best key=%08x%08x (score=%i)\n",
+ (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk->best_score);
+ }
+}
+
+typedef enum {
+ HBF_TYPE_64LE_1,
+ HBF_TYPE_64BE_1,
+ HBF_TYPE_32LE_1,
+ HBF_TYPE_32BE_1,
+ HBF_TYPE_64LE_4,
+ HBF_TYPE_64BE_4,
+ HBF_TYPE_32LE_4,
+ HBF_TYPE_32BE_4,
+} HBF_type_t;
+
+/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
+ * Kinda slow but acceptable for ~100MB exes, not very optimized. Unity usually has keys
+ * in plaintext (inside levelX or other base files) instead though, use test below. */
+static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) {
+ STREAMFILE* sf_keys = NULL;
+ uint8_t* buf = NULL;
+ uint32_t keys_size, bytes;
+ int pos, step;
+ uint64_t key = 0, old_key = 0;
+ hca_keytest_t hk = {0};
+
+ hk.subkey = subkey;
+
+
+ /* load whole file in memory for performance (exes with keys shouldn't be too big) */
+ sf_keys = open_streamfile_by_filename(sf, "keys.bin");
+ if (!sf_keys) return;
+
+ VGM_LOG("HCA BF: test keys.bin (type %i)\n", type);
+ *p_keycode = 0;
+
+ keys_size = get_streamfile_size(sf_keys);
+
+ buf = malloc(keys_size);
+ if (!buf) {
+ VGM_LOG("HCA BF: key file too big!\n");
+ goto done;
+ }
+
+ bytes = read_streamfile(buf, 0, keys_size, sf_keys);
+ if (bytes != keys_size) goto done;
+
+ VGM_LOG("HCA BF: start .bin\n");
+
+ switch(type) {
+ case HBF_TYPE_64LE_1:
+ case HBF_TYPE_64BE_1:
+ case HBF_TYPE_32LE_1:
+ case HBF_TYPE_32BE_1: step = 0x01; break;
+ case HBF_TYPE_64LE_4:
+ case HBF_TYPE_64BE_4:
+ case HBF_TYPE_32LE_4:
+ case HBF_TYPE_32BE_4: step = 0x04; break;
+ default: goto done;
+ }
+
+ pos = 0;
+ while (pos < keys_size - 8) {
+ VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos);
+
+ /* keys are usually u64le but other orders may exist */
+ switch(type) {
+ case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); break;
+ case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); break;
+ case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); break;
+ case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); break;
+ case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break;
+ case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break;
+ case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break;
+ case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break;
+ default: goto done;
+ }
+ pos += step;
+
+ if (key == 0 || key == old_key)
+ continue;
+ old_key = key;
+
+ hk.key = key;
+ test_hca_key(hca_data, &hk);
+ if (hk.best_score == 1)
+ goto done;
+ }
+
+done:
+ bruteforce_process_result(&hk, p_keycode);
+ close_streamfile(sf_keys);
+ free(buf);
+}
+
+static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1);
+/*
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1);
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
+
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4);
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4);
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4);
+ bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4);
+*/
+}
+
+
+#include
+//#include
+
+/* same as the above but for txt lines. */
+static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
+ STREAMFILE* sf_keys = NULL;
+ uint8_t* buf = NULL;
+ uint32_t keys_size, bytes;
+ char line[1024];
+ int i = 0, pos;
+ uint64_t key = 0;
+ hca_keytest_t hk = {0};
+
+ hk.subkey = subkey;
+
+
+ /* load whole file in memory for performance (exes with keys shouldn't be too big) */
+ sf_keys = open_streamfile_by_filename(sf, "keys.txt");
+ if (!sf_keys) return;
+
+ VGM_LOG("HCA BF: test keys.txt\n");
+ *p_keycode = 0;
+
+ keys_size = get_streamfile_size(sf_keys);
+
+ buf = malloc(keys_size);
+ if (!buf) {
+ VGM_LOG("HCA BF: key file too big!\n");
+ goto done;
+ }
+
+ bytes = read_streamfile(buf, 0, keys_size, sf_keys);
+ if (bytes != keys_size) goto done;
+
+ VGM_LOG("HCA BF: start .txt\n");
+
+ pos = 0;
+ while (pos < keys_size) {
+ int bytes_read, line_ok, count;
+ key = 0;
+
+ bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
+ pos += bytes_read;
+ if (!line_ok) continue; /* line too long */
+
+ count = sscanf(line, "%" SCNd64, &key);
+ if (count != 1) continue;
+
+ VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i);
+
+ if (key == 0)
+ continue;
+ i++;
+
+ hk.key = key;
+ test_hca_key(hca_data, &hk);
+ if (hk.best_score == 1)
+ goto done;
+ }
+
+done:
+ bruteforce_process_result(&hk, p_keycode);
+ close_streamfile(sf_keys);
+ free(buf);
+}
+
+/* same as the above but good ol' bruteforce numbers (useful for games with keys that are dates) */
+static void bruteforce_hca_key_num(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
+ STREAMFILE* sf_keys = NULL;
+ uint32_t keys_size;
+ uint64_t min, max;
+ uint64_t key = 0;
+ hca_keytest_t hk = {0};
+
+ hk.subkey = subkey;
+
+
+ /* load whole file in memory for performance (exes with keys shouldn't be too big) */
+ sf_keys = open_streamfile_by_filename(sf, "keys.num");
+ if (!sf_keys) return;
+
+ VGM_LOG("HCA BF: test keys.num\n");
+ *p_keycode = 0;
+
+ keys_size = get_streamfile_size(sf_keys);
+
+ /* don't set too high as it does ~70000 keys per second, do the math */
+ if (keys_size < 0x10) {
+ min = 0;
+ max = 0xFFFFFFFF;
+ }
+ else {
+ min = read_u64be(0x00, sf_keys);
+ max = read_u64be(0x08, sf_keys);
+ }
+
+ VGM_LOG("HCA BF: start .num\n");
+
+ while (min < max) {
+ key = min;
+
+ min++;
+ VGM_ASSERT(min % 0x100000 == 0, "HCA: count %x...\n", (uint32_t)min);
+
+ hk.key = key;
+ test_hca_key(hca_data, &hk);
+ if (hk.best_score == 1)
+ goto done;
+ }
+
+done:
+ bruteforce_process_result(&hk, p_keycode);
+ close_streamfile(sf_keys);
+}
+
+static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
+ bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey);
+ if (*p_keycode != 0)
+ return;
+
+ bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey);
+ if (*p_keycode != 0)
+ return;
+
+ bruteforce_hca_key_num(sf, hca_data, p_keycode, subkey);
+ if (*p_keycode != 0)
+ return;
+}
+
+#endif
+
+#endif /*_HCA_BF_*/
diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h
index 54aacc39..7f3a1ed6 100644
--- a/src/meta/hca_keys.h
+++ b/src/meta/hca_keys.h
@@ -67,11 +67,9 @@ static const hcakey_info hcakey_list[] = {
// Sonic Runners (iOS/Android)
{19910623}, // 00000000012FCFDF
- // Fate/Grand Order (iOS/Android) base assets
- {12345}, // 0000000000003039
-
- // Fate/Grand Order (iOS/Android) download assets *unconfirmed
- {9117927877783581796}, // 7E89631892EBF464
+ // Fate/Grand Order (iOS/Android)
+ {12345}, // 0000000000003039 - base assets
+ {9117927877783581796}, // 7E89631892EBF464 - downloaded assets *unconfirmed
// Raramagi (iOS/Android)
{45719322}, // 0000000002B99F1A
@@ -809,6 +807,12 @@ static const hcakey_info hcakey_list[] = {
{0x178a76b6436d20f0}, // Sng028
{0x3ff99f2fed65a1ed}, // Sng030
+ // Ulala: Idle Adventure (Android)
+ {20191022}, // 000000000134172E
+
+ // Girls' Frontline: Project Neural Cloud (Android)
+ {210222522032314}, // 0000BF323EBFE0BA
+
};
#endif/*_HCA_KEYS_H_*/
diff --git a/src/meta/str_wav.c b/src/meta/str_wav.c
index 6c32cbaa..7706927b 100644
--- a/src/meta/str_wav.c
+++ b/src/meta/str_wav.c
@@ -612,7 +612,7 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
strwav->codec = DSP;
strwav->dsps_table = 0xf0;
- strwav->interleave = strwav->tracks > 2 ? 0x8000 : 0x10000;
+ strwav->interleave = strwav->tracks >= 2 ? 0x8000 : 0x10000;
;VGM_LOG("STR+WAV: header SBCKK (GC)\n");
return 1;
}