diff --git a/ext_libs/clHCA.c b/ext_libs/clHCA.c index 813f2d13..eb5dfdf4 100644 --- a/ext_libs/clHCA.c +++ b/ext_libs/clHCA.c @@ -69,7 +69,7 @@ #define HCA_DEFAULT_RANDOM 1 -#define HCA_ERROR_OK 0 +#define HCA_RESULT_OK 0 #define HCA_ERROR_PARAMS -1 #define HCA_ERROR_HEADER -2 #define HCA_ERROR_CHECKSUM -3 @@ -472,7 +472,7 @@ static int ath_init(unsigned char* ath_curve, int type, unsigned int sample_rate default: return HCA_ERROR_HEADER; } - return HCA_ERROR_OK; + return HCA_RESULT_OK; } @@ -604,7 +604,7 @@ static int cipher_init(unsigned char* cipher_table, int type, unsigned long long default: return HCA_ERROR_HEADER; } - return HCA_ERROR_OK; + return HCA_RESULT_OK; } //-------------------------------------------------- @@ -973,7 +973,7 @@ int clHCA_DecodeHeader(clHCA* hca, const void *data, unsigned int size) { * (keycode is not changed between calls) */ hca->is_valid = 1; - return HCA_ERROR_OK; + return HCA_RESULT_OK; } void clHCA_SetKey(clHCA* hca, unsigned long long keycode) { @@ -993,18 +993,16 @@ void clHCA_SetKey(clHCA* hca, unsigned long long keycode) { int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) { const int frame_samples = HCA_SUBFRAMES_PER_FRAME * HCA_SAMPLES_PER_SUBFRAME; const float scale = 32768.0f; - unsigned int ch, sf, s; + unsigned int i, ch, sf, s; int status; int clips = 0, blanks = 0, channel_blanks[HCA_MAX_CHANNELS] = {0}; - + const unsigned char* buf = data; /* first blocks can be empty/silent, check all bytes but sync/crc */ { - int i; int is_empty = 1; - const unsigned char* buf = data; - for (i = 2; i < size - 0x02; i++) { + for (i = 0x02; i < size - 0x02; i++) { if (buf[i] != 0) { is_empty = 0; break; @@ -1021,7 +1019,30 @@ int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) { if (status < 0) return -1; - /* check decode results as bad keys may still get here */ + /* detect data errors */ + { + int bits_max = hca->frame_size * 8; + int byte_start; + + /* Should read all frame sans end checksum (16b), but allow 14b as one frame was found to + * read up to that (cross referenced with CRI's tools), perhaps some encoding hiccup + * [World of Final Fantasy Maxima (Switch) am_ev21_0170 video] */ + if (status + 14 > bits_max) + return HCA_ERROR_BITREADER; + + /* leftover data after read bits in HCA is always null (up to end 16b checksum), so bad keys + * give garbage beyond those bits (data is decrypted at this point and size >= frame_size) */ + byte_start = (status / 8) + (status % 8 ? 0x01 : 0); + /* maybe should memcmp with a null frame, unsure of max though, and in most cases + * should fail fast (this check catches almost everything) */ + for (i = byte_start; i < hca->frame_size - 0x02; i++) { + if (buf[i] != 0) { + return -1; + } + } + } + + /* check decode results as (rarely) bad keys may still get here */ for (ch = 0; ch < hca->channels; ch++) { for (sf = 0; sf < HCA_SUBFRAMES_PER_FRAME; sf++) { for (s = 0; s < HCA_SAMPLES_PER_SUBFRAME; s++) { @@ -1191,15 +1212,7 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { } - /* should read all frame sans checksum (16b) at most */ - /* one frame was found to read up to 14b left (cross referenced with CRI's tools), - * perhaps some encoding hiccup [World of Final Fantasy Maxima (Switch) am_ev21_0170 video], - * though this validation makes more sense when testing keys and isn't normally done on decode */ - if (br.bit + 14 > br.size) { /* relax validation a bit for that case */ - return HCA_ERROR_BITREADER; - } - - return HCA_ERROR_OK; + return br.bit; /* numbers of read bits for validations */ } //-------------------------------------------------- @@ -1303,7 +1316,7 @@ static int unpack_scalefactors(stChannel* ch, clData* br, unsigned int hfr_group ch->scalefactors[HCA_SAMPLES_PER_SUBFRAME - 1 - i] = ch->scalefactors[cs_count - i]; } - return HCA_ERROR_OK; + return HCA_RESULT_OK; } /* read intensity (for joint stereo R) or v2.0 high frequency scales (for regular channels) */ @@ -1386,7 +1399,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co } } - return HCA_ERROR_OK; + return HCA_RESULT_OK; } /* get resolutions, that determines range of values per encoded spectrum coefficients */ diff --git a/src/coding/hca_decoder.c b/src/coding/hca_decoder.c index f23a9bf8..122ca89a 100644 --- a/src/coding/hca_decoder.c +++ b/src/coding/hca_decoder.c @@ -179,6 +179,13 @@ void free_hca(hca_codec_data* data) { } +/* ************************************************************************* */ + +/* Test a single HCA key and assign an score for comparison. Multiple keys could potentially result + * in "playable" results (mostly silent with random clips), so it also checks the resulting PCM. + * Currently wrong keys should be detected during decoding+un-xor test, so this score may not + * be needed anymore, but keep around in case CRI breaks those tests in the future. */ + /* arbitrary scale to simplify score comparisons */ #define HCA_KEY_SCORE_SCALE 10 /* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */ @@ -215,7 +222,8 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) { /* read and test frame */ bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile); if (bytes != blockSize) { - total_score = -1; + /* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */ + //total_score = -1; break; } diff --git a/src/meta/hca.c b/src/meta/hca.c index b6872432..23f79066 100644 --- a/src/meta/hca.c +++ b/src/meta/hca.c @@ -10,11 +10,11 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t /* CRI HCA - streamed audio from CRI ADX2/Atom middleware */ -VGMSTREAM * init_vgmstream_hca(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_hca(STREAMFILE* sf) { return init_vgmstream_hca_subkey(sf, 0x0000); } -VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { +VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { VGMSTREAM * vgmstream = NULL; hca_codec_data* hca_data = NULL; clHCA_stInfo* hca_info; @@ -122,6 +122,9 @@ 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) ); } @@ -135,6 +138,9 @@ static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t sub 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;