src/mame/drivers/naomi.c
| r14530 | r14531 | |
| 6861 | 6861 | |
| 6862 | 6862 | ROM_REGION( 0x4300, "pic", ROMREGION_ERASEFF) |
| 6863 | 6863 | //PIC16C622A (317-0384-COM) |
| 6864 | | ROM_LOAD( "317-0384-com.pic", 0x000000, 0x004300, CRC(081ccd51) SHA1(598b3bd9e8b16f5954d15738c1ca55703609b690) ) |
| 6864 | ROM_LOAD( "317-0384-com.pic", 0x000000, 0x004300, CRC(081ccd51) SHA1(598b3bd9e8b16f5954d15738c1ca55703609b690) ) |
| 6865 | 6865 | ROM_END |
| 6866 | 6866 | |
| 6867 | 6867 | /* |
| r14530 | r14531 | |
| 7062 | 7062 | |
| 7063 | 7063 | ROM_REGION( 0xb000000, "rom_board", ROMREGION_ERASEFF) |
| 7064 | 7064 | // Cart has a Sega factory EPROM sticker stating "EPR-23838C" and a Sega factory sticker stating "Rev. A". Seriously. |
| 7065 | | ROM_LOAD( "epr-23838c.ic22", 0x000000, 0x400000, CRC(5e5fb00f) SHA1(c5e81ebead9072cc08f09d1715d609cb0f7631ba) ) |
| 7065 | ROM_LOAD( "epr-23838c.ic22", 0x000000, 0x400000, CRC(5e5fb00f) SHA1(c5e81ebead9072cc08f09d1715d609cb0f7631ba) ) |
| 7066 | 7066 | ROM_RELOAD( 0x400000, 0x400000) |
| 7067 | | ROM_LOAD( "ssf01.ic1s", 0x0800000, 0x800000, CRC(4f12f789) SHA1(7b79b687fc61e2e981b9e5e8e0939c4ad24a98f0) ) |
| 7068 | | ROM_LOAD( "ssf02.ic2s", 0x1000000, 0x800000, CRC(a255d41a) SHA1(3e932527eb68edf3e8538c1ad264a1c599f6a9d5) ) |
| 7069 | | ROM_LOAD( "ssf03.ic3s", 0x1800000, 0x800000, CRC(0f8d6577) SHA1(afaf440e667bacc941c0a5418a0e3b0f2bb725b7) ) |
| 7070 | | ROM_LOAD( "ssf04.ic4s", 0x2000000, 0x800000, CRC(bdf25bd0) SHA1(f79b1fdba9c48969c49617c43c1919637adb13ba) ) |
| 7071 | | ROM_LOAD( "ssf05.ic5s", 0x2800000, 0x800000, CRC(a74b3bb4) SHA1(0ce7cef849061a9af7a61d69dc633f6971a3a63d) ) |
| 7072 | | ROM_LOAD( "ssf06.ic6s", 0x3000000, 0x800000, CRC(3cd1f5d5) SHA1(77573c3a60af64e6e6a0eb85d5b8176ed98b0723) ) |
| 7073 | | ROM_LOAD( "ssf07.ic7s", 0x3800000, 0x800000, CRC(00d240f5) SHA1(43010fc596f2cdffdff35a6122f2ab02a5251bc0) ) |
| 7074 | | ROM_LOAD( "ssf08.ic8s", 0x4000000, 0x800000, CRC(d4907fa1) SHA1(79b1c771819f6e4baa048010bfb940a45370eba2) ) |
| 7075 | | ROM_LOAD( "ssf09.ic9s", 0x4800000, 0x800000, CRC(6327d49e) SHA1(a10e3c27f70dbf18e63cf51962b6a79a52eba26c) ) |
| 7076 | | ROM_LOAD( "ssf10.ic10s", 0x5000000, 0x800000, CRC(7975dc80) SHA1(81bda50968f0153a0c4432d8d81e817c1e82e5b2) ) |
| 7077 | | ROM_LOAD( "ssf11.ic11s", 0x5800000, 0x800000, CRC(a242f682) SHA1(435ea5bb1b3667f9ef3d7de081b15f4e8e6a0d01) ) |
| 7078 | | ROM_LOAD( "ssf12.ic12s", 0x6000000, 0x800000, CRC(45fa259e) SHA1(8d7e708e7a2cbc2d60b68715dd79bac28d894d4c) ) |
| 7079 | | ROM_LOAD( "ssf13.ic13s", 0x6800000, 0x800000, CRC(e9578063) SHA1(618f66d01f6bdacbf2a3242774a316b130594e02) ) |
| 7080 | | ROM_LOAD( "ssf14.ic14s", 0x7000000, 0x800000, CRC(2edc1311) SHA1(bceb54dd29012580e2e6f15f16c6b31195010153) ) |
| 7081 | | ROM_LOAD( "ssf15.ic15s", 0x7800000, 0x800000, CRC(416db320) SHA1(34536716a35260d9457703704bb9174fb1616d60) ) |
| 7082 | | ROM_LOAD( "ssf16.ic16s", 0x8000000, 0x800000, CRC(2530cc04) SHA1(6425c031e5a129a3c9451bc694b5da8553f154c2) ) |
| 7083 | | ROM_LOAD( "ssf17.ic17s", 0x8800000, 0x800000, CRC(9e6afcc2) SHA1(4fb69d834ea12c82e897af47a22dcc47f3c83768) ) |
| 7084 | | ROM_LOAD( "ssf18.ic18s", 0x9000000, 0x800000, CRC(854ed5e5) SHA1(e445599f6a9e9d05c279259307edc08bce5d6d1f) ) |
| 7085 | | ROM_LOAD( "ssf19.ic19s", 0x9800000, 0x800000, CRC(4f8ec86a) SHA1(406ab9eeccd99fa5515d4a2c229c8db1a5cb8f83) ) |
| 7086 | | ROM_LOAD( "ssf20.ic20s", 0xa000000, 0x800000, CRC(c90b960d) SHA1(66e9f09d1f7f6a991371574a2e095c0e22fb7031) ) |
| 7087 | | ROM_LOAD( "ssf21.ic21s", 0xa800000, 0x800000, CRC(1477c064) SHA1(87fb8d8a91d6bed70b246a8df88fa77fbf3db443) ) |
| 7067 | ROM_LOAD( "ssf01.ic1s", 0x0800000, 0x800000, CRC(4f12f789) SHA1(7b79b687fc61e2e981b9e5e8e0939c4ad24a98f0) ) |
| 7068 | ROM_LOAD( "ssf02.ic2s", 0x1000000, 0x800000, CRC(a255d41a) SHA1(3e932527eb68edf3e8538c1ad264a1c599f6a9d5) ) |
| 7069 | ROM_LOAD( "ssf03.ic3s", 0x1800000, 0x800000, CRC(0f8d6577) SHA1(afaf440e667bacc941c0a5418a0e3b0f2bb725b7) ) |
| 7070 | ROM_LOAD( "ssf04.ic4s", 0x2000000, 0x800000, CRC(bdf25bd0) SHA1(f79b1fdba9c48969c49617c43c1919637adb13ba) ) |
| 7071 | ROM_LOAD( "ssf05.ic5s", 0x2800000, 0x800000, CRC(a74b3bb4) SHA1(0ce7cef849061a9af7a61d69dc633f6971a3a63d) ) |
| 7072 | ROM_LOAD( "ssf06.ic6s", 0x3000000, 0x800000, CRC(3cd1f5d5) SHA1(77573c3a60af64e6e6a0eb85d5b8176ed98b0723) ) |
| 7073 | ROM_LOAD( "ssf07.ic7s", 0x3800000, 0x800000, CRC(00d240f5) SHA1(43010fc596f2cdffdff35a6122f2ab02a5251bc0) ) |
| 7074 | ROM_LOAD( "ssf08.ic8s", 0x4000000, 0x800000, CRC(d4907fa1) SHA1(79b1c771819f6e4baa048010bfb940a45370eba2) ) |
| 7075 | ROM_LOAD( "ssf09.ic9s", 0x4800000, 0x800000, CRC(6327d49e) SHA1(a10e3c27f70dbf18e63cf51962b6a79a52eba26c) ) |
| 7076 | ROM_LOAD( "ssf10.ic10s", 0x5000000, 0x800000, CRC(7975dc80) SHA1(81bda50968f0153a0c4432d8d81e817c1e82e5b2) ) |
| 7077 | ROM_LOAD( "ssf11.ic11s", 0x5800000, 0x800000, CRC(a242f682) SHA1(435ea5bb1b3667f9ef3d7de081b15f4e8e6a0d01) ) |
| 7078 | ROM_LOAD( "ssf12.ic12s", 0x6000000, 0x800000, CRC(45fa259e) SHA1(8d7e708e7a2cbc2d60b68715dd79bac28d894d4c) ) |
| 7079 | ROM_LOAD( "ssf13.ic13s", 0x6800000, 0x800000, CRC(e9578063) SHA1(618f66d01f6bdacbf2a3242774a316b130594e02) ) |
| 7080 | ROM_LOAD( "ssf14.ic14s", 0x7000000, 0x800000, CRC(2edc1311) SHA1(bceb54dd29012580e2e6f15f16c6b31195010153) ) |
| 7081 | ROM_LOAD( "ssf15.ic15s", 0x7800000, 0x800000, CRC(416db320) SHA1(34536716a35260d9457703704bb9174fb1616d60) ) |
| 7082 | ROM_LOAD( "ssf16.ic16s", 0x8000000, 0x800000, CRC(2530cc04) SHA1(6425c031e5a129a3c9451bc694b5da8553f154c2) ) |
| 7083 | ROM_LOAD( "ssf17.ic17s", 0x8800000, 0x800000, CRC(9e6afcc2) SHA1(4fb69d834ea12c82e897af47a22dcc47f3c83768) ) |
| 7084 | ROM_LOAD( "ssf18.ic18s", 0x9000000, 0x800000, CRC(854ed5e5) SHA1(e445599f6a9e9d05c279259307edc08bce5d6d1f) ) |
| 7085 | ROM_LOAD( "ssf19.ic19s", 0x9800000, 0x800000, CRC(4f8ec86a) SHA1(406ab9eeccd99fa5515d4a2c229c8db1a5cb8f83) ) |
| 7086 | ROM_LOAD( "ssf20.ic20s", 0xa000000, 0x800000, CRC(c90b960d) SHA1(66e9f09d1f7f6a991371574a2e095c0e22fb7031) ) |
| 7087 | ROM_LOAD( "ssf21.ic21s", 0xa800000, 0x800000, CRC(1477c064) SHA1(87fb8d8a91d6bed70b246a8df88fa77fbf3db443) ) |
| 7088 | 7088 | ROM_END |
| 7089 | 7089 | |
| 7090 | 7090 | /* |
| r14530 | r14531 | |
| 7855 | 7855 | /* 0062 */ GAME( 2002, clubkrte, naomi2, naomi2, naomi, naomi2, ROT0, "Sega", "Club Kart: European Session (Rev D)", GAME_UNEMULATED_PROTECTION|GAME_FLAGS ) |
| 7856 | 7856 | /* 0080 */ GAME( 2002, vf4cart, naomi2, naomi2m2, naomi, naomi2, ROT0, "Sega", "Virtua Fighter 4 (Cartridge)", GAME_UNEMULATED_PROTECTION|GAME_FLAGS ) |
| 7857 | 7857 | /* 0087 */ GAME( 2002, kingrt66, naomi2, naomi2, naomi, naomi2, ROT0, "Sega", "King of Route 66 (Rev A)", GAME_UNEMULATED_PROTECTION|GAME_FLAGS ) |
| 7858 | | /* 0095 */ GAME( 2002, soulsurf, naomi2, naomi2, naomi, naomi2, ROT0, "Sega", "Soul Surfer (Rev A)", GAME_FLAGS ) |
| 7858 | /* 0095 */ GAME( 2002, soulsurf, naomi2, naomi2, naomi, naomi2, ROT0, "Sega", "Soul Surfer (Rev A)", GAME_FLAGS ) |
| 7859 | 7859 | /* 0106 */ GAME( 2002, vf4evoct, naomi2, naomi2m1, naomi, vf4evoct, ROT0, "Sega", "Virtua Fighter 4 Evolution (Cartridge)", GAME_UNEMULATED_PROTECTION|GAME_FLAGS ) |
| 7860 | 7860 | // 0129 Club Kart Prize |
| 7861 | 7861 | |
| r14530 | r14531 | |
| 7948 | 7948 | // 0032A Initial D Arcade Stage Ver. 3 (Japan) (Rev A) |
| 7949 | 7949 | /* 0032B */ GAME( 2004, initdv3jb, initdv3j, naomigd, naomi, naomi2, ROT0, "Sega", "Initial D Arcade Stage Ver. 3 (Japan) (Rev. B) (GDS-0032B)", GAME_FLAGS ) |
| 7950 | 7950 | /* 0032C */ GAME( 2004, initdv3j, naomi2, naomi2gd,naomi, naomi2, ROT0, "Sega", "Initial D Arcade Stage Ver. 3 (Japan) (Rev. C) (GDS-0032C)", GAME_FLAGS ) |
| 7951 | | /* 0033 */ GAME( 2004, initdv3e, naomi2, naomi2gd,naomi, naomi2, ROT0, "Sega", "Initial D Arcade Stage Ver. 3 (Export) (GDS-0033)", GAME_FLAGS ) |
| 7951 | /* 0033 */ GAME( 2004, initdv3e, naomi2, naomi2gd,naomi, naomi2, ROT0, "Sega", "Initial D Arcade Stage Ver. 3 (Export) (GDS-0033)", GAME_FLAGS ) |
| 7952 | 7952 | // 0034 |
| 7953 | 7953 | // 0035 |
| 7954 | 7954 | // 0036 Virtua Fighter 4 Final Tuned |
src/tools/chdman.c
| r14530 | r14531 | |
| 215 | 215 | : m_file(file), |
| 216 | 216 | m_offset(offset), |
| 217 | 217 | m_maxoffset(MIN(maxoffset, (file != NULL) ? core_fsize(file) : 0)) { } |
| 218 | | |
| 218 | |
| 219 | 219 | // read interface |
| 220 | 220 | virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length) |
| 221 | 221 | { |
| r14530 | r14531 | |
| 247 | 247 | m_offset(offset), |
| 248 | 248 | m_maxoffset(MIN(maxoffset, file.logical_bytes())) { } |
| 249 | 249 | |
| 250 | | // read interface |
| 250 | // read interface |
| 251 | 251 | virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length) |
| 252 | 252 | { |
| 253 | 253 | offset += m_offset; |
| r14530 | r14531 | |
| 279 | 279 | : m_file(NULL), |
| 280 | 280 | m_toc(toc), |
| 281 | 281 | m_info(info) { } |
| 282 | | |
| 282 | |
| 283 | 283 | ~chd_cd_compressor() |
| 284 | 284 | { |
| 285 | 285 | if (m_file != NULL) |
| 286 | 286 | core_fclose(m_file); |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | | // read interface |
| 289 | // read interface |
| 290 | 290 | virtual UINT32 read_data(void *_dest, UINT64 offset, UINT32 length) |
| 291 | 291 | { |
| 292 | 292 | // verify assumptions made below |
| 293 | 293 | assert(offset % CD_FRAME_SIZE == 0); |
| 294 | 294 | assert(length % CD_FRAME_SIZE == 0); |
| 295 | | |
| 295 | |
| 296 | 296 | // initialize destination to 0 so that unused areas are filled |
| 297 | 297 | UINT8 *dest = reinterpret_cast<UINT8 *>(_dest); |
| 298 | 298 | memset(dest, 0, length); |
| 299 | | |
| 299 | |
| 300 | 300 | // find out which track we're starting in |
| 301 | 301 | UINT64 startoffs = 0; |
| 302 | 302 | UINT32 length_remaining = length; |
| r14530 | r14531 | |
| 316 | 316 | if (filerr != FILERR_NONE) |
| 317 | 317 | report_error(1, "Error opening input file (%s)'", m_lastfile.cstr()); |
| 318 | 318 | } |
| 319 | | |
| 319 | |
| 320 | 320 | // iterate over frames |
| 321 | 321 | UINT32 bytesperframe = trackinfo.datasize + trackinfo.subsize; |
| 322 | 322 | UINT64 src_track_start = m_info.track[tracknum].offset; |
| r14530 | r14531 | |
| 332 | 332 | UINT32 count = core_fread(m_file, dest, bytesperframe); |
| 333 | 333 | if (count != bytesperframe) |
| 334 | 334 | report_error(1, "Error reading input file (%s)'", m_lastfile.cstr()); |
| 335 | | |
| 335 | |
| 336 | 336 | // swap if appropriate |
| 337 | 337 | if (m_info.track[tracknum].swap) |
| 338 | 338 | for (UINT32 swapindex = 0; swapindex < 2352; swapindex += 2) |
| r14530 | r14531 | |
| 342 | 342 | dest[swapindex + 1] = temp; |
| 343 | 343 | } |
| 344 | 344 | } |
| 345 | | |
| 345 | |
| 346 | 346 | // advance |
| 347 | 347 | offset += CD_FRAME_SIZE; |
| 348 | 348 | dest += CD_FRAME_SIZE; |
| r14530 | r14531 | |
| 351 | 351 | break; |
| 352 | 352 | } |
| 353 | 353 | } |
| 354 | | |
| 354 | |
| 355 | 355 | // next track starts after the previous one |
| 356 | 356 | startoffs = endoffs; |
| 357 | 357 | } |
| r14530 | r14531 | |
| 381 | 381 | m_frame_count(num_frames), |
| 382 | 382 | m_ldframedata(num_frames * VBI_PACKED_BYTES), |
| 383 | 383 | m_rawdata(info.bytes_per_frame) { } |
| 384 | | |
| 384 | |
| 385 | 385 | // getters |
| 386 | 386 | const dynamic_buffer &ldframedata() const { return m_ldframedata; } |
| 387 | | |
| 388 | | // read interface |
| 387 | |
| 388 | // read interface |
| 389 | 389 | virtual UINT32 read_data(void *_dest, UINT64 offset, UINT32 length) |
| 390 | 390 | { |
| 391 | 391 | UINT8 *dest = reinterpret_cast<UINT8 *>(_dest); |
| r14530 | r14531 | |
| 402 | 402 | INT32 effframe = m_start_frame + framenum; |
| 403 | 403 | UINT32 first_sample = (UINT64(m_info.rate) * UINT64(effframe) * UINT64(1000000) + m_info.fps_times_1million - 1) / UINT64(m_info.fps_times_1million); |
| 404 | 404 | UINT32 samples = (UINT64(m_info.rate) * UINT64(effframe + 1) * UINT64(1000000) + m_info.fps_times_1million - 1) / UINT64(m_info.fps_times_1million) - first_sample; |
| 405 | | |
| 405 | |
| 406 | 406 | // loop over channels and read the samples |
| 407 | 407 | int channels = MIN(m_info.channels, ARRAY_LENGTH(m_audio)); |
| 408 | 408 | INT16 *samplesptr[ARRAY_LENGTH(m_audio)]; |
| r14530 | r14531 | |
| 437 | 437 | UINT32 rawsize = avhuff_encoder::raw_data_size(m_rawdata); |
| 438 | 438 | if (rawsize < m_rawdata.count()) |
| 439 | 439 | memset(&m_rawdata[rawsize], 0, m_rawdata.count() - rawsize); |
| 440 | | |
| 440 | |
| 441 | 441 | // copy to the destination |
| 442 | 442 | UINT64 start_offset = UINT64(framenum) * UINT64(m_info.bytes_per_frame); |
| 443 | 443 | UINT64 end_offset = start_offset + m_info.bytes_per_frame; |
| 444 | 444 | UINT32 bytes_to_copy = MIN(length_remaining, end_offset - offset); |
| 445 | 445 | memcpy(dest, &m_rawdata[offset - start_offset], bytes_to_copy); |
| 446 | | |
| 446 | |
| 447 | 447 | // advance |
| 448 | 448 | offset += bytes_to_copy; |
| 449 | 449 | dest += bytes_to_copy; |
| r14530 | r14531 | |
| 519 | 519 | // descriptions for each command |
| 520 | 520 | static const command_description s_commands[] = |
| 521 | 521 | { |
| 522 | | { COMMAND_INFO, do_info, ": displays information about a CHD", |
| 522 | { COMMAND_INFO, do_info, ": displays information about a CHD", |
| 523 | 523 | { |
| 524 | 524 | REQUIRED OPTION_INPUT, |
| 525 | 525 | OPTION_VERBOSE |
| 526 | | } |
| 526 | } |
| 527 | 527 | }, |
| 528 | | |
| 529 | | { COMMAND_VERIFY, do_verify, ": verifies a CHD's integrity", |
| 528 | |
| 529 | { COMMAND_VERIFY, do_verify, ": verifies a CHD's integrity", |
| 530 | 530 | { |
| 531 | 531 | REQUIRED OPTION_INPUT, |
| 532 | 532 | OPTION_INPUT_PARENT |
| 533 | | } |
| 533 | } |
| 534 | 534 | }, |
| 535 | | |
| 536 | | { COMMAND_CREATE_RAW, do_create_raw, ": create a raw CHD from the input file", |
| 535 | |
| 536 | { COMMAND_CREATE_RAW, do_create_raw, ": create a raw CHD from the input file", |
| 537 | 537 | { |
| 538 | | REQUIRED OPTION_OUTPUT, |
| 538 | REQUIRED OPTION_OUTPUT, |
| 539 | 539 | OPTION_OUTPUT_PARENT, |
| 540 | 540 | OPTION_OUTPUT_FORCE, |
| 541 | | REQUIRED OPTION_INPUT, |
| 542 | | OPTION_INPUT_START_BYTE, |
| 543 | | OPTION_INPUT_START_HUNK, |
| 544 | | OPTION_INPUT_LENGTH_BYTES, |
| 541 | REQUIRED OPTION_INPUT, |
| 542 | OPTION_INPUT_START_BYTE, |
| 543 | OPTION_INPUT_START_HUNK, |
| 544 | OPTION_INPUT_LENGTH_BYTES, |
| 545 | 545 | OPTION_INPUT_LENGTH_HUNKS, |
| 546 | 546 | REQUIRED OPTION_HUNK_SIZE, |
| 547 | 547 | REQUIRED OPTION_UNIT_SIZE, |
| r14530 | r14531 | |
| 551 | 551 | #endif |
| 552 | 552 | } |
| 553 | 553 | }, |
| 554 | | |
| 555 | | { COMMAND_CREATE_HD, do_create_hd, ": create a hard disk CHD from the input file", |
| 554 | |
| 555 | { COMMAND_CREATE_HD, do_create_hd, ": create a hard disk CHD from the input file", |
| 556 | 556 | { |
| 557 | | REQUIRED OPTION_OUTPUT, |
| 557 | REQUIRED OPTION_OUTPUT, |
| 558 | 558 | OPTION_OUTPUT_PARENT, |
| 559 | 559 | OPTION_OUTPUT_FORCE, |
| 560 | | OPTION_INPUT, |
| 561 | | OPTION_INPUT_START_BYTE, |
| 562 | | OPTION_INPUT_START_HUNK, |
| 563 | | OPTION_INPUT_LENGTH_BYTES, |
| 560 | OPTION_INPUT, |
| 561 | OPTION_INPUT_START_BYTE, |
| 562 | OPTION_INPUT_START_HUNK, |
| 563 | OPTION_INPUT_LENGTH_BYTES, |
| 564 | 564 | OPTION_INPUT_LENGTH_HUNKS, |
| 565 | 565 | OPTION_HUNK_SIZE, |
| 566 | 566 | OPTION_COMPRESSION, |
| r14530 | r14531 | |
| 572 | 572 | #endif |
| 573 | 573 | } |
| 574 | 574 | }, |
| 575 | | |
| 576 | | { COMMAND_CREATE_CD, do_create_cd, ": create a CD CHD from the input file", |
| 575 | |
| 576 | { COMMAND_CREATE_CD, do_create_cd, ": create a CD CHD from the input file", |
| 577 | 577 | { |
| 578 | | REQUIRED OPTION_OUTPUT, |
| 578 | REQUIRED OPTION_OUTPUT, |
| 579 | 579 | OPTION_OUTPUT_PARENT, |
| 580 | 580 | OPTION_OUTPUT_FORCE, |
| 581 | | REQUIRED OPTION_INPUT, |
| 581 | REQUIRED OPTION_INPUT, |
| 582 | 582 | OPTION_HUNK_SIZE, |
| 583 | 583 | OPTION_COMPRESSION, |
| 584 | 584 | #if NUM_PROCESSORS_SUPPORTED |
| r14530 | r14531 | |
| 586 | 586 | #endif |
| 587 | 587 | } |
| 588 | 588 | }, |
| 589 | | |
| 590 | | { COMMAND_CREATE_LD, do_create_ld, ": create a laserdisc CHD from the input file", |
| 589 | |
| 590 | { COMMAND_CREATE_LD, do_create_ld, ": create a laserdisc CHD from the input file", |
| 591 | 591 | { |
| 592 | | REQUIRED OPTION_OUTPUT, |
| 592 | REQUIRED OPTION_OUTPUT, |
| 593 | 593 | OPTION_OUTPUT_PARENT, |
| 594 | 594 | OPTION_OUTPUT_FORCE, |
| 595 | | REQUIRED OPTION_INPUT, |
| 595 | REQUIRED OPTION_INPUT, |
| 596 | 596 | OPTION_INPUT_START_FRAME, |
| 597 | 597 | OPTION_INPUT_LENGTH_FRAMES, |
| 598 | 598 | OPTION_HUNK_SIZE, |
| r14530 | r14531 | |
| 602 | 602 | #endif |
| 603 | 603 | } |
| 604 | 604 | }, |
| 605 | | |
| 606 | | { COMMAND_EXTRACT_RAW, do_extract_raw, ": extract raw file from a CHD input file", |
| 605 | |
| 606 | { COMMAND_EXTRACT_RAW, do_extract_raw, ": extract raw file from a CHD input file", |
| 607 | 607 | { |
| 608 | | REQUIRED OPTION_OUTPUT, |
| 608 | REQUIRED OPTION_OUTPUT, |
| 609 | 609 | OPTION_OUTPUT_FORCE, |
| 610 | | REQUIRED OPTION_INPUT, |
| 611 | | OPTION_INPUT_PARENT, |
| 612 | | OPTION_INPUT_START_BYTE, |
| 613 | | OPTION_INPUT_START_HUNK, |
| 614 | | OPTION_INPUT_LENGTH_BYTES, |
| 610 | REQUIRED OPTION_INPUT, |
| 611 | OPTION_INPUT_PARENT, |
| 612 | OPTION_INPUT_START_BYTE, |
| 613 | OPTION_INPUT_START_HUNK, |
| 614 | OPTION_INPUT_LENGTH_BYTES, |
| 615 | 615 | OPTION_INPUT_LENGTH_HUNKS |
| 616 | 616 | } |
| 617 | 617 | }, |
| 618 | | |
| 619 | | { COMMAND_EXTRACT_HD, do_extract_raw, ": extract raw hard disk file from a CHD input file", |
| 618 | |
| 619 | { COMMAND_EXTRACT_HD, do_extract_raw, ": extract raw hard disk file from a CHD input file", |
| 620 | 620 | { |
| 621 | | REQUIRED OPTION_OUTPUT, |
| 621 | REQUIRED OPTION_OUTPUT, |
| 622 | 622 | OPTION_OUTPUT_FORCE, |
| 623 | | REQUIRED OPTION_INPUT, |
| 624 | | OPTION_INPUT_PARENT, |
| 625 | | OPTION_INPUT_START_BYTE, |
| 626 | | OPTION_INPUT_START_HUNK, |
| 627 | | OPTION_INPUT_LENGTH_BYTES, |
| 623 | REQUIRED OPTION_INPUT, |
| 624 | OPTION_INPUT_PARENT, |
| 625 | OPTION_INPUT_START_BYTE, |
| 626 | OPTION_INPUT_START_HUNK, |
| 627 | OPTION_INPUT_LENGTH_BYTES, |
| 628 | 628 | OPTION_INPUT_LENGTH_HUNKS |
| 629 | 629 | } |
| 630 | 630 | }, |
| 631 | | |
| 632 | | { COMMAND_EXTRACT_CD, do_extract_cd, ": extract CD file from a CHD input file", |
| 631 | |
| 632 | { COMMAND_EXTRACT_CD, do_extract_cd, ": extract CD file from a CHD input file", |
| 633 | 633 | { |
| 634 | | REQUIRED OPTION_OUTPUT, |
| 635 | | OPTION_OUTPUT_BIN, |
| 634 | REQUIRED OPTION_OUTPUT, |
| 635 | OPTION_OUTPUT_BIN, |
| 636 | 636 | OPTION_OUTPUT_FORCE, |
| 637 | 637 | REQUIRED OPTION_INPUT, |
| 638 | | OPTION_INPUT_PARENT, |
| 638 | OPTION_INPUT_PARENT, |
| 639 | 639 | } |
| 640 | 640 | }, |
| 641 | | |
| 642 | | { COMMAND_EXTRACT_LD, do_extract_ld, ": extract laserdisc AVI from a CHD input file", |
| 641 | |
| 642 | { COMMAND_EXTRACT_LD, do_extract_ld, ": extract laserdisc AVI from a CHD input file", |
| 643 | 643 | { |
| 644 | | REQUIRED OPTION_OUTPUT, |
| 644 | REQUIRED OPTION_OUTPUT, |
| 645 | 645 | OPTION_OUTPUT_FORCE, |
| 646 | | REQUIRED OPTION_INPUT, |
| 647 | | OPTION_INPUT_PARENT, |
| 648 | | OPTION_INPUT_START_FRAME, |
| 646 | REQUIRED OPTION_INPUT, |
| 647 | OPTION_INPUT_PARENT, |
| 648 | OPTION_INPUT_START_FRAME, |
| 649 | 649 | OPTION_INPUT_LENGTH_FRAMES |
| 650 | 650 | } |
| 651 | 651 | }, |
| 652 | | |
| 653 | | { COMMAND_COPY, do_copy, ": copy data from one CHD to another of the same type", |
| 652 | |
| 653 | { COMMAND_COPY, do_copy, ": copy data from one CHD to another of the same type", |
| 654 | 654 | { |
| 655 | | REQUIRED OPTION_OUTPUT, |
| 655 | REQUIRED OPTION_OUTPUT, |
| 656 | 656 | OPTION_OUTPUT_PARENT, |
| 657 | 657 | OPTION_OUTPUT_FORCE, |
| 658 | | REQUIRED OPTION_INPUT, |
| 658 | REQUIRED OPTION_INPUT, |
| 659 | 659 | OPTION_INPUT_PARENT, |
| 660 | | OPTION_INPUT_START_BYTE, |
| 661 | | OPTION_INPUT_START_HUNK, |
| 660 | OPTION_INPUT_START_BYTE, |
| 661 | OPTION_INPUT_START_HUNK, |
| 662 | 662 | OPTION_INPUT_LENGTH_BYTES, |
| 663 | 663 | OPTION_INPUT_LENGTH_HUNKS, |
| 664 | 664 | OPTION_HUNK_SIZE, |
| r14530 | r14531 | |
| 668 | 668 | #endif |
| 669 | 669 | } |
| 670 | 670 | }, |
| 671 | | |
| 672 | | { COMMAND_ADD_METADATA, do_add_metadata, ": add metadata to the CHD", |
| 671 | |
| 672 | { COMMAND_ADD_METADATA, do_add_metadata, ": add metadata to the CHD", |
| 673 | 673 | { |
| 674 | | REQUIRED OPTION_INPUT, |
| 674 | REQUIRED OPTION_INPUT, |
| 675 | 675 | REQUIRED OPTION_TAG, |
| 676 | 676 | OPTION_INDEX, |
| 677 | 677 | OPTION_VALUE_TEXT, |
| r14530 | r14531 | |
| 679 | 679 | OPTION_NO_CHECKSUM |
| 680 | 680 | } |
| 681 | 681 | }, |
| 682 | | |
| 683 | | { COMMAND_DEL_METADATA, do_del_metadata, ": remove metadata from the CHD", |
| 682 | |
| 683 | { COMMAND_DEL_METADATA, do_del_metadata, ": remove metadata from the CHD", |
| 684 | 684 | { |
| 685 | | REQUIRED OPTION_INPUT, |
| 685 | REQUIRED OPTION_INPUT, |
| 686 | 686 | REQUIRED OPTION_TAG, |
| 687 | 687 | OPTION_INDEX |
| 688 | 688 | } |
| r14530 | r14531 | |
| 708 | 708 | fflush(stderr); |
| 709 | 709 | va_end(arg); |
| 710 | 710 | fprintf(stderr, "\n"); |
| 711 | | |
| 711 | |
| 712 | 712 | // reset time for progress and return the error |
| 713 | 713 | lastprogress = 0; |
| 714 | 714 | throw fatal_error(error); |
| r14530 | r14531 | |
| 782 | 782 | bool required = (option[0] == REQUIRED[0]); |
| 783 | 783 | if (required) |
| 784 | 784 | option++; |
| 785 | | |
| 785 | |
| 786 | 786 | // find the option |
| 787 | 787 | for (int optnum = 0; optnum < ARRAY_LENGTH(s_options); optnum++) |
| 788 | 788 | if (strcmp(option, s_options[optnum].name) == 0) |
| r14530 | r14531 | |
| 807 | 807 | // 0 is a special case |
| 808 | 808 | if (intvalue == 0) |
| 809 | 809 | return string.cpy("0"); |
| 810 | | |
| 810 | |
| 811 | 811 | // loop until all chunks are done |
| 812 | 812 | string.reset(); |
| 813 | 813 | bool first = true; |
| r14530 | r14531 | |
| 815 | 815 | { |
| 816 | 816 | int chunk = intvalue % 1000; |
| 817 | 817 | intvalue /= 1000; |
| 818 | | |
| 818 | |
| 819 | 819 | astring insert; |
| 820 | 820 | insert.format((intvalue != 0) ? "%03d" : "%d", chunk); |
| 821 | 821 | |
| r14530 | r14531 | |
| 850 | 850 | int length = strlen(string); |
| 851 | 851 | if (length == 0) |
| 852 | 852 | return 0; |
| 853 | | |
| 853 | |
| 854 | 854 | // scan forward over digits |
| 855 | 855 | UINT64 result = 0; |
| 856 | 856 | while (isdigit(*string)) |
| r14530 | r14531 | |
| 858 | 858 | result = (result * 10) + (*string - '0'); |
| 859 | 859 | string++; |
| 860 | 860 | } |
| 861 | | |
| 861 | |
| 862 | 862 | // handle multipliers |
| 863 | 863 | if (*string == 'k' || *string == 'K') |
| 864 | 864 | result *= 1024; |
| r14530 | r14531 | |
| 866 | 866 | result *= 1024 * 1024; |
| 867 | 867 | if (*string == 'g' || *string == 'G') |
| 868 | 868 | result *= 1024 * 1024 * 1024; |
| 869 | | |
| 869 | |
| 870 | 870 | return result; |
| 871 | 871 | } |
| 872 | 872 | |
| r14530 | r14531 | |
| 881 | 881 | // if this is a direct physical drive read, handle it specially |
| 882 | 882 | if (filename != NULL && osd_get_physical_drive_geometry(*filename, &cylinders, &heads, §ors, &bps)) |
| 883 | 883 | return; |
| 884 | | |
| 884 | |
| 885 | 885 | // if we have no length to work with, we can't guess |
| 886 | 886 | if (filesize == 0) |
| 887 | 887 | report_error(1, "Can't guess CHS values because there is no input file"); |
| r14530 | r14531 | |
| 913 | 913 | |
| 914 | 914 | |
| 915 | 915 | //------------------------------------------------- |
| 916 | | // parse_input_chd_parameters - parse the |
| 916 | // parse_input_chd_parameters - parse the |
| 917 | 917 | // standard set of input CHD parameters |
| 918 | 918 | //------------------------------------------------- |
| 919 | 919 | |
| r14530 | r14531 | |
| 962 | 962 | input_start = parse_number(*input_start_frame_str) * framebytes; |
| 963 | 963 | if (input_start >= input_end) |
| 964 | 964 | report_error(1, "Input start offset greater than input file size"); |
| 965 | | |
| 965 | |
| 966 | 966 | // process input length |
| 967 | 967 | astring *input_length_bytes_str = params.find(OPTION_INPUT_LENGTH_BYTES); |
| 968 | 968 | astring *input_length_hunks_str = params.find(OPTION_INPUT_LENGTH_HUNKS); |
| r14530 | r14531 | |
| 1001 | 1001 | |
| 1002 | 1002 | |
| 1003 | 1003 | //------------------------------------------------- |
| 1004 | | // parse_output_chd_parameters - parse the |
| 1004 | // parse_output_chd_parameters - parse the |
| 1005 | 1005 | // standard set of output CHD parameters |
| 1006 | 1006 | //------------------------------------------------- |
| 1007 | 1007 | |
| r14530 | r14531 | |
| 1025 | 1025 | |
| 1026 | 1026 | |
| 1027 | 1027 | //------------------------------------------------- |
| 1028 | | // parse_hunk_size - parse the hunk_size |
| 1028 | // parse_hunk_size - parse the hunk_size |
| 1029 | 1029 | // parameter in a standard way |
| 1030 | 1030 | //------------------------------------------------- |
| 1031 | 1031 | |
| r14530 | r14531 | |
| 1044 | 1044 | |
| 1045 | 1045 | |
| 1046 | 1046 | //------------------------------------------------- |
| 1047 | | // parse_compression - parse a standard |
| 1047 | // parse_compression - parse a standard |
| 1048 | 1048 | // compression parameter string |
| 1049 | 1049 | //------------------------------------------------- |
| 1050 | 1050 | |
| r14530 | r14531 | |
| 1061 | 1061 | compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE; |
| 1062 | 1062 | return; |
| 1063 | 1063 | } |
| 1064 | | |
| 1064 | |
| 1065 | 1065 | // iterate through compressors |
| 1066 | 1066 | int index = 0; |
| 1067 | 1067 | for (int start = 0, end = compression_str->chr(0, ','); index < 4; start = end + 1, end = compression_str->chr(end + 1, ',')) |
| r14530 | r14531 | |
| 1112 | 1112 | string.reset(); |
| 1113 | 1113 | if (compression[0] == CHD_CODEC_NONE) |
| 1114 | 1114 | return string.cpy("none"); |
| 1115 | | |
| 1115 | |
| 1116 | 1116 | // iterate over types |
| 1117 | 1117 | for (int index = 0; index < 4; index++) |
| 1118 | 1118 | { |
| r14530 | r14531 | |
| 1126 | 1126 | } |
| 1127 | 1127 | return string; |
| 1128 | 1128 | } |
| 1129 | | |
| 1130 | 1129 | |
| 1130 | |
| 1131 | 1131 | //------------------------------------------------- |
| 1132 | 1132 | // compress_common - standard compression loop |
| 1133 | 1133 | //------------------------------------------------- |
| r14530 | r14531 | |
| 1137 | 1137 | // begin compressing |
| 1138 | 1138 | chd.compress_begin(); |
| 1139 | 1139 | |
| 1140 | | // loop until done |
| 1140 | // loop until done |
| 1141 | 1141 | double complete, ratio; |
| 1142 | 1142 | chd_error err; |
| 1143 | 1143 | while ((err = chd.compress_continue(complete, ratio)) == CHDERR_WALKING_PARENT || err == CHDERR_COMPRESSING) |
| r14530 | r14531 | |
| 1190 | 1190 | tempstr.cpy("AUDIO"); |
| 1191 | 1191 | break; |
| 1192 | 1192 | } |
| 1193 | | |
| 1193 | |
| 1194 | 1194 | // output TRACK entry |
| 1195 | 1195 | core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr()); |
| 1196 | 1196 | |
| r14530 | r14531 | |
| 1205 | 1205 | if (info.postgap > 0) |
| 1206 | 1206 | core_fprintf(file, " POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap)); |
| 1207 | 1207 | } |
| 1208 | | |
| 1208 | |
| 1209 | 1209 | // non-CUE mode |
| 1210 | 1210 | else |
| 1211 | 1211 | { |
| r14530 | r14531 | |
| 1304 | 1304 | chd_error err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index, buffer, metatag, metaflags); |
| 1305 | 1305 | if (err != CHDERR_NONE) |
| 1306 | 1306 | break; |
| 1307 | | |
| 1307 | |
| 1308 | 1308 | // determine our index |
| 1309 | 1309 | UINT32 metaindex = ~0; |
| 1310 | 1310 | for (int cur = 0; cur < info.count(); cur++) |
| r14530 | r14531 | |
| 1313 | 1313 | metaindex = ++info[cur].index; |
| 1314 | 1314 | break; |
| 1315 | 1315 | } |
| 1316 | | |
| 1316 | |
| 1317 | 1317 | // if not found, add to our tracking |
| 1318 | 1318 | if (metaindex == ~0) |
| 1319 | 1319 | { |
| r14530 | r14531 | |
| 1335 | 1335 | printf("%c", isprint(UINT8(buffer[chnum])) ? buffer[chnum] : '.'); |
| 1336 | 1336 | printf("\n"); |
| 1337 | 1337 | } |
| 1338 | | |
| 1338 | |
| 1339 | 1339 | // print compression stats if verbose |
| 1340 | 1340 | if (params.find(OPTION_VERBOSE) != NULL) |
| 1341 | 1341 | { |
| r14530 | r14531 | |
| 1348 | 1348 | chd_error err = input_chd.hunk_info(hunknum, codec, compbytes); |
| 1349 | 1349 | if (err != CHDERR_NONE) |
| 1350 | 1350 | report_error(1, "Error getting info on hunk %d: %s", hunknum, chd_file::error_string(err)); |
| 1351 | | |
| 1351 | |
| 1352 | 1352 | // decode into our data |
| 1353 | 1353 | if (codec > CHD_CODEC_MINI) |
| 1354 | 1354 | for (int comptype = 0; comptype < 4; comptype++) |
| r14530 | r14531 | |
| 1359 | 1359 | } |
| 1360 | 1360 | if (codec > ARRAY_LENGTH(compression_types)) |
| 1361 | 1361 | codec = ARRAY_LENGTH(compression_types) - 1; |
| 1362 | | |
| 1362 | |
| 1363 | 1363 | // count stats |
| 1364 | 1364 | compression_types[codec]++; |
| 1365 | 1365 | } |
| 1366 | | |
| 1366 | |
| 1367 | 1367 | // output the stats |
| 1368 | 1368 | printf("\n"); |
| 1369 | 1369 | printf(" Hunks Percent Name\n"); |
| r14530 | r14531 | |
| 1385 | 1385 | name = chd_codec_list::codec_name(input_chd.compression(index)); |
| 1386 | 1386 | break; |
| 1387 | 1387 | } |
| 1388 | | |
| 1388 | |
| 1389 | 1389 | // output the stats |
| 1390 | 1390 | astring tempstr; |
| 1391 | | printf("%10s %5.1f%% %-40s\n", |
| 1391 | printf("%10s %5.1f%% %-40s\n", |
| 1392 | 1392 | big_int_string(tempstr, compression_types[comptype]), |
| 1393 | 1393 | 100.0 * double(compression_types[comptype]) / double(input_chd.hunk_count()), |
| 1394 | 1394 | name); |
| r14530 | r14531 | |
| 1417 | 1417 | |
| 1418 | 1418 | // create an array to read into |
| 1419 | 1419 | dynamic_buffer buffer((TEMP_BUFFER_SIZE / input_chd.hunk_bytes()) * input_chd.hunk_bytes()); |
| 1420 | | |
| 1420 | |
| 1421 | 1421 | // read all the data and build up an SHA-1 |
| 1422 | 1422 | sha1_creator rawsha1; |
| 1423 | 1423 | for (UINT64 offset = 0; offset < input_chd.logical_bytes(); ) |
| r14530 | r14531 | |
| 1429 | 1429 | chd_error err = input_chd.read_bytes(offset, buffer, bytes_to_read); |
| 1430 | 1430 | if (err != CHDERR_NONE) |
| 1431 | 1431 | report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->cstr(), chd_file::error_string(err)); |
| 1432 | | |
| 1432 | |
| 1433 | 1433 | // add to the checksum |
| 1434 | 1434 | rawsha1.append(buffer, bytes_to_read); |
| 1435 | 1435 | offset += bytes_to_read; |
| 1436 | 1436 | } |
| 1437 | 1437 | sha1_t computed_sha1 = rawsha1.finish(); |
| 1438 | | |
| 1438 | |
| 1439 | 1439 | // finish up |
| 1440 | 1440 | if (raw_sha1 != computed_sha1) |
| 1441 | 1441 | { |
| r14530 | r14531 | |
| 1453 | 1453 | else |
| 1454 | 1454 | { |
| 1455 | 1455 | printf("Raw SHA1 verification successful!\n"); |
| 1456 | | |
| 1456 | |
| 1457 | 1457 | // now include the metadata for >= v4 |
| 1458 | 1458 | if (input_chd.version() >= 4) |
| 1459 | 1459 | { |
| r14530 | r14531 | |
| 1498 | 1498 | // process output CHD |
| 1499 | 1499 | chd_file output_parent; |
| 1500 | 1500 | astring *output_chd_str = parse_output_chd_parameters(params, output_parent); |
| 1501 | | |
| 1501 | |
| 1502 | 1502 | // process hunk size |
| 1503 | 1503 | UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : 0; |
| 1504 | 1504 | parse_hunk_size(params, 1, hunk_size); |
| r14530 | r14531 | |
| 1517 | 1517 | UINT64 input_start; |
| 1518 | 1518 | UINT64 input_end; |
| 1519 | 1519 | parse_input_start_end(params, core_fsize(input_file), hunk_size, hunk_size, input_start, input_end); |
| 1520 | | |
| 1520 | |
| 1521 | 1521 | // process compression |
| 1522 | 1522 | chd_codec_type compression[4]; |
| 1523 | 1523 | memcpy(compression, s_default_raw_compression, sizeof(compression)); |
| 1524 | 1524 | parse_compression(params, compression); |
| 1525 | | |
| 1525 | |
| 1526 | 1526 | // process numprocessors |
| 1527 | 1527 | parse_numprocessors(params); |
| 1528 | 1528 | |
| r14530 | r14531 | |
| 1553 | 1553 | err = chd.create(*output_chd_str, input_end - input_start, hunk_size, unit_size, compression); |
| 1554 | 1554 | if (err != CHDERR_NONE) |
| 1555 | 1555 | report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err)); |
| 1556 | | |
| 1556 | |
| 1557 | 1557 | // if we have a parent, copy forward all the metadata |
| 1558 | 1558 | if (output_parent.opened()) |
| 1559 | 1559 | chd.clone_all_metadata(output_parent); |
| r14530 | r14531 | |
| 1588 | 1588 | if (filerr != FILERR_NONE) |
| 1589 | 1589 | report_error(1, "Unable to open file (%s)", input_file_str->cstr()); |
| 1590 | 1590 | } |
| 1591 | | |
| 1591 | |
| 1592 | 1592 | // process output CHD |
| 1593 | 1593 | chd_file output_parent; |
| 1594 | 1594 | astring *output_chd_str = parse_output_chd_parameters(params, output_parent); |
| 1595 | | |
| 1595 | |
| 1596 | 1596 | // process sectorsize |
| 1597 | 1597 | UINT32 sector_size = output_parent.opened() ? output_parent.unit_bytes() : IDE_SECTOR_SIZE; |
| 1598 | 1598 | astring *sectorsize_str = params.find(OPTION_SECTOR_SIZE); |
| r14530 | r14531 | |
| 1602 | 1602 | report_error(1, "Sector size does not apply when creating a diff from the parent"); |
| 1603 | 1603 | sector_size = parse_number(*sectorsize_str); |
| 1604 | 1604 | } |
| 1605 | | |
| 1605 | |
| 1606 | 1606 | // process hunk size (needs to know sector_size) |
| 1607 | 1607 | UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : MAX((4096 / sector_size) * sector_size, sector_size); |
| 1608 | 1608 | parse_hunk_size(params, sector_size, hunk_size); |
| 1609 | | |
| 1609 | |
| 1610 | 1610 | // process input start/end (needs to know hunk_size) |
| 1611 | 1611 | UINT64 input_start; |
| 1612 | 1612 | UINT64 input_end; |
| 1613 | 1613 | parse_input_start_end(params, core_fsize(input_file), hunk_size, hunk_size, input_start, input_end); |
| 1614 | | |
| 1614 | |
| 1615 | 1615 | // process compression |
| 1616 | 1616 | chd_codec_type compression[4]; |
| 1617 | 1617 | memcpy(compression, s_default_hd_compression, sizeof(compression)); |
| r14530 | r14531 | |
| 1656 | 1656 | heads = (identdata[7] << 8) | identdata[6]; |
| 1657 | 1657 | sectors = (identdata[13] << 8) | identdata[12]; |
| 1658 | 1658 | } |
| 1659 | | |
| 1659 | |
| 1660 | 1660 | // extract geometry from the parent if we have one |
| 1661 | 1661 | if (output_parent.opened() && cylinders == 0) |
| 1662 | 1662 | { |
| r14530 | r14531 | |
| 1666 | 1666 | if (sscanf(metadata, HARD_DISK_METADATA_FORMAT, &cylinders, &heads, §ors, §or_size) != 4) |
| 1667 | 1667 | report_error(1, "Error parsing hard disk metadata in parent CHD"); |
| 1668 | 1668 | } |
| 1669 | | |
| 1669 | |
| 1670 | 1670 | // if no CHS values, try to guess them |
| 1671 | 1671 | if (cylinders == 0) |
| 1672 | 1672 | { |
| r14530 | r14531 | |
| 1675 | 1675 | guess_chs(input_file_str, input_end - input_start, sector_size, cylinders, heads, sectors, sector_size); |
| 1676 | 1676 | } |
| 1677 | 1677 | UINT32 totalsectors = cylinders * heads * sectors; |
| 1678 | | |
| 1678 | |
| 1679 | 1679 | // print some info |
| 1680 | 1680 | astring tempstr; |
| 1681 | 1681 | printf("Output CHD: %s\n", output_chd_str->cstr()); |
| r14530 | r14531 | |
| 1758 | 1758 | if (err != CHDERR_NONE) |
| 1759 | 1759 | report_error(1, "Error parsing input file (%s: %s\n", input_file_str->cstr(), chd_file::error_string(err)); |
| 1760 | 1760 | } |
| 1761 | | |
| 1761 | |
| 1762 | 1762 | // process output CHD |
| 1763 | 1763 | chd_file output_parent; |
| 1764 | 1764 | astring *output_chd_str = parse_output_chd_parameters(params, output_parent); |
| r14530 | r14531 | |
| 1766 | 1766 | // process hunk size |
| 1767 | 1767 | UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : CD_FRAMES_PER_HUNK * CD_FRAME_SIZE; |
| 1768 | 1768 | parse_hunk_size(params, CD_FRAME_SIZE, hunk_size); |
| 1769 | | |
| 1769 | |
| 1770 | 1770 | // process compression |
| 1771 | 1771 | chd_codec_type compression[4]; |
| 1772 | 1772 | memcpy(compression, s_default_cd_compression, sizeof(compression)); |
| r14530 | r14531 | |
| 1847 | 1847 | report_error(1, "Error opening AVI file (%s): %s\n", input_file_str->cstr(), avi_error_string(avierr)); |
| 1848 | 1848 | } |
| 1849 | 1849 | const avi_movie_info *aviinfo = avi_get_movie_info(input_file); |
| 1850 | | |
| 1850 | |
| 1851 | 1851 | // process output CHD |
| 1852 | 1852 | chd_file output_parent; |
| 1853 | 1853 | astring *output_chd_str = parse_output_chd_parameters(params, output_parent); |
| 1854 | | |
| 1854 | |
| 1855 | 1855 | // process input start/end |
| 1856 | 1856 | UINT64 input_start; |
| 1857 | 1857 | UINT64 input_end; |
| 1858 | 1858 | parse_input_start_end(params, aviinfo->video_numsamples, 0, 1, input_start, input_end); |
| 1859 | | |
| 1859 | |
| 1860 | 1860 | // determine parameters of the incoming video stream |
| 1861 | 1861 | avi_info info; |
| 1862 | 1862 | info.fps_times_1million = UINT64(aviinfo->video_timescale) * 1000000 / aviinfo->video_sampletime; |
| r14530 | r14531 | |
| 1878 | 1878 | // determine the number of bytes per frame |
| 1879 | 1879 | info.max_samples_per_frame = (UINT64(info.rate) * 1000000 + info.fps_times_1million - 1) / info.fps_times_1million; |
| 1880 | 1880 | info.bytes_per_frame = avhuff_encoder::raw_data_size(info.width, info.height, info.channels, info.max_samples_per_frame); |
| 1881 | | |
| 1881 | |
| 1882 | 1882 | // process hunk size |
| 1883 | 1883 | UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : info.bytes_per_frame; |
| 1884 | 1884 | parse_hunk_size(params, info.bytes_per_frame, hunk_size); |
| 1885 | | |
| 1885 | |
| 1886 | 1886 | // process compression |
| 1887 | 1887 | chd_codec_type compression[4]; |
| 1888 | 1888 | memcpy(compression, s_default_ld_compression, sizeof(compression)); |
| r14530 | r14531 | |
| 1932 | 1932 | |
| 1933 | 1933 | // create the compressor and then run it generically |
| 1934 | 1934 | compress_common(chd); |
| 1935 | | |
| 1935 | |
| 1936 | 1936 | // write the final LD metadata |
| 1937 | 1937 | if (info.height == 524/2 || info.height == 624/2) |
| 1938 | 1938 | { |
| r14530 | r14531 | |
| 1972 | 1972 | // process output CHD |
| 1973 | 1973 | chd_file output_parent; |
| 1974 | 1974 | astring *output_chd_str = parse_output_chd_parameters(params, output_parent); |
| 1975 | | |
| 1975 | |
| 1976 | 1976 | // process hunk size |
| 1977 | 1977 | UINT32 hunk_size = input_chd.hunk_bytes(); |
| 1978 | 1978 | parse_hunk_size(params, 1, hunk_size); |
| 1979 | 1979 | if (hunk_size % input_chd.hunk_bytes() != 0 && input_chd.hunk_bytes() % hunk_size != 0) |
| 1980 | 1980 | report_error(1, "Hunk size is not an even multiple or divisor of input hunk size"); |
| 1981 | | |
| 1981 | |
| 1982 | 1982 | // process compression; we default to our current preferences using metadata to pick the type |
| 1983 | 1983 | chd_codec_type compression[4]; |
| 1984 | 1984 | { |
| r14530 | r14531 | |
| 2041 | 2041 | redo_cd = true; |
| 2042 | 2042 | continue; |
| 2043 | 2043 | } |
| 2044 | | |
| 2044 | |
| 2045 | 2045 | // otherwise, clone it |
| 2046 | 2046 | err = chd.write_metadata(metatag, CHDMETAINDEX_APPEND, metadata); |
| 2047 | 2047 | if (err != CHDERR_NONE) |
| 2048 | 2048 | report_error(1, "Error writing cloned metadata: %s", chd_file::error_string(err)); |
| 2049 | 2049 | } |
| 2050 | | |
| 2050 | |
| 2051 | 2051 | // if we need to re-do the CD metadata, do it now |
| 2052 | 2052 | if (redo_cd) |
| 2053 | 2053 | { |
| r14530 | r14531 | |
| 2059 | 2059 | if (err != CHDERR_NONE) |
| 2060 | 2060 | report_error(1, "Error writing upgraded CD metadata: %s", chd_file::error_string(err)); |
| 2061 | 2061 | } |
| 2062 | | |
| 2062 | |
| 2063 | 2063 | // compress it generically |
| 2064 | 2064 | compress_common(chd); |
| 2065 | 2065 | } |
| r14530 | r14531 | |
| 2090 | 2090 | UINT64 input_start; |
| 2091 | 2091 | UINT64 input_end; |
| 2092 | 2092 | parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end); |
| 2093 | | |
| 2093 | |
| 2094 | 2094 | // verify output file doesn't exist |
| 2095 | 2095 | astring *output_file_str = params.find(OPTION_OUTPUT); |
| 2096 | 2096 | if (output_file_str != NULL) |
| 2097 | 2097 | check_existing_output_file(params, *output_file_str); |
| 2098 | | |
| 2098 | |
| 2099 | 2099 | // print some info |
| 2100 | 2100 | astring tempstr; |
| 2101 | 2101 | printf("Output File: %s\n", output_file_str->cstr()); |
| r14530 | r14531 | |
| 2126 | 2126 | chd_error err = input_chd.read_bytes(offset, buffer, bytes_to_read); |
| 2127 | 2127 | if (err != CHDERR_NONE) |
| 2128 | 2128 | report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->cstr(), chd_file::error_string(err)); |
| 2129 | | |
| 2129 | |
| 2130 | 2130 | // write to the output |
| 2131 | 2131 | UINT32 count = core_fwrite(output_file, buffer, bytes_to_read); |
| 2132 | 2132 | if (count != bytes_to_read) |
| r14530 | r14531 | |
| 2135 | 2135 | // advance |
| 2136 | 2136 | offset += bytes_to_read; |
| 2137 | 2137 | } |
| 2138 | | |
| 2138 | |
| 2139 | 2139 | // finish up |
| 2140 | 2140 | core_fclose(output_file); |
| 2141 | 2141 | printf("Extraction complete \n"); |
| r14530 | r14531 | |
| 2170 | 2170 | if (cdrom == NULL) |
| 2171 | 2171 | report_error(1, "Unable to recognize CHD file as a CD"); |
| 2172 | 2172 | const cdrom_toc *toc = cdrom_get_toc(cdrom); |
| 2173 | | |
| 2173 | |
| 2174 | 2174 | // verify output file doesn't exist |
| 2175 | 2175 | astring *output_file_str = params.find(OPTION_OUTPUT); |
| 2176 | 2176 | if (output_file_str != NULL) |
| r14530 | r14531 | |
| 2186 | 2186 | if (output_bin_file_str == NULL) |
| 2187 | 2187 | output_bin_file_str = &default_name; |
| 2188 | 2188 | check_existing_output_file(params, *output_bin_file_str); |
| 2189 | | |
| 2189 | |
| 2190 | 2190 | // print some info |
| 2191 | 2191 | astring tempstr; |
| 2192 | 2192 | printf("Output TOC: %s\n", output_file_str->cstr()); |
| r14530 | r14531 | |
| 2213 | 2213 | UINT64 total_bytes = 0; |
| 2214 | 2214 | for (int tracknum = 0; tracknum < toc->numtrks; tracknum++) |
| 2215 | 2215 | total_bytes += toc->tracks[tracknum].frames * (toc->tracks[tracknum].datasize + toc->tracks[tracknum].subsize); |
| 2216 | | |
| 2216 | |
| 2217 | 2217 | // iterate over tracks and copy all data |
| 2218 | 2218 | UINT64 outputoffs = 0; |
| 2219 | 2219 | UINT32 discoffs = 0; |
| r14530 | r14531 | |
| 2227 | 2227 | // resize the buffer for the track |
| 2228 | 2228 | UINT32 output_frame_size = trackinfo.datasize + ((trackinfo.subtype != CD_SUB_NONE) ? trackinfo.subsize : 0); |
| 2229 | 2229 | buffer.resize((TEMP_BUFFER_SIZE / output_frame_size) * output_frame_size); |
| 2230 | | |
| 2230 | |
| 2231 | 2231 | // now read and output the actual data |
| 2232 | 2232 | UINT32 bufferoffs = 0; |
| 2233 | 2233 | for (int frame = 0; frame < trackinfo.frames; frame++) |
| r14530 | r14531 | |
| 2267 | 2267 | } |
| 2268 | 2268 | } |
| 2269 | 2269 | } |
| 2270 | | |
| 2270 | |
| 2271 | 2271 | // finish up |
| 2272 | 2272 | core_fclose(output_bin_file); |
| 2273 | 2273 | core_fclose(output_toc_file); |
| r14530 | r14531 | |
| 2328 | 2328 | frame_bytes = avhuff_encoder::raw_data_size(width, height, channels, max_samples_per_frame); |
| 2329 | 2329 | if (frame_bytes != input_chd.hunk_bytes()) |
| 2330 | 2330 | report_error(1, "Frame size does not match hunk size for this CHD"); |
| 2331 | | |
| 2331 | |
| 2332 | 2332 | // parse out input start/end |
| 2333 | 2333 | UINT64 input_start; |
| 2334 | 2334 | UINT64 input_end; |
| r14530 | r14531 | |
| 2386 | 2386 | audio_data[chnum].resize(max_samples_per_frame); |
| 2387 | 2387 | avconfig.audio[chnum] = audio_data[chnum]; |
| 2388 | 2388 | } |
| 2389 | | |
| 2389 | |
| 2390 | 2390 | // iterate over frames |
| 2391 | 2391 | bitmap_yuy16 fullbitmap(width, height * interlace_factor); |
| 2392 | 2392 | for (int framenum = input_start; framenum < input_end; framenum++) |
| r14530 | r14531 | |
| 2396 | 2396 | // set up the fake bitmap for this frame |
| 2397 | 2397 | avconfig.video.wrap(&fullbitmap.pix(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / interlace_factor, fullbitmap.rowpixels() * interlace_factor); |
| 2398 | 2398 | input_chd.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); |
| 2399 | | |
| 2399 | |
| 2400 | 2400 | // read the hunk into the buffers |
| 2401 | 2401 | chd_error err = input_chd.read_hunk(framenum, NULL); |
| 2402 | 2402 | if (err != CHDERR_NONE) |
| r14530 | r14531 | |
| 2454 | 2454 | tag_str->cat(" "); |
| 2455 | 2455 | tag = CHD_MAKE_TAG((*tag_str)[0], (*tag_str)[1], (*tag_str)[2], (*tag_str)[3]); |
| 2456 | 2456 | } |
| 2457 | | |
| 2457 | |
| 2458 | 2458 | // process index |
| 2459 | 2459 | UINT32 index = 0; |
| 2460 | 2460 | astring *index_str = params.find(OPTION_INDEX); |
| 2461 | 2461 | if (index_str != NULL) |
| 2462 | 2462 | index = atoi(*index_str); |
| 2463 | | |
| 2463 | |
| 2464 | 2464 | // process text input |
| 2465 | 2465 | astring *text_str = params.find(OPTION_VALUE_TEXT); |
| 2466 | 2466 | astring text; |
| r14530 | r14531 | |
| 2470 | 2470 | if (text[0] == '"' && text[text.len() - 1] == '"') |
| 2471 | 2471 | text.substr(1, text.len() - 2); |
| 2472 | 2472 | } |
| 2473 | | |
| 2473 | |
| 2474 | 2474 | // process file input |
| 2475 | 2475 | astring *file_str = params.find(OPTION_VALUE_FILE); |
| 2476 | 2476 | dynamic_buffer file; |
| r14530 | r14531 | |
| 2480 | 2480 | if (filerr != FILERR_NONE) |
| 2481 | 2481 | report_error(1, "Error reading metadata file (%s)", file_str->cstr()); |
| 2482 | 2482 | } |
| 2483 | | |
| 2483 | |
| 2484 | 2484 | // make sure we have one or the other |
| 2485 | 2485 | if (text_str == NULL && file_str == NULL) |
| 2486 | 2486 | report_error(1, "Error: missing either --valuetext/-vt or --valuefile/-vf parameters"); |
| 2487 | 2487 | if (text_str != NULL && file_str != NULL) |
| 2488 | 2488 | report_error(1, "Error: both --valuetext/-vt or --valuefile/-vf parameters specified; only one permitted"); |
| 2489 | | |
| 2489 | |
| 2490 | 2490 | // process no checksum |
| 2491 | 2491 | UINT8 flags = CHD_MDFLAGS_CHECKSUM; |
| 2492 | 2492 | if (params.find(OPTION_NO_CHECKSUM) != NULL) |
| 2493 | 2493 | flags &= ~CHD_MDFLAGS_CHECKSUM; |
| 2494 | | |
| 2494 | |
| 2495 | 2495 | // print some info |
| 2496 | 2496 | astring tempstr; |
| 2497 | 2497 | printf("Input file: %s\n", params.find(OPTION_INPUT)->cstr()); |
| r14530 | r14531 | |
| 2516 | 2516 | |
| 2517 | 2517 | |
| 2518 | 2518 | //------------------------------------------------- |
| 2519 | | // do_del_metadata - remove metadata from a CHD |
| 2519 | // do_del_metadata - remove metadata from a CHD |
| 2520 | 2520 | //------------------------------------------------- |
| 2521 | 2521 | |
| 2522 | 2522 | static void do_del_metadata(parameters_t ¶ms) |
| r14530 | r14531 | |
| 2534 | 2534 | tag_str->cat(" "); |
| 2535 | 2535 | tag = CHD_MAKE_TAG((*tag_str)[0], (*tag_str)[1], (*tag_str)[2], (*tag_str)[3]); |
| 2536 | 2536 | } |
| 2537 | | |
| 2537 | |
| 2538 | 2538 | // process index |
| 2539 | 2539 | UINT32 index = 0; |
| 2540 | 2540 | astring *index_str = params.find(OPTION_INDEX); |
| 2541 | 2541 | if (index_str != NULL) |
| 2542 | 2542 | index = atoi(*index_str); |
| 2543 | | |
| 2543 | |
| 2544 | 2544 | // print some info |
| 2545 | 2545 | astring tempstr; |
| 2546 | 2546 | printf("Input file: %s\n", params.find(OPTION_INPUT)->cstr()); |
| r14530 | r14531 | |
| 2578 | 2578 | return print_help(argv[0]); |
| 2579 | 2579 | command = argv[argnum++]; |
| 2580 | 2580 | } |
| 2581 | | |
| 2581 | |
| 2582 | 2582 | // iterate over commands to find our match |
| 2583 | 2583 | for (int cmdnum = 0; cmdnum < ARRAY_LENGTH(s_commands); cmdnum++) |
| 2584 | 2584 | if (strcmp(command, s_commands[cmdnum].name) == 0) |
| 2585 | 2585 | { |
| 2586 | 2586 | const command_description &desc = s_commands[cmdnum]; |
| 2587 | | |
| 2587 | |
| 2588 | 2588 | // print help if that was requested |
| 2589 | 2589 | if (help) |
| 2590 | 2590 | return print_help(argv[0], desc); |
| r14530 | r14531 | |
| 2629 | 2629 | return print_help(argv[0], desc, "Option is missing parameter"); |
| 2630 | 2630 | param = argv[argnum++]; |
| 2631 | 2631 | } |
| 2632 | | |
| 2632 | |
| 2633 | 2633 | // add to the map |
| 2634 | 2634 | if (parameters.add(odesc.name, new astring(param)) == TMERR_DUPLICATE) |
| 2635 | 2635 | return print_help(argv[0], desc, "Multiple parameters of the same type specified"); |
| r14530 | r14531 | |
| 2641 | 2641 | if (valid == ARRAY_LENGTH(desc.valid_options)) |
| 2642 | 2642 | return print_help(argv[0], desc, "Option not valid for this command"); |
| 2643 | 2643 | } |
| 2644 | | |
| 2644 | |
| 2645 | 2645 | // make sure we got all our required parameters |
| 2646 | 2646 | for (int valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++) |
| 2647 | 2647 | { |
| r14530 | r14531 | |
| 2651 | 2651 | if (*validname == REQUIRED[0] && parameters.find(++validname) == NULL) |
| 2652 | 2652 | return print_help(argv[0], desc, "Required parameters missing"); |
| 2653 | 2653 | } |
| 2654 | | |
| 2654 | |
| 2655 | 2655 | // all clear, run the command |
| 2656 | 2656 | try |
| 2657 | 2657 | { |
| r14530 | r14531 | |
| 2673 | 2673 | return 1; |
| 2674 | 2674 | } |
| 2675 | 2675 | } |
| 2676 | | |
| 2676 | |
| 2677 | 2677 | // print generic help if nothing found |
| 2678 | 2678 | return print_help(argv[0]); |
| 2679 | 2679 | } |
src/lib/util/chd.c
| r14530 | r14531 | |
| 90 | 90 | COMPRESSION_NONE = 4, // no compression; implicit length = hunkbytes |
| 91 | 91 | COMPRESSION_SELF = 5, // same as another block in this chd |
| 92 | 92 | COMPRESSION_PARENT = 6, // same as a hunk's worth of units in the parent chd |
| 93 | | |
| 93 | |
| 94 | 94 | // these additional pseudo-types are used for compressed encodings: |
| 95 | 95 | COMPRESSION_RLE_SMALL, // start of small RLE run (4-bit length) |
| 96 | 96 | COMPRESSION_RLE_LARGE, // start of large RLE run (8-bit length) |
| r14530 | r14531 | |
| 125 | 125 | |
| 126 | 126 | struct chd_file::metadata_hash |
| 127 | 127 | { |
| 128 | | UINT8 tag[4]; // tag of the metadata in big-endian |
| 129 | | sha1_t sha1; // hash data |
| 128 | UINT8 tag[4]; // tag of the metadata in big-endian |
| 129 | sha1_t sha1; // hash data |
| 130 | 130 | }; |
| 131 | 131 | |
| 132 | 132 | |
| r14530 | r14531 | |
| 179 | 179 | |
| 180 | 180 | |
| 181 | 181 | //------------------------------------------------- |
| 182 | | // be_write_sha1 - write a sha1_t to a data |
| 182 | // be_write_sha1 - write a sha1_t to a data |
| 183 | 183 | // stream in bigendian order |
| 184 | 184 | //------------------------------------------------- |
| 185 | 185 | |
| r14530 | r14531 | |
| 199 | 199 | // no file = failure |
| 200 | 200 | if (m_file == NULL) |
| 201 | 201 | throw CHDERR_NOT_OPEN; |
| 202 | | |
| 202 | |
| 203 | 203 | // seek and read |
| 204 | 204 | core_fseek(m_file, offset, SEEK_SET); |
| 205 | 205 | UINT32 count = core_fread(m_file, dest, length); |
| r14530 | r14531 | |
| 218 | 218 | // no file = failure |
| 219 | 219 | if (m_file == NULL) |
| 220 | 220 | throw CHDERR_NOT_OPEN; |
| 221 | | |
| 221 | |
| 222 | 222 | // seek and write |
| 223 | 223 | core_fseek(m_file, offset, SEEK_SET); |
| 224 | 224 | UINT32 count = core_fwrite(m_file, source, length); |
| r14530 | r14531 | |
| 229 | 229 | |
| 230 | 230 | //------------------------------------------------- |
| 231 | 231 | // file_append - append to the file at the given |
| 232 | | // offset, ensuring we start at the given |
| 232 | // offset, ensuring we start at the given |
| 233 | 233 | // alignment; on failure throw an error |
| 234 | 234 | //------------------------------------------------- |
| 235 | 235 | |
| r14530 | r14531 | |
| 346 | 346 | // determine offset within the file for data-only |
| 347 | 347 | if (m_rawsha1_offset == 0) |
| 348 | 348 | throw CHDERR_UNSUPPORTED_VERSION; |
| 349 | | |
| 349 | |
| 350 | 350 | // read the big-endian version |
| 351 | 351 | UINT8 rawbuf[sizeof(sha1_t)]; |
| 352 | 352 | file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf)); |
| r14530 | r14531 | |
| 371 | 371 | // determine offset within the file |
| 372 | 372 | if (m_parentsha1_offset == 0) |
| 373 | 373 | throw CHDERR_UNSUPPORTED_VERSION; |
| 374 | | |
| 374 | |
| 375 | 375 | // read the big-endian version |
| 376 | 376 | UINT8 rawbuf[sizeof(sha1_t)]; |
| 377 | 377 | file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); |
| r14530 | r14531 | |
| 395 | 395 | // error if invalid |
| 396 | 396 | if (hunknum >= m_hunkcount) |
| 397 | 397 | return CHDERR_HUNK_OUT_OF_RANGE; |
| 398 | | |
| 398 | |
| 399 | 399 | // get the map pointer |
| 400 | 400 | UINT8 *rawmap; |
| 401 | 401 | switch (m_version) |
| r14530 | r14531 | |
| 410 | 410 | compressor = CHD_CODEC_ZLIB; |
| 411 | 411 | compbytes = be_read(&rawmap[12], 2) + (rawmap[14] << 16); |
| 412 | 412 | break; |
| 413 | | |
| 413 | |
| 414 | 414 | case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: |
| 415 | 415 | compressor = CHD_CODEC_NONE; |
| 416 | 416 | compbytes = m_hunkbytes; |
| 417 | 417 | break; |
| 418 | | |
| 418 | |
| 419 | 419 | case V34_MAP_ENTRY_TYPE_MINI: |
| 420 | 420 | compressor = CHD_CODEC_MINI; |
| 421 | 421 | compbytes = 0; |
| 422 | 422 | break; |
| 423 | | |
| 423 | |
| 424 | 424 | case V34_MAP_ENTRY_TYPE_SELF_HUNK: |
| 425 | 425 | compressor = CHD_CODEC_SELF; |
| 426 | 426 | compbytes = 0; |
| r14530 | r14531 | |
| 432 | 432 | break; |
| 433 | 433 | } |
| 434 | 434 | break; |
| 435 | | |
| 435 | |
| 436 | 436 | // v5 map entries |
| 437 | 437 | case 5: |
| 438 | 438 | rawmap = m_rawmap + m_mapentrybytes * hunknum; |
| r14530 | r14531 | |
| 452 | 452 | } |
| 453 | 453 | break; |
| 454 | 454 | } |
| 455 | | |
| 455 | |
| 456 | 456 | // compressed case |
| 457 | 457 | switch (rawmap[0]) |
| 458 | 458 | { |
| r14530 | r14531 | |
| 473 | 473 | compressor = CHD_CODEC_SELF; |
| 474 | 474 | compbytes = 0; |
| 475 | 475 | break; |
| 476 | | |
| 476 | |
| 477 | 477 | case COMPRESSION_PARENT: |
| 478 | 478 | compressor = CHD_CODEC_PARENT; |
| 479 | 479 | compbytes = 0; |
| r14530 | r14531 | |
| 494 | 494 | // create a big-endian version |
| 495 | 495 | UINT8 rawbuf[sizeof(sha1_t)]; |
| 496 | 496 | be_write_sha1(rawbuf, rawdata); |
| 497 | | |
| 497 | |
| 498 | 498 | // write to the header |
| 499 | 499 | UINT64 offset = (m_rawsha1_offset != 0) ? m_rawsha1_offset : m_sha1_offset; |
| 500 | 500 | assert(offset != 0); |
| 501 | 501 | file_write(offset, rawbuf, sizeof(rawbuf)); |
| 502 | | |
| 502 | |
| 503 | 503 | // if we have a separate rawsha1_offset, update the full sha1 as well |
| 504 | 504 | if (m_rawsha1_offset != 0) |
| 505 | 505 | metadata_update_hash(); |
| r14530 | r14531 | |
| 519 | 519 | // create a big-endian version |
| 520 | 520 | UINT8 rawbuf[sizeof(sha1_t)]; |
| 521 | 521 | be_write_sha1(rawbuf, parent); |
| 522 | | |
| 522 | |
| 523 | 523 | // write to the header |
| 524 | 524 | assert(m_parentsha1_offset != 0); |
| 525 | 525 | file_write(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); |
| r14530 | r14531 | |
| 602 | 602 | // create the file normally, then claim the file |
| 603 | 603 | chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression); |
| 604 | 604 | m_owns_file = true; |
| 605 | | |
| 605 | |
| 606 | 606 | // if an error happened, close and delete the file |
| 607 | 607 | if (chderr != CHDERR_NONE) |
| 608 | 608 | { |
| r14530 | r14531 | |
| 633 | 633 | // create the file normally, then claim the file |
| 634 | 634 | chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent); |
| 635 | 635 | m_owns_file = true; |
| 636 | | |
| 636 | |
| 637 | 637 | // if an error happened, close and delete the file |
| 638 | 638 | if (chderr != CHDERR_NONE) |
| 639 | 639 | { |
| r14530 | r14531 | |
| 669 | 669 | core_fclose(file); |
| 670 | 670 | return err; |
| 671 | 671 | } |
| 672 | | |
| 672 | |
| 673 | 673 | // we now own this file |
| 674 | 674 | m_owns_file = true; |
| 675 | 675 | return err; |
| r14530 | r14531 | |
| 708 | 708 | m_owns_file = false; |
| 709 | 709 | m_allow_reads = false; |
| 710 | 710 | m_allow_writes = false; |
| 711 | | |
| 711 | |
| 712 | 712 | // reset core parameters from the header |
| 713 | 713 | m_version = HEADER_VERSION; |
| 714 | 714 | m_logicalbytes = 0; |
| r14530 | r14531 | |
| 759 | 759 | // punt if no file |
| 760 | 760 | if (m_file == NULL) |
| 761 | 761 | throw CHDERR_NOT_OPEN; |
| 762 | | |
| 762 | |
| 763 | 763 | // return an error if out of range |
| 764 | 764 | if (hunknum >= m_hunkcount) |
| 765 | 765 | throw CHDERR_HUNK_OUT_OF_RANGE; |
| r14530 | r14531 | |
| 787 | 787 | if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != NULL && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) |
| 788 | 788 | throw CHDERR_DECOMPRESSION_ERROR; |
| 789 | 789 | return CHDERR_NONE; |
| 790 | | |
| 790 | |
| 791 | 791 | case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: |
| 792 | 792 | file_read(blockoffs, dest, m_hunkbytes); |
| 793 | 793 | if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) |
| 794 | 794 | throw CHDERR_DECOMPRESSION_ERROR; |
| 795 | 795 | return CHDERR_NONE; |
| 796 | | |
| 796 | |
| 797 | 797 | case V34_MAP_ENTRY_TYPE_MINI: |
| 798 | 798 | be_write(dest, blockoffs, 8); |
| 799 | 799 | for (UINT32 bytes = 8; bytes < m_hunkbytes; bytes++) |
| r14530 | r14531 | |
| 801 | 801 | if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) |
| 802 | 802 | throw CHDERR_DECOMPRESSION_ERROR; |
| 803 | 803 | return CHDERR_NONE; |
| 804 | | |
| 804 | |
| 805 | 805 | case V34_MAP_ENTRY_TYPE_SELF_HUNK: |
| 806 | 806 | return read_hunk(blockoffs, dest); |
| 807 | 807 | |
| r14530 | r14531 | |
| 811 | 811 | return m_parent->read_hunk(blockoffs, dest); |
| 812 | 812 | } |
| 813 | 813 | break; |
| 814 | | |
| 814 | |
| 815 | 815 | // v5 map entries |
| 816 | 816 | case 5: |
| 817 | 817 | rawmap = m_rawmap + m_mapentrybytes * hunknum; |
| r14530 | r14531 | |
| 819 | 819 | // uncompressed case |
| 820 | 820 | if (!compressed()) |
| 821 | 821 | { |
| 822 | | blockoffs = UINT64(be_read(rawmap, 4)) * UINT64(m_hunkbytes); |
| 822 | blockoffs = UINT64(be_read(rawmap, 4)) * UINT64(m_hunkbytes); |
| 823 | 823 | if (blockoffs != 0) |
| 824 | 824 | file_read(blockoffs, dest, m_hunkbytes); |
| 825 | 825 | else if (m_parent_missing) |
| r14530 | r14531 | |
| 830 | 830 | memset(dest, 0, m_hunkbytes); |
| 831 | 831 | return CHDERR_NONE; |
| 832 | 832 | } |
| 833 | | |
| 833 | |
| 834 | 834 | // compressed case |
| 835 | 835 | blocklen = be_read(&rawmap[1], 3); |
| 836 | 836 | blockoffs = be_read(&rawmap[4], 6); |
| r14530 | r14531 | |
| 857 | 857 | |
| 858 | 858 | case COMPRESSION_SELF: |
| 859 | 859 | return read_hunk(blockoffs, dest); |
| 860 | | |
| 860 | |
| 861 | 861 | case COMPRESSION_PARENT: |
| 862 | 862 | if (m_parent_missing) |
| 863 | 863 | throw CHDERR_REQUIRES_PARENT; |
| r14530 | r14531 | |
| 865 | 865 | } |
| 866 | 866 | break; |
| 867 | 867 | } |
| 868 | | |
| 868 | |
| 869 | 869 | // if we get here, something was wrong |
| 870 | 870 | throw CHDERR_READ_ERROR; |
| 871 | 871 | } |
| 872 | | |
| 872 | |
| 873 | 873 | // just return errors |
| 874 | 874 | catch (chd_error &err) |
| 875 | 875 | { |
| r14530 | r14531 | |
| 902 | 902 | // uncompressed writes only via this interface |
| 903 | 903 | if (compressed()) |
| 904 | 904 | throw CHDERR_FILE_NOT_WRITEABLE; |
| 905 | | |
| 905 | |
| 906 | 906 | // see if we have allocated the space on disk for this hunk |
| 907 | 907 | UINT8 *rawmap = m_rawmap + hunknum * 4; |
| 908 | 908 | UINT32 rawentry = be_read(rawmap, 4); |
| r14530 | r14531 | |
| 919 | 919 | all_zeros = false; |
| 920 | 920 | break; |
| 921 | 921 | } |
| 922 | | |
| 922 | |
| 923 | 923 | // if it's all zeros, do nothing more |
| 924 | 924 | if (all_zeros) |
| 925 | 925 | return CHDERR_NONE; |
| 926 | | |
| 926 | |
| 927 | 927 | // append new data to the end of the file, aligning the first chunk |
| 928 | 928 | rawentry = file_append(buffer, m_hunkbytes, m_hunkbytes) / m_hunkbytes; |
| 929 | | |
| 929 | |
| 930 | 930 | // write the map entry back |
| 931 | 931 | be_write(rawmap, rawentry, 4); |
| 932 | 932 | file_write(m_mapoffset + hunknum * 4, rawmap, 4); |
| 933 | | |
| 933 | |
| 934 | 934 | // update the cached hunk if we just wrote it |
| 935 | 935 | if (hunknum == m_cachehunk && buffer != m_cache) |
| 936 | 936 | memcpy(m_cache, buffer, m_hunkbytes); |
| 937 | 937 | } |
| 938 | | |
| 938 | |
| 939 | 939 | // otherwise, just overwrite |
| 940 | 940 | else |
| 941 | 941 | file_write(UINT64(rawentry) * UINT64(m_hunkbytes), buffer, m_hunkbytes); |
| 942 | 942 | return CHDERR_NONE; |
| 943 | 943 | } |
| 944 | | |
| 944 | |
| 945 | 945 | // just return errors |
| 946 | 946 | catch (chd_error &err) |
| 947 | 947 | { |
| r14530 | r14531 | |
| 973 | 973 | |
| 974 | 974 | |
| 975 | 975 | //------------------------------------------------- |
| 976 | | // read_bytes - read from the CHD at a byte level, |
| 976 | // read_bytes - read from the CHD at a byte level, |
| 977 | 977 | // using the cache to handle partial hunks |
| 978 | 978 | //------------------------------------------------- |
| 979 | 979 | |
| r14530 | r14531 | |
| 988 | 988 | // determine start/end boundaries |
| 989 | 989 | UINT32 startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; |
| 990 | 990 | UINT32 endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); |
| 991 | | |
| 991 | |
| 992 | 992 | // if it's a full block, just read directly from disk unless it's the cached hunk |
| 993 | 993 | chd_error err = CHDERR_NONE; |
| 994 | 994 | if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) |
| 995 | 995 | err = read_hunk(curhunk, dest); |
| 996 | | |
| 996 | |
| 997 | 997 | // otherwise, read from the cache |
| 998 | 998 | else |
| 999 | 999 | { |
| r14530 | r14531 | |
| 1032 | 1032 | // determine start/end boundaries |
| 1033 | 1033 | UINT32 startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; |
| 1034 | 1034 | UINT32 endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); |
| 1035 | | |
| 1035 | |
| 1036 | 1036 | // if it's a full block, just write directly to disk unless it's the cached hunk |
| 1037 | 1037 | chd_error err = CHDERR_NONE; |
| 1038 | 1038 | if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) |
| 1039 | 1039 | err = write_hunk(curhunk, source); |
| 1040 | | |
| 1040 | |
| 1041 | 1041 | // otherwise, write from the cache |
| 1042 | 1042 | else |
| 1043 | 1043 | { |
| r14530 | r14531 | |
| 1080 | 1080 | file_read(metaentry.offset + METADATA_HEADER_SIZE, output.stringbuffer(metaentry.length), metaentry.length); |
| 1081 | 1081 | return CHDERR_NONE; |
| 1082 | 1082 | } |
| 1083 | | |
| 1083 | |
| 1084 | 1084 | // just return errors |
| 1085 | 1085 | catch (chd_error &err) |
| 1086 | 1086 | { |
| r14530 | r14531 | |
| 1103 | 1103 | file_read(metaentry.offset + METADATA_HEADER_SIZE, output, metaentry.length); |
| 1104 | 1104 | return CHDERR_NONE; |
| 1105 | 1105 | } |
| 1106 | | |
| 1106 | |
| 1107 | 1107 | // just return errors |
| 1108 | 1108 | catch (chd_error &err) |
| 1109 | 1109 | { |
| r14530 | r14531 | |
| 1126 | 1126 | file_read(metaentry.offset + METADATA_HEADER_SIZE, output, MIN(outputlen, resultlen)); |
| 1127 | 1127 | return CHDERR_NONE; |
| 1128 | 1128 | } |
| 1129 | | |
| 1129 | |
| 1130 | 1130 | // just return errors |
| 1131 | 1131 | catch (chd_error &err) |
| 1132 | 1132 | { |
| r14530 | r14531 | |
| 1151 | 1151 | resultflags = metaentry.flags; |
| 1152 | 1152 | return CHDERR_NONE; |
| 1153 | 1153 | } |
| 1154 | | |
| 1154 | |
| 1155 | 1155 | // just return errors |
| 1156 | 1156 | catch (chd_error &err) |
| 1157 | 1157 | { |
| r14530 | r14531 | |
| 1191 | 1191 | be_write(length, inputlen, 3); |
| 1192 | 1192 | file_write(metaentry.offset + 5, length, sizeof(length)); |
| 1193 | 1193 | } |
| 1194 | | |
| 1194 | |
| 1195 | 1195 | // indicate we did everything |
| 1196 | 1196 | finished = true; |
| 1197 | 1197 | } |
| 1198 | | |
| 1198 | |
| 1199 | 1199 | // if it doesn't fit, unlink the current entry |
| 1200 | 1200 | else |
| 1201 | 1201 | metadata_set_previous_next(metaentry.prev, metaentry.next); |
| 1202 | 1202 | } |
| 1203 | | |
| 1203 | |
| 1204 | 1204 | // if not yet done, create a new entry and append |
| 1205 | 1205 | if (!finished) |
| 1206 | 1206 | { |
| r14530 | r14531 | |
| 1210 | 1210 | raw_meta_header[4] = flags; |
| 1211 | 1211 | be_write(&raw_meta_header[5], (inputlen & 0x00ffffff) | (flags << 24), 3); |
| 1212 | 1212 | be_write(&raw_meta_header[8], 0, 8); |
| 1213 | | |
| 1213 | |
| 1214 | 1214 | // append the new header, then the data |
| 1215 | 1215 | UINT64 offset = file_append(raw_meta_header, sizeof(raw_meta_header)); |
| 1216 | 1216 | file_append(inputbuf, inputlen); |
| r14530 | r14531 | |
| 1223 | 1223 | metadata_update_hash(); |
| 1224 | 1224 | return CHDERR_NONE; |
| 1225 | 1225 | } |
| 1226 | | |
| 1226 | |
| 1227 | 1227 | // return any errors |
| 1228 | 1228 | catch (chd_error &err) |
| 1229 | 1229 | { |
| r14530 | r14531 | |
| 1246 | 1246 | metadata_entry metaentry; |
| 1247 | 1247 | if (!metadata_find(metatag, metaindex, metaentry)) |
| 1248 | 1248 | throw CHDERR_METADATA_NOT_FOUND; |
| 1249 | | |
| 1249 | |
| 1250 | 1250 | // point the previous to the next, unlinking us |
| 1251 | 1251 | metadata_set_previous_next(metaentry.prev, metaentry.next); |
| 1252 | 1252 | return CHDERR_NONE; |
| 1253 | 1253 | } |
| 1254 | | |
| 1254 | |
| 1255 | 1255 | // return any errors |
| 1256 | 1256 | catch (chd_error &err) |
| 1257 | 1257 | { |
| r14530 | r14531 | |
| 1261 | 1261 | |
| 1262 | 1262 | |
| 1263 | 1263 | //------------------------------------------------- |
| 1264 | | // clone_all_metadata - clone the metadata from |
| 1264 | // clone_all_metadata - clone the metadata from |
| 1265 | 1265 | // one CHD to a second |
| 1266 | 1266 | //------------------------------------------------- |
| 1267 | 1267 | |
| r14530 | r14531 | |
| 1282 | 1282 | // read the metadata item |
| 1283 | 1283 | filedata.resize(metaentry.length); |
| 1284 | 1284 | source.file_read(metaentry.offset + METADATA_HEADER_SIZE, filedata, metaentry.length); |
| 1285 | | |
| 1285 | |
| 1286 | 1286 | // write it to the destination |
| 1287 | | chd_error err = write_metadata(metaentry.metatag, -1, filedata, metaentry.length, metaentry.flags); |
| 1287 | chd_error err = write_metadata(metaentry.metatag, (UINT32)-1, filedata, metaentry.length, metaentry.flags); |
| 1288 | 1288 | if (err != CHDERR_NONE) |
| 1289 | 1289 | throw err; |
| 1290 | 1290 | } |
| 1291 | 1291 | return CHDERR_NONE; |
| 1292 | 1292 | } |
| 1293 | | |
| 1293 | |
| 1294 | 1294 | // return any errors |
| 1295 | 1295 | catch (chd_error &err) |
| 1296 | 1296 | { |
| r14530 | r14531 | |
| 1363 | 1363 | } |
| 1364 | 1364 | return CHDERR_INVALID_PARAMETER; |
| 1365 | 1365 | } |
| 1366 | | |
| 1366 | |
| 1367 | 1367 | // return any errors |
| 1368 | 1368 | catch (chd_error &err) |
| 1369 | 1369 | { |
| r14530 | r14531 | |
| 1425 | 1425 | |
| 1426 | 1426 | //------------------------------------------------- |
| 1427 | 1427 | // guess_unitbytes - for older CHD formats, take |
| 1428 | | // a guess at the bytes/unit based on metadata |
| 1428 | // a guess at the bytes/unit based on metadata |
| 1429 | 1429 | //------------------------------------------------- |
| 1430 | 1430 | |
| 1431 | 1431 | UINT32 chd_file::guess_unitbytes() |
| r14530 | r14531 | |
| 1441 | 1441 | read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || |
| 1442 | 1442 | read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE) |
| 1443 | 1443 | return CD_FRAME_SIZE; |
| 1444 | | |
| 1444 | |
| 1445 | 1445 | // otherwise, just map 1:1 with the hunk size |
| 1446 | 1446 | return m_hunkbytes; |
| 1447 | 1447 | } |
| r14530 | r14531 | |
| 1464 | 1464 | m_metaoffset = be_read(&rawheader[36], 8); |
| 1465 | 1465 | m_hunkbytes = be_read(&rawheader[76], 4); |
| 1466 | 1466 | m_hunkcount = be_read(&rawheader[24], 4); |
| 1467 | | |
| 1467 | |
| 1468 | 1468 | // extract parent SHA-1 |
| 1469 | 1469 | UINT32 flags = be_read(&rawheader[16], 4); |
| 1470 | 1470 | if ((flags & 2) && m_allow_writes) |
| r14530 | r14531 | |
| 1480 | 1480 | default: throw CHDERR_UNKNOWN_COMPRESSION; |
| 1481 | 1481 | } |
| 1482 | 1482 | m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE; |
| 1483 | | |
| 1483 | |
| 1484 | 1484 | // describe the format |
| 1485 | 1485 | m_mapoffset_offset = 0; |
| 1486 | 1486 | m_metaoffset_offset = 36; |
| 1487 | 1487 | m_sha1_offset = 80; |
| 1488 | 1488 | m_rawsha1_offset = 0; |
| 1489 | 1489 | m_parentsha1_offset = 100; |
| 1490 | | |
| 1490 | |
| 1491 | 1491 | // determine properties of map entries |
| 1492 | 1492 | m_mapentrybytes = 16; |
| 1493 | 1493 | |
| 1494 | 1494 | // extract parent SHA-1 |
| 1495 | 1495 | if (flags & 1) |
| 1496 | 1496 | parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]); |
| 1497 | | |
| 1497 | |
| 1498 | 1498 | // guess at the units based on snooping the metadata |
| 1499 | 1499 | m_unitbytes = guess_unitbytes(); |
| 1500 | 1500 | m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; |
| r14530 | r14531 | |
| 1518 | 1518 | m_metaoffset = be_read(&rawheader[36], 8); |
| 1519 | 1519 | m_hunkbytes = be_read(&rawheader[44], 4); |
| 1520 | 1520 | m_hunkcount = be_read(&rawheader[24], 4); |
| 1521 | | |
| 1521 | |
| 1522 | 1522 | // extract parent SHA-1 |
| 1523 | 1523 | UINT32 flags = be_read(&rawheader[16], 4); |
| 1524 | 1524 | if ((flags & 2) && m_allow_writes) |
| r14530 | r14531 | |
| 1534 | 1534 | default: throw CHDERR_UNKNOWN_COMPRESSION; |
| 1535 | 1535 | } |
| 1536 | 1536 | m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE; |
| 1537 | | |
| 1537 | |
| 1538 | 1538 | // describe the format |
| 1539 | 1539 | m_mapoffset_offset = 0; |
| 1540 | 1540 | m_metaoffset_offset = 36; |
| 1541 | 1541 | m_sha1_offset = 48; |
| 1542 | 1542 | m_rawsha1_offset = 88; |
| 1543 | 1543 | m_parentsha1_offset = 68; |
| 1544 | | |
| 1544 | |
| 1545 | 1545 | // determine properties of map entries |
| 1546 | 1546 | m_mapentrybytes = 16; |
| 1547 | 1547 | |
| 1548 | 1548 | // extract parent SHA-1 |
| 1549 | 1549 | if (flags & 1) |
| 1550 | 1550 | parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]); |
| 1551 | | |
| 1551 | |
| 1552 | 1552 | // guess at the units based on snooping the metadata |
| 1553 | 1553 | m_unitbytes = guess_unitbytes(); |
| 1554 | 1554 | m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; |
| r14530 | r14531 | |
| 1574 | 1574 | m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes; |
| 1575 | 1575 | m_unitbytes = be_read(&rawheader[60], 4); |
| 1576 | 1576 | m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; |
| 1577 | | |
| 1577 | |
| 1578 | 1578 | // determine compression |
| 1579 | 1579 | m_compression[0] = be_read(&rawheader[16], 4); |
| 1580 | 1580 | m_compression[1] = be_read(&rawheader[20], 4); |
| 1581 | 1581 | m_compression[2] = be_read(&rawheader[24], 4); |
| 1582 | 1582 | m_compression[3] = be_read(&rawheader[28], 4); |
| 1583 | | |
| 1583 | |
| 1584 | 1584 | // describe the format |
| 1585 | 1585 | m_mapoffset_offset = 40; |
| 1586 | 1586 | m_metaoffset_offset = 48; |
| 1587 | 1587 | m_sha1_offset = 84; |
| 1588 | 1588 | m_rawsha1_offset = 64; |
| 1589 | 1589 | m_parentsha1_offset = 104; |
| 1590 | | |
| 1590 | |
| 1591 | 1591 | // determine properties of map entries |
| 1592 | 1592 | m_mapentrybytes = compressed() ? 12 : 4; |
| 1593 | 1593 | |
| r14530 | r14531 | |
| 1608 | 1608 | // first get a CRC-16 of the original rawmap |
| 1609 | 1609 | crc16_t mapcrc = crc16_creator::simple(m_rawmap, m_hunkcount * 12); |
| 1610 | 1610 | |
| 1611 | | // create a buffer to hold the RLE data |
| 1611 | // create a buffer to hold the RLE data |
| 1612 | 1612 | dynamic_buffer compression_rle(m_hunkcount); |
| 1613 | 1613 | UINT8 *dest = compression_rle; |
| 1614 | | |
| 1614 | |
| 1615 | 1615 | // use a huffman encoder for 16 different codes, maximum length is 8 bits |
| 1616 | 1616 | huffman_encoder<16, 8> encoder; |
| 1617 | 1617 | encoder.histo_reset(); |
| r14530 | r14531 | |
| 1627 | 1627 | for (int hunknum = 0; hunknum < m_hunkcount; hunknum++) |
| 1628 | 1628 | { |
| 1629 | 1629 | UINT8 curcomp = m_rawmap[hunknum * 12 + 0]; |
| 1630 | | |
| 1630 | |
| 1631 | 1631 | // promote self block references to more compact forms |
| 1632 | 1632 | if (curcomp == COMPRESSION_SELF) |
| 1633 | 1633 | { |
| r14530 | r14531 | |
| 1655 | 1655 | max_parent = MAX(max_parent, refunit); |
| 1656 | 1656 | last_parent = refunit; |
| 1657 | 1657 | } |
| 1658 | | |
| 1658 | |
| 1659 | 1659 | // track maximum compressed length |
| 1660 | | else // if (curcomp >= COMPRESSION_TYPE_0 && curcomp <= COMPRESSION_TYPE_3) |
| 1660 | else //if (curcomp >= COMPRESSION_TYPE_0 && curcomp <= COMPRESSION_TYPE_3) |
| 1661 | 1661 | max_complen = MAX(max_complen, be_read(&m_rawmap[hunknum * 12 + 1], 3)); |
| 1662 | | |
| 1662 | |
| 1663 | 1663 | // track repeats |
| 1664 | 1664 | if (curcomp == lastcomp) |
| 1665 | 1665 | count++; |
| 1666 | | |
| 1666 | |
| 1667 | 1667 | // if no repeat, or we're at the end, flush it |
| 1668 | 1668 | if (curcomp != lastcomp || hunknum == m_hunkcount - 1) |
| 1669 | 1669 | { |
| r14530 | r14531 | |
| 1690 | 1690 | encoder.histo_one(*dest++ = lastcomp = curcomp); |
| 1691 | 1691 | } |
| 1692 | 1692 | } |
| 1693 | | |
| 1693 | |
| 1694 | 1694 | // compute a tree and export it to the buffer |
| 1695 | 1695 | dynamic_buffer compressed(m_hunkcount * 6); |
| 1696 | 1696 | bitstream_out bitbuf(&compressed[16], compressed.count() - 16); |
| r14530 | r14531 | |
| 1704 | 1704 | // encode the data |
| 1705 | 1705 | for (UINT8 *src = compression_rle; src < dest; src++) |
| 1706 | 1706 | encoder.encode_one(bitbuf, *src); |
| 1707 | | |
| 1707 | |
| 1708 | 1708 | // determine the number of bits we need to hold the a length |
| 1709 | 1709 | // and a hunk index |
| 1710 | 1710 | UINT8 lengthbits = bits_for_value(max_complen); |
| r14530 | r14531 | |
| 1722 | 1722 | UINT32 length = be_read(&rawmap[1], 3); |
| 1723 | 1723 | UINT64 offset = be_read(&rawmap[4], 6); |
| 1724 | 1724 | UINT16 crc = be_read(&rawmap[10], 2); |
| 1725 | | |
| 1725 | |
| 1726 | 1726 | // if no count remaining, fetch the next entry |
| 1727 | 1727 | if (count == 0) |
| 1728 | 1728 | { |
| r14530 | r14531 | |
| 1736 | 1736 | } |
| 1737 | 1737 | else |
| 1738 | 1738 | count--; |
| 1739 | | |
| 1739 | |
| 1740 | 1740 | // output additional data needed for this entry |
| 1741 | 1741 | switch (lastcomp) |
| 1742 | 1742 | { |
| r14530 | r14531 | |
| 1750 | 1750 | if (firstoffs == 0) |
| 1751 | 1751 | firstoffs = offset; |
| 1752 | 1752 | break; |
| 1753 | | |
| 1753 | |
| 1754 | 1754 | case COMPRESSION_NONE: |
| 1755 | 1755 | bitbuf.write(crc, 16); |
| 1756 | 1756 | if (firstoffs == 0) |
| 1757 | 1757 | firstoffs = offset; |
| 1758 | 1758 | break; |
| 1759 | | |
| 1759 | |
| 1760 | 1760 | case COMPRESSION_SELF: |
| 1761 | 1761 | assert(offset < (UINT64(1) << selfbits)); |
| 1762 | 1762 | bitbuf.write(offset, selfbits); |
| 1763 | 1763 | break; |
| 1764 | | |
| 1764 | |
| 1765 | 1765 | case COMPRESSION_PARENT: |
| 1766 | 1766 | assert(offset < (UINT64(1) << parentbits)); |
| 1767 | 1767 | bitbuf.write(offset, parentbits); |
| 1768 | 1768 | break; |
| 1769 | | |
| 1769 | |
| 1770 | 1770 | case COMPRESSION_SELF_0: |
| 1771 | 1771 | case COMPRESSION_SELF_1: |
| 1772 | 1772 | case COMPRESSION_PARENT_SELF: |
| r14530 | r14531 | |
| 1775 | 1775 | break; |
| 1776 | 1776 | } |
| 1777 | 1777 | } |
| 1778 | | |
| 1778 | |
| 1779 | 1779 | // write the map header |
| 1780 | 1780 | UINT32 complen = bitbuf.flush(); |
| 1781 | 1781 | assert(!bitbuf.overflow()); |
| r14530 | r14531 | |
| 1785 | 1785 | compressed[12] = lengthbits; |
| 1786 | 1786 | compressed[13] = selfbits; |
| 1787 | 1787 | compressed[14] = parentbits; |
| 1788 | | |
| 1788 | |
| 1789 | 1789 | // write the result |
| 1790 | 1790 | m_mapoffset = file_append(compressed, complen + 16); |
| 1791 | | |
| 1791 | |
| 1792 | 1792 | // then write the map offset |
| 1793 | 1793 | UINT8 rawbuf[sizeof(UINT64)]; |
| 1794 | 1794 | be_write(rawbuf, m_mapoffset, 8); |
| r14530 | r14531 | |
| 1824 | 1824 | UINT8 lengthbits = rawbuf[12]; |
| 1825 | 1825 | UINT8 selfbits = rawbuf[13]; |
| 1826 | 1826 | UINT8 parentbits = rawbuf[14]; |
| 1827 | | |
| 1827 | |
| 1828 | 1828 | // now read the map |
| 1829 | 1829 | dynamic_buffer compressed(mapbytes); |
| 1830 | 1830 | file_read(m_mapoffset + 16, compressed, mapbytes); |
| 1831 | 1831 | bitstream_in bitbuf(compressed, compressed.count()); |
| 1832 | | |
| 1832 | |
| 1833 | 1833 | // first decode the compression types |
| 1834 | 1834 | huffman_decoder<16, 8> decoder; |
| 1835 | 1835 | huffman_error err = decoder.import_tree_rle(bitbuf); |
| r14530 | r14531 | |
| 1853 | 1853 | rawmap[0] = lastcomp = val; |
| 1854 | 1854 | } |
| 1855 | 1855 | } |
| 1856 | | |
| 1856 | |
| 1857 | 1857 | // then iterate through the hunks and extract the needed data |
| 1858 | 1858 | UINT64 curoffset = firstoffs; |
| 1859 | 1859 | UINT32 last_self = 0; |
| r14530 | r14531 | |
| 1874 | 1874 | curoffset += length = bitbuf.read(lengthbits); |
| 1875 | 1875 | crc = bitbuf.read(16); |
| 1876 | 1876 | break; |
| 1877 | | |
| 1877 | |
| 1878 | 1878 | case COMPRESSION_NONE: |
| 1879 | 1879 | curoffset += length = m_hunkbytes; |
| 1880 | 1880 | crc = bitbuf.read(16); |
| 1881 | 1881 | break; |
| 1882 | | |
| 1882 | |
| 1883 | 1883 | case COMPRESSION_SELF: |
| 1884 | 1884 | last_self = offset = bitbuf.read(selfbits); |
| 1885 | 1885 | break; |
| 1886 | | |
| 1886 | |
| 1887 | 1887 | case COMPRESSION_PARENT: |
| 1888 | 1888 | offset = bitbuf.read(parentbits); |
| 1889 | 1889 | last_parent = offset; |
| 1890 | 1890 | break; |
| 1891 | | |
| 1891 | |
| 1892 | 1892 | // pseudo-types; convert into base types |
| 1893 | 1893 | case COMPRESSION_SELF_1: |
| 1894 | 1894 | last_self++; |
| r14530 | r14531 | |
| 1896 | 1896 | rawmap[0] = COMPRESSION_SELF; |
| 1897 | 1897 | offset = last_self; |
| 1898 | 1898 | break; |
| 1899 | | |
| 1899 | |
| 1900 | 1900 | case COMPRESSION_PARENT_SELF: |
| 1901 | 1901 | rawmap[0] = COMPRESSION_PARENT; |
| 1902 | 1902 | last_parent = offset = (UINT64(hunknum) * UINT64(m_hunkbytes)) / m_unitbytes; |
| 1903 | 1903 | break; |
| 1904 | | |
| 1904 | |
| 1905 | 1905 | case COMPRESSION_PARENT_1: |
| 1906 | 1906 | last_parent += m_hunkbytes / m_unitbytes; |
| 1907 | 1907 | case COMPRESSION_PARENT_0: |
| r14530 | r14531 | |
| 1913 | 1913 | be_write(&rawmap[4], offset, 6); |
| 1914 | 1914 | be_write(&rawmap[10], crc, 2); |
| 1915 | 1915 | } |
| 1916 | | |
| 1916 | |
| 1917 | 1917 | // verify the final CRC |
| 1918 | 1918 | if (crc16_creator::simple(m_rawmap, m_hunkcount * 12) != mapcrc) |
| 1919 | 1919 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1920 | 1920 | } |
| 1921 | | |
| 1922 | 1921 | |
| 1922 | |
| 1923 | 1923 | //------------------------------------------------- |
| 1924 | 1924 | // create_common - command path when creating a |
| 1925 | 1925 | // new CHD file |
| r14530 | r14531 | |
| 1933 | 1933 | // if we have a parent, it must be V3 or later |
| 1934 | 1934 | if (m_parent != NULL && m_parent->version() < 3) |
| 1935 | 1935 | throw CHDERR_UNSUPPORTED_VERSION; |
| 1936 | | |
| 1936 | |
| 1937 | 1937 | // must be an even number of units per hunk |
| 1938 | 1938 | if (m_hunkbytes % m_unitbytes != 0) |
| 1939 | 1939 | throw CHDERR_INVALID_PARAMETER; |
| 1940 | 1940 | if (m_parent != NULL && m_unitbytes != m_parent->unit_bytes()) |
| 1941 | 1941 | throw CHDERR_INVALID_PARAMETER; |
| 1942 | | |
| 1942 | |
| 1943 | 1943 | // writes are obviously permitted; reads only if uncompressed |
| 1944 | 1944 | m_allow_writes = true; |
| 1945 | 1945 | m_allow_reads = !compressed(); |
| 1946 | | |
| 1946 | |
| 1947 | 1947 | // verify the compression types |
| 1948 | 1948 | bool found_zero = false; |
| 1949 | 1949 | for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compression); codecnum++) |
| r14530 | r14531 | |
| 1978 | 1978 | |
| 1979 | 1979 | // write the resulting header |
| 1980 | 1980 | file_write(0, rawheader, sizeof(rawheader)); |
| 1981 | | |
| 1981 | |
| 1982 | 1982 | // parse it back out to set up fields appropriately |
| 1983 | 1983 | sha1_t parentsha1; |
| 1984 | 1984 | parse_v5_header(rawheader, parentsha1); |
| 1985 | | |
| 1985 | |
| 1986 | 1986 | // write out the map (if not compressed) |
| 1987 | 1987 | if (!compressed()) |
| 1988 | 1988 | { |
| r14530 | r14531 | |
| 2001 | 2001 | // finish opening the file |
| 2002 | 2002 | create_open_common(); |
| 2003 | 2003 | } |
| 2004 | | |
| 2004 | |
| 2005 | 2005 | // handle errors by closing ourself |
| 2006 | 2006 | catch (chd_error &err) |
| 2007 | 2007 | { |
| r14530 | r14531 | |
| 2030 | 2030 | // reads are always permitted; writes possibly as well |
| 2031 | 2031 | m_allow_reads = true; |
| 2032 | 2032 | m_allow_writes = writeable; |
| 2033 | | |
| 2033 | |
| 2034 | 2034 | // read the raw header |
| 2035 | 2035 | UINT8 rawheader[MAX_HEADER_SIZE]; |
| 2036 | 2036 | file_read(0, rawheader, sizeof(rawheader)); |
| 2037 | | |
| 2037 | |
| 2038 | 2038 | // verify the signature |
| 2039 | 2039 | if (memcmp(rawheader, "MComprHD", 8) != 0) |
| 2040 | 2040 | throw CHDERR_INVALID_FILE; |
| 2041 | | |
| 2041 | |
| 2042 | 2042 | // only allow writes to the most recent version |
| 2043 | 2043 | m_version = be_read(&rawheader[12], 4); |
| 2044 | 2044 | if (m_allow_writes && m_version < HEADER_VERSION) |
| 2045 | 2045 | throw CHDERR_UNSUPPORTED_VERSION; |
| 2046 | | |
| 2046 | |
| 2047 | 2047 | // read the header if we support it |
| 2048 | 2048 | sha1_t parentsha1 = sha1_t::null; |
| 2049 | 2049 | switch (m_version) |
| r14530 | r14531 | |
| 2051 | 2051 | case 3: parse_v3_header(rawheader, parentsha1); break; |
| 2052 | 2052 | case 4: parse_v4_header(rawheader, parentsha1); break; |
| 2053 | 2053 | case 5: parse_v5_header(rawheader, parentsha1); break; |
| 2054 | | default: throw CHDERR_UNSUPPORTED_VERSION; |
| 2054 | default: throw CHDERR_UNSUPPORTED_VERSION; |
| 2055 | 2055 | } |
| 2056 | | |
| 2056 | |
| 2057 | 2057 | // make sure we have a parent if we need one (and don't if we don't) |
| 2058 | 2058 | if (parentsha1 != sha1_t::null) |
| 2059 | 2059 | { |
| r14530 | r14531 | |
| 2064 | 2064 | } |
| 2065 | 2065 | else if (parentsha1 == sha1_t::null && m_parent != NULL) |
| 2066 | 2066 | throw CHDERR_INVALID_PARAMETER; |
| 2067 | | |
| 2067 | |
| 2068 | 2068 | // finish opening the file |
| 2069 | 2069 | create_open_common(); |
| 2070 | 2070 | return CHDERR_NONE; |
| 2071 | 2071 | } |
| 2072 | | |
| 2072 | |
| 2073 | 2073 | // handle errors by closing ourself |
| 2074 | 2074 | catch (chd_error &err) |
| 2075 | 2075 | { |
| r14530 | r14531 | |
| 2093 | 2093 | if (m_decompressor[decompnum] == NULL && m_compression[decompnum] != 0) |
| 2094 | 2094 | throw CHDERR_UNKNOWN_COMPRESSION; |
| 2095 | 2095 | } |
| 2096 | | |
| 2096 | |
| 2097 | 2097 | // read the map; v5+ compressed drives need to read and decompress their map |
| 2098 | 2098 | m_rawmap.resize(m_hunkcount * m_mapentrybytes); |
| 2099 | 2099 | if (m_version >= 5 && compressed()) |
| r14530 | r14531 | |
| 2135 | 2135 | UINT8 *rawmap = &m_rawmap[hunknum * 12]; |
| 2136 | 2136 | if (rawmap[0] != 0xff) |
| 2137 | 2137 | throw CHDERR_COMPRESSION_ERROR; |
| 2138 | | |
| 2138 | |
| 2139 | 2139 | // if this isn't the first block, only permitted to write immediately |
| 2140 | 2140 | // after the previous one |
| 2141 | 2141 | if (hunknum != 0 && rawmap[-12] == 0xff) |
| 2142 | 2142 | throw CHDERR_COMPRESSION_ERROR; |
| 2143 | 2143 | } |
| 2144 | | |
| 2145 | 2144 | |
| 2145 | |
| 2146 | 2146 | //------------------------------------------------- |
| 2147 | | // hunk_write_compressed - write a hunk to a |
| 2147 | // hunk_write_compressed - write a hunk to a |
| 2148 | 2148 | // compressed CHD, discovering the best |
| 2149 | 2149 | // technique |
| 2150 | 2150 | //------------------------------------------------- |
| r14530 | r14531 | |
| 2153 | 2153 | { |
| 2154 | 2154 | // verify that we are appending properly to a compressed file |
| 2155 | 2155 | verify_proper_compression_append(hunknum); |
| 2156 | | |
| 2156 | |
| 2157 | 2157 | // write the final result |
| 2158 | 2158 | UINT64 offset = file_append(compressed, complength); |
| 2159 | | |
| 2159 | |
| 2160 | 2160 | // update the map entry |
| 2161 | 2161 | UINT8 *rawmap = &m_rawmap[hunknum * 12]; |
| 2162 | 2162 | rawmap[0] = (compression == -1) ? COMPRESSION_NONE : compression; |
| r14530 | r14531 | |
| 2175 | 2175 | { |
| 2176 | 2176 | // verify that we are appending properly to a compressed file |
| 2177 | 2177 | verify_proper_compression_append(hunknum); |
| 2178 | | |
| 2178 | |
| 2179 | 2179 | // only permitted to reference prior hunks |
| 2180 | 2180 | if (otherhunk >= hunknum) |
| 2181 | | throw CHDERR_INVALID_PARAMETER; |
| 2181 | throw CHDERR_INVALID_PARAMETER; |
| 2182 | 2182 | |
| 2183 | 2183 | // update the map entry |
| 2184 | 2184 | UINT8 *rawmap = &m_rawmap[hunknum * 12]; |
| r14530 | r14531 | |
| 2273 | 2273 | // otherwise, update the link in the previous header |
| 2274 | 2274 | else |
| 2275 | 2275 | offset = prevoffset + 8; |
| 2276 | | |
| 2276 | |
| 2277 | 2277 | // create a big-endian version |
| 2278 | 2278 | UINT8 rawbuf[sizeof(UINT64)]; |
| 2279 | 2279 | be_write(rawbuf, nextoffset, 8); |
| 2280 | | |
| 2280 | |
| 2281 | 2281 | // write to the header and update our local copy |
| 2282 | 2282 | file_write(offset, rawbuf, sizeof(rawbuf)); |
| 2283 | 2283 | } |
| r14530 | r14531 | |
| 2296 | 2296 | |
| 2297 | 2297 | // compute the new overall hash |
| 2298 | 2298 | sha1_t fullsha1 = compute_overall_sha1(raw_sha1()); |
| 2299 | | |
| 2299 | |
| 2300 | 2300 | // create a big-endian version |
| 2301 | 2301 | UINT8 rawbuf[sizeof(sha1_t)]; |
| 2302 | 2302 | be_write_sha1(&rawbuf[0], fullsha1); |
| 2303 | | |
| 2303 | |
| 2304 | 2304 | // write to the header |
| 2305 | 2305 | file_write(m_sha1_offset, rawbuf, sizeof(rawbuf)); |
| 2306 | 2306 | } |
| r14530 | r14531 | |
| 2356 | 2356 | // free the work queues |
| 2357 | 2357 | osd_work_queue_free(m_read_queue); |
| 2358 | 2358 | osd_work_queue_free(m_work_queue); |
| 2359 | | |
| 2359 | |
| 2360 | 2360 | // delete allocated arrays |
| 2361 | 2361 | for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_codecs); codecnum++) |
| 2362 | 2362 | delete m_codecs[codecnum]; |
| r14530 | r14531 | |
| 2374 | 2374 | m_total_in = 0; |
| 2375 | 2375 | m_total_out = 0; |
| 2376 | 2376 | m_compsha1.reset(); |
| 2377 | | |
| 2377 | |
| 2378 | 2378 | // reset our maps |
| 2379 | 2379 | m_parent_map.reset(); |
| 2380 | 2380 | m_current_map.reset(); |
| 2381 | | |
| 2381 | |
| 2382 | 2382 | // reset read state |
| 2383 | 2383 | m_read_queue_offset = 0; |
| 2384 | 2384 | m_read_done_offset = 0; |
| 2385 | 2385 | m_read_error = false; |
| 2386 | | |
| 2386 | |
| 2387 | 2387 | // reset work item state |
| 2388 | 2388 | m_work_buffer.resize(hunk_bytes() * (WORK_BUFFER_HUNKS + 1)); |
| 2389 | 2389 | m_compressed_buffer.resize(hunk_bytes() * WORK_BUFFER_HUNKS); |
| r14530 | r14531 | |
| 2395 | 2395 | item.m_compressed = m_compressed_buffer + hunk_bytes() * itemnum; |
| 2396 | 2396 | item.m_hash.resize(hunk_bytes() / unit_bytes()); |
| 2397 | 2397 | } |
| 2398 | | |
| 2398 | |
| 2399 | 2399 | // initialize codec instances |
| 2400 | 2400 | for (int instance = 0; instance < ARRAY_LENGTH(m_codecs); instance++) |
| 2401 | 2401 | { |
| 2402 | 2402 | delete m_codecs[instance]; |
| 2403 | 2403 | m_codecs[instance] = new chd_compressor_group(*this, m_compression); |
| 2404 | 2404 | } |
| 2405 | | |
| 2405 | |
| 2406 | 2406 | // reset write state |
| 2407 | 2407 | m_write_hunk = 0; |
| 2408 | 2408 | } |
| r14530 | r14531 | |
| 2429 | 2429 | if (m_work_item[curitem % WORK_BUFFER_HUNKS].m_status != WS_READY) |
| 2430 | 2430 | break; |
| 2431 | 2431 | |
| 2432 | | // if it's not all clear, defer |
| 2432 | // if it's not all clear, defer |
| 2433 | 2433 | if (curitem != enditem) |
| 2434 | 2434 | break; |
| 2435 | | |
| 2435 | |
| 2436 | 2436 | // if we're walking the parent, we want one more item to have cleared so we |
| 2437 | 2437 | // can read an extra hunk there |
| 2438 | 2438 | if (m_walking_parent && m_work_item[curitem % WORK_BUFFER_HUNKS].m_status != WS_READY) |
| r14530 | r14531 | |
| 2444 | 2444 | osd_work_item_queue(m_read_queue, async_read_static, this, WORK_ITEM_FLAG_AUTO_RELEASE); |
| 2445 | 2445 | m_read_queue_offset += WORK_BUFFER_HUNKS * hunk_bytes() / 2; |
| 2446 | 2446 | } |
| 2447 | | |
| 2447 | |
| 2448 | 2448 | // flush out any finished items |
| 2449 | 2449 | while (m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status == WS_COMPLETE) |
| 2450 | 2450 | { |
| 2451 | 2451 | work_item &item = m_work_item[m_write_hunk % WORK_BUFFER_HUNKS]; |
| 2452 | | |
| 2452 | |
| 2453 | 2453 | // free any OSD work item |
| 2454 | 2454 | if (item.m_osd != NULL) |
| 2455 | 2455 | osd_work_item_release(item.m_osd); |
| r14530 | r14531 | |
| 2466 | 2466 | if (m_parent_map.find(item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1) == hashmap::NOT_FOUND) |
| 2467 | 2467 | m_parent_map.add(item.m_hunknum * uph + unit, item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1); |
| 2468 | 2468 | } |
| 2469 | | |
| 2469 | |
| 2470 | 2470 | // if we're uncompressed, use regular writes |
| 2471 | 2471 | else if (!compressed()) |
| 2472 | 2472 | { |
| 2473 | 2473 | chd_error err = write_hunk(item.m_hunknum, item.m_data); |
| 2474 | 2474 | if (err != CHDERR_NONE) |
| 2475 | 2475 | return err; |
| 2476 | | |
| 2477 | | // writes of all-0 data don't actually take space, so see if we count this |
| 2476 | |
| 2477 | // writes of all-0 data don't actually take space, so see if we count this |
| 2478 | 2478 | chd_codec_type codec = CHD_CODEC_NONE; |
| 2479 | 2479 | UINT32 complen; |
| 2480 | 2480 | hunk_info(item.m_hunknum, codec, complen); |
| 2481 | 2481 | if (codec == CHD_CODEC_NONE) |
| 2482 | 2482 | m_total_out += m_hunkbytes; |
| 2483 | 2483 | } |
| 2484 | | |
| 2484 | |
| 2485 | 2485 | // for compressing, process the result |
| 2486 | 2486 | else do |
| 2487 | 2487 | { |
| r14530 | r14531 | |
| 2492 | 2492 | hunk_copy_from_self(item.m_hunknum, selfhunk); |
| 2493 | 2493 | break; |
| 2494 | 2494 | } |
| 2495 | | |
| 2495 | |
| 2496 | 2496 | // if not, see if it's in the parent map |
| 2497 | 2497 | if (m_parent != NULL) |
| 2498 | 2498 | { |
| r14530 | r14531 | |
| 2503 | 2503 | break; |
| 2504 | 2504 | } |
| 2505 | 2505 | } |
| 2506 | | |
| 2506 | |
| 2507 | 2507 | // otherwise, append it compressed and add to the self map |
| 2508 | 2508 | hunk_write_compressed(item.m_hunknum, item.m_compression, item.m_compressed, item.m_complen, item.m_hash[0].m_crc16); |
| 2509 | 2509 | m_total_out += item.m_complen; |
| 2510 | 2510 | m_current_map.add(item.m_hunknum, item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); |
| 2511 | 2511 | } while (0); |
| 2512 | | |
| 2512 | |
| 2513 | 2513 | // reset the item and advance |
| 2514 | 2514 | item.m_status = WS_READY; |
| 2515 | 2515 | m_write_hunk++; |
| 2516 | | |
| 2516 | |
| 2517 | 2517 | // if we hit the end, finalize |
| 2518 | 2518 | if (m_write_hunk == m_hunkcount) |
| 2519 | 2519 | { |
| r14530 | r14531 | |
| 2526 | 2526 | for (int itemnum = 0; itemnum < WORK_BUFFER_HUNKS; itemnum++) |
| 2527 | 2527 | m_work_item[itemnum].m_status = WS_READY; |
| 2528 | 2528 | } |
| 2529 | | |
| 2529 | |
| 2530 | 2530 | // wait for all reads to finish and if we're compressed, write the final SHA1 and map |
| 2531 | 2531 | else |
| 2532 | 2532 | { |
| r14530 | r14531 | |
| 2538 | 2538 | } |
| 2539 | 2539 | } |
| 2540 | 2540 | } |
| 2541 | | |
| 2541 | |
| 2542 | 2542 | // update progress and ratio |
| 2543 | 2543 | if (m_walking_parent) |
| 2544 | 2544 | progress = double(m_read_done_offset) / double(logical_bytes()); |
| r14530 | r14531 | |
| 2582 | 2582 | |
| 2583 | 2583 | |
| 2584 | 2584 | //------------------------------------------------- |
| 2585 | | // async_compress_hunk - handle asynchronous |
| 2585 | // async_compress_hunk - handle asynchronous |
| 2586 | 2586 | // hunk compression |
| 2587 | 2587 | //------------------------------------------------- |
| 2588 | 2588 | |
| r14530 | r14531 | |
| 2615 | 2615 | |
| 2616 | 2616 | |
| 2617 | 2617 | //------------------------------------------------- |
| 2618 | | // async_read - handle asynchronous source file |
| 2618 | // async_read - handle asynchronous source file |
| 2619 | 2619 | // reading |
| 2620 | 2620 | //------------------------------------------------- |
| 2621 | 2621 | |
| r14530 | r14531 | |
| 2655 | 2655 | curdest += hunk_bytes(); |
| 2656 | 2656 | } |
| 2657 | 2657 | } |
| 2658 | | |
| 2658 | |
| 2659 | 2659 | // otherwise, call the virtual function |
| 2660 | 2660 | else |
| 2661 | 2661 | read_data(dest, m_read_done_offset, numbytes); |
| 2662 | | |
| 2662 | |
| 2663 | 2663 | // spawn off work for each hunk |
| 2664 | 2664 | for (UINT64 curoffs = m_read_done_offset; curoffs < end_offset; curoffs += hunk_bytes()) |
| 2665 | 2665 | { |
| r14530 | r14531 | |
| 2678 | 2678 | m_compsha1.append(dest, numbytes); |
| 2679 | 2679 | m_total_in += numbytes; |
| 2680 | 2680 | } |
| 2681 | | |
| 2681 | |
| 2682 | 2682 | // advance the read pointer |
| 2683 | 2683 | m_read_done_offset += numbytes; |
| 2684 | 2684 | } |
| r14530 | r14531 | |
| 2730 | 2730 | delete block; |
| 2731 | 2731 | } |
| 2732 | 2732 | m_block_list->m_nextalloc = 0; |
| 2733 | | |
| 2733 | |
| 2734 | 2734 | // reset the hash |
| 2735 | 2735 | memset(m_map, 0, sizeof(m_map)); |
| 2736 | 2736 | } |
src/lib/util/chd.h
| r14530 | r14531 | |
| 55 | 55 | |
| 56 | 56 | Compressed Hunks of Data header format. All numbers are stored in |
| 57 | 57 | Motorola (big-endian) byte ordering. |
| 58 | | |
| 58 | |
| 59 | 59 | ========================================================================= |
| 60 | 60 | |
| 61 | 61 | V1 header: |
| r14530 | r14531 | |
| 78 | 78 | 0x00000001 - set if this drive has a parent |
| 79 | 79 | 0x00000002 - set if this drive allows writes |
| 80 | 80 | |
| 81 | | Compression types: |
| 82 | | CHDCOMPRESSION_NONE = 0 |
| 83 | | CHDCOMPRESSION_ZLIB = 1 |
| 84 | | |
| 81 | Compression types: |
| 82 | CHDCOMPRESSION_NONE = 0 |
| 83 | CHDCOMPRESSION_ZLIB = 1 |
| 84 | |
| 85 | 85 | V1 map format: |
| 86 | | |
| 87 | | [ 0] UINT64 offset : 44; // starting offset within the file |
| 88 | | [ 0] UINT64 length : 20; // length of data; if == hunksize, data is uncompressed |
| 89 | | |
| 86 | |
| 87 | [ 0] UINT64 offset : 44; // starting offset within the file |
| 88 | [ 0] UINT64 length : 20; // length of data; if == hunksize, data is uncompressed |
| 89 | |
| 90 | 90 | ========================================================================= |
| 91 | 91 | |
| 92 | 92 | V2 header: |
| r14530 | r14531 | |
| 105 | 105 | [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file |
| 106 | 106 | [ 76] UINT32 seclen; // number of bytes per sector |
| 107 | 107 | [ 80] (V2 header length) |
| 108 | | |
| 108 | |
| 109 | 109 | Flags and map format are same as V1 |
| 110 | | |
| 110 | |
| 111 | 111 | ========================================================================= |
| 112 | 112 | |
| 113 | 113 | V3 header: |
| r14530 | r14531 | |
| 126 | 126 | [ 80] UINT8 sha1[20]; // SHA1 checksum of raw data |
| 127 | 127 | [100] UINT8 parentsha1[20];// SHA1 checksum of parent file |
| 128 | 128 | [120] (V3 header length) |
| 129 | | |
| 129 | |
| 130 | 130 | Flags are the same as V1 |
| 131 | 131 | |
| 132 | | Compression types: |
| 133 | | CHDCOMPRESSION_NONE = 0 |
| 134 | | CHDCOMPRESSION_ZLIB = 1 |
| 135 | | CHDCOMPRESSION_ZLIB_PLUS = 2 |
| 136 | | |
| 132 | Compression types: |
| 133 | CHDCOMPRESSION_NONE = 0 |
| 134 | CHDCOMPRESSION_ZLIB = 1 |
| 135 | CHDCOMPRESSION_ZLIB_PLUS = 2 |
| 136 | |
| 137 | 137 | V3 map format: |
| 138 | 138 | |
| 139 | 139 | [ 0] UINT64 offset; // starting offset within the file |
| 140 | | [ 8] UINT32 crc32; // 32-bit CRC of the uncompressed data |
| 141 | | [ 12] UINT16 length_lo; // lower 16 bits of length |
| 142 | | [ 14] UINT8 length_hi; // upper 8 bits of length |
| 143 | | [ 15] UINT8 flags; // flags, indicating compression info |
| 140 | [ 8] UINT32 crc32; // 32-bit CRC of the uncompressed data |
| 141 | [ 12] UINT16 length_lo; // lower 16 bits of length |
| 142 | [ 14] UINT8 length_hi; // upper 8 bits of length |
| 143 | [ 15] UINT8 flags; // flags, indicating compression info |
| 144 | 144 | |
| 145 | 145 | ========================================================================= |
| 146 | 146 | |
| r14530 | r14531 | |
| 159 | 159 | [ 68] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent |
| 160 | 160 | [ 88] UINT8 rawsha1[20]; // raw data SHA1 |
| 161 | 161 | [108] (V4 header length) |
| 162 | | |
| 162 | |
| 163 | 163 | Flags are the same as V1 |
| 164 | | |
| 165 | | Compression types: |
| 166 | | CHDCOMPRESSION_NONE = 0 |
| 167 | | CHDCOMPRESSION_ZLIB = 1 |
| 168 | | CHDCOMPRESSION_ZLIB_PLUS = 2 |
| 169 | | CHDCOMPRESSION_AV = 3 |
| 170 | | |
| 164 | |
| 165 | Compression types: |
| 166 | CHDCOMPRESSION_NONE = 0 |
| 167 | CHDCOMPRESSION_ZLIB = 1 |
| 168 | CHDCOMPRESSION_ZLIB_PLUS = 2 |
| 169 | CHDCOMPRESSION_AV = 3 |
| 170 | |
| 171 | 171 | Map format is the same as V3 |
| 172 | | |
| 172 | |
| 173 | 173 | ========================================================================= |
| 174 | 174 | |
| 175 | 175 | V5 header: |
| 176 | | |
| 176 | |
| 177 | 177 | [ 0] char tag[8]; // 'MComprHD' |
| 178 | 178 | [ 8] UINT32 length; // length of header (including tag and length fields) |
| 179 | 179 | [ 12] UINT32 version; // drive format version |
| r14530 | r14531 | |
| 188 | 188 | [104] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent |
| 189 | 189 | [124] (V5 header length) |
| 190 | 190 | |
| 191 | | If parentsha1 != 0, we have a parent (no need for flags) |
| 192 | | If compressors[0] == 0, we are uncompressed (including maps) |
| 193 | | |
| 191 | If parentsha1 != 0, we have a parent (no need for flags) |
| 192 | If compressors[0] == 0, we are uncompressed (including maps) |
| 193 | |
| 194 | 194 | V5 uncompressed map format: |
| 195 | | |
| 196 | | [ 0] UINT32 offset; // starting offset / hunk size |
| 197 | | |
| 195 | |
| 196 | [ 0] UINT32 offset; // starting offset / hunk size |
| 197 | |
| 198 | 198 | V5 compressed map format header: |
| 199 | | |
| 200 | | [ 0] UINT32 length; // length of compressed map |
| 201 | | [ 4] UINT48 datastart; // offset of first block |
| 202 | | [ 10] UINT16 crc; // crc-16 of the map |
| 203 | | [ 12] UINT8 lengthbits; // bits used to encode complength |
| 204 | | [ 13] UINT8 hunkbits; // bits used to encode self-refs |
| 205 | | [ 14] UINT8 parentunitbits; // bits used to encode parent unit refs |
| 206 | | [ 15] UINT8 reserved; // future use |
| 199 | |
| 200 | [ 0] UINT32 length; // length of compressed map |
| 201 | [ 4] UINT48 datastart; // offset of first block |
| 202 | [ 10] UINT16 crc; // crc-16 of the map |
| 203 | [ 12] UINT8 lengthbits; // bits used to encode complength |
| 204 | [ 13] UINT8 hunkbits; // bits used to encode self-refs |
| 205 | [ 14] UINT8 parentunitbits; // bits used to encode parent unit refs |
| 206 | [ 15] UINT8 reserved; // future use |
| 207 | 207 | [ 16] (compressed header length) |
| 208 | | |
| 208 | |
| 209 | 209 | Each compressed map entry, once expanded, looks like: |
| 210 | | |
| 211 | | [ 0] UINT8 compression; // compression type |
| 212 | | [ 1] UINT24 complength; // compressed length |
| 213 | | [ 4] UINT48 offset; // offset |
| 214 | | [ 10] UINT16 crc; // crc-16 of the data |
| 215 | 210 | |
| 211 | [ 0] UINT8 compression; // compression type |
| 212 | [ 1] UINT24 complength; // compressed length |
| 213 | [ 4] UINT48 offset; // offset |
| 214 | [ 10] UINT16 crc; // crc-16 of the data |
| 215 | |
| 216 | 216 | ***************************************************************************/ |
| 217 | 217 | |
| 218 | 218 | |
| r14530 | r14531 | |
| 222 | 222 | |
| 223 | 223 | // pseudo-codecs returned by hunk_info |
| 224 | 224 | const chd_codec_type CHD_CODEC_SELF = 1; // copy of another hunk |
| 225 | | const chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk |
| 225 | const chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk |
| 226 | 226 | const chd_codec_type CHD_CODEC_MINI = 3; // legacy "mini" 8-byte repeat |
| 227 | 227 | |
| 228 | 228 | // core types |
| r14530 | r14531 | |
| 322 | 322 | static const UINT32 V4_HEADER_SIZE = 108; |
| 323 | 323 | static const UINT32 V5_HEADER_SIZE = 124; |
| 324 | 324 | static const UINT32 MAX_HEADER_SIZE = V5_HEADER_SIZE; |
| 325 | | |
| 325 | |
| 326 | 326 | public: |
| 327 | 327 | // construction/destruction |
| 328 | 328 | chd_file(); |
| r14530 | r14531 | |
| 360 | 360 | // file open |
| 361 | 361 | chd_error open(const char *filename, bool writeable = false, chd_file *parent = NULL); |
| 362 | 362 | chd_error open(core_file &file, bool writeable = false, chd_file *parent = NULL); |
| 363 | | |
| 363 | |
| 364 | 364 | // file close |
| 365 | 365 | void close(); |
| 366 | 366 | |
| r14530 | r14531 | |
| 382 | 382 | chd_error write_metadata(chd_metadata_tag metatag, UINT32 metaindex, const dynamic_buffer &input, UINT8 flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input, input.count(), flags = CHD_MDFLAGS_CHECKSUM); } |
| 383 | 383 | chd_error delete_metadata(chd_metadata_tag metatag, UINT32 metaindex); |
| 384 | 384 | chd_error clone_all_metadata(chd_file &source); |
| 385 | | |
| 385 | |
| 386 | 386 | // hashing helper |
| 387 | 387 | sha1_t compute_overall_sha1(sha1_t rawsha1); |
| 388 | 388 | |
| 389 | 389 | // codec interfaces |
| 390 | 390 | chd_error codec_configure(chd_codec_type codec, int param, void *config); |
| 391 | | |
| 391 | |
| 392 | 392 | // static helpers |
| 393 | 393 | static const char *error_string(chd_error err); |
| 394 | 394 | |
| 395 | 395 | private: |
| 396 | 396 | struct metadata_entry; |
| 397 | 397 | struct metadata_hash; |
| 398 | | |
| 398 | |
| 399 | 399 | // inline helpers |
| 400 | 400 | UINT64 be_read(const UINT8 *base, int numbytes); |
| 401 | 401 | void be_write(UINT8 *base, UINT64 value, int numbytes); |
| r14530 | r14531 | |
| 430 | 430 | bool m_owns_file; // flag indicating if this file should be closed on chd_close() |
| 431 | 431 | bool m_allow_reads; // permit reads from this CHD? |
| 432 | 432 | bool m_allow_writes; // permit writes to this CHD? |
| 433 | | |
| 433 | |
| 434 | 434 | // core parameters from the header |
| 435 | 435 | UINT32 m_version; // version of the header |
| 436 | 436 | UINT64 m_logicalbytes; // logical size of the raw CHD data in bytes |
| r14530 | r14531 | |
| 443 | 443 | chd_codec_type m_compression[4]; // array of compression types used |
| 444 | 444 | chd_file * m_parent; // pointer to parent file, or NULL if none |
| 445 | 445 | bool m_parent_missing; // are we missing our parent? |
| 446 | | |
| 446 | |
| 447 | 447 | // key offsets within the header |
| 448 | 448 | UINT64 m_mapoffset_offset; // offset of map offset field |
| 449 | 449 | UINT64 m_metaoffset_offset;// offset of metaoffset field |
| 450 | 450 | UINT64 m_sha1_offset; // offset of SHA1 field |
| 451 | 451 | UINT64 m_rawsha1_offset; // offset of raw SHA1 field |
| 452 | 452 | UINT64 m_parentsha1_offset;// offset of paren SHA1 field |
| 453 | | |
| 453 | |
| 454 | 454 | // map information |
| 455 | 455 | UINT32 m_mapentrybytes; // length of each entry in a map |
| 456 | 456 | dynamic_buffer m_rawmap; // raw map data |
| r14530 | r14531 | |
| 458 | 458 | // compression management |
| 459 | 459 | chd_decompressor * m_decompressor[4]; // array of decompression codecs |
| 460 | 460 | dynamic_buffer m_compressed; // temporary buffer for compressed data |
| 461 | | |
| 461 | |
| 462 | 462 | // caching |
| 463 | 463 | dynamic_buffer m_cache; // single-hunk cache for partial reads/writes |
| 464 | 464 | UINT32 m_cachehunk; // which hunk is in the cache? |
| r14530 | r14531 | |
| 474 | 474 | // construction/destruction |
| 475 | 475 | chd_file_compressor(); |
| 476 | 476 | virtual ~chd_file_compressor(); |
| 477 | | |
| 477 | |
| 478 | 478 | // compression management |
| 479 | 479 | void compress_begin(); |
| 480 | 480 | chd_error compress_continue(double &progress, double &ratio); |
| r14530 | r14531 | |
| 482 | 482 | protected: |
| 483 | 483 | // required override: read more data |
| 484 | 484 | virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length) = 0; |
| 485 | | |
| 485 | |
| 486 | 486 | private: |
| 487 | 487 | // hash map for looking up values |
| 488 | 488 | class hashmap |
| r14530 | r14531 | |
| 491 | 491 | // construction/destruction |
| 492 | 492 | hashmap(); |
| 493 | 493 | ~hashmap(); |
| 494 | | |
| 494 | |
| 495 | 495 | // operations |
| 496 | 496 | void reset(); |
| 497 | 497 | UINT64 find(crc16_t crc16, sha1_t sha1); |
| 498 | 498 | void add(UINT64 itemnum, crc16_t crc16, sha1_t sha1); |
| 499 | | |
| 499 | |
| 500 | 500 | // constants |
| 501 | 501 | static const UINT64 NOT_FOUND = ~UINT64(0); |
| 502 | 502 | private: |
| r14530 | r14531 | |
| 507 | 507 | UINT64 m_itemnum; // item number |
| 508 | 508 | sha1_t m_sha1; // SHA-1 of the block |
| 509 | 509 | }; |
| 510 | | |
| 510 | |
| 511 | 511 | // block of entries |
| 512 | 512 | struct entry_block |
| 513 | 513 | { |
| 514 | 514 | entry_block(entry_block *prev) |
| 515 | 515 | : m_next(prev), m_nextalloc(0) { } |
| 516 | | |
| 516 | |
| 517 | 517 | entry_block * m_next; // next block in list |
| 518 | 518 | UINT32 m_nextalloc; // next to be allocated |
| 519 | 519 | entry_t m_array[16384]; // array of entries |
| r14530 | r14531 | |
| 532 | 532 | WS_QUEUED, |
| 533 | 533 | WS_COMPLETE |
| 534 | 534 | }; |
| 535 | | |
| 535 | |
| 536 | 536 | // a CRC-16/SHA-1 pair |
| 537 | 537 | struct hash_pair |
| 538 | 538 | { |
| r14530 | r14531 | |
| 540 | 540 | sha1_t m_sha1; // calculated SHA-1 |
| 541 | 541 | }; |
| 542 | 542 | |
| 543 | | // a single work item |
| 543 | // a single work item |
| 544 | 544 | struct work_item |
| 545 | 545 | { |
| 546 | 546 | osd_work_item * m_osd; // OSD work item running on this block |
| r14530 | r14531 | |
| 554 | 554 | chd_compressor_group *m_codecs; // codec instance |
| 555 | 555 | dynamic_array<hash_pair> m_hash; // array of hashes |
| 556 | 556 | }; |
| 557 | | |
| 557 | |
| 558 | 558 | // internal helpers |
| 559 | 559 | static void *async_walk_parent_static(void *param, int threadid); |
| 560 | 560 | void async_walk_parent(work_item &item); |
| r14530 | r14531 | |
| 563 | 563 | static void *async_read_static(void *param, int threadid); |
| 564 | 564 | void async_read(); |
| 565 | 565 | |
| 566 | | // current compression status |
| 567 | | bool m_walking_parent; // are we building the parent map? |
| 566 | // current compression status |
| 567 | bool m_walking_parent; // are we building the parent map? |
| 568 | 568 | UINT64 m_total_in; // total bytes in |
| 569 | 569 | UINT64 m_total_out; // total bytes out |
| 570 | 570 | sha1_creator m_compsha1; // running SHA-1 on raw data |
| 571 | 571 | |
| 572 | 572 | // hash lookup maps |
| 573 | | hashmap m_parent_map; // hash map for parent |
| 574 | | hashmap m_current_map; // hash map for current |
| 573 | hashmap m_parent_map; // hash map for parent |
| 574 | hashmap m_current_map; // hash map for current |
| 575 | 575 | |
| 576 | 576 | // read I/O thread |
| 577 | 577 | osd_work_queue * m_read_queue; // work queue for reading |
src/lib/util/flac.c
| r14530 | r14531 | |
| 82 | 82 | |
| 83 | 83 | |
| 84 | 84 | //------------------------------------------------- |
| 85 | | // reset - reset state with the original |
| 85 | // reset - reset state with the original |
| 86 | 86 | // parameters |
| 87 | 87 | //------------------------------------------------- |
| 88 | 88 | |
| r14530 | r14531 | |
| 96 | 96 | // configure the encoder in a standard way |
| 97 | 97 | // note we do this on each reset; if we don't, results are NOT consistent! |
| 98 | 98 | FLAC__stream_encoder_set_verify(m_encoder, false); |
| 99 | | // FLAC__stream_encoder_set_do_md5(m_encoder, false); |
| 99 | // FLAC__stream_encoder_set_do_md5(m_encoder, false); |
| 100 | 100 | FLAC__stream_encoder_set_compression_level(m_encoder, 8); |
| 101 | 101 | FLAC__stream_encoder_set_channels(m_encoder, m_channels); |
| 102 | 102 | FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16); |
| r14530 | r14531 | |
| 161 | 161 | for (UINT32 sampnum = 0; sampnum < cur_samples; sampnum++) |
| 162 | 162 | for (int channel = 0; channel < num_channels; channel++, srcindex++) |
| 163 | 163 | *dest++ = INT16((UINT16(samples[srcindex]) << shift) | (UINT16(samples[srcindex]) >> shift)); |
| 164 | | |
| 164 | |
| 165 | 165 | // process this batch |
| 166 | 166 | if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples)) |
| 167 | 167 | return false; |
| r14530 | r14531 | |
| 194 | 194 | for (UINT32 sampnum = 0; sampnum < cur_samples; sampnum++, srcindex++) |
| 195 | 195 | for (int channel = 0; channel < num_channels; channel++) |
| 196 | 196 | *dest++ = INT16((UINT16(samples[channel][srcindex]) << shift) | (UINT16(samples[channel][srcindex]) >> shift)); |
| 197 | | |
| 197 | |
| 198 | 198 | // process this batch |
| 199 | 199 | if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples)) |
| 200 | 200 | return false; |
| r14530 | r14531 | |
| 205 | 205 | |
| 206 | 206 | |
| 207 | 207 | //------------------------------------------------- |
| 208 | | // finish - complete encoding and flush the |
| 208 | // finish - complete encoding and flush the |
| 209 | 209 | // stream |
| 210 | 210 | //------------------------------------------------- |
| 211 | 211 | |
| r14530 | r14531 | |
| 227 | 227 | m_encoder = FLAC__stream_encoder_new(); |
| 228 | 228 | if (m_encoder == NULL) |
| 229 | 229 | throw std::bad_alloc(); |
| 230 | | |
| 230 | |
| 231 | 231 | // initialize default state |
| 232 | 232 | m_file = NULL; |
| 233 | 233 | m_compressed_offset = 0; |
| r14530 | r14531 | |
| 243 | 243 | |
| 244 | 244 | |
| 245 | 245 | //------------------------------------------------- |
| 246 | | // write_callback - handle writes to the |
| 246 | // write_callback - handle writes to the |
| 247 | 247 | // output stream |
| 248 | 248 | //------------------------------------------------- |
| 249 | 249 | |
| r14530 | r14531 | |
| 265 | 265 | offset += ignore; |
| 266 | 266 | m_ignore_bytes -= ignore; |
| 267 | 267 | } |
| 268 | | |
| 268 | |
| 269 | 269 | // if we haven't hit the end of metadata, process a new piece |
| 270 | 270 | else if (!m_found_audio) |
| 271 | 271 | { |
| r14530 | r14531 | |
| 275 | 275 | offset += 4; |
| 276 | 276 | } |
| 277 | 277 | |
| 278 | | // otherwise process as audio data and copy to the output |
| 278 | // otherwise process as audio data and copy to the output |
| 279 | 279 | else |
| 280 | 280 | { |
| 281 | 281 | int count = bytes - offset; |
| r14530 | r14531 | |
| 360 | 360 | |
| 361 | 361 | |
| 362 | 362 | //------------------------------------------------- |
| 363 | | // reset - reset state with the original |
| 363 | // reset - reset state with the original |
| 364 | 364 | // parameters |
| 365 | 365 | //------------------------------------------------- |
| 366 | 366 | |
| 367 | 367 | bool flac_decoder::reset() |
| 368 | 368 | { |
| 369 | 369 | m_compressed_offset = 0; |
| 370 | | if (FLAC__stream_decoder_init_stream(m_decoder, |
| 371 | | &flac_decoder::read_callback_static, |
| 372 | | NULL, |
| 373 | | &flac_decoder::tell_callback_static, |
| 374 | | NULL, |
| 375 | | NULL, |
| 376 | | &flac_decoder::write_callback_static, |
| 377 | | &flac_decoder::metadata_callback_static, |
| 370 | if (FLAC__stream_decoder_init_stream(m_decoder, |
| 371 | &flac_decoder::read_callback_static, |
| 372 | NULL, |
| 373 | &flac_decoder::tell_callback_static, |
| 374 | NULL, |
| 375 | NULL, |
| 376 | &flac_decoder::write_callback_static, |
| 377 | &flac_decoder::metadata_callback_static, |
| 378 | 378 | &flac_decoder::error_callback_static, this) != FLAC__STREAM_DECODER_INIT_STATUS_OK) |
| 379 | 379 | return false; |
| 380 | 380 | return FLAC__stream_decoder_process_until_end_of_metadata(m_decoder); |
| r14530 | r14531 | |
| 407 | 407 | static const UINT8 s_header_template[0x2a] = |
| 408 | 408 | { |
| 409 | 409 | 0x66, 0x4C, 0x61, 0x43, // +00: 'fLaC' stream header |
| 410 | | 0x80, // +04: metadata block type 0 (STREAMINFO), |
| 410 | 0x80, // +04: metadata block type 0 (STREAMINFO), |
| 411 | 411 | // flagged as last block |
| 412 | | 0x00, 0x00, 0x22, // +05: metadata block length = 0x22 |
| 412 | 0x00, 0x00, 0x22, // +05: metadata block length = 0x22 |
| 413 | 413 | 0x00, 0x00, // +08: minimum block size |
| 414 | 414 | 0x00, 0x00, // +0A: maximum block size |
| 415 | | 0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown) |
| 416 | | 0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown) |
| 417 | | 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100), |
| 418 | | // numchannels (2), sample bits (16), |
| 415 | 0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown) |
| 416 | 0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown) |
| 417 | 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100), |
| 418 | // numchannels (2), sample bits (16), |
| 419 | 419 | // samples in stream (0 == unknown) |
| 420 | 420 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none) |
| 421 | 421 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // |
| r14530 | r14531 | |
| 466 | 466 | m_uncompressed_offset = 0; |
| 467 | 467 | m_uncompressed_length = num_samples; |
| 468 | 468 | m_uncompressed_swap = swap_endian; |
| 469 | | |
| 469 | |
| 470 | 470 | // loop until we get everything we want |
| 471 | 471 | while (m_uncompressed_offset < m_uncompressed_length) |
| 472 | 472 | if (!FLAC__stream_decoder_process_single(m_decoder)) |
| r14530 | r14531 | |
| 494 | 494 | m_uncompressed_offset = 0; |
| 495 | 495 | m_uncompressed_length = num_samples; |
| 496 | 496 | m_uncompressed_swap = swap_endian; |
| 497 | | |
| 497 | |
| 498 | 498 | // loop until we get everything we want |
| 499 | 499 | while (m_uncompressed_offset < m_uncompressed_length) |
| 500 | 500 | if (!FLAC__stream_decoder_process_single(m_decoder)) |
| r14530 | r14531 | |
| 513 | 513 | FLAC__uint64 position = 0; |
| 514 | 514 | FLAC__stream_decoder_get_decode_position(m_decoder, &position); |
| 515 | 515 | FLAC__stream_decoder_finish(m_decoder); |
| 516 | | |
| 516 | |
| 517 | 517 | // adjust position if we provided the header |
| 518 | 518 | if (position == 0) |
| 519 | 519 | return 0; |
| r14530 | r14531 | |
| 536 | 536 | FLAC__StreamDecoderReadStatus flac_decoder::read_callback(FLAC__byte buffer[], size_t *bytes) |
| 537 | 537 | { |
| 538 | 538 | UINT32 expected = *bytes; |
| 539 | | |
| 539 | |
| 540 | 540 | // if a file, just read |
| 541 | 541 | if (m_file != NULL) |
| 542 | 542 | *bytes = core_fread(m_file, buffer, expected); |
| 543 | | |
| 543 | |
| 544 | 544 | // otherwise, copy from memory |
| 545 | 545 | else |
| 546 | 546 | { |
| r14530 | r14531 | |
| 553 | 553 | outputpos += bytes_to_copy; |
| 554 | 554 | m_compressed_offset += bytes_to_copy; |
| 555 | 555 | } |
| 556 | | |
| 556 | |
| 557 | 557 | // once we're out of that, copy from the secondary buffer |
| 558 | 558 | if (outputpos < *bytes && m_compressed_offset < m_compressed_length + m_compressed2_length) |
| 559 | 559 | { |
| r14530 | r14531 | |
| 579 | 579 | // ignore all but STREAMINFO metadata |
| 580 | 580 | if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) |
| 581 | 581 | return; |
| 582 | | |
| 582 | |
| 583 | 583 | // parse out the data we care about |
| 584 | 584 | flac_decoder *fldecoder = reinterpret_cast<flac_decoder *>(client_data); |
| 585 | 585 | fldecoder->m_sample_rate = metadata->data.stream_info.sample_rate; |
| r14530 | r14531 | |
| 613 | 613 | FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) |
| 614 | 614 | { |
| 615 | 615 | assert(frame->header.channels == channels()); |
| 616 | | |
| 616 | |
| 617 | 617 | // interleaved case |
| 618 | 618 | int shift = m_uncompressed_swap ? 8 : 0; |
| 619 | 619 | int blocksize = frame->header.blocksize; |
| r14530 | r14531 | |
| 624 | 624 | for (int chan = 0; chan < frame->header.channels; chan++) |
| 625 | 625 | *dest++ = INT16((UINT16(buffer[chan][sampnum]) << shift) | (UINT16(buffer[chan][sampnum]) >> shift)); |
| 626 | 626 | } |
| 627 | | |
| 627 | |
| 628 | 628 | // non-interleaved case |
| 629 | 629 | else |
| 630 | 630 | { |
src/lib/util/hashing.c
| r14530 | r14531 | |
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | | hashing.c |
| 3 | hashing.c |
| 4 | 4 | |
| 5 | | Hashing helper classes. |
| 5 | Hashing helper classes. |
| 6 | 6 | |
| 7 | 7 | **************************************************************************** |
| 8 | 8 | |
| 9 | | Copyright Aaron Giles |
| 10 | | All rights reserved. |
| 9 | Copyright Aaron Giles |
| 10 | All rights reserved. |
| 11 | 11 | |
| 12 | | Redistribution and use in source and binary forms, with or without |
| 13 | | modification, are permitted provided that the following conditions are |
| 14 | | met: |
| 12 | Redistribution and use in source and binary forms, with or without |
| 13 | modification, are permitted provided that the following conditions are |
| 14 | met: |
| 15 | 15 | |
| 16 | | * Redistributions of source code must retain the above copyright |
| 17 | | notice, this list of conditions and the following disclaimer. |
| 18 | | * Redistributions in binary form must reproduce the above copyright |
| 19 | | notice, this list of conditions and the following disclaimer in |
| 20 | | the documentation and/or other materials provided with the |
| 21 | | distribution. |
| 22 | | * Neither the name 'MAME' nor the names of its contributors may be |
| 23 | | used to endorse or promote products derived from this software |
| 24 | | without specific prior written permission. |
| 16 | * Redistributions of source code must retain the above copyright |
| 17 | notice, this list of conditions and the following disclaimer. |
| 18 | * Redistributions in binary form must reproduce the above copyright |
| 19 | notice, this list of conditions and the following disclaimer in |
| 20 | the documentation and/or other materials provided with the |
| 21 | distribution. |
| 22 | * Neither the name 'MAME' nor the names of its contributors may be |
| 23 | used to endorse or promote products derived from this software |
| 24 | without specific prior written permission. |
| 25 | 25 | |
| 26 | | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 27 | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 28 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 29 | | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 30 | | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 31 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 32 | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 34 | | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 35 | | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 36 | | POSSIBILITY OF SUCH DAMAGE. |
| 26 | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 27 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 28 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 29 | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 30 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 31 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 34 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 35 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 36 | POSSIBILITY OF SUCH DAMAGE. |
| 37 | 37 | |
| 38 | 38 | ***************************************************************************/ |
| 39 | 39 | |
| r14530 | r14531 | |
| 57 | 57 | //************************************************************************** |
| 58 | 58 | |
| 59 | 59 | //------------------------------------------------- |
| 60 | | // char_to_hex - return the hex value of a |
| 60 | // char_to_hex - return the hex value of a |
| 61 | 61 | // character |
| 62 | 62 | //------------------------------------------------- |
| 63 | 63 | |
| r14530 | r14531 | |
| 89 | 89 | length = strlen(string); |
| 90 | 90 | if (length < 2 * sizeof(m_raw)) |
| 91 | 91 | return false; |
| 92 | | |
| 92 | |
| 93 | 93 | // iterate through our raw buffer |
| 94 | 94 | for (int bytenum = 0; bytenum < sizeof(m_raw); bytenum++) |
| 95 | 95 | { |
| r14530 | r14531 | |
| 111 | 111 | { |
| 112 | 112 | buffer.reset(); |
| 113 | 113 | for (int i = 0; i < ARRAY_LENGTH(m_raw); i++) |
| 114 | | buffer.catformat("%02x", m_raw[i]); |
| 114 | buffer.catformat("%02x", m_raw[i]); |
| 115 | 115 | return buffer; |
| 116 | 116 | } |
| 117 | 117 | |
| r14530 | r14531 | |
| 131 | 131 | length = strlen(string); |
| 132 | 132 | if (length < 2 * sizeof(m_raw)) |
| 133 | 133 | return false; |
| 134 | | |
| 134 | |
| 135 | 135 | // iterate through our raw buffer |
| 136 | 136 | for (int bytenum = 0; bytenum < sizeof(m_raw); bytenum++) |
| 137 | 137 | { |
| r14530 | r14531 | |
| 153 | 153 | { |
| 154 | 154 | buffer.reset(); |
| 155 | 155 | for (int i = 0; i < ARRAY_LENGTH(m_raw); i++) |
| 156 | | buffer.catformat("%02x", m_raw[i]); |
| 156 | buffer.catformat("%02x", m_raw[i]); |
| 157 | 157 | return buffer; |
| 158 | 158 | } |
| 159 | 159 | |
| r14530 | r14531 | |
| 174 | 174 | length = strlen(string); |
| 175 | 175 | if (length < 2 * sizeof(m_raw)) |
| 176 | 176 | return false; |
| 177 | | |
| 177 | |
| 178 | 178 | // iterate through our raw buffer |
| 179 | 179 | m_raw = 0; |
| 180 | 180 | for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++) |
| r14530 | r14531 | |
| 199 | 199 | |
| 200 | 200 | |
| 201 | 201 | //------------------------------------------------- |
| 202 | | // append - hash a block of data, appending to |
| 202 | // append - hash a block of data, appending to |
| 203 | 203 | // the currently-accumulated value |
| 204 | 204 | //------------------------------------------------- |
| 205 | 205 | |
| r14530 | r14531 | |
| 225 | 225 | length = strlen(string); |
| 226 | 226 | if (length < 2 * sizeof(m_raw)) |
| 227 | 227 | return false; |
| 228 | | |
| 228 | |
| 229 | 229 | // iterate through our raw buffer |
| 230 | 230 | m_raw = 0; |
| 231 | 231 | for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++) |
| r14530 | r14531 | |
| 250 | 250 | |
| 251 | 251 | |
| 252 | 252 | //------------------------------------------------- |
| 253 | | // append - hash a block of data, appending to |
| 253 | // append - hash a block of data, appending to |
| 254 | 254 | // the currently-accumulated value |
| 255 | 255 | //------------------------------------------------- |
| 256 | 256 | |
| 257 | 257 | void crc16_creator::append(const void *data, UINT32 length) |
| 258 | 258 | { |
| 259 | | static const UINT16 s_table[256] = |
| 259 | static const UINT16 s_table[256] = |
| 260 | 260 | { |
| 261 | 261 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, |
| 262 | 262 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, |
| r14530 | r14531 | |
| 293 | 293 | }; |
| 294 | 294 | |
| 295 | 295 | const UINT8 *src = reinterpret_cast<const UINT8 *>(data); |
| 296 | | |
| 296 | |
| 297 | 297 | // fetch the current value into a local and rip through the source data |
| 298 | 298 | UINT16 crc = m_accum.m_raw; |
| 299 | 299 | while (length-- != 0) |
src/lib/util/hashing.h
| r14530 | r14531 | |
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | | hashing.h |
| 3 | hashing.h |
| 4 | 4 | |
| 5 | | Hashing helper classes. |
| 5 | Hashing helper classes. |
| 6 | 6 | |
| 7 | 7 | **************************************************************************** |
| 8 | 8 | |
| 9 | | Copyright Aaron Giles |
| 10 | | All rights reserved. |
| 9 | Copyright Aaron Giles |
| 10 | All rights reserved. |
| 11 | 11 | |
| 12 | | Redistribution and use in source and binary forms, with or without |
| 13 | | modification, are permitted provided that the following conditions are |
| 14 | | met: |
| 12 | Redistribution and use in source and binary forms, with or without |
| 13 | modification, are permitted provided that the following conditions are |
| 14 | met: |
| 15 | 15 | |
| 16 | | * Redistributions of source code must retain the above copyright |
| 17 | | notice, this list of conditions and the following disclaimer. |
| 18 | | * Redistributions in binary form must reproduce the above copyright |
| 19 | | notice, this list of conditions and the following disclaimer in |
| 20 | | the documentation and/or other materials provided with the |
| 21 | | distribution. |
| 22 | | * Neither the name 'MAME' nor the names of its contributors may be |
| 23 | | used to endorse or promote products derived from this software |
| 24 | | without specific prior written permission. |
| 16 | * Redistributions of source code must retain the above copyright |
| 17 | notice, this list of conditions and the following disclaimer. |
| 18 | * Redistributions in binary form must reproduce the above copyright |
| 19 | notice, this list of conditions and the following disclaimer in |
| 20 | the documentation and/or other materials provided with the |
| 21 | distribution. |
| 22 | * Neither the name 'MAME' nor the names of its contributors may be |
| 23 | used to endorse or promote products derived from this software |
| 24 | without specific prior written permission. |
| 25 | 25 | |
| 26 | | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 27 | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 28 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 29 | | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 30 | | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 31 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 32 | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 34 | | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 35 | | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 36 | | POSSIBILITY OF SUCH DAMAGE. |
| 26 | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 27 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 28 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 29 | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 30 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 31 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 34 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 35 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 36 | POSSIBILITY OF SUCH DAMAGE. |
| 37 | 37 | |
| 38 | 38 | ***************************************************************************/ |
| 39 | 39 | |
| r14530 | r14531 | |
| 73 | 73 | public: |
| 74 | 74 | // construction/destruction |
| 75 | 75 | sha1_creator() { reset(); } |
| 76 | | |
| 76 | |
| 77 | 77 | // reset |
| 78 | 78 | void reset() { sha1_init(&m_context); } |
| 79 | | |
| 79 | |
| 80 | 80 | // append data |
| 81 | 81 | void append(const void *data, UINT32 length) { sha1_update(&m_context, length, reinterpret_cast<const UINT8 *>(data)); } |
| 82 | | |
| 82 | |
| 83 | 83 | // finalize and compute the final digest |
| 84 | 84 | sha1_t finish() |
| 85 | 85 | { |
| r14530 | r14531 | |
| 92 | 92 | // static wrapper to just get the digest from a block |
| 93 | 93 | static sha1_t simple(const void *data, UINT32 length) |
| 94 | 94 | { |
| 95 | | sha1_creator creator; |
| 96 | | creator.append(data, length); |
| 95 | sha1_creator creator; |
| 96 | creator.append(data, length); |
| 97 | 97 | return creator.finish(); |
| 98 | 98 | } |
| 99 | 99 | |
| r14530 | r14531 | |
| 124 | 124 | public: |
| 125 | 125 | // construction/destruction |
| 126 | 126 | md5_creator() { reset(); } |
| 127 | | |
| 127 | |
| 128 | 128 | // reset |
| 129 | 129 | void reset() { MD5Init(&m_context); } |
| 130 | | |
| 130 | |
| 131 | 131 | // append data |
| 132 | 132 | void append(const void *data, UINT32 length) { MD5Update(&m_context, reinterpret_cast<const unsigned char *>(data), length); } |
| 133 | | |
| 133 | |
| 134 | 134 | // finalize and compute the final digest |
| 135 | 135 | md5_t finish() |
| 136 | 136 | { |
| r14530 | r14531 | |
| 142 | 142 | // static wrapper to just get the digest from a block |
| 143 | 143 | static md5_t simple(const void *data, UINT32 length) |
| 144 | 144 | { |
| 145 | | md5_creator creator; |
| 146 | | creator.append(data, length); |
| 145 | md5_creator creator; |
| 146 | creator.append(data, length); |
| 147 | 147 | return creator.finish(); |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | protected: |
| 151 | 151 | // internal state |
| 152 | | struct MD5Context m_context; // internal context |
| 152 | struct MD5Context m_context; // internal context |
| 153 | 153 | }; |
| 154 | 154 | |
| 155 | 155 | |
| r14530 | r14531 | |
| 175 | 175 | public: |
| 176 | 176 | // construction/destruction |
| 177 | 177 | crc32_creator() { reset(); } |
| 178 | | |
| 178 | |
| 179 | 179 | // reset |
| 180 | 180 | void reset() { m_accum.m_raw = 0; } |
| 181 | | |
| 181 | |
| 182 | 182 | // append data |
| 183 | 183 | void append(const void *data, UINT32 length); |
| 184 | | |
| 184 | |
| 185 | 185 | // finalize and compute the final digest |
| 186 | 186 | crc32_t finish() { return m_accum; } |
| 187 | 187 | |
| 188 | 188 | // static wrapper to just get the digest from a block |
| 189 | 189 | static crc32_t simple(const void *data, UINT32 length) |
| 190 | 190 | { |
| 191 | | crc32_creator creator; |
| 192 | | creator.append(data, length); |
| 191 | crc32_creator creator; |
| 192 | creator.append(data, length); |
| 193 | 193 | return creator.finish(); |
| 194 | 194 | } |
| 195 | 195 | |
| r14530 | r14531 | |
| 221 | 221 | public: |
| 222 | 222 | // construction/destruction |
| 223 | 223 | crc16_creator() { reset(); } |
| 224 | | |
| 224 | |
| 225 | 225 | // reset |
| 226 | 226 | void reset() { m_accum.m_raw = 0xffff; } |
| 227 | | |
| 227 | |
| 228 | 228 | // append data |
| 229 | 229 | void append(const void *data, UINT32 length); |
| 230 | | |
| 230 | |
| 231 | 231 | // finalize and compute the final digest |
| 232 | 232 | crc16_t finish() { return m_accum; } |
| 233 | 233 | |
| 234 | 234 | // static wrapper to just get the digest from a block |
| 235 | 235 | static crc16_t simple(const void *data, UINT32 length) |
| 236 | 236 | { |
| 237 | | crc16_creator creator; |
| 238 | | creator.append(data, length); |
| 237 | crc16_creator creator; |
| 238 | creator.append(data, length); |
| 239 | 239 | return creator.finish(); |
| 240 | 240 | } |
| 241 | 241 | |
src/lib/util/chdcodec.c
| r14530 | r14531 | |
| 64 | 64 | // construction/destruction |
| 65 | 65 | chd_zlib_allocator(); |
| 66 | 66 | ~chd_zlib_allocator(); |
| 67 | | |
| 67 | |
| 68 | 68 | // installation |
| 69 | 69 | void install(z_stream &stream); |
| 70 | 70 | |
| r14530 | r14531 | |
| 150 | 150 | |
| 151 | 151 | // core functionality |
| 152 | 152 | virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest); |
| 153 | | |
| 153 | |
| 154 | 154 | // helpers |
| 155 | 155 | static void configure_properties(CLzmaEncProps &props, chd_file &chd); |
| 156 | 156 | |
| r14530 | r14531 | |
| 346 | 346 | public: |
| 347 | 347 | // construction/destruction |
| 348 | 348 | chd_avhuff_compressor(chd_file &chd, bool lossy); |
| 349 | | |
| 349 | |
| 350 | 350 | // core functionality |
| 351 | 351 | virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest); |
| 352 | 352 | |
| r14530 | r14531 | |
| 368 | 368 | public: |
| 369 | 369 | // construction/destruction |
| 370 | 370 | chd_avhuff_decompressor(chd_file &chd, bool lossy); |
| 371 | | |
| 371 | |
| 372 | 372 | // core functionality |
| 373 | 373 | virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen); |
| 374 | 374 | virtual void configure(int param, void *config); |
| r14530 | r14531 | |
| 420 | 420 | chd_codec::~chd_codec() |
| 421 | 421 | { |
| 422 | 422 | } |
| 423 | | |
| 424 | 423 | |
| 424 | |
| 425 | 425 | //------------------------------------------------- |
| 426 | 426 | // configure - configuration |
| 427 | 427 | //------------------------------------------------- |
| r14530 | r14531 | |
| 597 | 597 | catch (...) |
| 598 | 598 | { |
| 599 | 599 | } |
| 600 | | |
| 600 | |
| 601 | 601 | if (memcmp(src, m_decompressed, m_hunkbytes) != 0) |
| 602 | 602 | { |
| 603 | 603 | compbytes = m_compressor[codecnum]->compress(src, m_hunkbytes, m_compress_test); |
| r14530 | r14531 | |
| 621 | 621 | } |
| 622 | 622 | catch (...) { } |
| 623 | 623 | } |
| 624 | | |
| 624 | |
| 625 | 625 | // if the best is none, copy it over |
| 626 | 626 | if (compression == -1) |
| 627 | 627 | memcpy(compressed, src, m_hunkbytes); |
| 628 | 628 | return compression; |
| 629 | 629 | } |
| 630 | | |
| 631 | 630 | |
| 632 | 631 | |
| 632 | |
| 633 | 633 | //************************************************************************** |
| 634 | 634 | // ZLIB ALLOCATOR HELPER |
| 635 | 635 | //************************************************************************** |
| r14530 | r14531 | |
| 832 | 832 | |
| 833 | 833 | |
| 834 | 834 | //------------------------------------------------- |
| 835 | | // decompress - decompress data using the ZLIB |
| 835 | // decompress - decompress data using the ZLIB |
| 836 | 836 | // codec |
| 837 | 837 | //------------------------------------------------- |
| 838 | 838 | |
| r14530 | r14531 | |
| 869 | 869 | { |
| 870 | 870 | // reset pointer list |
| 871 | 871 | memset(m_allocptr, 0, sizeof(m_allocptr)); |
| 872 | | |
| 872 | |
| 873 | 873 | // set our pointers |
| 874 | 874 | Alloc = &chd_lzma_allocator::fast_alloc; |
| 875 | 875 | Free = &chd_lzma_allocator::fast_free; |
| r14530 | r14531 | |
| 936 | 936 | { |
| 937 | 937 | if (address == NULL) |
| 938 | 938 | return; |
| 939 | | |
| 939 | |
| 940 | 940 | chd_lzma_allocator *codec = reinterpret_cast<chd_lzma_allocator *>(p); |
| 941 | 941 | |
| 942 | 942 | // find the hunk |
| r14530 | r14531 | |
| 994 | 994 | SRes res = LzmaEnc_SetProps(encoder, &m_props); |
| 995 | 995 | if (res != SZ_OK) |
| 996 | 996 | throw CHDERR_COMPRESSION_ERROR; |
| 997 | | |
| 997 | |
| 998 | 998 | // run it |
| 999 | 999 | SizeT complen = srclen; |
| 1000 | 1000 | res = LzmaEnc_MemEncode(encoder, dest, &complen, src, srclen, 0, NULL, &m_allocator, &m_allocator); |
| r14530 | r14531 | |
| 1046 | 1046 | // configure the properties like the compressor did |
| 1047 | 1047 | CLzmaEncProps encoder_props; |
| 1048 | 1048 | chd_lzma_compressor::configure_properties(encoder_props, chd); |
| 1049 | | |
| 1049 | |
| 1050 | 1050 | // convert to decoder properties |
| 1051 | 1051 | CLzmaProps decoder_props; |
| 1052 | 1052 | decoder_props.lc = encoder_props.lc; |
| 1053 | 1053 | decoder_props.lp = encoder_props.lp; |
| 1054 | 1054 | decoder_props.pb = encoder_props.pb; |
| 1055 | 1055 | decoder_props.dicSize = encoder_props.dictSize; |
| 1056 | | |
| 1056 | |
| 1057 | 1057 | // do memory allocations |
| 1058 | 1058 | SRes res = LzmaDec_Allocate_MAME(&m_decoder, &decoder_props, &m_allocator); |
| 1059 | 1059 | if (res != SZ_OK) |
| r14530 | r14531 | |
| 1073 | 1073 | |
| 1074 | 1074 | |
| 1075 | 1075 | //------------------------------------------------- |
| 1076 | | // decompress - decompress data using the LZMA |
| 1076 | // decompress - decompress data using the LZMA |
| 1077 | 1077 | // codec |
| 1078 | 1078 | //------------------------------------------------- |
| 1079 | 1079 | |
| r14530 | r14531 | |
| 1081 | 1081 | { |
| 1082 | 1082 | // initialize |
| 1083 | 1083 | LzmaDec_Init(&m_decoder); |
| 1084 | | |
| 1084 | |
| 1085 | 1085 | // decode |
| 1086 | 1086 | SizeT consumedlen = complen; |
| 1087 | 1087 | SizeT decodedlen = destlen; |
| r14530 | r14531 | |
| 1108 | 1108 | |
| 1109 | 1109 | |
| 1110 | 1110 | //------------------------------------------------- |
| 1111 | | // compress - compress data using the Huffman |
| 1111 | // compress - compress data using the Huffman |
| 1112 | 1112 | // codec |
| 1113 | 1113 | //------------------------------------------------- |
| 1114 | 1114 | |
| r14530 | r14531 | |
| 1137 | 1137 | |
| 1138 | 1138 | |
| 1139 | 1139 | //------------------------------------------------- |
| 1140 | | // decompress - decompress data using the Huffman |
| 1140 | // decompress - decompress data using the Huffman |
| 1141 | 1141 | // codec |
| 1142 | 1142 | //------------------------------------------------- |
| 1143 | 1143 | |
| r14530 | r14531 | |
| 1167 | 1167 | m_swap_endian = bigendian; |
| 1168 | 1168 | else |
| 1169 | 1169 | m_swap_endian = !bigendian; |
| 1170 | | |
| 1170 | |
| 1171 | 1171 | // configure the encoder |
| 1172 | 1172 | m_encoder.set_sample_rate(44100); |
| 1173 | 1173 | m_encoder.set_num_channels(2); |
| r14530 | r14531 | |
| 1218 | 1218 | |
| 1219 | 1219 | |
| 1220 | 1220 | //------------------------------------------------- |
| 1221 | | // decompress - decompress data using the FLAC |
| 1221 | // decompress - decompress data using the FLAC |
| 1222 | 1222 | // codec |
| 1223 | 1223 | //------------------------------------------------- |
| 1224 | 1224 | |
| r14530 | r14531 | |
| 1256 | 1256 | UINT16 native_endian = 0; |
| 1257 | 1257 | *reinterpret_cast<UINT8 *>(&native_endian) = 1; |
| 1258 | 1258 | m_swap_endian = (native_endian == 1); |
| 1259 | | |
| 1259 | |
| 1260 | 1260 | // configure the encoder |
| 1261 | 1261 | m_encoder.set_sample_rate(44100); |
| 1262 | 1262 | m_encoder.set_num_channels(2); |
| r14530 | r14531 | |
| 1310 | 1310 | |
| 1311 | 1311 | // finish up |
| 1312 | 1312 | UINT32 complen = m_encoder.finish(); |
| 1313 | | |
| 1313 | |
| 1314 | 1314 | // deflate the subcode data |
| 1315 | 1315 | m_deflater.next_in = const_cast<Bytef *>(&m_buffer[frames * CD_MAX_SECTOR_DATA]); |
| 1316 | 1316 | m_deflater.avail_in = frames * CD_MAX_SUBCODE_DATA; |
| r14530 | r14531 | |
| 1380 | 1380 | |
| 1381 | 1381 | |
| 1382 | 1382 | //------------------------------------------------- |
| 1383 | | // decompress - decompress data using the FLAC |
| 1383 | // decompress - decompress data using the FLAC |
| 1384 | 1384 | // codec |
| 1385 | 1385 | //------------------------------------------------- |
| 1386 | 1386 | |
| r14530 | r14531 | |
| 1410 | 1410 | zerr = inflate(&m_inflater, Z_FINISH); |
| 1411 | 1411 | if (m_inflater.total_out != frames * CD_MAX_SUBCODE_DATA) |
| 1412 | 1412 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1413 | | |
| 1413 | |
| 1414 | 1414 | // reassemble the data |
| 1415 | 1415 | for (UINT32 framenum = 0; framenum < frames; framenum++) |
| 1416 | 1416 | { |
| r14530 | r14531 | |
| 1474 | 1474 | |
| 1475 | 1475 | |
| 1476 | 1476 | //------------------------------------------------- |
| 1477 | | // postinit - actual initialization of avhuff |
| 1478 | | // happens here, on the first attempt to compress |
| 1477 | // postinit - actual initialization of avhuff |
| 1478 | // happens here, on the first attempt to compress |
| 1479 | 1479 | // or decompress data |
| 1480 | 1480 | //------------------------------------------------- |
| 1481 | 1481 | |
| r14530 | r14531 | |
| 1520 | 1520 | |
| 1521 | 1521 | |
| 1522 | 1522 | //------------------------------------------------- |
| 1523 | | // decompress - decompress data using the A/V |
| 1523 | // decompress - decompress data using the A/V |
| 1524 | 1524 | // codec |
| 1525 | 1525 | //------------------------------------------------- |
| 1526 | 1526 | |
| r14530 | r14531 | |
| 1542 | 1542 | |
| 1543 | 1543 | |
| 1544 | 1544 | //------------------------------------------------- |
| 1545 | | // config - codec-specific configuration for the |
| 1545 | // config - codec-specific configuration for the |
| 1546 | 1546 | // A/V codec |
| 1547 | 1547 | //------------------------------------------------- |
| 1548 | 1548 | |
| r14530 | r14531 | |
| 1551 | 1551 | // if we're getting the decompression configuration, apply it now |
| 1552 | 1552 | if (param == AVHUFF_CODEC_DECOMPRESS_CONFIG) |
| 1553 | 1553 | m_decoder.configure(*reinterpret_cast<avhuff_decompress_config *>(config)); |
| 1554 | | |
| 1554 | |
| 1555 | 1555 | // anything else is invalid |
| 1556 | 1556 | else |
| 1557 | 1557 | throw CHDERR_INVALID_PARAMETER; |