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.
- checksums.yaml +4 -4
- data/THIRD_PARTY_NOTICES +37 -2
- data/assets/placeholder_boxart.png +0 -0
- data/bin/gemba +2 -2
- data/ext/gemba/extconf.rb +23 -1
- data/ext/gemba/gemba_ext.c +436 -2
- data/ext/gemba/gemba_ext.h +2 -0
- data/gemba.gemspec +5 -3
- data/lib/gemba/achievements/achievement.rb +23 -0
- data/lib/gemba/achievements/backend.rb +186 -0
- data/lib/gemba/achievements/cache.rb +70 -0
- data/lib/gemba/achievements/credentials_presenter.rb +142 -0
- data/lib/gemba/achievements/fake_backend.rb +205 -0
- data/lib/gemba/achievements/null_backend.rb +11 -0
- data/lib/gemba/achievements/offline_backend.rb +168 -0
- data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
- data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
- data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
- data/lib/gemba/achievements.rb +19 -0
- data/lib/gemba/achievements_window.rb +556 -0
- data/lib/gemba/app_controller.rb +1015 -0
- data/lib/gemba/bios.rb +54 -0
- data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
- data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
- data/lib/gemba/boxart_fetcher.rb +79 -0
- data/lib/gemba/bus_emitter.rb +13 -0
- data/lib/gemba/child_window.rb +24 -1
- data/lib/gemba/cli/commands/config_cmd.rb +83 -0
- data/lib/gemba/cli/commands/decode.rb +154 -0
- data/lib/gemba/cli/commands/patch.rb +78 -0
- data/lib/gemba/cli/commands/play.rb +78 -0
- data/lib/gemba/cli/commands/record.rb +114 -0
- data/lib/gemba/cli/commands/replay.rb +161 -0
- data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
- data/lib/gemba/cli/commands/version.rb +22 -0
- data/lib/gemba/cli.rb +52 -364
- data/lib/gemba/config.rb +134 -1
- data/lib/gemba/data/gb_games.json +1 -0
- data/lib/gemba/data/gb_md5.json +1 -0
- data/lib/gemba/data/gba_games.json +1 -0
- data/lib/gemba/data/gba_md5.json +1 -0
- data/lib/gemba/data/gbc_games.json +1 -0
- data/lib/gemba/data/gbc_md5.json +1 -0
- data/lib/gemba/emulator_frame.rb +1060 -0
- data/lib/gemba/event_bus.rb +48 -0
- data/lib/gemba/frame_stack.rb +60 -0
- data/lib/gemba/game_index.rb +84 -0
- data/lib/gemba/game_picker_frame.rb +268 -0
- data/lib/gemba/gamepad_map.rb +103 -0
- data/lib/gemba/headless.rb +6 -5
- data/lib/gemba/headless_player.rb +33 -3
- data/lib/gemba/help_window.rb +61 -0
- data/lib/gemba/hotkey_map.rb +3 -1
- data/lib/gemba/input_recorder.rb +107 -0
- data/lib/gemba/input_replayer.rb +119 -0
- data/lib/gemba/keyboard_map.rb +90 -0
- data/lib/gemba/locales/en.yml +97 -5
- data/lib/gemba/locales/ja.yml +97 -5
- data/lib/gemba/main_window.rb +56 -0
- data/lib/gemba/modal_stack.rb +81 -0
- data/lib/gemba/patcher_window.rb +223 -0
- data/lib/gemba/platform/gb.rb +21 -0
- data/lib/gemba/platform/gba.rb +21 -0
- data/lib/gemba/platform/gbc.rb +23 -0
- data/lib/gemba/platform.rb +20 -0
- data/lib/gemba/platform_open.rb +19 -0
- data/lib/gemba/recorder.rb +4 -3
- data/lib/gemba/replay_player.rb +691 -0
- data/lib/gemba/rom_info.rb +57 -0
- data/lib/gemba/rom_info_window.rb +16 -3
- data/lib/gemba/rom_library.rb +106 -0
- data/lib/gemba/rom_overrides.rb +47 -0
- data/lib/gemba/rom_patcher/bps.rb +161 -0
- data/lib/gemba/rom_patcher/ips.rb +101 -0
- data/lib/gemba/rom_patcher/ups.rb +118 -0
- data/lib/gemba/rom_patcher.rb +109 -0
- data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
- data/lib/gemba/runtime.rb +59 -26
- data/lib/gemba/save_state_manager.rb +4 -7
- data/lib/gemba/save_state_picker.rb +17 -4
- data/lib/gemba/session_logger.rb +64 -0
- data/lib/gemba/settings/audio_tab.rb +77 -0
- data/lib/gemba/settings/gamepad_tab.rb +351 -0
- data/lib/gemba/settings/hotkeys_tab.rb +259 -0
- data/lib/gemba/settings/paths.rb +11 -0
- data/lib/gemba/settings/recording_tab.rb +83 -0
- data/lib/gemba/settings/save_states_tab.rb +91 -0
- data/lib/gemba/settings/system_tab.rb +362 -0
- data/lib/gemba/settings/video_tab.rb +318 -0
- data/lib/gemba/settings_window.rb +162 -1036
- data/lib/gemba/version.rb +1 -1
- data/lib/gemba/virtual_keyboard.rb +19 -0
- data/lib/gemba.rb +2 -12
- data/test/achievements_window/test_bulk_sync.rb +218 -0
- data/test/achievements_window/test_bus_events.rb +125 -0
- data/test/achievements_window/test_close_confirmation.rb +201 -0
- data/test/achievements_window/test_initial_state.rb +164 -0
- data/test/achievements_window/test_sorting.rb +227 -0
- data/test/achievements_window/test_tree_rendering.rb +133 -0
- data/test/fixtures/fake_bios.bin +0 -0
- data/test/fixtures/pong.gba +0 -0
- data/test/fixtures/test.gb +0 -0
- data/test/fixtures/test.gbc +0 -0
- data/test/fixtures/test_quicksave.ss +0 -0
- data/test/screenshots/no_focus.png +0 -0
- data/test/shared/teek_test_worker.rb +17 -1
- data/test/shared/tk_test_helper.rb +91 -4
- data/test/support/achievements_window_helpers.rb +18 -0
- data/test/support/fake_core.rb +25 -0
- data/test/support/fake_ra_runtime.rb +74 -0
- data/test/support/fake_requester.rb +68 -0
- data/test/support/player_helpers.rb +20 -5
- data/test/test_achievement.rb +32 -0
- data/test/{test_player.rb → test_app_controller.rb} +353 -85
- data/test/test_bios.rb +123 -0
- data/test/test_boxart_fetcher.rb +150 -0
- data/test/test_cli.rb +17 -265
- data/test/test_cli_config.rb +64 -0
- data/test/test_cli_decode.rb +97 -0
- data/test/test_cli_patch.rb +58 -0
- data/test/test_cli_play.rb +213 -0
- data/test/test_cli_ra.rb +175 -0
- data/test/test_cli_record.rb +69 -0
- data/test/test_cli_replay.rb +72 -0
- data/test/test_cli_sync_requester.rb +152 -0
- data/test/test_cli_version.rb +27 -0
- data/test/test_config.rb +2 -3
- data/test/test_config_ra.rb +69 -0
- data/test/test_core.rb +62 -1
- data/test/test_credentials_presenter.rb +192 -0
- data/test/test_event_bus.rb +100 -0
- data/test/test_fake_backend_achievements.rb +130 -0
- data/test/test_fake_backend_auth.rb +68 -0
- data/test/test_game_index.rb +77 -0
- data/test/test_game_picker_frame.rb +310 -0
- data/test/test_gamepad_map.rb +1 -3
- data/test/test_headless_player.rb +17 -3
- data/test/test_help_window.rb +82 -0
- data/test/test_hotkey_map.rb +22 -1
- data/test/test_input_recorder.rb +179 -0
- data/test/test_input_replay_determinism.rb +113 -0
- data/test/test_input_replayer.rb +162 -0
- data/test/test_keyboard_map.rb +1 -3
- data/test/test_libretro_backend.rb +41 -0
- data/test/test_locale.rb +1 -1
- data/test/test_logging.rb +123 -0
- data/test/test_null_backend.rb +42 -0
- data/test/test_offline_backend.rb +116 -0
- data/test/test_overlay_renderer.rb +1 -1
- data/test/test_platform.rb +149 -0
- data/test/test_ra_backend.rb +313 -0
- data/test/test_ra_backend_unlock_gate.rb +56 -0
- data/test/test_recorder.rb +0 -3
- data/test/test_replay_player.rb +316 -0
- data/test/test_rom_info.rb +149 -0
- data/test/test_rom_overrides.rb +86 -0
- data/test/test_rom_patcher.rb +382 -0
- data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
- data/test/test_save_state_manager.rb +2 -4
- data/test/test_settings_audio.rb +107 -0
- data/test/test_settings_hotkeys.rb +83 -66
- data/test/test_settings_recording.rb +49 -0
- data/test/test_settings_save_states.rb +97 -0
- data/test/test_settings_system.rb +133 -0
- data/test/test_settings_video.rb +450 -0
- data/test/test_settings_window.rb +76 -507
- data/test/test_tip_service.rb +6 -6
- data/test/test_toast_overlay.rb +1 -1
- data/test/test_virtual_events.rb +156 -0
- data/test/test_virtual_keyboard.rb +1 -1
- data/vendor/rcheevos/CHANGELOG.md +495 -0
- data/vendor/rcheevos/LICENSE +21 -0
- data/vendor/rcheevos/Package.swift +33 -0
- data/vendor/rcheevos/README.md +67 -0
- data/vendor/rcheevos/include/module.modulemap +70 -0
- data/vendor/rcheevos/include/rc_api_editor.h +296 -0
- data/vendor/rcheevos/include/rc_api_info.h +280 -0
- data/vendor/rcheevos/include/rc_api_request.h +77 -0
- data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
- data/vendor/rcheevos/include/rc_api_user.h +262 -0
- data/vendor/rcheevos/include/rc_client.h +877 -0
- data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
- data/vendor/rcheevos/include/rc_consoles.h +138 -0
- data/vendor/rcheevos/include/rc_error.h +59 -0
- data/vendor/rcheevos/include/rc_export.h +100 -0
- data/vendor/rcheevos/include/rc_hash.h +200 -0
- data/vendor/rcheevos/include/rc_runtime.h +148 -0
- data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
- data/vendor/rcheevos/include/rc_util.h +51 -0
- data/vendor/rcheevos/include/rcheevos.h +8 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
- data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
- data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
- data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
- data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
- data/vendor/rcheevos/src/rc_client.c +6941 -0
- data/vendor/rcheevos/src/rc_client_external.c +281 -0
- data/vendor/rcheevos/src/rc_client_external.h +177 -0
- data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
- data/vendor/rcheevos/src/rc_client_internal.h +409 -0
- data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
- data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
- data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
- data/vendor/rcheevos/src/rc_compat.c +251 -0
- data/vendor/rcheevos/src/rc_compat.h +121 -0
- data/vendor/rcheevos/src/rc_libretro.c +915 -0
- data/vendor/rcheevos/src/rc_libretro.h +98 -0
- data/vendor/rcheevos/src/rc_util.c +199 -0
- data/vendor/rcheevos/src/rc_version.c +11 -0
- data/vendor/rcheevos/src/rc_version.h +32 -0
- data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
- data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
- data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
- data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
- data/vendor/rcheevos/src/rcheevos/format.c +330 -0
- data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
- data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
- data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
- data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
- data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
- data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
- data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
- data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
- data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
- data/vendor/rcheevos/src/rcheevos/value.c +935 -0
- data/vendor/rcheevos/src/rhash/aes.c +480 -0
- data/vendor/rcheevos/src/rhash/aes.h +49 -0
- data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
- data/vendor/rcheevos/src/rhash/hash.c +1402 -0
- data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
- data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
- data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
- data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
- data/vendor/rcheevos/src/rhash/md5.c +382 -0
- data/vendor/rcheevos/src/rhash/md5.h +91 -0
- data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
- data/vendor/rcheevos/test/libretro.h +205 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
- data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
- data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
- data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
- data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
- data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
- data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
- data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
- data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
- data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
- data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
- data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
- data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
- data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
- data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
- data/vendor/rcheevos/test/rhash/data.c +657 -0
- data/vendor/rcheevos/test/rhash/data.h +32 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
- data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
- data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
- data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
- data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
- data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
- data/vendor/rcheevos/test/test.c +113 -0
- data/vendor/rcheevos/test/test_framework.h +205 -0
- data/vendor/rcheevos/test/test_rc_client.c +10509 -0
- data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
- data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
- data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
- data/vendor/rcheevos/test/test_types.natvis +9 -0
- data/vendor/rcheevos/validator/validator.c +658 -0
- data/vendor/rcheevos/validator/validator.vcxproj +152 -0
- data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
- metadata +274 -11
- data/lib/gemba/input_mappings.rb +0 -214
- data/lib/gemba/player.rb +0 -1525
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
#include "data.h"
|
|
2
|
+
|
|
3
|
+
#include "../src/rc_compat.h"
|
|
4
|
+
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
void fill_image(uint8_t* image, size_t size)
|
|
9
|
+
{
|
|
10
|
+
int seed = (int)(size ^ (size >> 8) ^ ((size - 1) * 25387));
|
|
11
|
+
int count;
|
|
12
|
+
uint8_t value;
|
|
13
|
+
|
|
14
|
+
while (size > 0)
|
|
15
|
+
{
|
|
16
|
+
switch (seed & 0xFF)
|
|
17
|
+
{
|
|
18
|
+
case 0:
|
|
19
|
+
count = (((seed >> 8) & 0x3F) & ~(size & 0x0F));
|
|
20
|
+
if (count == 0)
|
|
21
|
+
count = 1;
|
|
22
|
+
value = 0;
|
|
23
|
+
break;
|
|
24
|
+
|
|
25
|
+
case 1:
|
|
26
|
+
count = ((seed >> 8) & 0x07) + 1;
|
|
27
|
+
value = ((seed >> 16) & 0xFF);
|
|
28
|
+
break;
|
|
29
|
+
|
|
30
|
+
case 2:
|
|
31
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
32
|
+
value = ((seed >> 16) & 0xFF) ^ 0xFF;
|
|
33
|
+
break;
|
|
34
|
+
|
|
35
|
+
case 3:
|
|
36
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
37
|
+
value = ((seed >> 16) & 0xFF) ^ 0xA5;
|
|
38
|
+
break;
|
|
39
|
+
|
|
40
|
+
case 4:
|
|
41
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
42
|
+
value = ((seed >> 16) & 0xFF) ^ 0xC3;
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
case 5:
|
|
46
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
47
|
+
value = ((seed >> 16) & 0xFF) ^ 0x96;
|
|
48
|
+
break;
|
|
49
|
+
|
|
50
|
+
case 6:
|
|
51
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
52
|
+
value = ((seed >> 16) & 0xFF) ^ 0x78;
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
case 7:
|
|
56
|
+
count = ((seed >> 8) & 0x03) + 1;
|
|
57
|
+
value = ((seed >> 16) & 0xFF) ^ 0x78;
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
default:
|
|
61
|
+
count = 1;
|
|
62
|
+
value = ((seed >> 8) ^ (seed >> 16)) & 0xFF;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
do
|
|
67
|
+
{
|
|
68
|
+
*image++ = value;
|
|
69
|
+
--size;
|
|
70
|
+
} while (size && --count);
|
|
71
|
+
|
|
72
|
+
/* state mutation from psuedo-random number generator */
|
|
73
|
+
seed = (seed * 0x41C64E6D + 12345) & 0x7FFFFFFF;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
uint8_t* generate_gamecube_iso(size_t mb, size_t* image_size)
|
|
78
|
+
{
|
|
79
|
+
uint8_t* image;
|
|
80
|
+
const size_t size_needed = mb * 1024 * 1024;
|
|
81
|
+
int ix;
|
|
82
|
+
|
|
83
|
+
image = (uint8_t*)calloc(size_needed, 1);
|
|
84
|
+
if (image != NULL)
|
|
85
|
+
{
|
|
86
|
+
uint32_t apploader_sizes_addr = 0x2440 + 0x14;
|
|
87
|
+
uint32_t dol_offset_addr = 0x420;
|
|
88
|
+
uint32_t dol_sizes_addr = 0x3000;
|
|
89
|
+
|
|
90
|
+
fill_image(image, size_needed);
|
|
91
|
+
|
|
92
|
+
image[0x1c] = 0xC2;
|
|
93
|
+
image[0x1d] = 0x33;
|
|
94
|
+
image[0x1e] = 0x9F;
|
|
95
|
+
image[0x1f] = 0x3D;
|
|
96
|
+
|
|
97
|
+
for (ix = 0; ix < 8; ix++)
|
|
98
|
+
{
|
|
99
|
+
/* 0x000000ff for both */
|
|
100
|
+
image[apploader_sizes_addr + ix] = (ix % 4 == 3) ? 0xff : 0;
|
|
101
|
+
}
|
|
102
|
+
for (ix = 0; ix < 4; ix++)
|
|
103
|
+
{
|
|
104
|
+
/* 0x00003000 */
|
|
105
|
+
image[dol_offset_addr + ix] = (ix % 4 == 2) ? 0x30 : 0;
|
|
106
|
+
}
|
|
107
|
+
for (ix = 0; ix < 18 * 4; ix++)
|
|
108
|
+
{
|
|
109
|
+
/* offsets start at 0x00003100 and increment */
|
|
110
|
+
image[dol_sizes_addr + ix] = (ix % 4 == 2) ? (0x30 + 1 + ix / 4) : 0;
|
|
111
|
+
/* 0x000000ff for every other size */
|
|
112
|
+
image[dol_sizes_addr + 0x90 + ix] = (ix % 8 == 3) ? 0xff : 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (image_size)
|
|
117
|
+
*image_size = size_needed;
|
|
118
|
+
return image;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
uint8_t* generate_3do_bin(uint32_t root_directory_sectors, uint32_t binary_size, size_t* image_size)
|
|
122
|
+
{
|
|
123
|
+
const uint8_t volume_header[] = {
|
|
124
|
+
0x01, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x01, 0x00, /* header */
|
|
125
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* comment */
|
|
126
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
127
|
+
'C', 'D', '-', 'R', 'O', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* label */
|
|
128
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
129
|
+
0x2D, 0x79, 0x6E, 0x96, /* identifier */
|
|
130
|
+
0x00, 0x00, 0x08, 0x00, /* block size */
|
|
131
|
+
0x00, 0x00, 0x05, 0x00, /* block count */
|
|
132
|
+
0x31, 0x5a, 0xf2, 0xe6, /* root directory identifier */
|
|
133
|
+
0x00, 0x00, 0x00, 0x01, /* root directory size in blocks */
|
|
134
|
+
0x00, 0x00, 0x08, 0x00, /* block size in root directory */
|
|
135
|
+
0x00, 0x00, 0x00, 0x06, /* number of copies of root directory */
|
|
136
|
+
0x00, 0x00, 0x00, 0x01, /* block location of root directory */
|
|
137
|
+
0x00, 0x00, 0x00, 0x01, /* block location of first copy of root directory */
|
|
138
|
+
0x00, 0x00, 0x00, 0x01,
|
|
139
|
+
0x00, 0x00, 0x00, 0x01,
|
|
140
|
+
0x00, 0x00, 0x00, 0x01,
|
|
141
|
+
0x00, 0x00, 0x00, 0x01,
|
|
142
|
+
0x00, 0x00, 0x00, 0x01, /* block location of last copy of root directory */
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const uint8_t directory_data[] = {
|
|
146
|
+
0xFF, 0xFF, 0xFF, 0xFF, /* next block */
|
|
147
|
+
0xFF, 0xFF, 0xFF, 0xFF, /* previous block */
|
|
148
|
+
0x00, 0x00, 0x00, 0x00, /* flags */
|
|
149
|
+
0x00, 0x00, 0x00, 0xA4, /* end of block */
|
|
150
|
+
0x00, 0x00, 0x00, 0x14, /* start of block */
|
|
151
|
+
|
|
152
|
+
0x00, 0x00, 0x00, 0x07, /* flags - directory */
|
|
153
|
+
0x00, 0x00, 0x00, 0x00, /* identifier */
|
|
154
|
+
0x00, 0x00, 0x00, 0x00, /* type */
|
|
155
|
+
0x00, 0x00, 0x08, 0x00, /* block size */
|
|
156
|
+
0x00, 0x00, 0x00, 0x00, /* length in bytes */
|
|
157
|
+
0x00, 0x00, 0x00, 0x00, /* length in blocks */
|
|
158
|
+
0x00, 0x00, 0x00, 0x00, /* burst */
|
|
159
|
+
0x00, 0x00, 0x00, 0x00, /* gap */
|
|
160
|
+
'f', 'o', 'l', 'd', 'e', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* filename */
|
|
161
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
162
|
+
0x00, 0x00, 0x00, 0x00, /* extra copies */
|
|
163
|
+
0x00, 0x00, 0x00, 0x00, /* directory block address */
|
|
164
|
+
|
|
165
|
+
0x00, 0x00, 0x00, 0x02, /* flags - file */
|
|
166
|
+
0x00, 0x00, 0x00, 0x00, /* identifier */
|
|
167
|
+
0x00, 0x00, 0x00, 0x00, /* type */
|
|
168
|
+
0x00, 0x00, 0x08, 0x00, /* block size */
|
|
169
|
+
0x00, 0x00, 0x00, 0x00, /* length in bytes */
|
|
170
|
+
0x00, 0x00, 0x00, 0x00, /* length in blocks */
|
|
171
|
+
0x00, 0x00, 0x00, 0x00, /* burst */
|
|
172
|
+
0x00, 0x00, 0x00, 0x00, /* gap */
|
|
173
|
+
'L', 'a', 'u', 'n', 'c', 'h', 'M', 'e', 0, 0, 0, 0, 0, 0, 0, 0, /* filename */
|
|
174
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
175
|
+
0x00, 0x00, 0x00, 0x00, /* extra copies */
|
|
176
|
+
0x00, 0x00, 0x00, 0x02, /* directory block address */
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
size_t size_needed = (root_directory_sectors + 1 + ((binary_size + 2047) / 2048)) * 2048;
|
|
180
|
+
uint8_t* image = (uint8_t*)calloc(size_needed, 1);
|
|
181
|
+
size_t offset = 2048;
|
|
182
|
+
uint32_t i;
|
|
183
|
+
|
|
184
|
+
if (!image)
|
|
185
|
+
return NULL;
|
|
186
|
+
|
|
187
|
+
/* first sector - volume header */
|
|
188
|
+
memcpy(image, volume_header, sizeof(volume_header));
|
|
189
|
+
image[0x5B] = (uint8_t)root_directory_sectors;
|
|
190
|
+
|
|
191
|
+
/* root directory sectors */
|
|
192
|
+
for (i = 0; i < root_directory_sectors; ++i)
|
|
193
|
+
{
|
|
194
|
+
memcpy(&image[offset], directory_data, sizeof(directory_data));
|
|
195
|
+
if (i < root_directory_sectors - 1)
|
|
196
|
+
{
|
|
197
|
+
image[offset + 0] = 0;
|
|
198
|
+
image[offset + 1] = 0;
|
|
199
|
+
image[offset + 2] = 0;
|
|
200
|
+
image[offset + 3] = (uint8_t)(i + 1);
|
|
201
|
+
|
|
202
|
+
memcpy(&image[offset + 0x14 + 0x48 + 0x20], "filename", 8);
|
|
203
|
+
}
|
|
204
|
+
else
|
|
205
|
+
{
|
|
206
|
+
image[offset + 0x14 + 0x48 + 0x11] = (binary_size >> 16) & 0xFF;
|
|
207
|
+
image[offset + 0x14 + 0x48 + 0x12] = (binary_size >> 8) & 0xFF;
|
|
208
|
+
image[offset + 0x14 + 0x48 + 0x13] = (binary_size & 0xFF);
|
|
209
|
+
|
|
210
|
+
image[offset + 0x14 + 0x48 + 0x16] = (((binary_size + 2047) / 2048) >> 8) & 0xFF;
|
|
211
|
+
image[offset + 0x14 + 0x48 + 0x17] = ((binary_size + 2047) / 2048) & 0xFF;
|
|
212
|
+
|
|
213
|
+
image[offset + 0x14 + 0x48 + 0x47] = (uint8_t)(i + 2);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (i > 0)
|
|
217
|
+
{
|
|
218
|
+
image[offset + 4] = 0;
|
|
219
|
+
image[offset + 5] = 0;
|
|
220
|
+
image[offset + 6] = 0;
|
|
221
|
+
image[offset + 7] = (uint8_t)(i - 1);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
offset += 2048;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* binary data */
|
|
228
|
+
fill_image(&image[offset], binary_size);
|
|
229
|
+
|
|
230
|
+
*image_size = size_needed;
|
|
231
|
+
return image;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
uint8_t* generate_dreamcast_bin(uint32_t track_first_sector, uint32_t binary_size, size_t* image_size)
|
|
235
|
+
{
|
|
236
|
+
/* https://mc.pp.se/dc/ip0000.bin.html */
|
|
237
|
+
const uint8_t volume_header[] =
|
|
238
|
+
"SEGA SEGAKATANA "
|
|
239
|
+
"SEGA ENTERPRISES"
|
|
240
|
+
"5966 GD-ROM1/1 " /* device info */
|
|
241
|
+
" U 918FA01 " /* region and peripherals */
|
|
242
|
+
"X-1234N V1.001" /* product number and version */
|
|
243
|
+
"20200910 " /* release date */
|
|
244
|
+
"1ST_READ.BIN " /* boot file */
|
|
245
|
+
"RETROACHIEVEMENT" /* company name */
|
|
246
|
+
"UNIT TEST " /* product name */
|
|
247
|
+
" "
|
|
248
|
+
" "
|
|
249
|
+
" "
|
|
250
|
+
" "
|
|
251
|
+
" "
|
|
252
|
+
" "
|
|
253
|
+
" ";
|
|
254
|
+
|
|
255
|
+
const uint8_t directory_data[] = {
|
|
256
|
+
0x30, /* length of directory record */
|
|
257
|
+
0x00, /* extended attribute record length */
|
|
258
|
+
0xD9, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* first logical block of file */
|
|
259
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* length in bytes */
|
|
260
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* date/time */
|
|
261
|
+
0x00, 0x00, 0x00, /* flags, unit size, gap size */
|
|
262
|
+
0x00, 0x00, 0x00, 0x00, /* sequence number*/
|
|
263
|
+
0x0E, /* length of file identifier */
|
|
264
|
+
'1', 'S', 'T', '_', 'R', 'E', 'A', 'D', '.', 'B', 'I', 'N', ';', '1', /* file identifier */
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const size_t binary_sectors = (binary_size + 2047) / 2048;
|
|
268
|
+
const size_t size_needed = (binary_sectors + 18) * 2048;
|
|
269
|
+
uint8_t* image = (uint8_t*)calloc(size_needed, 1);
|
|
270
|
+
if (!image)
|
|
271
|
+
return NULL;
|
|
272
|
+
|
|
273
|
+
/* volume header goes in sector 0 */
|
|
274
|
+
memcpy(&image[0], volume_header, sizeof(volume_header));
|
|
275
|
+
|
|
276
|
+
/* directory information goes in sectors 16 and 17 */
|
|
277
|
+
memcpy(&image[2048 * 16], "1CD001", 6);
|
|
278
|
+
image[2048 * 16 + 156 + 2] = 45017 & 0xFF;
|
|
279
|
+
image[2048 * 16 + 156 + 3] = (45017 >> 8) & 0xFF;
|
|
280
|
+
image[2048 * 16 + 156 + 4] = (45017 >> 16) & 0xFF;
|
|
281
|
+
memcpy(&image[2048 * 17], directory_data, sizeof(directory_data));
|
|
282
|
+
|
|
283
|
+
track_first_sector += 18;
|
|
284
|
+
image[2048 * 17 + 2] = (track_first_sector & 0xFF);
|
|
285
|
+
image[2048 * 17 + 3] = ((track_first_sector >> 8) & 0xFF);
|
|
286
|
+
image[2048 * 17 + 4] = ((track_first_sector >> 16) & 0xFF);
|
|
287
|
+
image[2048 * 17 + 10] = (binary_size & 0xFF);
|
|
288
|
+
image[2048 * 17 + 11] = ((binary_size >> 8) & 0xFF);
|
|
289
|
+
image[2048 * 17 + 12] = ((binary_size >> 16) & 0xFF);
|
|
290
|
+
image[2048 * 17 + 13] = ((binary_size >> 24) & 0xFF);
|
|
291
|
+
|
|
292
|
+
/* binary data */
|
|
293
|
+
fill_image(&image[2048 * 18], binary_sectors * 2048);
|
|
294
|
+
|
|
295
|
+
*image_size = size_needed;
|
|
296
|
+
return image;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
uint8_t* generate_pce_cd_bin(uint32_t binary_sectors, size_t* image_size)
|
|
300
|
+
{
|
|
301
|
+
const uint8_t volume_header[] = {
|
|
302
|
+
0x00, 0x00, 0x02, /* first sector of boot code */
|
|
303
|
+
0x14, /* number of sectors for boot code */
|
|
304
|
+
0x00, 0x40, /* program load address */
|
|
305
|
+
0x00, 0x40, /* program execute address */
|
|
306
|
+
0, 1, 2, 3, 4, /* IPLMPR */
|
|
307
|
+
0, /* open mode */
|
|
308
|
+
0, 0, 0, 0, 0, 0, /* GRPBLK and addr */
|
|
309
|
+
0, 0, 0, 0, 0, /* ADPBLK and rate */
|
|
310
|
+
0, 0, 0, 0, 0, 0, 0, /* reserved */
|
|
311
|
+
'P', 'C', ' ', 'E', 'n', 'g', 'i', 'n', 'e', ' ', 'C', 'D', '-', 'R', 'O', 'M',
|
|
312
|
+
' ', 'S', 'Y', 'S', 'T', 'E', 'M', '\0', 'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h',
|
|
313
|
+
't', ' ', 'H', 'U', 'D', 'S', 'O', 'N', ' ', 'S', 'O', 'F', 'T', ' ', '/', ' ',
|
|
314
|
+
'N', 'E', 'C', ' ', 'H', 'o', 'm', 'e', ' ', 'E', 'l', 'e', 'c', 't', 'r', 'o',
|
|
315
|
+
'n', 'i', 'c', 's', ',', 'L', 't', 'd', '.', '\0', 'G', 'A', 'M', 'E', 'N', 'A',
|
|
316
|
+
'M', 'E', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
size_t size_needed = (binary_sectors + 2) * 2048;
|
|
320
|
+
uint8_t* image = (uint8_t*)calloc(size_needed, 1);
|
|
321
|
+
if (!image)
|
|
322
|
+
return NULL;
|
|
323
|
+
|
|
324
|
+
/* volume header goes in second sector */
|
|
325
|
+
memcpy(&image[2048], volume_header, sizeof(volume_header));
|
|
326
|
+
image[2048 + 0x03] = (uint8_t)binary_sectors;
|
|
327
|
+
|
|
328
|
+
/* binary data */
|
|
329
|
+
fill_image(&image[4096], binary_sectors * 2048);
|
|
330
|
+
|
|
331
|
+
*image_size = size_needed;
|
|
332
|
+
return image;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
uint8_t* generate_pcfx_bin(uint32_t binary_sectors, size_t* image_size)
|
|
336
|
+
{
|
|
337
|
+
const uint8_t volume_header[] = {
|
|
338
|
+
'G', 'A', 'M', 'E', 'N', 'A', 'M', 'E', 0, 0, 0, 0, 0, 0, 0, 0, /* title (32-bytes) */
|
|
339
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
340
|
+
0x02, 0x00, 0x00, 0x00, /* first sector of boot code */
|
|
341
|
+
0x14, 0x00, 0x00, 0x00, /* number of sectors for boot code */
|
|
342
|
+
0x00, 0x80, 0x00, 0x00, /* program load address */
|
|
343
|
+
0x00, 0x80, 0x00, 0x00, /* program execute address */
|
|
344
|
+
'N', '/', 'A', '\0', /* maker id */
|
|
345
|
+
'r', 'c', 'h', 'e', 'e', 'v', 'o', 's', 't', 'e', 's', 't', 0, 0, 0, 0, /* maker name (60-bytes) */
|
|
346
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
347
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
348
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
349
|
+
0x00, 0x00, 0x00, 0x00, /* volume number */
|
|
350
|
+
0x00, 0x01, /* version */
|
|
351
|
+
0x01, 0x00, /* country */
|
|
352
|
+
'2', '0', '2', '0', 'X', 'X', 'X', 'X', /* date */
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
size_t size_needed = (binary_sectors + 2) * 2048;
|
|
356
|
+
uint8_t* image = (uint8_t*)calloc(size_needed, 1);
|
|
357
|
+
if (!image)
|
|
358
|
+
return NULL;
|
|
359
|
+
|
|
360
|
+
/* volume header goes in second sector */
|
|
361
|
+
strcpy_s((char*)&image[0], size_needed, "PC-FX:Hu_CD-ROM");
|
|
362
|
+
memcpy(&image[2048], volume_header, sizeof(volume_header));
|
|
363
|
+
image[2048 + 0x24] = (uint8_t)binary_sectors;
|
|
364
|
+
|
|
365
|
+
/* binary data */
|
|
366
|
+
fill_image(&image[4096], binary_sectors * 2048);
|
|
367
|
+
|
|
368
|
+
*image_size = size_needed;
|
|
369
|
+
return image;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
uint8_t* generate_iso9660_bin(uint32_t num_sectors, const char* volume_label, size_t* image_size)
|
|
373
|
+
{
|
|
374
|
+
const uint8_t identifier[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
|
|
375
|
+
uint8_t* volume_descriptor;;
|
|
376
|
+
uint8_t* image;
|
|
377
|
+
|
|
378
|
+
*image_size = num_sectors * 2048;
|
|
379
|
+
image = calloc(*image_size, 1);
|
|
380
|
+
if (!image)
|
|
381
|
+
return NULL;
|
|
382
|
+
|
|
383
|
+
volume_descriptor = &image[16 * 2048];
|
|
384
|
+
|
|
385
|
+
/* CD001 identifier */
|
|
386
|
+
memcpy(volume_descriptor, identifier, 8);
|
|
387
|
+
|
|
388
|
+
/* volume label */
|
|
389
|
+
memcpy(&volume_descriptor[40], volume_label, strlen(volume_label));
|
|
390
|
+
|
|
391
|
+
/* number of sectors (little endian, then big endian) */
|
|
392
|
+
volume_descriptor[80] = image[87] = num_sectors & 0xFF;
|
|
393
|
+
volume_descriptor[81] = image[86] = (num_sectors >> 8) & 0xFF;
|
|
394
|
+
volume_descriptor[82] = image[85] = (num_sectors >> 16) & 0xFF;
|
|
395
|
+
volume_descriptor[83] = image[84] = (num_sectors >> 24) & 0xFF;
|
|
396
|
+
|
|
397
|
+
/* size of each sector */
|
|
398
|
+
volume_descriptor[128] = (2048) & 0xFF;
|
|
399
|
+
volume_descriptor[129] = (2048 >> 8) & 0xFF;
|
|
400
|
+
|
|
401
|
+
/* root directory record location */
|
|
402
|
+
volume_descriptor[158] = 17;
|
|
403
|
+
|
|
404
|
+
/* helper for tracking next free sector - not actually part of iso9660 spec */
|
|
405
|
+
image[17 * 2048 - 4] = 18;
|
|
406
|
+
|
|
407
|
+
return image;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
uint8_t* generate_iso9660_file(uint8_t* image, const char* filename, const uint8_t* contents, size_t contents_size)
|
|
411
|
+
{
|
|
412
|
+
const uint32_t root_directory_record_offset = 17 * 2048;
|
|
413
|
+
uint8_t* file_entry_start = &image[root_directory_record_offset];
|
|
414
|
+
uint8_t* file_contents_start;
|
|
415
|
+
size_t filename_len;
|
|
416
|
+
uint32_t next_free_sector = image[root_directory_record_offset - 4] |
|
|
417
|
+
(image[root_directory_record_offset - 3] << 8) | (image[root_directory_record_offset - 2] << 16);
|
|
418
|
+
const char* separator;
|
|
419
|
+
|
|
420
|
+
/* we start at the root. ignore explicit root path */
|
|
421
|
+
if (*filename == '\\')
|
|
422
|
+
++filename;
|
|
423
|
+
|
|
424
|
+
/* handle subdirectories */
|
|
425
|
+
do
|
|
426
|
+
{
|
|
427
|
+
separator = filename;
|
|
428
|
+
while (*separator && *separator != '\\')
|
|
429
|
+
++separator;
|
|
430
|
+
|
|
431
|
+
if (!*separator)
|
|
432
|
+
break;
|
|
433
|
+
|
|
434
|
+
filename_len = separator - filename;
|
|
435
|
+
int found = 0;
|
|
436
|
+
while (*file_entry_start)
|
|
437
|
+
{
|
|
438
|
+
if (file_entry_start[25] && /* is directory */
|
|
439
|
+
file_entry_start[33 + filename_len] == '\0' && memcmp(&file_entry_start[33], filename, filename_len) == 0)
|
|
440
|
+
{
|
|
441
|
+
const uint32_t directory_sector = file_entry_start[2];
|
|
442
|
+
file_entry_start = &image[directory_sector * 2048];
|
|
443
|
+
found = 1;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
file_entry_start += *file_entry_start;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (!found)
|
|
451
|
+
{
|
|
452
|
+
/* entry size*/
|
|
453
|
+
file_entry_start[0] = (filename_len & 0xFF) + 48;
|
|
454
|
+
|
|
455
|
+
/* directory sector */
|
|
456
|
+
file_entry_start[2] = next_free_sector & 0xFF;
|
|
457
|
+
file_entry_start[3] = (next_free_sector >> 8) & 0xFF;
|
|
458
|
+
|
|
459
|
+
/* is directory */
|
|
460
|
+
file_entry_start[25] = 1;
|
|
461
|
+
|
|
462
|
+
/* directory name */
|
|
463
|
+
file_entry_start[32] = filename_len & 0xFF;
|
|
464
|
+
memcpy(&file_entry_start[33], filename, filename_len);
|
|
465
|
+
file_entry_start[33 + filename_len] = '\0';
|
|
466
|
+
|
|
467
|
+
/* advance to next sector */
|
|
468
|
+
file_entry_start = &image[next_free_sector * 2048];
|
|
469
|
+
next_free_sector++;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
filename = separator + 1;
|
|
473
|
+
} while (1);
|
|
474
|
+
|
|
475
|
+
/* skip over any items already in the directory */
|
|
476
|
+
while (*file_entry_start)
|
|
477
|
+
file_entry_start += *file_entry_start;
|
|
478
|
+
|
|
479
|
+
/* create the new entry */
|
|
480
|
+
|
|
481
|
+
/* entry size*/
|
|
482
|
+
filename_len = separator - filename;
|
|
483
|
+
file_entry_start[0] = (filename_len & 0xFF) + 48;
|
|
484
|
+
|
|
485
|
+
/* file sector */
|
|
486
|
+
file_entry_start[2] = next_free_sector & 0xFF;
|
|
487
|
+
file_entry_start[3] = (next_free_sector >> 8) & 0xFF;
|
|
488
|
+
|
|
489
|
+
/* file size */
|
|
490
|
+
file_entry_start[10] = contents_size & 0xFF;
|
|
491
|
+
file_entry_start[11] = (contents_size >> 8) & 0xFF;
|
|
492
|
+
file_entry_start[12] = (contents_size >> 16) & 0xFF;
|
|
493
|
+
|
|
494
|
+
/* file name */
|
|
495
|
+
file_entry_start[32] = (filename_len + 2) & 0xFF;
|
|
496
|
+
memcpy(&file_entry_start[33], filename, filename_len);
|
|
497
|
+
file_entry_start[33 + filename_len] = ';';
|
|
498
|
+
file_entry_start[34 + filename_len] = '1';
|
|
499
|
+
|
|
500
|
+
/* contents */
|
|
501
|
+
file_contents_start = &image[next_free_sector * 2048];
|
|
502
|
+
|
|
503
|
+
if (contents)
|
|
504
|
+
memcpy(file_contents_start, contents, contents_size);
|
|
505
|
+
else
|
|
506
|
+
fill_image(file_contents_start, contents_size);
|
|
507
|
+
|
|
508
|
+
/* update next free sector */
|
|
509
|
+
next_free_sector += (unsigned)(contents_size + 2047) / 2048;
|
|
510
|
+
image[root_directory_record_offset - 4] = (next_free_sector & 0xFF);
|
|
511
|
+
image[root_directory_record_offset - 3] = (next_free_sector >> 8) & 0xFF;
|
|
512
|
+
image[root_directory_record_offset - 2] = (next_free_sector >> 16) & 0xFF;
|
|
513
|
+
|
|
514
|
+
/* return pointer to contents so caller can modify if desired */
|
|
515
|
+
return file_contents_start;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
uint8_t* generate_jaguarcd_bin(uint32_t header_offset, uint32_t binary_size, int byteswapped, size_t* image_size)
|
|
519
|
+
{
|
|
520
|
+
size_t size_needed = (((binary_size + 64 + 32 + 8) + 2351) / 2352) * 2352;
|
|
521
|
+
uint8_t* image = (uint8_t*)calloc(size_needed, 1);
|
|
522
|
+
size_t i;
|
|
523
|
+
|
|
524
|
+
if (!image)
|
|
525
|
+
return NULL;
|
|
526
|
+
|
|
527
|
+
/* header is 64 bytes of ATRI repeating followed by approved data message, load address, and binary size */
|
|
528
|
+
for (i = 0; i < 64; i += 4)
|
|
529
|
+
memcpy(&image[header_offset + i], "ATRI", 4);
|
|
530
|
+
memcpy(&image[header_offset + 64], "ATARI APPROVED DATA HEADER ATRI ", 32);
|
|
531
|
+
image[header_offset + 64 + 32 + 2] = 0xA0;
|
|
532
|
+
image[header_offset + 64 + 32 + 4 + 1] = (binary_size >> 16);
|
|
533
|
+
image[header_offset + 64 + 32 + 4 + 2] = (binary_size >> 8) & 0xFF;
|
|
534
|
+
image[header_offset + 64 + 32 + 4 + 3] = (binary_size & 0xFF);
|
|
535
|
+
|
|
536
|
+
/* binary data */
|
|
537
|
+
fill_image(&image[header_offset + 64 + 32 + 8], size_needed - (header_offset + 64 + 32 + 8));
|
|
538
|
+
|
|
539
|
+
if (byteswapped)
|
|
540
|
+
{
|
|
541
|
+
for (i = 0; i < size_needed; i += 2)
|
|
542
|
+
{
|
|
543
|
+
uint8_t tmp = image[i];
|
|
544
|
+
image[i] = image[i + 1];
|
|
545
|
+
image[i + 1] = tmp;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
*image_size = size_needed;
|
|
550
|
+
return image;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
uint8_t* generate_psx_bin(const char* binary_name, uint32_t binary_size, size_t* image_size)
|
|
554
|
+
{
|
|
555
|
+
const uint32_t sectors_needed = (((binary_size + 2047) / 2048) + 20);
|
|
556
|
+
char system_cnf[256];
|
|
557
|
+
uint8_t* image;
|
|
558
|
+
uint8_t* exe;
|
|
559
|
+
|
|
560
|
+
snprintf(system_cnf, sizeof(system_cnf), "BOOT=cdrom:\\%s;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n", binary_name);
|
|
561
|
+
|
|
562
|
+
image = generate_iso9660_bin(sectors_needed, "TEST", image_size);
|
|
563
|
+
generate_iso9660_file(image, "SYSTEM.CNF", (const uint8_t*)system_cnf, strlen(system_cnf));
|
|
564
|
+
|
|
565
|
+
/* binary data */
|
|
566
|
+
exe = generate_iso9660_file(image, binary_name, NULL, binary_size);
|
|
567
|
+
memcpy(exe, "PS-X EXE", 8);
|
|
568
|
+
|
|
569
|
+
binary_size -= 2048;
|
|
570
|
+
exe[28] = binary_size & 0xFF;
|
|
571
|
+
exe[29] = (binary_size >> 8) & 0xFF;
|
|
572
|
+
exe[30] = (binary_size >> 16) & 0xFF;
|
|
573
|
+
exe[31] = (binary_size >> 24) & 0xFF;
|
|
574
|
+
|
|
575
|
+
return image;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
uint8_t* generate_ps2_bin(const char* binary_name, uint32_t binary_size, size_t* image_size)
|
|
579
|
+
{
|
|
580
|
+
const uint32_t sectors_needed = (((binary_size + 2047) / 2048) + 20);
|
|
581
|
+
char system_cnf[256];
|
|
582
|
+
uint8_t* image;
|
|
583
|
+
uint8_t* exe;
|
|
584
|
+
|
|
585
|
+
snprintf(system_cnf, sizeof(system_cnf), "BOOT2 = cdrom0:\\%s;1\nVER = 1.0\nVMODE = NTSC\n", binary_name);
|
|
586
|
+
|
|
587
|
+
image = generate_iso9660_bin(sectors_needed, "TEST", image_size);
|
|
588
|
+
generate_iso9660_file(image, "SYSTEM.CNF", (const uint8_t*)system_cnf, strlen(system_cnf));
|
|
589
|
+
|
|
590
|
+
/* binary data */
|
|
591
|
+
exe = generate_iso9660_file(image, binary_name, NULL, binary_size);
|
|
592
|
+
memcpy(exe, "\x7f\x45\x4c\x46", 4);
|
|
593
|
+
|
|
594
|
+
return image;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
uint8_t* generate_generic_file(size_t size)
|
|
598
|
+
{
|
|
599
|
+
uint8_t* image;
|
|
600
|
+
image = (uint8_t*)calloc(size, 1);
|
|
601
|
+
if (image != NULL)
|
|
602
|
+
fill_image(image, size);
|
|
603
|
+
|
|
604
|
+
return image;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
uint8_t* convert_to_2352(uint8_t* input, size_t* size, uint32_t first_sector)
|
|
608
|
+
{
|
|
609
|
+
const uint32_t num_sectors = (uint32_t)((*size + 2047) / 2048);
|
|
610
|
+
const uint32_t output_size = num_sectors * 2352;
|
|
611
|
+
const uint8_t sync_pattern[] = {
|
|
612
|
+
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
|
613
|
+
};
|
|
614
|
+
uint8_t* output = (uint8_t*)malloc(output_size);
|
|
615
|
+
uint8_t* input_ptr = input;
|
|
616
|
+
uint8_t* ptr = output;
|
|
617
|
+
uint8_t minutes, seconds, frames;
|
|
618
|
+
uint32_t i;
|
|
619
|
+
|
|
620
|
+
first_sector += 150;
|
|
621
|
+
frames = (first_sector % 75);
|
|
622
|
+
first_sector /= 75;
|
|
623
|
+
seconds = (first_sector % 60);
|
|
624
|
+
minutes = first_sector / 60;
|
|
625
|
+
|
|
626
|
+
for (i = 0; i < num_sectors; i++)
|
|
627
|
+
{
|
|
628
|
+
/* 16 - byte sync header */
|
|
629
|
+
memcpy(ptr, sync_pattern, 12);
|
|
630
|
+
ptr += 12;
|
|
631
|
+
*ptr++ = ((minutes / 10) << 4) | (minutes % 10);
|
|
632
|
+
*ptr++ = ((seconds / 10) << 4) | (seconds % 10);
|
|
633
|
+
*ptr++ = ((frames / 10) << 4) | (frames % 10);
|
|
634
|
+
if (++frames == 75)
|
|
635
|
+
{
|
|
636
|
+
frames = 0;
|
|
637
|
+
if (++seconds == 60)
|
|
638
|
+
{
|
|
639
|
+
seconds = 0;
|
|
640
|
+
++minutes;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
*ptr++ = 2;
|
|
644
|
+
|
|
645
|
+
/* 2048 bytes data */
|
|
646
|
+
memcpy(ptr, input_ptr, 2048);
|
|
647
|
+
input_ptr += 2048;
|
|
648
|
+
|
|
649
|
+
/* 288 bytes parity / checksums */
|
|
650
|
+
ptr += 2352 - 16;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
free(input);
|
|
654
|
+
*size = output_size;
|
|
655
|
+
return output;
|
|
656
|
+
}
|
|
657
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#ifndef RHASH_TEST_DATA_H
|
|
2
|
+
#define RHASH_TEST_DATA_H
|
|
3
|
+
|
|
4
|
+
#include "rc_export.h"
|
|
5
|
+
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stddef.h>
|
|
8
|
+
|
|
9
|
+
RC_BEGIN_C_DECLS
|
|
10
|
+
|
|
11
|
+
uint8_t* generate_generic_file(size_t size);
|
|
12
|
+
|
|
13
|
+
uint8_t* convert_to_2352(uint8_t* input, size_t* input_size, uint32_t first_sector);
|
|
14
|
+
|
|
15
|
+
uint8_t* generate_3do_bin(uint32_t root_directory_sectors, uint32_t binary_size, size_t* image_size);
|
|
16
|
+
uint8_t* generate_dreamcast_bin(uint32_t track_first_sector, uint32_t binary_size, size_t* image_size);
|
|
17
|
+
uint8_t* generate_jaguarcd_bin(uint32_t header_offset, uint32_t binary_size, int byteswapped, size_t* image_size);
|
|
18
|
+
uint8_t* generate_pce_cd_bin(uint32_t binary_sectors, size_t* image_size);
|
|
19
|
+
uint8_t* generate_pcfx_bin(uint32_t binary_sectors, size_t* image_size);
|
|
20
|
+
uint8_t* generate_psx_bin(const char* binary_name, uint32_t binary_size, size_t* image_size);
|
|
21
|
+
uint8_t* generate_ps2_bin(const char* binary_name, uint32_t binary_size, size_t* image_size);
|
|
22
|
+
|
|
23
|
+
uint8_t* generate_gamecube_iso(size_t mb, size_t* image_size);
|
|
24
|
+
|
|
25
|
+
uint8_t* generate_iso9660_bin(uint32_t binary_sectors, const char* volume_label, size_t* image_size);
|
|
26
|
+
uint8_t* generate_iso9660_file(uint8_t* image, const char* filename, const uint8_t* contents, size_t contents_size);
|
|
27
|
+
|
|
28
|
+
void fill_image(uint8_t* image, size_t size);
|
|
29
|
+
|
|
30
|
+
RC_END_C_DECLS
|
|
31
|
+
|
|
32
|
+
#endif /* RHASH_TEST_DATA_H */
|