#include "rc_hash.h" #include "../rc_compat.h" #include "../test_framework.h" #include "data.h" #include "mock_filereader.h" #include extern struct rc_hash_cdreader* cdreader; /* as defined in cdreader.c */ typedef struct cdrom_t { void* file_handle; int sector_size; int sector_header_size; int raw_data_size; int64_t file_track_offset; int track_first_sector; int track_pregap_sectors; #ifndef NDEBUG uint32_t track_id; #endif } cdrom_t; static const uint8_t sync_pattern[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }; static char cue_single_track[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 MODE2/2352\n" " INDEX 01 00:00:00\n"; static char cue_single_bin_multiple_data[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" " TRACK 02 MODE1/2352\n" " PREGAP 00:03:00\n" " INDEX 01 00:55:45\n" " TRACK 03 MODE1/2352\n" " INDEX 01 11:30:74\n" " TRACK 04 MODE1/2352\n" " INDEX 01 13:31:51\n" " TRACK 05 MODE1/2352\n" " INDEX 01 13:48:56\n" " TRACK 06 MODE1/2352\n" " INDEX 01 34:48:19\n" " TRACK 07 MODE1/2352\n" " INDEX 01 50:42:74\n" " TRACK 08 MODE1/2352\n" " INDEX 01 55:20:74\n" " TRACK 09 MODE1/2352\n" " INDEX 01 56:25:67\n" " TRACK 10 MODE1/2352\n" " INDEX 01 59:04:08\n" " TRACK 11 MODE1/2352\n" " INDEX 01 61:17:18\n" " TRACK 12 MODE1/2352\n" " INDEX 01 62:44:33\n" " TRACK 13 AUDIO\n" " PREGAP 00:02:00\n" " INDEX 01 66:24:37\n"; static char cue_multiple_bin_multiple_data[] = "FILE \"track1.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" "FILE \"track2.bin\" BINARY\n" " TRACK 02 MODE1/2352\n" " INDEX 00 00:00:00\n" " INDEX 01 00:03:00\n" "FILE \"track3.bin\" BINARY\n" " TRACK 03 MODE1/2352\n" " INDEX 00 00:00:00\n" " INDEX 01 00:02:00\n" "FILE \"track4.bin\" BINARY\n" " TRACK 04 AUDIO\n" " INDEX 00 00:00:00\n"; static char gdi_three_tracks[] = "3\n" "1 0 4 2352 track01.bin 0\n" "2 600 0 2352 track02.raw 0\n" "3 45000 4 2352 track03.bin 0"; static char gdi_many_tracks[] = "26\n" "1 0 4 2352 track01.bin 0\n" "2 450 0 2352 track02.raw 0\n" "3 45000 4 2352 track03.bin 0\n" "4 370673 0 2352 track04.raw 0\n" "5 371347 0 2352 track05.raw 0\n" "6 372014 0 2352 track06.raw 0\n" "7 372915 0 2352 track07.raw 0\n" "8 373626 0 2352 track08.raw 0\n" "9 379011 0 2352 track09.raw 0\n" "10 384738 0 2352 track10.raw 0\n" "11 390481 0 2352 track11.raw 0\n" "12 395473 0 2352 track12.raw 0\n" "13 398926 0 2352 track13.raw 0\n" "14 404448 0 2352 track14.raw 0\n" "15 425246 0 2352 track15.raw 0\n" "16 445520 0 2352 track16.raw 0\n" "17 466032 0 2352 track17.raw 0\n" "18 474231 0 2352 track18.raw 0\n" "19 485598 0 2352 track19.raw 0\n" "20 486386 0 2352 track20.raw 0\n" "21 487098 0 2352 track21.raw 0\n" "22 487822 0 2352 track22.raw 0\n" "23 498356 0 2352 track23.raw 0\n" "24 508297 0 2352 track24.raw 0\n" "25 527383 0 2352 track25.raw 0\n" "26 548106 4 2352 track26.bin 0\n"; static void test_open_cue_track_2() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 2); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 9807840); /* track 2: 0x95A7E0 */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_cue_track_12() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 12); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 664047216); /* track 12: 0x27948E70 */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_cue_track_14() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); /* only 13 tracks */ track_handle = (cdrom_t*)cdreader->open_track("game.cue", 14); ASSERT_PTR_NULL(track_handle); } static void test_open_cue_track_missing_bin() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 2); ASSERT_PTR_NULL(track_handle); } static void test_open_gdi_track_3() { cdrom_t* track_handle; mock_file_text(0, "game.gdi", gdi_three_tracks); mock_empty_file(1, "track03.bin", 1185760800); track_handle = (cdrom_t*)cdreader->open_track("game.gdi", 3); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track03.bin"); ASSERT_NUM64_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->track_first_sector, 45000); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_gdi_track_3_quoted() { const char gdi_contents[] = "3\n" "1 0 4 2352 \"track 01.bin\" 0\n" "2 600 0 2352 \"track 02.raw\" 0\n" "3 45000 4 2352 \"track 03.bin\" 0"; cdrom_t* track_handle; mock_file_text(0, "game.gdi", gdi_contents); mock_empty_file(1, "track 03.bin", 1185760800); track_handle = (cdrom_t*)cdreader->open_track("game.gdi", 3); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track 03.bin"); ASSERT_NUM64_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->track_first_sector, 45000); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_gdi_track_3_extra_whitespace() { const char gdi_contents[] = "3\n\n" " 1 0 4 2352 \"track 01.bin\" 0\n\n" " 2 600 0 2352 \"track 02.raw\" 0\n\n" " 3 45000 4 2352 \"track 03.bin\" 0\n\n"; cdrom_t* track_handle; mock_file_text(0, "game.gdi", gdi_contents); mock_empty_file(1, "track 03.bin", 1185760800); track_handle = (cdrom_t*)cdreader->open_track("game.gdi", 3); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track 03.bin"); ASSERT_NUM64_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->track_first_sector, 45000); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_gdi_track_last() { cdrom_t* track_handle; mock_file_text(0, "game.gdi", gdi_many_tracks); mock_empty_file(1, "track26.bin", 2457600); track_handle = (cdrom_t*)cdreader->open_track("game.gdi", RC_HASH_CDTRACK_LAST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track26.bin"); ASSERT_NUM64_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->track_first_sector, 548106); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_LARGEST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 146190912); /* track 5: 0x8B6B240 */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_multiple_bin() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_multiple_bin_multiple_data); mock_empty_file(1, "track2.bin", 406423248); mock_empty_file(2, "track3.bin", 11553024); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_LARGEST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track2.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 225); /* INDEX 01 00:03:00 */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_backwards_compatibility() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); /* before defining the enum, 0 meant largest */ track_handle = (cdrom_t*)cdreader->open_track("game.cue", 0); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 146190912); /* track 5: 0x8B6B240 */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_last_track() { cdrom_t* track_handle; const char cue[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" " TRACK 02 MODE1/2352\n" " PREGAP 00:03:00\n" " INDEX 01 00:55:45\n" " TRACK 03 MODE1/2352\n" " INDEX 01 11:30:74\n" " TRACK 04 MODE1/2352\n" " INDEX 01 13:31:51\n" " TRACK 05 MODE1/2352\n" " INDEX 01 13:48:56\n"; mock_file_text(0, "game.cue", cue); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_LARGEST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 146190912); /* track 5: 0x8B6B240 (13:48:56) */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_index0s() { cdrom_t* track_handle; const char cue[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" " TRACK 02 MODE1/2352\n" " INDEX 00 00:44:65\n" " INDEX 01 00:47:65\n" " TRACK 03 AUDIO\n" " INDEX 00 01:19:52\n" " INDEX 01 01:21:52\n"; mock_file_text(0, "game.cue", cue); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_LARGEST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 7914480); /* track 2: 0x78C3F0 (00:44:65) */ ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 225); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_index2() { cdrom_t* track_handle; const char cue[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" " TRACK 02 MODE1/2352\n" " INDEX 00 00:00:00\n" " INDEX 01 00:02:00\n" " INDEX 02 00:08:64\n"; mock_file_text(0, "game.cue", cue); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_LARGEST); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 150); /* 00:02:00 = 150 frames in */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_multiple_bins() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_multiple_bin_multiple_data); mock_empty_file(1, "track1.bin", 4132464); mock_empty_file(2, "track2.bin", 30080102); mock_empty_file(3, "track3.bin", 40343152); mock_empty_file(4, "track4.bin", 47277552); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 0); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track3.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 150); /* 00:02:00 = 150 frames in */ ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_open_cue_track_largest_data_only_audio() { const char cue[] = "FILE \"track1.bin\" BINARY\n" " TRACK 01 AUDIO\n" " INDEX 01 00:00:00\n" "FILE \"track2.bin\" BINARY\n" " TRACK 02 AUDIO\n" " INDEX 00 00:00:00\n" " INDEX 01 00:03:00\n" "FILE \"track3.bin\" BINARY\n" " TRACK 03 AUDIO\n" " INDEX 00 00:00:00\n" " INDEX 01 00:02:00\n" "FILE \"track4.bin\" BINARY\n" " TRACK 04 AUDIO\n" " INDEX 00 00:00:00\n"; cdrom_t* track_handle; mock_file_text(0, "game.cue", cue); mock_empty_file(1, "track1.bin", 4132464); mock_empty_file(2, "track2.bin", 30080102); mock_empty_file(3, "track3.bin", 40343152); mock_empty_file(4, "track4.bin", 47277552); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 0); ASSERT_PTR_NULL(track_handle); } static void test_open_cue_track_first_data() { cdrom_t* track_handle; mock_file_text(0, "game.cue", cue_single_bin_multiple_data); mock_empty_file(1, "game.bin", 718310208); track_handle = (cdrom_t*)cdreader->open_track("game.cue", RC_HASH_CDTRACK_FIRST_DATA); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 9807840); /* track 2: 0x0095a7e0 (00:55:45) */ ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); cdreader->close_track(track_handle); } static void test_determine_sector_size_sync(int sector_size) { cdrom_t* track_handle; const size_t image_size = (size_t)sector_size * 32; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue_single_track); mock_file(1, "game.bin", image, image_size); memset(image, 0, image_size); memcpy(&image[sector_size * 16], sync_pattern, sizeof(sync_pattern)); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, sector_size); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_determine_sector_size_sync_primary_volume_descriptor(int sector_size) { cdrom_t* track_handle; const size_t image_size = (size_t)sector_size * 32; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue_single_track); mock_file(1, "game.bin", image, image_size); memset(image, 0, image_size); memcpy(&image[sector_size * 16], sync_pattern, sizeof(sync_pattern)); memcpy(&image[sector_size * 16 + 25], "CD001", 5); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, sector_size); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 24); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_determine_sector_size_sync_primary_volume_descriptor_index0(int sector_size) { char cue[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 MODE2/2352\n" " INDEX 00 00:00:00\n" " INDEX 01 00:02:00\n"; cdrom_t* track_handle; const size_t image_size = (size_t)sector_size * 200; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue); mock_file(1, "game.bin", image, image_size); char sector_size_str[16]; snprintf(sector_size_str, sizeof(sector_size_str), "%d", sector_size); memcpy(&cue[40], sector_size_str, 4); memset(image, 0, image_size); memcpy(&image[sector_size * (150 + 16)], sync_pattern, sizeof(sync_pattern)); memcpy(&image[sector_size * (150 + 16) + 25], "CD001", 5); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 150); ASSERT_NUM_EQUALS(track_handle->sector_size, sector_size); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 24); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_determine_sector_size_sync_2048() { cdrom_t* track_handle; const int sector_size = 2048; const size_t image_size = (size_t)sector_size * 32; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue_single_track); mock_file(1, "game.bin", image, image_size); memset(image, 0, image_size); /* 2048 byte sectors don't have a sync pattern - will use mode specified in header */ track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 24); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_determine_sector_size_sync_primary_volume_descriptor_2048() { cdrom_t* track_handle; const int sector_size = 2048; const size_t image_size = (size_t)sector_size * 32; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue_single_track); mock_file(1, "game.bin", image, image_size); memset(image, 0, image_size); memcpy(&image[sector_size * 16 + 1], "CD001", 5); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, sector_size); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 0); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_determine_sector_size_sync_primary_volume_descriptor_index0_2048() { char cue[] = "FILE \"game.bin\" BINARY\n" " TRACK 01 MODE1/2048\n" " INDEX 00 00:00:00\n" " INDEX 01 00:02:00\n"; cdrom_t* track_handle; const int sector_size = 2048; const size_t image_size = (size_t)sector_size * 200; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue); mock_file(1, "game.bin", image, image_size); char sector_size_str[16]; snprintf(sector_size_str, sizeof(sector_size_str), "%d", sector_size); memcpy(&cue[40], sector_size_str, 4); memset(image, 0, image_size); memcpy(&image[sector_size * (150 + 16) + 1], "CD001", 5); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->file_track_offset, 0); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 150); ASSERT_NUM_EQUALS(track_handle->sector_size, sector_size); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 0); ASSERT_NUM_EQUALS(track_handle->raw_data_size, 2048); cdreader->close_track(track_handle); free(image); } static void test_absolute_sector_to_track_sector_cue_pregap() { const char cue[] = "FILE \"game1.bin\" BINARY\n"/* file contains 500 sectors of data [1176000 bytes] */ " TRACK 01 MODE2/2352\n" " INDEX 00 00:00:00\n" /* 150 pre-gap sectors */ " INDEX 01 00:02:00\n" /* 350 sectors of data */ "FILE \"game2.bin\" BINARY\n" " TRACK 02 MODE2/2352\n" " INDEX 00 00:00:00\n" /* 150 pre-gap sectors */ " INDEX 01 00:02:00\n"; cdrom_t* track_handle; const size_t image_size = (size_t)60 * 200; uint8_t* image = (uint8_t*)malloc(image_size); ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue); mock_file(1, "game1.bin", NULL, (size_t)500 * 2352); mock_file(2, "game2.bin", image, image_size); track_handle = (cdrom_t*)cdreader->open_track("game.cue", 2); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game2.bin"); /* pregap of second track starts at sector 500 */ ASSERT_NUM_EQUALS(track_handle->track_first_sector, 500); ASSERT_NUM_EQUALS(track_handle->track_pregap_sectors, 150); /* data for second track starts at sector 650 */ ASSERT_NUM_EQUALS(cdreader->first_track_sector(track_handle), 650); cdreader->close_track(track_handle); free(image); } static void test_absolute_sector_to_track_sector_gdi() { cdrom_t* track_handle; mock_file_text(0, "game.gdi", gdi_many_tracks); mock_file(1, "track26.bin", NULL, 1234567); track_handle = (cdrom_t*)cdreader->open_track("game.gdi", 26); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "track26.bin"); ASSERT_NUM_EQUALS(track_handle->track_first_sector, 548106); ASSERT_NUM_EQUALS(cdreader->first_track_sector(track_handle), 548106); cdreader->close_track(track_handle); } static void test_read_sector() { char buffer[4096]; cdrom_t* track_handle; const size_t image_size = (size_t)2352 * 32; uint8_t* image = (uint8_t*)malloc(image_size); int offset, i; ASSERT_PTR_NOT_NULL(image); mock_file_text(0, "game.cue", cue_single_track); mock_file(1, "game.bin", image, image_size); memset(image, 0, image_size); memcpy(&image[2352 * 16], sync_pattern, sizeof(sync_pattern)); image[2352 * 16 + 12] = 0; image[2352 * 16 + 13] = 2; image[2352 * 16 + 14] = 0x16; image[2352 * 16 + 15] = 2; offset = 2352 * 1 + 16; for (i = 0; i < 26; i++) { memset(&image[offset], i + 'A', 256); offset += 256; if ((i % 8) == 7) offset += (2352 - 2048); } track_handle = (cdrom_t*)cdreader->open_track("game.cue", 1); ASSERT_PTR_NOT_NULL(track_handle); ASSERT_PTR_NOT_NULL(track_handle->file_handle); ASSERT_STR_EQUALS(get_mock_filename(track_handle->file_handle), "game.bin"); ASSERT_NUM64_EQUALS(track_handle->track_pregap_sectors, 0); ASSERT_NUM_EQUALS(track_handle->sector_size, 2352); ASSERT_NUM_EQUALS(track_handle->sector_header_size, 16); /* read across multiple sectors */ ASSERT_NUM_EQUALS(cdreader->read_sector(track_handle, 1, buffer, sizeof(buffer)), 4096); ASSERT_NUM_EQUALS(buffer[0], 'A'); ASSERT_NUM_EQUALS(buffer[255], 'A'); ASSERT_NUM_EQUALS(buffer[256], 'B'); ASSERT_NUM_EQUALS(buffer[2047], 'H'); ASSERT_NUM_EQUALS(buffer[2048], 'I'); ASSERT_NUM_EQUALS(buffer[4095], 'P'); /* read of partial sector */ ASSERT_NUM_EQUALS(cdreader->read_sector(track_handle, 2, buffer, 10), 10); ASSERT_NUM_EQUALS(buffer[0], 'I'); ASSERT_NUM_EQUALS(buffer[9], 'I'); ASSERT_NUM_EQUALS(buffer[10], 'A'); cdreader->close_track(track_handle); free(image); } /* ========================================================================= */ void test_cdreader(void) { TEST_SUITE_BEGIN(); init_mock_filereader(); rc_hash_init_default_cdreader(); TEST(test_open_cue_track_2); TEST(test_open_cue_track_12); TEST(test_open_cue_track_14); TEST(test_open_cue_track_missing_bin); TEST(test_open_gdi_track_3); TEST(test_open_gdi_track_3_quoted); TEST(test_open_gdi_track_3_extra_whitespace); TEST(test_open_gdi_track_last); TEST(test_open_cue_track_largest_data); TEST(test_open_cue_track_largest_data_multiple_bin); TEST(test_open_cue_track_largest_data_backwards_compatibility); TEST(test_open_cue_track_largest_data_last_track); TEST(test_open_cue_track_largest_data_index0s); TEST(test_open_cue_track_largest_data_index2); TEST(test_open_cue_track_largest_data_multiple_bins); TEST(test_open_cue_track_largest_data_only_audio); TEST(test_open_cue_track_first_data); TEST_PARAMS1(test_determine_sector_size_sync, 2352); TEST_PARAMS1(test_determine_sector_size_sync_primary_volume_descriptor, 2352); TEST_PARAMS1(test_determine_sector_size_sync_primary_volume_descriptor_index0, 2352); TEST_PARAMS1(test_determine_sector_size_sync, 2336); TEST_PARAMS1(test_determine_sector_size_sync_primary_volume_descriptor, 2336); TEST_PARAMS1(test_determine_sector_size_sync_primary_volume_descriptor_index0, 2336); TEST(test_determine_sector_size_sync_2048); TEST(test_determine_sector_size_sync_primary_volume_descriptor_2048); TEST(test_determine_sector_size_sync_primary_volume_descriptor_index0_2048); TEST(test_absolute_sector_to_track_sector_cue_pregap); TEST(test_absolute_sector_to_track_sector_gdi); TEST(test_read_sector); TEST_SUITE_END(); }