gemba 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. checksums.yaml +4 -4
  2. data/THIRD_PARTY_NOTICES +37 -2
  3. data/assets/placeholder_boxart.png +0 -0
  4. data/bin/gemba +2 -2
  5. data/ext/gemba/extconf.rb +23 -1
  6. data/ext/gemba/gemba_ext.c +436 -2
  7. data/ext/gemba/gemba_ext.h +2 -0
  8. data/gemba.gemspec +5 -3
  9. data/lib/gemba/achievements/achievement.rb +23 -0
  10. data/lib/gemba/achievements/backend.rb +186 -0
  11. data/lib/gemba/achievements/cache.rb +70 -0
  12. data/lib/gemba/achievements/credentials_presenter.rb +142 -0
  13. data/lib/gemba/achievements/fake_backend.rb +205 -0
  14. data/lib/gemba/achievements/null_backend.rb +11 -0
  15. data/lib/gemba/achievements/offline_backend.rb +168 -0
  16. data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
  17. data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
  18. data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
  19. data/lib/gemba/achievements.rb +19 -0
  20. data/lib/gemba/achievements_window.rb +556 -0
  21. data/lib/gemba/app_controller.rb +1015 -0
  22. data/lib/gemba/bios.rb +54 -0
  23. data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
  24. data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
  25. data/lib/gemba/boxart_fetcher.rb +79 -0
  26. data/lib/gemba/bus_emitter.rb +13 -0
  27. data/lib/gemba/child_window.rb +24 -1
  28. data/lib/gemba/cli/commands/config_cmd.rb +83 -0
  29. data/lib/gemba/cli/commands/decode.rb +154 -0
  30. data/lib/gemba/cli/commands/patch.rb +78 -0
  31. data/lib/gemba/cli/commands/play.rb +78 -0
  32. data/lib/gemba/cli/commands/record.rb +114 -0
  33. data/lib/gemba/cli/commands/replay.rb +161 -0
  34. data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
  35. data/lib/gemba/cli/commands/version.rb +22 -0
  36. data/lib/gemba/cli.rb +52 -364
  37. data/lib/gemba/config.rb +134 -1
  38. data/lib/gemba/data/gb_games.json +1 -0
  39. data/lib/gemba/data/gb_md5.json +1 -0
  40. data/lib/gemba/data/gba_games.json +1 -0
  41. data/lib/gemba/data/gba_md5.json +1 -0
  42. data/lib/gemba/data/gbc_games.json +1 -0
  43. data/lib/gemba/data/gbc_md5.json +1 -0
  44. data/lib/gemba/emulator_frame.rb +1060 -0
  45. data/lib/gemba/event_bus.rb +48 -0
  46. data/lib/gemba/frame_stack.rb +60 -0
  47. data/lib/gemba/game_index.rb +84 -0
  48. data/lib/gemba/game_picker_frame.rb +268 -0
  49. data/lib/gemba/gamepad_map.rb +103 -0
  50. data/lib/gemba/headless.rb +6 -5
  51. data/lib/gemba/headless_player.rb +33 -3
  52. data/lib/gemba/help_window.rb +61 -0
  53. data/lib/gemba/hotkey_map.rb +3 -1
  54. data/lib/gemba/input_recorder.rb +107 -0
  55. data/lib/gemba/input_replayer.rb +119 -0
  56. data/lib/gemba/keyboard_map.rb +90 -0
  57. data/lib/gemba/locales/en.yml +97 -5
  58. data/lib/gemba/locales/ja.yml +97 -5
  59. data/lib/gemba/main_window.rb +56 -0
  60. data/lib/gemba/modal_stack.rb +81 -0
  61. data/lib/gemba/patcher_window.rb +223 -0
  62. data/lib/gemba/platform/gb.rb +21 -0
  63. data/lib/gemba/platform/gba.rb +21 -0
  64. data/lib/gemba/platform/gbc.rb +23 -0
  65. data/lib/gemba/platform.rb +20 -0
  66. data/lib/gemba/platform_open.rb +19 -0
  67. data/lib/gemba/recorder.rb +4 -3
  68. data/lib/gemba/replay_player.rb +691 -0
  69. data/lib/gemba/rom_info.rb +57 -0
  70. data/lib/gemba/rom_info_window.rb +16 -3
  71. data/lib/gemba/rom_library.rb +106 -0
  72. data/lib/gemba/rom_overrides.rb +47 -0
  73. data/lib/gemba/rom_patcher/bps.rb +161 -0
  74. data/lib/gemba/rom_patcher/ips.rb +101 -0
  75. data/lib/gemba/rom_patcher/ups.rb +118 -0
  76. data/lib/gemba/rom_patcher.rb +109 -0
  77. data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
  78. data/lib/gemba/runtime.rb +59 -26
  79. data/lib/gemba/save_state_manager.rb +4 -7
  80. data/lib/gemba/save_state_picker.rb +17 -4
  81. data/lib/gemba/session_logger.rb +64 -0
  82. data/lib/gemba/settings/audio_tab.rb +77 -0
  83. data/lib/gemba/settings/gamepad_tab.rb +351 -0
  84. data/lib/gemba/settings/hotkeys_tab.rb +259 -0
  85. data/lib/gemba/settings/paths.rb +11 -0
  86. data/lib/gemba/settings/recording_tab.rb +83 -0
  87. data/lib/gemba/settings/save_states_tab.rb +91 -0
  88. data/lib/gemba/settings/system_tab.rb +362 -0
  89. data/lib/gemba/settings/video_tab.rb +318 -0
  90. data/lib/gemba/settings_window.rb +162 -1036
  91. data/lib/gemba/version.rb +1 -1
  92. data/lib/gemba/virtual_keyboard.rb +19 -0
  93. data/lib/gemba.rb +2 -12
  94. data/test/achievements_window/test_bulk_sync.rb +218 -0
  95. data/test/achievements_window/test_bus_events.rb +125 -0
  96. data/test/achievements_window/test_close_confirmation.rb +201 -0
  97. data/test/achievements_window/test_initial_state.rb +164 -0
  98. data/test/achievements_window/test_sorting.rb +227 -0
  99. data/test/achievements_window/test_tree_rendering.rb +133 -0
  100. data/test/fixtures/fake_bios.bin +0 -0
  101. data/test/fixtures/pong.gba +0 -0
  102. data/test/fixtures/test.gb +0 -0
  103. data/test/fixtures/test.gbc +0 -0
  104. data/test/fixtures/test_quicksave.ss +0 -0
  105. data/test/screenshots/no_focus.png +0 -0
  106. data/test/shared/teek_test_worker.rb +17 -1
  107. data/test/shared/tk_test_helper.rb +91 -4
  108. data/test/support/achievements_window_helpers.rb +18 -0
  109. data/test/support/fake_core.rb +25 -0
  110. data/test/support/fake_ra_runtime.rb +74 -0
  111. data/test/support/fake_requester.rb +68 -0
  112. data/test/support/player_helpers.rb +20 -5
  113. data/test/test_achievement.rb +32 -0
  114. data/test/{test_player.rb → test_app_controller.rb} +353 -85
  115. data/test/test_bios.rb +123 -0
  116. data/test/test_boxart_fetcher.rb +150 -0
  117. data/test/test_cli.rb +17 -265
  118. data/test/test_cli_config.rb +64 -0
  119. data/test/test_cli_decode.rb +97 -0
  120. data/test/test_cli_patch.rb +58 -0
  121. data/test/test_cli_play.rb +213 -0
  122. data/test/test_cli_ra.rb +175 -0
  123. data/test/test_cli_record.rb +69 -0
  124. data/test/test_cli_replay.rb +72 -0
  125. data/test/test_cli_sync_requester.rb +152 -0
  126. data/test/test_cli_version.rb +27 -0
  127. data/test/test_config.rb +2 -3
  128. data/test/test_config_ra.rb +69 -0
  129. data/test/test_core.rb +62 -1
  130. data/test/test_credentials_presenter.rb +192 -0
  131. data/test/test_event_bus.rb +100 -0
  132. data/test/test_fake_backend_achievements.rb +130 -0
  133. data/test/test_fake_backend_auth.rb +68 -0
  134. data/test/test_game_index.rb +77 -0
  135. data/test/test_game_picker_frame.rb +310 -0
  136. data/test/test_gamepad_map.rb +1 -3
  137. data/test/test_headless_player.rb +17 -3
  138. data/test/test_help_window.rb +82 -0
  139. data/test/test_hotkey_map.rb +22 -1
  140. data/test/test_input_recorder.rb +179 -0
  141. data/test/test_input_replay_determinism.rb +113 -0
  142. data/test/test_input_replayer.rb +162 -0
  143. data/test/test_keyboard_map.rb +1 -3
  144. data/test/test_libretro_backend.rb +41 -0
  145. data/test/test_locale.rb +1 -1
  146. data/test/test_logging.rb +123 -0
  147. data/test/test_null_backend.rb +42 -0
  148. data/test/test_offline_backend.rb +116 -0
  149. data/test/test_overlay_renderer.rb +1 -1
  150. data/test/test_platform.rb +149 -0
  151. data/test/test_ra_backend.rb +313 -0
  152. data/test/test_ra_backend_unlock_gate.rb +56 -0
  153. data/test/test_recorder.rb +0 -3
  154. data/test/test_replay_player.rb +316 -0
  155. data/test/test_rom_info.rb +149 -0
  156. data/test/test_rom_overrides.rb +86 -0
  157. data/test/test_rom_patcher.rb +382 -0
  158. data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
  159. data/test/test_save_state_manager.rb +2 -4
  160. data/test/test_settings_audio.rb +107 -0
  161. data/test/test_settings_hotkeys.rb +83 -66
  162. data/test/test_settings_recording.rb +49 -0
  163. data/test/test_settings_save_states.rb +97 -0
  164. data/test/test_settings_system.rb +133 -0
  165. data/test/test_settings_video.rb +450 -0
  166. data/test/test_settings_window.rb +76 -507
  167. data/test/test_tip_service.rb +6 -6
  168. data/test/test_toast_overlay.rb +1 -1
  169. data/test/test_virtual_events.rb +156 -0
  170. data/test/test_virtual_keyboard.rb +1 -1
  171. data/vendor/rcheevos/CHANGELOG.md +495 -0
  172. data/vendor/rcheevos/LICENSE +21 -0
  173. data/vendor/rcheevos/Package.swift +33 -0
  174. data/vendor/rcheevos/README.md +67 -0
  175. data/vendor/rcheevos/include/module.modulemap +70 -0
  176. data/vendor/rcheevos/include/rc_api_editor.h +296 -0
  177. data/vendor/rcheevos/include/rc_api_info.h +280 -0
  178. data/vendor/rcheevos/include/rc_api_request.h +77 -0
  179. data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
  180. data/vendor/rcheevos/include/rc_api_user.h +262 -0
  181. data/vendor/rcheevos/include/rc_client.h +877 -0
  182. data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
  183. data/vendor/rcheevos/include/rc_consoles.h +138 -0
  184. data/vendor/rcheevos/include/rc_error.h +59 -0
  185. data/vendor/rcheevos/include/rc_export.h +100 -0
  186. data/vendor/rcheevos/include/rc_hash.h +200 -0
  187. data/vendor/rcheevos/include/rc_runtime.h +148 -0
  188. data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
  189. data/vendor/rcheevos/include/rc_util.h +51 -0
  190. data/vendor/rcheevos/include/rcheevos.h +8 -0
  191. data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
  192. data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
  193. data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
  194. data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
  195. data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
  196. data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
  197. data/vendor/rcheevos/src/rc_client.c +6941 -0
  198. data/vendor/rcheevos/src/rc_client_external.c +281 -0
  199. data/vendor/rcheevos/src/rc_client_external.h +177 -0
  200. data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
  201. data/vendor/rcheevos/src/rc_client_internal.h +409 -0
  202. data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
  203. data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
  204. data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
  205. data/vendor/rcheevos/src/rc_compat.c +251 -0
  206. data/vendor/rcheevos/src/rc_compat.h +121 -0
  207. data/vendor/rcheevos/src/rc_libretro.c +915 -0
  208. data/vendor/rcheevos/src/rc_libretro.h +98 -0
  209. data/vendor/rcheevos/src/rc_util.c +199 -0
  210. data/vendor/rcheevos/src/rc_version.c +11 -0
  211. data/vendor/rcheevos/src/rc_version.h +32 -0
  212. data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
  213. data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
  214. data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
  215. data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
  216. data/vendor/rcheevos/src/rcheevos/format.c +330 -0
  217. data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
  218. data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
  219. data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
  220. data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
  221. data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
  222. data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
  223. data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
  224. data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
  225. data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
  226. data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
  227. data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
  228. data/vendor/rcheevos/src/rcheevos/value.c +935 -0
  229. data/vendor/rcheevos/src/rhash/aes.c +480 -0
  230. data/vendor/rcheevos/src/rhash/aes.h +49 -0
  231. data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
  232. data/vendor/rcheevos/src/rhash/hash.c +1402 -0
  233. data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
  234. data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
  235. data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
  236. data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
  237. data/vendor/rcheevos/src/rhash/md5.c +382 -0
  238. data/vendor/rcheevos/src/rhash/md5.h +91 -0
  239. data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
  240. data/vendor/rcheevos/test/libretro.h +205 -0
  241. data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
  242. data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
  243. data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
  244. data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
  245. data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
  246. data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
  247. data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
  248. data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
  249. data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
  250. data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
  251. data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
  252. data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
  253. data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
  254. data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
  255. data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
  256. data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
  257. data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
  258. data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
  259. data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
  260. data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
  261. data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
  262. data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
  263. data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
  264. data/vendor/rcheevos/test/rhash/data.c +657 -0
  265. data/vendor/rcheevos/test/rhash/data.h +32 -0
  266. data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
  267. data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
  268. data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
  269. data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
  270. data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
  271. data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
  272. data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
  273. data/vendor/rcheevos/test/test.c +113 -0
  274. data/vendor/rcheevos/test/test_framework.h +205 -0
  275. data/vendor/rcheevos/test/test_rc_client.c +10509 -0
  276. data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
  277. data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
  278. data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
  279. data/vendor/rcheevos/test/test_types.natvis +9 -0
  280. data/vendor/rcheevos/validator/validator.c +658 -0
  281. data/vendor/rcheevos/validator/validator.vcxproj +152 -0
  282. data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
  283. metadata +274 -11
  284. data/lib/gemba/input_mappings.rb +0 -214
  285. data/lib/gemba/player.rb +0 -1525
