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,551 @@
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
+ typedef struct mock_zip_file_t {
13
+ uint8_t* buffer;
14
+ uint8_t* ptr;
15
+ uint8_t* file_ptr[8];
16
+ uint32_t num_files;
17
+ uint8_t is_zip64;
18
+ } mock_zip_file_t;
19
+
20
+ static void mock_zip_add_file(mock_zip_file_t* zip, const char* filename, uint32_t crc32, uint32_t size)
21
+ {
22
+ const size_t filename_len = strlen(filename);
23
+ uint8_t* out = zip->ptr;
24
+
25
+ zip->file_ptr[zip->num_files++] = out;
26
+
27
+ /* local file signature */
28
+ *out++ = 'P';
29
+ *out++ = 'K';
30
+ *out++ = 0x03;
31
+ *out++ = 0x04;
32
+
33
+ /* version needed to extract */
34
+ *out++ = 0x14;
35
+ *out++ = 0x00;
36
+
37
+ /* general purpose bit flag*/
38
+ *out++ = 0x02;
39
+ *out++ = 0x00;
40
+
41
+ /* compression method */
42
+ *out++ = 0x08;
43
+ *out++ = 0x00;
44
+
45
+ /* file last modified time */
46
+ *out++ = 0x00;
47
+ *out++ = 0xBC;
48
+
49
+ /* file list modified date */
50
+ *out++ = 0x98;
51
+ *out++ = 0x21;
52
+
53
+ /* CRC-32 */
54
+ *out++ = crc32 & 0xFF;
55
+ *out++ = (crc32 >> 8) & 0xFF;
56
+ *out++ = (crc32 >> 16) & 0xFF;
57
+ *out++ = (crc32 >> 24) & 0xFF;
58
+
59
+ /* compressed size */
60
+ *out++ = size & 0xFF;
61
+ *out++ = (size >> 8) & 0xFF;
62
+ *out++ = (size >> 16) & 0xFF;
63
+ *out++ = (size >> 24) & 0xFF;
64
+
65
+ /* uncompressed size */
66
+ *out++ = size & 0xFF;
67
+ *out++ = (size >> 8) & 0xFF;
68
+ *out++ = (size >> 16) & 0xFF;
69
+ *out++ = (size >> 24) & 0xFF;
70
+
71
+ /* file name length */
72
+ *out++ = filename_len & 0xFF;
73
+ *out++ = (filename_len >> 8) & 0xFF;
74
+
75
+ /* extra field length */
76
+ *out++ = 0;
77
+ *out++ = 0;
78
+
79
+ /* file name */
80
+ memcpy(out, filename, filename_len);
81
+ out += filename_len;
82
+
83
+ /* compressed content */
84
+ *out++ = 0x73;
85
+ *out++ = 0x02;
86
+ *out++ = 0x00;
87
+
88
+ zip->ptr = out;
89
+ }
90
+
91
+ static size_t mock_zip_finalize(mock_zip_file_t* zip, const char* comment)
92
+ {
93
+ size_t comment_len = strlen(comment);
94
+ uint8_t* out = zip->ptr;
95
+ uint8_t* first_cdir_entry = zip->ptr;
96
+ size_t offset;
97
+ uint32_t filename_len;
98
+ uint32_t i;
99
+
100
+ for (i = 0; i < zip->num_files; i++) {
101
+ uint8_t* in = zip->file_ptr[i];
102
+
103
+ /* central directory file header */
104
+ *out++ = 'P';
105
+ *out++ = 'K';
106
+ *out++ = 0x01;
107
+ *out++ = 0x02;
108
+
109
+ /* version made by */
110
+ *out++ = 0x14;
111
+ *out++ = 0x00;
112
+
113
+ /* version needed to extract (2) */
114
+ /* general purpose bit flag (2) */
115
+ /* compression method (2) */
116
+ /* file last modified time (2) */
117
+ /* file list modified date (2) */
118
+ /* CRC-32 (4) */
119
+ /* compressed size (4) */
120
+ /* uncompressed size (4) */
121
+ /* file name length (2) */
122
+ /* extra field length (2) */
123
+ memcpy(out, &in[4], 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 2 + 2);
124
+ if (zip->is_zip64) {
125
+ /* in zip64 mode, blank out the size and the actual size will be appended in an extended field */
126
+ memset(&out[14], 0xFF, 8);
127
+ out[24] = 0x14; /* extra field length */
128
+ }
129
+ out += 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 2 + 2;
130
+
131
+ /* file comment length */
132
+ *out++ = 0;
133
+ *out++ = 0;
134
+
135
+ /* disk number where file starts */
136
+ *out++ = 0;
137
+ *out++ = 0;
138
+
139
+ /* internal file attributes */
140
+ *out++ = 0;
141
+ *out++ = 0;
142
+
143
+ /* external file attributes */
144
+ *out++ = 0;
145
+ *out++ = 0;
146
+ *out++ = 0;
147
+ *out++ = 0;
148
+
149
+ /* local file header offset */
150
+ offset = in - zip->buffer;
151
+ *out++ = offset & 0xFF;
152
+ *out++ = (offset >> 8) & 0xFF;
153
+ *out++ = (offset >> 16) & 0xFF;
154
+ *out++ = (offset >> 24) & 0xFF;
155
+
156
+ /* file name */
157
+ filename_len = (in[27] << 8) | in[26];
158
+ memcpy(out, &in[30], filename_len);
159
+ out += filename_len;
160
+
161
+ if (zip->is_zip64) {
162
+ /* zip64 extended information extra field header id */
163
+ *out++ = 0x01;
164
+ *out++ = 0x00;
165
+
166
+ /* size of extra field chunk */
167
+ *out++ = 0x10; /* only providing file sizes */
168
+ *out++ = 0x00;
169
+
170
+ /* uncompressed file size */
171
+ memset(out, 0, 28);
172
+ memcpy(out, &in[22], 4);
173
+ out += 8;
174
+
175
+ /* compressed file size */
176
+ memset(out, 0, 16);
177
+ memcpy(out, &in[18], 4);
178
+ out += 8;
179
+ }
180
+ }
181
+
182
+ zip->ptr = out;
183
+
184
+ if (zip->is_zip64) {
185
+ /* end of central directory header */
186
+ *out++ = 'P';
187
+ *out++ = 'K';
188
+ *out++ = 0x06;
189
+ *out++ = 0x06;
190
+
191
+ /* size of EOCD64 minus 12 */
192
+ *out++ = 0x2C;
193
+ *out++ = 0;
194
+ *out++ = 0;
195
+ *out++ = 0;
196
+ *out++ = 0;
197
+ *out++ = 0;
198
+ *out++ = 0;
199
+ *out++ = 0;
200
+
201
+ /* version made by */
202
+ *out++ = 0x2D;
203
+ *out++ = 0x00;
204
+
205
+ /* version needed to extract */
206
+ *out++ = 0x2D;
207
+ *out++ = 0x00;
208
+
209
+ /* disk number */
210
+ *out++ = 0;
211
+ *out++ = 0;
212
+ *out++ = 0;
213
+ *out++ = 0;
214
+
215
+ /* disk number of central directory */
216
+ *out++ = 0;
217
+ *out++ = 0;
218
+ *out++ = 0;
219
+ *out++ = 0;
220
+
221
+ /* number of central directory records on this disk */
222
+ *out++ = zip->num_files & 0xFF;
223
+ *out++ = 0;
224
+ *out++ = 0;
225
+ *out++ = 0;
226
+ *out++ = 0;
227
+ *out++ = 0;
228
+ *out++ = 0;
229
+ *out++ = 0;
230
+
231
+ /* total number of central directory records */
232
+ *out++ = zip->num_files & 0xFF;
233
+ *out++ = 0;
234
+ *out++ = 0;
235
+ *out++ = 0;
236
+ *out++ = 0;
237
+ *out++ = 0;
238
+ *out++ = 0;
239
+ *out++ = 0;
240
+
241
+ /* size of central directory */
242
+ offset = zip->ptr - first_cdir_entry;
243
+ *out++ = offset & 0xFF;
244
+ *out++ = (offset >> 8) & 0xFF;
245
+ *out++ = (offset >> 16) & 0xFF;
246
+ *out++ = (offset >> 24) & 0xFF;
247
+ *out++ = 0;
248
+ *out++ = 0;
249
+ *out++ = 0;
250
+ *out++ = 0;
251
+
252
+ /* address of first central directory entry */
253
+ offset = first_cdir_entry - zip->buffer;
254
+ *out++ = offset & 0xFF;
255
+ *out++ = (offset >> 8) & 0xFF;
256
+ *out++ = (offset >> 16) & 0xFF;
257
+ *out++ = (offset >> 24) & 0xFF;
258
+ *out++ = 0;
259
+ *out++ = 0;
260
+ *out++ = 0;
261
+ *out++ = 0;
262
+
263
+ /* end of central directory locator header */
264
+ *out++ = 'P';
265
+ *out++ = 'K';
266
+ *out++ = 0x06;
267
+ *out++ = 0x07;
268
+
269
+ /* disk number */
270
+ *out++ = 0;
271
+ *out++ = 0;
272
+ *out++ = 0;
273
+ *out++ = 0;
274
+
275
+ /* address of central directory 64 */
276
+ offset = zip->ptr - zip->buffer;
277
+ *out++ = offset & 0xFF;
278
+ *out++ = (offset >> 8) & 0xFF;
279
+ *out++ = (offset >> 16) & 0xFF;
280
+ *out++ = (offset >> 24) & 0xFF;
281
+ *out++ = 0;
282
+ *out++ = 0;
283
+ *out++ = 0;
284
+ *out++ = 0;
285
+
286
+ /* total number of disks */
287
+ *out++ = 1;
288
+ *out++ = 0;
289
+ *out++ = 0;
290
+ *out++ = 0;
291
+
292
+ zip->ptr = out;
293
+ }
294
+
295
+ /* end of central directory header */
296
+ *out++ = 'P';
297
+ *out++ = 'K';
298
+ *out++ = 0x05;
299
+ *out++ = 0x06;
300
+
301
+ /* disk number */
302
+ *out++ = 0;
303
+ *out++ = 0;
304
+
305
+ /* central directory disk number */
306
+ *out++ = 0;
307
+ *out++ = 0;
308
+
309
+ /* number of central directory records on this disk */
310
+ *out++ = zip->num_files & 0xFF;
311
+ *out++ = 0;
312
+
313
+ /* total number of central directory records */
314
+ *out++ = zip->num_files & 0xFF;
315
+ *out++ = 0;
316
+
317
+ if (zip->is_zip64) {
318
+ /* size and address of central directory are -1 in zip64 */
319
+ memset(out, 0xFF, 8);
320
+ out += 8;
321
+ }
322
+ else {
323
+ /* size of central directory */
324
+ offset = zip->ptr - first_cdir_entry;
325
+ *out++ = offset & 0xFF;
326
+ *out++ = (offset >> 8) & 0xFF;
327
+ *out++ = (offset >> 16) & 0xFF;
328
+ *out++ = (offset >> 24) & 0xFF;
329
+
330
+ /* address of first central directory entry */
331
+ offset = first_cdir_entry - zip->buffer;
332
+ *out++ = offset & 0xFF;
333
+ *out++ = (offset >> 8) & 0xFF;
334
+ *out++ = (offset >> 16) & 0xFF;
335
+ *out++ = (offset >> 24) & 0xFF;
336
+ }
337
+
338
+ /* comment length */
339
+ *out++ = comment_len & 0xFF;
340
+ *out++ = (comment_len >> 8) & 0xFF;
341
+
342
+ if (comment_len) {
343
+ memcpy(out, comment, comment_len);
344
+ out += comment_len;
345
+ }
346
+
347
+ zip->ptr = out;
348
+
349
+ return (zip->ptr - zip->buffer);
350
+ }
351
+
352
+ /* ========================================================================= */
353
+
354
+ static void test_hash_arduboy_fx()
355
+ {
356
+ char hash_file[33], hash_iterator[33];
357
+ mock_zip_file_t zip;
358
+ uint8_t zip_contents[768];
359
+ size_t zip_size;
360
+ const char* expected_md5 = "e696445c353e9d6b3d60bf5d194b82cf";
361
+ int result_file, result_iterator;
362
+
363
+ memset(&zip, 0, sizeof(zip));
364
+ zip.ptr = zip.buffer = zip_contents;
365
+ mock_zip_add_file(&zip, "info.json", 0xA40B2541, 35);
366
+ mock_zip_add_file(&zip, "game.bin", 0x5AA654C0, 96);
367
+ mock_zip_add_file(&zip, "save.bin", 0xFF000000, 1);
368
+ mock_zip_add_file(&zip, "interp_s2_ArduboyFX.hex", 0x50648360, 71);
369
+ mock_zip_add_file(&zip, "screenshot.png", 0x30056694, 48);
370
+ zip_size = mock_zip_finalize(&zip, "");
371
+ ASSERT_NUM_LESS_EQUALS(zip_size, sizeof(zip_contents));
372
+
373
+ mock_file(0, "game.arduboy", zip_contents, zip_size);
374
+
375
+ /* test file hash */
376
+ result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_ARDUBOY, "game.arduboy");
377
+
378
+ /* test file identification from iterator */
379
+ struct rc_hash_iterator iterator;
380
+ rc_hash_initialize_iterator(&iterator, "game.arduboy", NULL, 0);
381
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
382
+ rc_hash_destroy_iterator(&iterator);
383
+
384
+ /* validation */
385
+ ASSERT_NUM_EQUALS(result_file, 1);
386
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
387
+
388
+ ASSERT_NUM_EQUALS(result_iterator, 1);
389
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
390
+ }
391
+
392
+ /* ========================================================================= */
393
+
394
+ static void test_hash_msdos_dosz()
395
+ {
396
+ char hash_file[33], hash_iterator[33];
397
+ mock_zip_file_t zip;
398
+ uint8_t zip_contents[512];
399
+ size_t zip_size;
400
+ const char* expected_md5 = "59a255662262f5ada32791b8c36e8ea7";
401
+ int result_file, result_iterator;
402
+
403
+ memset(&zip, 0, sizeof(zip));
404
+ zip.ptr = zip.buffer = zip_contents;
405
+ mock_zip_add_file(&zip, "FOLDER/", 0, 0);
406
+ mock_zip_add_file(&zip, "FOLDER/SUB.TXT", 0x4AD0CF31, 1);
407
+ mock_zip_add_file(&zip, "ROOT.TXT", 0xD3D99E8B, 1);
408
+ zip_size = mock_zip_finalize(&zip, "TORRENTZIPPED-FD07C52C");
409
+ ASSERT_NUM_LESS_EQUALS(zip_size, sizeof(zip_contents));
410
+
411
+ mock_file(0, "game.dosz", zip_contents, zip_size);
412
+
413
+ /* test file hash */
414
+ result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_MS_DOS, "game.dosz");
415
+
416
+ /* test file identification from iterator */
417
+ struct rc_hash_iterator iterator;
418
+ rc_hash_initialize_iterator(&iterator, "game.dosz", NULL, 0);
419
+ result_iterator = rc_hash_iterate(hash_iterator, &iterator);
420
+ rc_hash_destroy_iterator(&iterator);
421
+
422
+ /* validation */
423
+ ASSERT_NUM_EQUALS(result_file, 1);
424
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
425
+
426
+ ASSERT_NUM_EQUALS(result_iterator, 1);
427
+ ASSERT_STR_EQUALS(hash_iterator, expected_md5);
428
+ }
429
+
430
+ static void test_hash_msdos_dosz_zip64()
431
+ {
432
+ char hash_file[33];
433
+ mock_zip_file_t zip;
434
+ uint8_t zip_contents[512];
435
+ size_t zip_size;
436
+ const char* expected_md5 = "927dad0a57a2860267ab7bcdb8bc3f61";
437
+ int result_file;
438
+
439
+ memset(&zip, 0, sizeof(zip));
440
+ zip.ptr = zip.buffer = zip_contents;
441
+ zip.is_zip64 = 1;
442
+ mock_zip_add_file(&zip, "README", 0x69FFE77E, 36);
443
+ zip_size = mock_zip_finalize(&zip, "");
444
+ ASSERT_NUM_LESS_EQUALS(zip_size, sizeof(zip_contents));
445
+
446
+ mock_file(0, "game.dosz", zip_contents, zip_size);
447
+
448
+ /* test file hash */
449
+ result_file = rc_hash_generate_from_file(hash_file, RC_CONSOLE_MS_DOS, "game.dosz");
450
+
451
+ /* validation */
452
+ ASSERT_NUM_EQUALS(result_file, 1);
453
+ ASSERT_STR_EQUALS(hash_file, expected_md5);
454
+ }
455
+
456
+ static void test_hash_msdos_dosz_with_dosc()
457
+ {
458
+ char hash_dosc[33];
459
+ const char* expected_dosc_md5 = "dd0c0b0c170c30722784e5e962764c35";
460
+ mock_zip_file_t zip;
461
+ uint8_t zip_contents[512];
462
+ size_t zip_size;
463
+ int result_dosc;
464
+
465
+ memset(&zip, 0, sizeof(zip));
466
+ zip.ptr = zip.buffer = zip_contents;
467
+ mock_zip_add_file(&zip, "FOLDER/", 0, 0);
468
+ mock_zip_add_file(&zip, "FOLDER/SUB.TXT", 0x4AD0CF31, 1);
469
+ mock_zip_add_file(&zip, "ROOT.TXT", 0xD3D99E8B, 1);
470
+ zip_size = mock_zip_finalize(&zip, "TORRENTZIPPED-FD07C52C");
471
+ ASSERT_NUM_LESS_EQUALS(zip_size, sizeof(zip_contents));
472
+
473
+ /* Add main dosz file and overlay dosc file which will get hashed together */
474
+ /* Just use the same file for both to simplify the test */
475
+ mock_file(0, "game.dosz", zip_contents, zip_size);
476
+ mock_file(1, "game.dosc", zip_contents, zip_size);
477
+
478
+ /* test file hash */
479
+ result_dosc = rc_hash_generate_from_file(hash_dosc, RC_CONSOLE_MS_DOS, "game.dosz");
480
+
481
+ /* validation */
482
+ ASSERT_NUM_EQUALS(result_dosc, 1);
483
+ ASSERT_STR_EQUALS(hash_dosc, expected_dosc_md5);
484
+ }
485
+
486
+ static void test_hash_msdos_dosz_with_parent()
487
+ {
488
+ char hash_dosz[33], hash_dosc[33], hash_dosc2[33];
489
+ const char* expected_dosz_md5 = "623c759476b8b5adb46362f8f0b60769";
490
+ const char* expected_dosc_md5 = "ecd9d776cbaad63094829d7b8dbe5959";
491
+ const char* expected_dosc2_md5 = "cb55c123936ad84479032ea6444cb1a1";
492
+ mock_zip_file_t dosz, dosc;
493
+ uint8_t dosz_contents[512], dosc_contents[512];
494
+ size_t dosz_size, dosc_size;
495
+ int result_dosz, result_dosc, result_dosc2;
496
+
497
+ memset(&dosz, 0, sizeof(dosz));
498
+ dosz.ptr = dosz.buffer = dosz_contents;
499
+ mock_zip_add_file(&dosz, "FOLDER/", 0, 0);
500
+ mock_zip_add_file(&dosz, "FOLDER/SUB.TXT", 0x4AD0CF31, 1);
501
+ mock_zip_add_file(&dosz, "ROOT.TXT", 0xD3D99E8B, 1);
502
+ dosz_size = mock_zip_finalize(&dosz, "TORRENTZIPPED-FD07C52C");
503
+ ASSERT_NUM_LESS_EQUALS(dosz_size, sizeof(dosz_contents));
504
+
505
+ memset(&dosc, 0, sizeof(dosz));
506
+ dosc.ptr = dosc.buffer = dosc_contents;
507
+ mock_zip_add_file(&dosc, "base.dosz.parent", 0, 0);
508
+ mock_zip_add_file(&dosc, "CHILD.TXT", 0x22B35429, 5);
509
+ dosc_size = mock_zip_finalize(&dosc, "");
510
+ ASSERT_NUM_LESS_EQUALS(dosz_size, sizeof(dosc_contents));
511
+
512
+ /* Add base dosz file and child dosz file which will get hashed together */
513
+ mock_file(0, "base.dosz", dosz_contents, dosz_size);
514
+ mock_file(1, "child.dosz", dosc_contents, dosc_size);
515
+
516
+ /* test file hash */
517
+ result_dosz = rc_hash_generate_from_file(hash_dosz, RC_CONSOLE_MS_DOS, "child.dosz");
518
+
519
+ /* test file hash with base.dosc also existing */
520
+ mock_file(2, "base.dosc", dosz_contents, dosz_size);
521
+ result_dosc = rc_hash_generate_from_file(hash_dosc, RC_CONSOLE_MS_DOS, "child.dosz");
522
+
523
+ /* test file hash with child.dosc also existing */
524
+ mock_file(3, "child.dosc", dosz_contents, dosz_size);
525
+ result_dosc2 = rc_hash_generate_from_file(hash_dosc2, RC_CONSOLE_MS_DOS, "child.dosz");
526
+
527
+ /* validation */
528
+ ASSERT_NUM_EQUALS(result_dosz, 1);
529
+ ASSERT_NUM_EQUALS(result_dosc, 1);
530
+ ASSERT_NUM_EQUALS(result_dosc2, 1);
531
+ ASSERT_STR_EQUALS(hash_dosz, expected_dosz_md5);
532
+ ASSERT_STR_EQUALS(hash_dosc, expected_dosc_md5);
533
+ ASSERT_STR_EQUALS(hash_dosc2, expected_dosc2_md5);
534
+ }
535
+
536
+ /* ========================================================================= */
537
+
538
+ void test_hash_zip(void) {
539
+ TEST_SUITE_BEGIN();
540
+
541
+ /* Arduboy FX */
542
+ TEST(test_hash_arduboy_fx);
543
+
544
+ /* MS DOS */
545
+ TEST(test_hash_msdos_dosz);
546
+ TEST(test_hash_msdos_dosz_zip64);
547
+ TEST(test_hash_msdos_dosz_with_dosc);
548
+ TEST(test_hash_msdos_dosz_with_parent);
549
+
550
+ TEST_SUITE_END();
551
+ }
@@ -0,0 +1,113 @@
1
+ #include "rc_internal.h"
2
+
3
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
4
+ #include "rc_client_raintegration.h"
5
+ #endif
6
+
7
+ #include "test_framework.h"
8
+
9
+ #include <assert.h>
10
+
11
+ #define TIMING_TEST 0
12
+
13
+ extern void test_timing();
14
+
15
+ extern void test_condition();
16
+ extern void test_memref();
17
+ extern void test_operand();
18
+ extern void test_condset();
19
+ extern void test_trigger();
20
+ extern void test_value();
21
+ extern void test_format();
22
+ extern void test_lboard();
23
+ extern void test_richpresence();
24
+ extern void test_runtime();
25
+ extern void test_runtime_progress();
26
+
27
+ extern void test_client();
28
+ #ifdef RC_CLIENT_SUPPORTS_EXTERNAL
29
+ extern void test_client_external();
30
+ #endif
31
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
32
+ extern void test_client_raintegration();
33
+ #endif
34
+
35
+ extern void test_consoleinfo();
36
+ extern void test_rc_libretro();
37
+ extern void test_rc_validate();
38
+
39
+ extern void test_hash();
40
+ #ifndef RC_HASH_NO_ROM
41
+ extern void test_hash_rom();
42
+ #endif
43
+ #ifndef RC_HASH_NO_DISC
44
+ extern void test_cdreader();
45
+ extern void test_hash_disc();
46
+ #endif
47
+ #ifndef RC_HASH_NO_ZIP
48
+ extern void test_hash_zip();
49
+ #endif
50
+
51
+ extern void test_rapi_common();
52
+ extern void test_rapi_user();
53
+ extern void test_rapi_runtime();
54
+ extern void test_rapi_info();
55
+ extern void test_rapi_editor();
56
+
57
+ TEST_FRAMEWORK_DECLARATIONS()
58
+
59
+ int main(void) {
60
+ TEST_FRAMEWORK_INIT();
61
+
62
+ #if TIMING_TEST
63
+ test_timing();
64
+ #else
65
+ test_memref();
66
+ test_operand();
67
+ test_condition();
68
+ test_condset();
69
+ test_trigger();
70
+ test_value();
71
+ test_format();
72
+ test_lboard();
73
+ test_richpresence();
74
+ test_runtime();
75
+ test_runtime_progress();
76
+
77
+ test_consoleinfo();
78
+ test_rc_validate();
79
+
80
+ test_rapi_common();
81
+ test_rapi_user();
82
+ test_rapi_runtime();
83
+ test_rapi_info();
84
+ test_rapi_editor();
85
+
86
+ test_client();
87
+ #ifdef RC_CLIENT_SUPPORTS_EXTERNAL
88
+ test_client_external();
89
+ #endif
90
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
91
+ test_client_raintegration();
92
+ #endif
93
+ #ifdef RC_CLIENT_SUPPORTS_HASH
94
+ /* no direct compile option for hash support, so leverage RC_CLIENT_SUPPORTS_HASH */
95
+ test_rc_libretro(); /* libretro extensions require hash support */
96
+ test_hash();
97
+ #ifndef RC_HASH_NO_ROM
98
+ test_hash_rom();
99
+ #endif
100
+ #ifndef RC_HASH_NO_DISC
101
+ test_cdreader();
102
+ test_hash_disc();
103
+ #endif
104
+ #ifndef RC_HASH_NO_ZIP
105
+ test_hash_zip();
106
+ #endif
107
+ #endif
108
+ #endif
109
+
110
+ TEST_FRAMEWORK_SHUTDOWN();
111
+
112
+ return TEST_FRAMEWORK_PASSED() ? 0 : 1;
113
+ }