An audio player for macOS 10.8 and newer. https://kode54.net/cog
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
5.2KB

  1. #include "meta.h"
  2. #include "hca_keys.h"
  3. #include "../coding/coding.h"
  4. static void find_hca_key(hca_codec_data * hca_data, unsigned long long * out_keycode, uint16_t subkey);
  5. VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) {
  6. return init_vgmstream_hca_subkey(streamFile, 0x0000);
  7. }
  8. VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) {
  9. VGMSTREAM * vgmstream = NULL;
  10. hca_codec_data * hca_data = NULL;
  11. unsigned long long keycode = 0;
  12. /* checks */
  13. if ( !check_extensions(streamFile, "hca"))
  14. return NULL;
  15. if (((uint32_t)read_32bitBE(0x00,streamFile) & 0x7f7f7f7f) != 0x48434100) /* "HCA\0", possibly masked */
  16. goto fail;
  17. /* init vgmstream and library's context, will validate the HCA */
  18. hca_data = init_hca(streamFile);
  19. if (!hca_data) goto fail;
  20. /* find decryption key in external file or preloaded list */
  21. if (hca_data->info.encryptionEnabled) {
  22. uint8_t keybuf[0x08+0x02];
  23. size_t keysize;
  24. keysize = read_key_file(keybuf, 0x08+0x04, streamFile);
  25. if (keysize == 0x08) { /* standard */
  26. keycode = (uint64_t)get_64bitBE(keybuf+0x00);
  27. }
  28. else if (keysize == 0x08+0x02) { /* seed key + AWB subkey */
  29. uint64_t key = (uint64_t)get_64bitBE(keybuf+0x00);
  30. uint16_t sub = (uint16_t)get_16bitBE(keybuf+0x08);
  31. keycode = key * ( ((uint64_t)sub << 16u) | ((uint16_t)~sub + 2u) );
  32. }
  33. else {
  34. find_hca_key(hca_data, &keycode, subkey);
  35. }
  36. clHCA_SetKey(hca_data->handle, keycode); //maybe should be done through hca_decoder.c?
  37. }
  38. /* build the VGMSTREAM */
  39. vgmstream = allocate_vgmstream(hca_data->info.channelCount, hca_data->info.loopEnabled);
  40. if (!vgmstream) goto fail;
  41. vgmstream->meta_type = meta_HCA;
  42. vgmstream->sample_rate = hca_data->info.samplingRate;
  43. vgmstream->num_samples = hca_data->info.blockCount * hca_data->info.samplesPerBlock -
  44. hca_data->info.encoderDelay - hca_data->info.encoderPadding;
  45. vgmstream->loop_start_sample = hca_data->info.loopStartBlock * hca_data->info.samplesPerBlock -
  46. hca_data->info.encoderDelay + hca_data->info.loopStartDelay;
  47. vgmstream->loop_end_sample = hca_data->info.loopEndBlock * hca_data->info.samplesPerBlock -
  48. hca_data->info.encoderDelay + (hca_data->info.samplesPerBlock - hca_data->info.loopEndPadding);
  49. /* After loop end CRI's encoder removes the rest of the original samples and puts some
  50. * garbage in the last frame that should be ignored. Optionally it can encode fully preserving
  51. * the file too, but it isn't detectable, so we'll allow the whole thing just in case */
  52. //if (vgmstream->loop_end_sample && vgmstream->num_samples > vgmstream->loop_end_sample)
  53. // vgmstream->num_samples = vgmstream->loop_end_sample;
  54. vgmstream->coding_type = coding_CRI_HCA;
  55. vgmstream->layout_type = layout_none;
  56. vgmstream->codec_data = hca_data;
  57. return vgmstream;
  58. fail:
  59. free_hca(hca_data);
  60. return NULL;
  61. }
  62. static inline void test_key(hca_codec_data * hca_data, uint64_t key, uint16_t subkey, int *best_score, uint64_t *best_keycode) {
  63. int score;
  64. if (subkey) {
  65. key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
  66. }
  67. score = test_hca_key(hca_data, (unsigned long long)key);
  68. //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n",
  69. // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score);
  70. /* wrong key */
  71. if (score < 0)
  72. return;
  73. /* update if something better is found */
  74. if (*best_score <= 0 || (score < *best_score && score > 0)) {
  75. *best_score = score;
  76. *best_keycode = key;
  77. }
  78. }
  79. /* Try to find the decryption key from a list. */
  80. static void find_hca_key(hca_codec_data * hca_data, unsigned long long * out_keycode, uint16_t subkey) {
  81. const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info);
  82. int best_score = -1;
  83. int i,j;
  84. *out_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
  85. /* find a candidate key */
  86. for (i = 0; i < keys_length; i++) {
  87. uint64_t key = hcakey_list[i].key;
  88. size_t subkeys_size = hcakey_list[i].subkeys_size;
  89. const uint16_t *subkeys = hcakey_list[i].subkeys;
  90. /* try once with external subkey, if any */
  91. test_key(hca_data, key, subkey, &best_score, out_keycode);
  92. if (best_score == 1) /* best possible score */
  93. goto done;
  94. /* try subkey list */
  95. if (subkeys_size > 0 && subkey == 0) {
  96. for (j = 0; j < subkeys_size; j++) {
  97. test_key(hca_data, key, subkeys[j], &best_score, out_keycode);
  98. if (best_score == 1) /* best possible score */
  99. goto done;
  100. }
  101. }
  102. }
  103. done:
  104. //;VGM_LOG("HCA: best key=%08x%08x (score=%i)\n",
  105. // (uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score);
  106. VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
  107. (uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score);
  108. VGM_ASSERT(best_score < 0, "HCA: key not found\n");
  109. }