@@ -0,0 +1,899 @@
1
+ #include "rc_hash.h"
2
+
3
+ #include "../rhash/rc_hash_internal.h"
4
+
5
+ #include "../rc_compat.h"
6
+ #include "../test_framework.h"
7
+ #include "data.h"
8
+ #include "mock_filereader.h"
9
+
10
+ #include <stdlib.h>
11
+
12
+ /* in test_hash.c */
13
+ void test_hash_full_file(uint32_t console_id, const char* filename, size_t size, const char* expected_md5);
14
+ void test_hash_m3u(uint32_t console_id, const char* filename, size_t size, const char* expected_md5);
15
+
16
+ /* ========================================================================= */
17
+
18
+ static void test_hash_arcade(const char* path, const char* expected_md5)
19
+ {
20
+ char hash_file[33], hash_iterator[33];
21
+
22
+ /* test file hash */
23
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_ARCADE, path);
24
+
25
+ /* test file identification from iterator */
26
+ int result_iterator;
27
+ struct rc_hash_iterator iterator;
28
+
29
+ rc_hash_initialize_iterator(&iterator, path, NULL, 0);
30
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
31
+ rc_hash_destroy_iterator(&iterator);
32
+
33
+ /* validation */
34
+ ASSERT_NUM_EQUALS(result_file, 1);
35
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
36
+
37
+ ASSERT_NUM_EQUALS(result_iterator, 1);
38
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
39
+ }
40
+
41
+ /* ========================================================================= */
42
+
43
+ static void test_hash_arduboy()
44
+ {
45
+ char hash_file[33], hash_iterator[33];
46
+ const char* expected_md5 = "67b64633285a7f965064ba29dab45148";
47
+
48
+ const char* hex_input =
49
+ ":100000000C94690D0C94910D0C94910D0C94910D20\n"
50
+ ":100010000C94910D0C94910D0C94910D0C94910DE8\n"
51
+ ":100020000C94910D0C94910D0C94C32A0C94352BC7\n"
52
+ ":00000001FF\n";
53
+ mock_file(0, "game.hex", (const uint8_t*)hex_input, strlen(hex_input));
54
+
55
+ /* test file hash */
56
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_ARDUBOY, "game.hex");
57
+
58
+ /* test file identification from iterator */
59
+ int result_iterator;
60
+ struct rc_hash_iterator iterator;
61
+
62
+ rc_hash_initialize_iterator(&iterator, "game.hex", NULL, 0);
63
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
64
+ rc_hash_destroy_iterator(&iterator);
65
+
66
+ /* validation */
67
+ ASSERT_NUM_EQUALS(result_file, 1);
68
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
69
+
70
+ ASSERT_NUM_EQUALS(result_iterator, 1);
71
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
72
+ }
73
+
74
+ static void test_hash_arduboy_crlf()
75
+ {
76
+ char hash_file[33], hash_iterator[33];
77
+ const char* expected_md5 = "67b64633285a7f965064ba29dab45148";
78
+
79
+ const char* hex_input =
80
+ ":100000000C94690D0C94910D0C94910D0C94910D20\r\n"
81
+ ":100010000C94910D0C94910D0C94910D0C94910DE8\r\n"
82
+ ":100020000C94910D0C94910D0C94C32A0C94352BC7\r\n"
83
+ ":00000001FF\r\n";
84
+ mock_file(0, "game.hex", (const uint8_t*)hex_input, strlen(hex_input));
85
+
86
+ /* test file hash */
87
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_ARDUBOY, "game.hex");
88
+
89
+ /* test file identification from iterator */
90
+ int result_iterator;
91
+ struct rc_hash_iterator iterator;
92
+
93
+ rc_hash_initialize_iterator(&iterator, "game.hex", NULL, 0);
94
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
95
+ rc_hash_destroy_iterator(&iterator);
96
+
97
+ /* validation */
98
+ ASSERT_NUM_EQUALS(result_file, 1);
99
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
100
+
101
+ ASSERT_NUM_EQUALS(result_iterator, 1);
102
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
103
+ }
104
+
105
+ static void test_hash_arduboy_no_final_lf()
106
+ {
107
+ char hash_file[33], hash_iterator[33];
108
+ const char* expected_md5 = "67b64633285a7f965064ba29dab45148";
109
+
110
+ const char* hex_input =
111
+ ":100000000C94690D0C94910D0C94910D0C94910D20\n"
112
+ ":100010000C94910D0C94910D0C94910D0C94910DE8\n"
113
+ ":100020000C94910D0C94910D0C94C32A0C94352BC7\n"
114
+ ":00000001FF";
115
+ mock_file(0, "game.hex", (const uint8_t*)hex_input, strlen(hex_input));
116
+
117
+ /* test file hash */
118
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_ARDUBOY, "game.hex");
119
+
120
+ /* test file identification from iterator */
121
+ int result_iterator;
122
+ struct rc_hash_iterator iterator;
123
+
124
+ rc_hash_initialize_iterator(&iterator, "game.hex", NULL, 0);
125
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
126
+ rc_hash_destroy_iterator(&iterator);
127
+
128
+ /* validation */
129
+ ASSERT_NUM_EQUALS(result_file, 1);
130
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
131
+
132
+ ASSERT_NUM_EQUALS(result_iterator, 1);
133
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
134
+ }
135
+
136
+ /* ========================================================================= */
137
+
138
+ static uint8_t* generate_atari_7800_file(size_t kb, int with_header, size_t* image_size)
139
+ {
140
+ uint8_t* image;
141
+ size_t size_needed = kb * 1024;
142
+ if (with_header)
143
+ size_needed += 128;
144
+
145
+ image = (uint8_t*)calloc(size_needed, 1);
146
+ if (image != NULL) {
147
+ if (with_header) {
148
+ const uint8_t header[128] = {
149
+ 3, 'A', 'T', 'A', 'R', 'I', '7', '8', '0', '0', 0, 0, 0, 0, 0, 0, /* version + magic text */
150
+ 0, 'G', 'a', 'm', 'e', 'N', 'a', 'm', 'e', 0, 0, 0, 0, 0, 0, 0, /* game name */
151
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* game name (cont'd) */
152
+ 0, 0, 2, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* attributes */
153
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* unused */
154
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* unused */
155
+ 0, 0, 0, 0, 'A', 'C', 'T', 'U', 'A', 'L', ' ', 'C', 'A', 'R', 'T',/* magic text*/
156
+ 'D', 'A', 'T', 'A', ' ', 'S', 'T', 'A', 'R', 'T', 'S', ' ', 'H', 'E', 'R', 'E' /* magic text */
157
+ };
158
+ memcpy(image, header, sizeof(header));
159
+ image[50] = (uint8_t)(kb / 4); /* 4-byte value starting at address 49 is the ROM size without header */
160
+
161
+ fill_image(image + 128, size_needed - 128);
162
+ }
163
+ else {
164
+ fill_image(image, size_needed);
165
+ }
166
+ }
167
+
168
+ if (image_size)
169
+ *image_size = size_needed;
170
+ return image;
171
+ }
172
+
173
+ static void test_hash_atari_7800()
174
+ {
175
+ size_t image_size;
176
+ uint8_t* image = generate_atari_7800_file(16, 0, &image_size);
177
+ char hash[33];
178
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_ATARI_7800, image, image_size);
179
+ free(image);
180
+
181
+ ASSERT_NUM_EQUALS(result, 1);
182
+ ASSERT_STR_EQUALS(hash, "455f07d8500f3fabc54906737866167f");
183
+ ASSERT_NUM_EQUALS(image_size, 16384);
184
+ }
185
+
186
+ static void test_hash_atari_7800_with_header()
187
+ {
188
+ size_t image_size;
189
+ uint8_t* image = generate_atari_7800_file(16, 1, &image_size);
190
+ char hash[33];
191
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_ATARI_7800, image, image_size);
192
+ free(image);
193
+
194
+ /* NOTE: expectation is that this hash matches the hash in test_hash_atari_7800 */
195
+ ASSERT_NUM_EQUALS(result, 1);
196
+ ASSERT_STR_EQUALS(hash, "455f07d8500f3fabc54906737866167f");
197
+ ASSERT_NUM_EQUALS(image_size, 16384 + 128);
198
+ }
199
+
200
+ /* ========================================================================= */
201
+
202
+ uint8_t* generate_nes_file(size_t kb, int with_header, size_t* image_size)
203
+ {
204
+ uint8_t* image;
205
+ size_t size_needed = kb * 1024;
206
+ if (with_header)
207
+ size_needed += 16;
208
+
209
+ image = (uint8_t*)calloc(size_needed, 1);
210
+ if (image != NULL) {
211
+ if (with_header) {
212
+ image[0] = 'N';
213
+ image[1] = 'E';
214
+ image[2] = 'S';
215
+ image[3] = '\x1A';
216
+ image[4] = (uint8_t)(kb / 16);
217
+
218
+ fill_image(image + 16, size_needed - 16);
219
+ }
220
+ else {
221
+ fill_image(image, size_needed);
222
+ }
223
+ }
224
+
225
+ if (image_size)
226
+ *image_size = size_needed;
227
+ return image;
228
+ }
229
+
230
+ static uint8_t* generate_fds_file(size_t sides, int with_header, size_t* image_size)
231
+ {
232
+ uint8_t* image;
233
+ size_t size_needed = sides * 65500;
234
+ if (with_header)
235
+ size_needed += 16;
236
+
237
+ image = (uint8_t*)calloc(size_needed, 1);
238
+ if (image != NULL) {
239
+ if (with_header) {
240
+ image[0] = 'F';
241
+ image[1] = 'D';
242
+ image[2] = 'S';
243
+ image[3] = '\x1A';
244
+ image[4] = (uint8_t)sides;
245
+
246
+ fill_image(image + 16, size_needed - 16);
247
+ }
248
+ else {
249
+ fill_image(image, size_needed);
250
+ }
251
+ }
252
+
253
+ if (image_size)
254
+ *image_size = size_needed;
255
+ return image;
256
+ }
257
+
258
+ static void test_hash_nes_32k()
259
+ {
260
+ size_t image_size;
261
+ uint8_t* image = generate_nes_file(32, 0, &image_size);
262
+ char hash[33];
263
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO, image, image_size);
264
+ free(image);
265
+
266
+ ASSERT_NUM_EQUALS(result, 1);
267
+ ASSERT_STR_EQUALS(hash, "6a2305a2b6675a97ff792709be1ca857");
268
+ ASSERT_NUM_EQUALS(image_size, 32768);
269
+ }
270
+
271
+ static void test_hash_nes_32k_with_header()
272
+ {
273
+ size_t image_size;
274
+ uint8_t* image = generate_nes_file(32, 1, &image_size);
275
+ char hash[33];
276
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO, image, image_size);
277
+ free(image);
278
+
279
+ /* NOTE: expectation is that this hash matches the hash in test_hash_nes_32k */
280
+ ASSERT_NUM_EQUALS(result, 1);
281
+ ASSERT_STR_EQUALS(hash, "6a2305a2b6675a97ff792709be1ca857");
282
+ ASSERT_NUM_EQUALS(image_size, 32768 + 16);
283
+ }
284
+
285
+ static void test_hash_nes_256k()
286
+ {
287
+ size_t image_size;
288
+ uint8_t* image = generate_nes_file(256, 0, &image_size);
289
+ char hash[33];
290
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO, image, image_size);
291
+ free(image);
292
+
293
+ ASSERT_NUM_EQUALS(result, 1);
294
+ ASSERT_STR_EQUALS(hash, "545d527301b8ae148153988d6c4fcb84");
295
+ ASSERT_NUM_EQUALS(image_size, 262144);
296
+ }
297
+
298
+ static void test_hash_fds_two_sides()
299
+ {
300
+ size_t image_size;
301
+ uint8_t* image = generate_fds_file(2, 0, &image_size);
302
+ char hash[33];
303
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO, image, image_size);
304
+ free(image);
305
+
306
+ ASSERT_NUM_EQUALS(result, 1);
307
+ ASSERT_STR_EQUALS(hash, "fd770d4d34c00760fabda6ad294a8f0b");
308
+ ASSERT_NUM_EQUALS(image_size, 65500 * 2);
309
+ }
310
+
311
+ static void test_hash_fds_two_sides_with_header()
312
+ {
313
+ size_t image_size;
314
+ uint8_t* image = generate_fds_file(2, 1, &image_size);
315
+ char hash[33];
316
+ int result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO, image, image_size);
317
+ free(image);
318
+
319
+ /* NOTE: expectation is that this hash matches the hash in test_hash_fds_two_sides */
320
+ ASSERT_NUM_EQUALS(result, 1);
321
+ ASSERT_STR_EQUALS(hash, "fd770d4d34c00760fabda6ad294a8f0b");
322
+ ASSERT_NUM_EQUALS(image_size, 65500 * 2 + 16);
323
+ }
324
+
325
+ static void test_hash_nes_file_32k()
326
+ {
327
+ size_t image_size;
328
+ uint8_t* image = generate_nes_file(32, 0, &image_size);
329
+ char hash[33];
330
+ int result;
331
+
332
+ mock_file(0, "test.nes", image, image_size);
333
+ result = rc_hash_generate_from_file(hash, RC_CONSOLE_NINTENDO, "test.nes");
334
+ free(image);
335
+
336
+ ASSERT_NUM_EQUALS(result, 1);
337
+ ASSERT_STR_EQUALS(hash, "6a2305a2b6675a97ff792709be1ca857");
338
+ ASSERT_NUM_EQUALS(image_size, 32768);
339
+ }
340
+
341
+ static void test_hash_nes_iterator_32k()
342
+ {
343
+ size_t image_size;
344
+ uint8_t* image = generate_nes_file(32, 0, &image_size);
345
+ char hash1[33], hash2[33];
346
+ int result1, result2;
347
+ struct rc_hash_iterator iterator;
348
+
349
+ mock_file(0, "test.nes", image, image_size);
350
+ rc_hash_initialize_iterator(&iterator, "test.nes", NULL, 0);
351
+ result1 = rc_hash_iterate(hash1, &iterator);
352
+ result2 = rc_hash_iterate(hash2, &iterator);
353
+ rc_hash_destroy_iterator(&iterator);
354
+ free(image);
355
+
356
+ ASSERT_NUM_EQUALS(result1, 1);
357
+ ASSERT_STR_EQUALS(hash1, "6a2305a2b6675a97ff792709be1ca857");
358
+
359
+ ASSERT_NUM_EQUALS(result2, 0);
360
+ ASSERT_STR_EQUALS(hash2, "");
361
+ }
362
+
363
+ static void test_hash_nes_file_iterator_32k()
364
+ {
365
+ size_t image_size;
366
+ uint8_t* image = generate_nes_file(32, 0, &image_size);
367
+ char hash1[33], hash2[33];
368
+ int result1, result2;
369
+ struct rc_hash_iterator iterator;
370
+ rc_hash_initialize_iterator(&iterator, "test.nes", image, image_size);
371
+ result1 = rc_hash_iterate(hash1, &iterator);
372
+ result2 = rc_hash_iterate(hash2, &iterator);
373
+ rc_hash_destroy_iterator(&iterator);
374
+ free(image);
375
+
376
+ ASSERT_NUM_EQUALS(result1, 1);
377
+ ASSERT_STR_EQUALS(hash1, "6a2305a2b6675a97ff792709be1ca857");
378
+
379
+ ASSERT_NUM_EQUALS(result2, 0);
380
+ ASSERT_STR_EQUALS(hash2, "");
381
+ }
382
+
383
+ /* ========================================================================= */
384
+
385
+ /* first 64 bytes of SUPER MARIO 64 ROM in each N64 format */
386
+ static uint8_t test_rom_z64[64] = {
387
+ 0x80, 0x37, 0x12, 0x40, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x24, 0x60, 0x00, 0x00, 0x00, 0x14, 0x44,
388
+ 0x63, 0x5A, 0x2B, 0xFF, 0x8B, 0x02, 0x23, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389
+ 0x53, 0x55, 0x50, 0x45, 0x52, 0x20, 0x4D, 0x41, 0x52, 0x49, 0x4F, 0x20, 0x36, 0x34, 0x20, 0x20,
390
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x53, 0x4D, 0x45, 0x00
391
+ };
392
+
393
+ static uint8_t test_rom_v64[64] = {
394
+ 0x37, 0x80, 0x40, 0x12, 0x00, 0x00, 0x0F, 0x00, 0x24, 0x80, 0x00, 0x60, 0x00, 0x00, 0x44, 0x14,
395
+ 0x5A, 0x63, 0xFF, 0x2B, 0x02, 0x8B, 0x26, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396
+ 0x55, 0x53, 0x45, 0x50, 0x20, 0x52, 0x41, 0x4D, 0x49, 0x52, 0x20, 0x4F, 0x34, 0x36, 0x20, 0x20,
397
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x4D, 0x53, 0x00, 0x45
398
+ };
399
+
400
+ static uint8_t test_rom_n64[64] = {
401
+ 0x40, 0x12, 0x37, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x60, 0x24, 0x80, 0x44, 0x14, 0x00, 0x00,
402
+ 0xFF, 0x2B, 0x5A, 0x63, 0x26, 0x23, 0x02, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403
+ 0x45, 0x50, 0x55, 0x53, 0x41, 0x4D, 0x20, 0x52, 0x20, 0x4F, 0x49, 0x52, 0x20, 0x20, 0x34, 0x36,
404
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x45, 0x4D, 0x53
405
+ };
406
+
407
+ /* first 64 bytes of DOSHIN THE GIANT in ndd format */
408
+ static uint8_t test_rom_ndd[64] = {
409
+ 0xE8, 0x48, 0xD3, 0x16, 0x10, 0x13, 0x00, 0x45, 0x0C, 0x18, 0x24, 0x30, 0x3C, 0x48, 0x54, 0x60,
410
+ 0x6C, 0x78, 0x84, 0x90, 0x9C, 0xA8, 0xB4, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x02, 0x5C, 0x00,
411
+ 0x10, 0x16, 0x1C, 0x22, 0x28, 0x2A, 0x31, 0x32, 0x3A, 0x40, 0x46, 0x4C, 0x04, 0x0C, 0x14, 0x1C,
412
+ 0x24, 0x2C, 0x34, 0x3C, 0x44, 0x4C, 0x54, 0x5C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x34, 0x3C
413
+ };
414
+
415
+ static void test_hash_n64(uint8_t* buffer, size_t buffer_size, const char* expected_hash)
416
+ {
417
+ char hash[33];
418
+ int result;
419
+
420
+ rc_hash_reset_filereader(); /* explicitly unset the filereader */
421
+ result = rc_hash_generate_from_buffer(hash, RC_CONSOLE_NINTENDO_64, buffer, buffer_size);
422
+ init_mock_filereader(); /* restore the mock filereader */
423
+
424
+ ASSERT_NUM_EQUALS(result, 1);
425
+ ASSERT_STR_EQUALS(hash, expected_hash);
426
+ }
427
+
428
+ static void test_hash_n64_file(const char* filename, uint8_t* buffer, size_t buffer_size, const char* expected_hash)
429
+ {
430
+ char hash_file[33], hash_iterator[33];
431
+ mock_file(0, filename, buffer, buffer_size);
432
+
433
+ /* test file hash */
434
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_NINTENDO_64, filename);
435
+
436
+ /* test file identification from iterator */
437
+ int result_iterator;
438
+ struct rc_hash_iterator iterator;
439
+
440
+ rc_hash_initialize_iterator(&iterator, filename, NULL, 0);
441
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
442
+ rc_hash_destroy_iterator(&iterator);
443
+
444
+ /* validation */
445
+ ASSERT_NUM_EQUALS(result_file, 1);
446
+ ASSERT_STR_EQUALS(hash_file, expected_hash);
447
+
448
+ ASSERT_NUM_EQUALS(result_iterator, 1);
449
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
450
+ }
451
+
452
+ /* ========================================================================= */
453
+
454
+ static uint8_t* generate_nds_file(size_t mb, uint32_t arm9_size, uint32_t arm7_size, size_t* image_size)
455
+ {
456
+ uint8_t* image;
457
+ const size_t size_needed = mb * 1024 * 1024;
458
+
459
+ image = (uint8_t*)calloc(size_needed, 1);
460
+ if (image != NULL) {
461
+ uint32_t arm9_addr = 65536;
462
+ uint32_t arm7_addr = arm9_addr + arm9_size;
463
+ uint32_t icon_addr = arm7_addr + arm7_size;
464
+
465
+ fill_image(image, size_needed);
466
+
467
+ image[0x20] = (arm9_addr & 0xFF);
468
+ image[0x21] = ((arm9_addr >> 8) & 0xFF);
469
+ image[0x22] = ((arm9_addr >> 16) & 0xFF);
470
+ image[0x23] = ((arm9_addr >> 24) & 0xFF);
471
+ image[0x2C] = (arm9_size & 0xFF);
472
+ image[0x2D] = ((arm9_size >> 8) & 0xFF);
473
+ image[0x2E] = ((arm9_size >> 16) & 0xFF);
474
+ image[0x2F] = ((arm9_size >> 24) & 0xFF);
475
+
476
+ image[0x30] = (arm7_addr & 0xFF);
477
+ image[0x31] = ((arm7_addr >> 8) & 0xFF);
478
+ image[0x32] = ((arm7_addr >> 16) & 0xFF);
479
+ image[0x33] = ((arm7_addr >> 24) & 0xFF);
480
+ image[0x3C] = (arm7_size & 0xFF);
481
+ image[0x3D] = ((arm7_size >> 8) & 0xFF);
482
+ image[0x3E] = ((arm7_size >> 16) & 0xFF);
483
+ image[0x3F] = ((arm7_size >> 24) & 0xFF);
484
+
485
+ image[0x68] = (icon_addr & 0xFF);
486
+ image[0x69] = ((icon_addr >> 8) & 0xFF);
487
+ image[0x6A] = ((icon_addr >> 16) & 0xFF);
488
+ image[0x6B] = ((icon_addr >> 24) & 0xFF);
489
+ }
490
+
491
+ if (image_size)
492
+ *image_size = size_needed;
493
+ return image;
494
+ }
495
+
496
+ static void test_hash_nds()
497
+ {
498
+ size_t image_size;
499
+ uint8_t* image = generate_nds_file(2, 1234567, 654321, &image_size);
500
+ char hash_file[33], hash_iterator[33];
501
+ const char* expected_hash = "56b30c276cba4affa886bd38e8e34d7e";
502
+
503
+ mock_file(0, "game.nds", image, image_size);
504
+
505
+ /* test file hash */
506
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_NINTENDO_DS, "game.nds");
507
+
508
+ /* test file identification from iterator */
509
+ int result_iterator;
510
+ struct rc_hash_iterator iterator;
511
+
512
+ rc_hash_initialize_iterator(&iterator, "game.nds", NULL, 0);
513
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
514
+ rc_hash_destroy_iterator(&iterator);
515
+
516
+ /* cleanup */
517
+ free(image);
518
+
519
+ /* validation */
520
+ ASSERT_NUM_EQUALS(result_file, 1);
521
+ ASSERT_STR_EQUALS(hash_file, expected_hash);
522
+
523
+ ASSERT_NUM_EQUALS(result_iterator, 1);
524
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
525
+ }
526
+
527
+ static void test_hash_nds_supercard()
528
+ {
529
+ size_t image_size, image2_size;
530
+ uint8_t* image = generate_nds_file(2, 1234567, 654321, &image_size);
531
+ char hash_file[33], hash_iterator[33];
532
+ const char* expected_hash = "56b30c276cba4affa886bd38e8e34d7e";
533
+ ASSERT_PTR_NOT_NULL(image);
534
+ ASSERT_NUM_GREATER(image_size, 0);
535
+
536
+ /* inject the SuperCard header (512 bytes) */
537
+ image2_size = image_size + 512;
538
+ uint8_t* image2 = malloc(image2_size);
539
+ ASSERT_PTR_NOT_NULL(image2);
540
+ memcpy(&image2[512], &image[0], image_size);
541
+ memset(&image2[0], 0, 512);
542
+ image2[0] = 0x2E;
543
+ image2[1] = 0x00;
544
+ image2[2] = 0x00;
545
+ image2[3] = 0xEA;
546
+ image2[0xB0] = 0x44;
547
+ image2[0xB1] = 0x46;
548
+ image2[0xB2] = 0x96;
549
+ image2[0xB3] = 0x00;
550
+
551
+ mock_file(0, "game.nds", image2, image2_size);
552
+
553
+ /* test file hash */
554
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_NINTENDO_DS, "game.nds");
555
+
556
+ /* test file identification from iterator */
557
+ int result_iterator;
558
+ struct rc_hash_iterator iterator;
559
+
560
+ rc_hash_initialize_iterator(&iterator, "game.nds", NULL, 0);
561
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
562
+ rc_hash_destroy_iterator(&iterator);
563
+
564
+ /* cleanup */
565
+ free(image);
566
+ free(image2);
567
+
568
+ /* validation */
569
+ ASSERT_NUM_EQUALS(result_file, 1);
570
+ ASSERT_STR_EQUALS(hash_file, expected_hash);
571
+
572
+ ASSERT_NUM_EQUALS(result_iterator, 1);
573
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
574
+ }
575
+
576
+ static void test_hash_nds_buffered()
577
+ {
578
+ size_t image_size;
579
+ uint8_t* image = generate_nds_file(2, 1234567, 654321, &image_size);
580
+ char hash_buffer[33], hash_iterator[33];
581
+ const char* expected_hash = "56b30c276cba4affa886bd38e8e34d7e";
582
+
583
+ /* test file hash */
584
+ int result_buffer = rc_hash_generate_from_buffer(hash_buffer, RC_CONSOLE_NINTENDO_DS, image, image_size);
585
+
586
+ /* test file identification from iterator */
587
+ int result_iterator;
588
+ struct rc_hash_iterator iterator;
589
+
590
+ rc_hash_initialize_iterator(&iterator, "game.nds", image, image_size);
591
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
592
+ rc_hash_destroy_iterator(&iterator);
593
+
594
+ /* cleanup */
595
+ free(image);
596
+
597
+ /* validation */
598
+ ASSERT_NUM_EQUALS(result_buffer, 1);
599
+ ASSERT_STR_EQUALS(hash_buffer, expected_hash);
600
+
601
+ ASSERT_NUM_EQUALS(result_iterator, 1);
602
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
603
+ }
604
+
605
+ /* ========================================================================= */
606
+
607
+ static void test_hash_dsi()
608
+ {
609
+ size_t image_size;
610
+ uint8_t* image = generate_nds_file(2, 1234567, 654321, &image_size);
611
+ char hash_file[33], hash_iterator[33];
612
+ const char* expected_hash = "56b30c276cba4affa886bd38e8e34d7e";
613
+
614
+ mock_file(0, "game.nds", image, image_size);
615
+
616
+ /* test file hash */
617
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_NINTENDO_DSI, "game.nds");
618
+
619
+ /* test file identification from iterator */
620
+ int result_iterator;
621
+ struct rc_hash_iterator iterator;
622
+
623
+ rc_hash_initialize_iterator(&iterator, "game.nds", NULL, 0);
624
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
625
+ rc_hash_destroy_iterator(&iterator);
626
+
627
+ /* cleanup */
628
+ free(image);
629
+
630
+ /* validation */
631
+ ASSERT_NUM_EQUALS(result_file, 1);
632
+ ASSERT_STR_EQUALS(hash_file, expected_hash);
633
+
634
+ ASSERT_NUM_EQUALS(result_iterator, 1);
635
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
636
+ }
637
+
638
+ static void test_hash_dsi_buffered()
639
+ {
640
+ size_t image_size;
641
+ uint8_t* image = generate_nds_file(2, 1234567, 654321, &image_size);
642
+ char hash_buffer[33], hash_iterator[33];
643
+ const char* expected_hash = "56b30c276cba4affa886bd38e8e34d7e";
644
+
645
+ /* test file hash */
646
+ int result_buffer = rc_hash_generate_from_buffer(hash_buffer, RC_CONSOLE_NINTENDO_DSI, image, image_size);
647
+
648
+ /* test file identification from iterator */
649
+ int result_iterator;
650
+ struct rc_hash_iterator iterator;
651
+
652
+ rc_hash_initialize_iterator(&iterator, "game.nds", image, image_size);
653
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
654
+ rc_hash_destroy_iterator(&iterator);
655
+
656
+ /* cleanup */
657
+ free(image);
658
+
659
+ /* validation */
660
+ ASSERT_NUM_EQUALS(result_buffer, 1);
661
+ ASSERT_STR_EQUALS(hash_buffer, expected_hash);
662
+
663
+ ASSERT_NUM_EQUALS(result_iterator, 1);
664
+ ASSERT_STR_EQUALS(hash_iterator, expected_hash);
665
+ }
666
+
667
+ /* ========================================================================= */
668
+
669
+ static void test_hash_scv_cart()
670
+ {
671
+ size_t image_size = 32768 + 32;
672
+ uint8_t* image = generate_generic_file(image_size);
673
+ char hash_file[33], hash_iterator[33];
674
+ const char* expected_md5 = "4309c9844b44f9ff8256dfc04687b8fd";
675
+
676
+ memcpy(image, "EmuSCV....CART..................", 32);
677
+
678
+ mock_file(0, "game.cart", image, image_size);
679
+ /* test file hash */
680
+ int result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_SUPER_CASSETTEVISION, "game.cart");
681
+
682
+ /* test file identification from iterator */
683
+ int result_iterator;
684
+ struct rc_hash_iterator iterator;
685
+
686
+ rc_hash_initialize_iterator(&iterator, "game.cart", NULL, 0);
687
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
688
+ rc_hash_destroy_iterator(&iterator);
689
+
690
+ /* cleanup */
691
+ free(image);
692
+
693
+ /* validation */
694
+ ASSERT_NUM_EQUALS(result_file, 1);
695
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
696
+
697
+ ASSERT_NUM_EQUALS(result_iterator, 1);
698
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
699
+ }
700
+
701
+ /* ========================================================================= */
702
+
703
+ void test_hash_rom(void) {
704
+ TEST_SUITE_BEGIN();
705
+
706
+ init_mock_filereader();
707
+
708
+ /* Arcade */
709
+ TEST_PARAMS2(test_hash_arcade, "game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
710
+ TEST_PARAMS2(test_hash_arcade, "game.7z", "c8d46d341bea4fd5bff866a65ff8aea9");
711
+ TEST_PARAMS2(test_hash_arcade, "/game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
712
+ TEST_PARAMS2(test_hash_arcade, "\\game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
713
+ TEST_PARAMS2(test_hash_arcade, "roms\\game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
714
+ TEST_PARAMS2(test_hash_arcade, "C:\\roms\\game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
715
+ TEST_PARAMS2(test_hash_arcade, "/home/user/roms/game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
716
+ TEST_PARAMS2(test_hash_arcade, "/home/user/games/game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
717
+ TEST_PARAMS2(test_hash_arcade, "/home/user/roms/game.7z", "c8d46d341bea4fd5bff866a65ff8aea9");
718
+
719
+ TEST_PARAMS2(test_hash_arcade, "/home/user/nes_game.zip", "9b7aad36b365712fc93728088de4c209");
720
+ TEST_PARAMS2(test_hash_arcade, "/home/user/nes/game.zip", "9b7aad36b365712fc93728088de4c209");
721
+ TEST_PARAMS2(test_hash_arcade, "C:\\roms\\nes\\game.zip", "9b7aad36b365712fc93728088de4c209");
722
+ TEST_PARAMS2(test_hash_arcade, "C:\\roms\\NES\\game.zip", "9b7aad36b365712fc93728088de4c209");
723
+ TEST_PARAMS2(test_hash_arcade, "nes\\game.zip", "9b7aad36b365712fc93728088de4c209");
724
+ TEST_PARAMS2(test_hash_arcade, "/home/user/snes/game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
725
+ TEST_PARAMS2(test_hash_arcade, "/home/user/nes2/game.zip", "c8d46d341bea4fd5bff866a65ff8aea9");
726
+
727
+ /* we don't care that multiple aliases for the same system generate different hashes - the point is
728
+ * that they don't generate the same hash as an actual arcade ROM with the same filename. */
729
+ TEST_PARAMS2(test_hash_arcade, "/home/user/chf/game.zip", "6ef57f16562ea0c7f49d93853b313e32");
730
+ TEST_PARAMS2(test_hash_arcade, "/home/user/channelf/game.zip", "7b6506637a0cc79bd1d24a43a34fa3b9");
731
+ TEST_PARAMS2(test_hash_arcade, "/home/user/coleco/game.zip", "c546f63ae7de98add4b9f221a4749260");
732
+ TEST_PARAMS2(test_hash_arcade, "/home/user/colecovision/game.zip", "47279207b94dbf2a45cb13efa56d685e");
733
+ TEST_PARAMS2(test_hash_arcade, "/home/user/msx/game.zip", "59ab85f6b56324fd81b4e324b804c29f");
734
+ TEST_PARAMS2(test_hash_arcade, "/home/user/msx1/game.zip", "33328d832dcb0854383cdd4a4565c459");
735
+ TEST_PARAMS2(test_hash_arcade, "/home/user/pce/game.zip", "c414a783f3983bbe2e9e01d9d5320c7e");
736
+ TEST_PARAMS2(test_hash_arcade, "/home/user/pcengine/game.zip", "49370c3cbe98bdcdce545c68379487db");
737
+ TEST_PARAMS2(test_hash_arcade, "/home/user/sgx/game.zip", "db545ab29694bfda1010317d4bac83b8");
738
+ TEST_PARAMS2(test_hash_arcade, "/home/user/supergrafx/game.zip", "5665c9ef4c2f6609d8e420c4d86ba692");
739
+ TEST_PARAMS2(test_hash_arcade, "/home/user/tg16/game.zip", "8b6c5c2e54915be2cdba63973862e143");
740
+ TEST_PARAMS2(test_hash_arcade, "/home/user/fds/game.zip", "c0c135a97e8c577cfdf9204823ff211f");
741
+ TEST_PARAMS2(test_hash_arcade, "/home/user/gamegear/game.zip", "f6f471e952b8103032b723f57bdbe767");
742
+ TEST_PARAMS2(test_hash_arcade, "/home/user/mastersystem/game.zip", "f4805afe0ff5647140a26bd0a1057373");
743
+ TEST_PARAMS2(test_hash_arcade, "/home/user/sms/game.zip", "43f35f575dead94dd2f42f9caf69fe5a");
744
+ TEST_PARAMS2(test_hash_arcade, "/home/user/megadriv/game.zip", "f99d0aaf12ba3eb6ced9878c76692c63");
745
+ TEST_PARAMS2(test_hash_arcade, "/home/user/megadrive/game.zip", "73eb5d7034b382093b1d36414d9e84e4");
746
+ TEST_PARAMS2(test_hash_arcade, "/home/user/genesis/game.zip", "b62f810c63e1cba7f5b7569643bec236");
747
+ TEST_PARAMS2(test_hash_arcade, "/home/user/sg1000/game.zip", "e8f6c711c4371f09537b4f2a7a304d6c");
748
+ TEST_PARAMS2(test_hash_arcade, "/home/user/spectrum/game.zip", "a5f62157b2617bd728c4b1bc885c29e9");
749
+ TEST_PARAMS2(test_hash_arcade, "/home/user/ngp/game.zip", "d4133b74c4e57274ca514e27a370dcb6");
750
+
751
+ /* Arduboy */
752
+ TEST(test_hash_arduboy);
753
+ TEST(test_hash_arduboy_crlf);
754
+ TEST(test_hash_arduboy_no_final_lf);
755
+
756
+ /* Arcadia 2001 */
757
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ARCADIA_2001, "test.bin", 4096, "572686c3a073162e4ec6eff86e6f6e3a");
758
+
759
+ /* Atari 2600 */
760
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ATARI_2600, "test.bin", 2048, "02c3f2fa186388ba8eede9147fb431c4");
761
+
762
+ /* Atari 7800 */
763
+ TEST(test_hash_atari_7800);
764
+ TEST(test_hash_atari_7800_with_header);
765
+
766
+ /* Atari Jaguar */
767
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ATARI_JAGUAR, "test.jag", 0x400000, "a247ec8a8c42e18fcb80702dfadac14b");
768
+
769
+ /* Colecovision */
770
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_COLECOVISION, "test.col", 16384, "455f07d8500f3fabc54906737866167f");
771
+
772
+ /* Elektor TV Games Computer */
773
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER, "test.pgm", 4096, "572686c3a073162e4ec6eff86e6f6e3a");
774
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER, "test.tvc", 1861, "37097124a29aff663432d049654a17dc");
775
+
776
+ /* Fairchild Channel F */
777
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_FAIRCHILD_CHANNEL_F, "test.bin", 2048, "02c3f2fa186388ba8eede9147fb431c4");
778
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_FAIRCHILD_CHANNEL_F, "test.chf", 2048, "02c3f2fa186388ba8eede9147fb431c4");
779
+
780
+ /* Gameboy */
781
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_GAMEBOY, "test.gb", 131072, "a0f425b23200568132ba76b2405e3933");
782
+
783
+ /* Gameboy Color */
784
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_GAMEBOY_COLOR, "test.gbc", 2097152, "cf86acf519625a25a17b1246975e90ae");
785
+
786
+ /* Gameboy Advance */
787
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_GAMEBOY_COLOR, "test.gba", 4194304, "a247ec8a8c42e18fcb80702dfadac14b");
788
+
789
+ /* Game Gear */
790
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_GAME_GEAR, "test.gg", 524288, "68f0f13b598e0b66461bc578375c3888");
791
+
792
+ /* Intellivision */
793
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_INTELLIVISION, "test.bin", 8192, "ce1127f881b40ce6a67ecefba50e2835");
794
+
795
+ /* Interton VC 4000 */
796
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_INTERTON_VC_4000, "test.bin", 2048, "02c3f2fa186388ba8eede9147fb431c4");
797
+
798
+ /* Magnavox Odyssey 2 */
799
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_MAGNAVOX_ODYSSEY2, "test.bin", 4096, "572686c3a073162e4ec6eff86e6f6e3a");
800
+
801
+ /* Master System */
802
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_MASTER_SYSTEM, "test.sms", 131072, "a0f425b23200568132ba76b2405e3933");
803
+
804
+ /* Mega Drive */
805
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_MEGA_DRIVE, "test.md", 1048576, "da9461b3b0f74becc3ccf6c2a094c516");
806
+ TEST_PARAMS4(test_hash_m3u, RC_CONSOLE_MEGA_DRIVE, "test.md", 1048576, "da9461b3b0f74becc3ccf6c2a094c516");
807
+
808
+ /* Mega Duck */
809
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_MEGADUCK, "test.bin", 65536, "8e6576cd5c21e44e0bbfc4480577b040");
810
+
811
+ /* Neo Geo Pocket */
812
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_NEOGEO_POCKET, "test.ngc", 2097152, "cf86acf519625a25a17b1246975e90ae");
813
+
814
+ /* NES */
815
+ TEST(test_hash_nes_32k);
816
+ TEST(test_hash_nes_32k_with_header);
817
+ TEST(test_hash_nes_256k);
818
+ TEST(test_hash_fds_two_sides);
819
+ TEST(test_hash_fds_two_sides_with_header);
820
+
821
+ TEST(test_hash_nes_file_32k);
822
+ TEST(test_hash_nes_file_iterator_32k);
823
+ TEST(test_hash_nes_iterator_32k);
824
+
825
+ /* Nintendo 64 */
826
+ TEST_PARAMS3(test_hash_n64, test_rom_z64, sizeof(test_rom_z64), "06096d7ce21cb6bcde38391534c4eb91");
827
+ TEST_PARAMS3(test_hash_n64, test_rom_v64, sizeof(test_rom_v64), "06096d7ce21cb6bcde38391534c4eb91");
828
+ TEST_PARAMS3(test_hash_n64, test_rom_n64, sizeof(test_rom_n64), "06096d7ce21cb6bcde38391534c4eb91");
829
+ TEST_PARAMS4(test_hash_n64_file, "game.z64", test_rom_z64, sizeof(test_rom_z64), "06096d7ce21cb6bcde38391534c4eb91");
830
+ TEST_PARAMS4(test_hash_n64_file, "game.v64", test_rom_v64, sizeof(test_rom_v64), "06096d7ce21cb6bcde38391534c4eb91");
831
+ TEST_PARAMS4(test_hash_n64_file, "game.n64", test_rom_n64, sizeof(test_rom_n64), "06096d7ce21cb6bcde38391534c4eb91");
832
+ TEST_PARAMS4(test_hash_n64_file, "game.n64", test_rom_z64, sizeof(test_rom_z64), "06096d7ce21cb6bcde38391534c4eb91"); /* misnamed */
833
+ TEST_PARAMS4(test_hash_n64_file, "game.z64", test_rom_n64, sizeof(test_rom_n64), "06096d7ce21cb6bcde38391534c4eb91"); /* misnamed */
834
+ TEST_PARAMS3(test_hash_n64, test_rom_ndd, sizeof(test_rom_ndd), "a698b32a52970d8a52a5a52c83acc2a9");
835
+
836
+ /* Nintendo DS */
837
+ TEST(test_hash_nds);
838
+ TEST(test_hash_nds_supercard);
839
+ TEST(test_hash_nds_buffered);
840
+
841
+ /* Nintendo DSi */
842
+ TEST(test_hash_dsi);
843
+ TEST(test_hash_dsi_buffered);
844
+
845
+ /* Oric (no fixed file size) */
846
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_ORIC, "test.tap", 18119, "953a2baa3232c63286aeae36b2172cef");
847
+
848
+ /* PC Engine */
849
+ /* NOTE: because the data after the header doesn't match, the headered and non-headered hashes won't match
850
+ * but the test results ensure that we're only hashing the portion after the header when detected */
851
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_PC_ENGINE, "test.pce", 524288, "68f0f13b598e0b66461bc578375c3888");
852
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_PC_ENGINE, "test.pce", 524288 + 512, "258c93ebaca1c3f488ab48218e5e8d38");
853
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_PC_ENGINE, "test.pce", 491520 + 512, "ebb565a7f964ccdfaecdce0d6ed540af");
854
+
855
+ /* Pokemon Mini */
856
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_POKEMON_MINI, "test.min", 524288, "68f0f13b598e0b66461bc578375c3888");
857
+
858
+ /* Sega 32X */
859
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SEGA_32X, "test.bin", 3145728, "07d733f252896ec41b4fd521fe610e2c");
860
+
861
+ /* SG-1000 */
862
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SG1000, "test.sg", 32768, "6a2305a2b6675a97ff792709be1ca857");
863
+
864
+ /* SNES */
865
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SUPER_NINTENDO, "test.smc", 524288, "68f0f13b598e0b66461bc578375c3888");
866
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SUPER_NINTENDO, "test.smc", 524288 + 512, "258c93ebaca1c3f488ab48218e5e8d38");
867
+
868
+ /* Super Cassette Vision */
869
+ TEST(test_hash_scv_cart);
870
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SUPER_CASSETTEVISION, "test.bin", 32768, "6a2305a2b6675a97ff792709be1ca857");
871
+
872
+ /* TI-83 */
873
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_TI83, "test.83g", 1695, "bfb6048395a425c69743900785987c42");
874
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_TI83, "test.83p", 2500, "6e81d530ee9a79d4f4f505729ad74bb5");
875
+
876
+ /* TIC-80 */
877
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_TIC80, "test.tic", 67682, "79b96f4ffcedb3ce8210a83b22cd2c69");
878
+
879
+ /* Uzebox */
880
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_UZEBOX, "test.uze", 53654, "a9aab505e92edc034d3c732869159789");
881
+
882
+ /* Vectrex */
883
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SG1000, "test.vec", 4096, "572686c3a073162e4ec6eff86e6f6e3a");
884
+
885
+ /* VirtualBoy */
886
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SG1000, "test.vb", 524288, "68f0f13b598e0b66461bc578375c3888");
887
+
888
+ /* Watara Supervision */
889
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_SUPERVISION, "test.sv", 32768, "6a2305a2b6675a97ff792709be1ca857");
890
+
891
+ /* WASM-4 */
892
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_WASM4, "test.wasm", 33454, "bce38bb5f05622fc7e0e56757059d180");
893
+
894
+ /* WonderSwan */
895
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_WONDERSWAN, "test.ws", 524288, "68f0f13b598e0b66461bc578375c3888");
896
+ TEST_PARAMS4(test_hash_full_file, RC_CONSOLE_WONDERSWAN, "test.wsc", 4194304, "a247ec8a8c42e18fcb80702dfadac14b");
897
+
898
+ TEST_SUITE_END();
899
+ }