Previous 15994 Revisions Next

r14482 Thursday 16th February, 2012 at 14:07:23 UTC by Miodrag Milanović
Sync with MAME r15406 (no whatsnew)
[src/emu]audit.c clifront.c emu.h emuopts.c romload.c romload.h
[src/emu/imagedev]chd_cd.c chd_cd.h harddriv.c harddriv.h
[src/emu/machine]idectrl.c laserdsc.c laserdsc.h
[src/ldplayer]ldplayer.c
[src/lib]lib.mak
[src/lib/lib7z]LzmaDec.c Ppmd7.c
[src/lib/util]astring.h avcomp.c avcomp.h avhuff.c* avhuff.h* aviio.c bitmap.c bitmap.h bitstream.h* cdrom.c cdrom.h chd.c chd.h chdcd.c chdcd.h chdcodec.c* chdcodec.h* corefile.c corefile.h coretmpl.h* flac.c* flac.h* harddisk.c harddisk.h hashing.c* hashing.h* huffman.c huffman.h tagmap.h
[src/mame]mame.lst
[src/mame/drivers]aleck64.c bfm_sc2.c cps3.c decocass.c harddriv.c jpmimpct.c kinst.c marineb.c model2.c mpu4.c proconn.c seicross.c sms.c taitogn.c vamphalf.c
[src/mame/includes]harddriv.h
[src/mame/machine]harddriv.c n64.c
[src/mame/video]nmk16.c
[src/osd/sdl]README_SDL13.txt README_SDL20.txt input.c sdlinc.h testkeys.c
[src/osd/sdl/keymaps]km-de.txt
[src/osd/windows]wintime.c winwork.c
[src/tools]chdman.c tools.mak

src/mame/mame.lst
r14481r14482
32293229sfiii3a         // 12/05/1999 (c) 1999 (Euro)
32303230sfiii3u         // 08/06/1999 (c) 1999 (USA)
32313231sfiii3au      // 12/05/1999 (c) 1999 (USA)
3232jojoba         // 13/09/1999 (c) 1999 (Japan)
3232jojoba         // 27/09/1999 (c) 1999 (Japan)
3233jojobaa         // 13/09/1999 (c) 1999 (Japan)
32333234
32343235sfiiin         // 04/02/1997 (c) 1997 (Asia)
32353236sfiii2n         // 30/09/1997 (c) 1997 (Asia)
r14481r14482
32373238jojoan         // 02/12/1998 (c) 1998 (Asia)
32383239sfiii3n         // 08/06/1999 (c) 1999 (Japan)
32393240sfiii3an      // 12/05/1999 (c) 1999 (Japan)
3240jojoban         // 13/09/1999 (c) 1999 (Japan)
3241jojobane      // 13/09/1999 (c) 1999 (Euro)
3241jojoban         // 27/09/1999 (c) 1999 (Japan)
3242jojobaan      // 13/09/1999 (c) 1999 (Japan)
3243jojobane      // 27/09/1999 (c) 1999 (Euro)
3244jojobaane      // 13/09/1999 (c) 1999 (Euro)
32423245
32433246// Capcom ZN1
32443247cpzn1
r14481r14482
45204523srallycb      // 1995.02 Sega Rally Championship - Rev B
45214524vcop2         // 1995.09 Virtua Cop 2
45224525vf2         // 1995.09 Virtua Fighter 2.1
4523            // 1995.10 Sky Target
4526skytargt      // 1995.10 Sky Target
45244527manxtt         // 1995.11 Manx T.T.
4525            // 1996.08 Dynamite Baseball
45264528doaa         // 1996.11 Dead or Alive
4527            // 1997.04 Dynamite Baseball '97
45284529motoraid      // 1997.10 Motor Raid
45294530zeroguna      // 1997.12 Zero Gunner
45304531zerogunaj      // 1997.12 Zero Gunner (Japan)
r14481r14482
45334534pltkidsa      // 1999.03 Pilot Kids
45344535
45354536// Model 2B-CRX (SHARC, SCSP sound board)
4536vstriker      // 1995.05 virtua Striker
4537vstrikero      // 1995.05 virtua Striker
4537vstriker      // 1995.05 Virtua Striker
4538vstrikero      // 1995.05 Virtua Striker
45384539rchase2         // 1995.06 Rail Chase 2 (Arcade TV Game List - P.104, Left, 12 from top)
45394540indy500         // 1995.07 Indy 500
45404541indy500d      // 1995.07 Indy 500
45414542indy500to      // 1995.07 Indy 500
4542skytargt      // 1995.10 Sky Target
45434543fvipers         // 1995.11 Fighting Vipers
45444544von         // 1996.01 Dennou Senki Virtual-On (USA)
45454545vonj         // 1996.01 Dennou Senki Virtual-On (Japan)
r14481r14482
45524552sgt24h         // 1996.07 Super GT 24h
45534553dynabb         // 1996.08 Dynamite Baseball
45544554doa         // 1996.11 Dead or Alive
4555            // 1997.04 Dynamite Baseball '97
4555dynabb97      // 1997.04 Dynamite Baseball 97
45564556zerogun         // 1997.12 Zero Gunner
45574557zerogunj      // 1997.12 Zero Gunner (Japan)
45584558dyndeka2b      // 1998.05 Dynamite Deka 2
r14481r14482
45694569topskatr      // 1997.05 Top Skater
45704570topskatru      // 1997.05 Top Skater (USA)
45714571topskatrj      // 1997.05 Top Skater (Japan)
4572overrev         // 1997.09 Overrev
4572overrev         // 1997.09 Over Rev
45734573segawski      // 1997.09 Sega Water Ski
45744574dynamcopc      // 1998.09 Dynamite Cop
45754575bel         // 1998.12 Behind Enemy Lines
r14481r14482
52195219cppicf         // 39 1984.02 Peter Pepper's Ice Cream Factory
52205220cppicf2         // 39
52215221cfghtice      // 40 1984.04 Fighting Ice Hockey
5222            // 41 1984.05 Oozumou/The Grand Sumo
5222cgsumo         // 41 1984.05 Oozumou/The Grand Sumo
52235223            // 42 1984.08 Hellow Gateball // not a typo, this is official spelling
52245224            // 43 1984.08 Yellow Cab
52255225cbdash         // 44 1985.08 Boulder Dash
r14481r14482
1043810438finalgdr      // (c) 2001 Semicom
1043910439mrkicker      // (c) 2001 Semicom
1044010440wyvernwg      // (c) 2001 Semicom / Game Vision
10441wyvernwga      // (c) 2001 Semicom / Game Vision
1044110442rbmk         // (c) 1995 GMS
1044210443go2000         // (c) 2000 SA
1044310444mirax         // (c) 1985 Current Technologies
r14481r14482
1870018701pr_medl         // Medalist (Project)
1870118702pr_megmn      // Mega Money (Project)
1870218703pr_nudxs      // Nudge XS (Project)
18704pr_qksht      // Quickshot (Maygay)
1870318705pr_rags         // Rags To Riches (Project)
1870418706pr_reflx      // Reflex (Project)
1870518707pr_roadr      // Road Riot (Project)
src/mame/machine/n64.c
r14481r14482
118118    if (boot_checksum == U64(0x000000d057e84864))
119119    {
120120        // CIC-NUS-6101
121        //printf("CIC-NUS-6102 detected\n");
121        printf("CIC-NUS-6102 detected\n");
122122        pif_ram[0x24] = 0x00;
123123        pif_ram[0x25] = 0x02;
124124        pif_ram[0x26] = 0x3f;
r14481r14482
128128    else if (boot_checksum == U64(0x000000cffb830843) || boot_checksum == U64(0x000000d0027fdf31))
129129    {
130130        // CIC-NUS-6103
131        //printf("CIC-NUS-6101 detected\n");
131        printf("CIC-NUS-6101 detected\n");
132132        // crc_seed = 0x78;
133133        pif_ram[0x24] = 0x00;
134134        pif_ram[0x25] = 0x06;
r14481r14482
138138    else if (boot_checksum == U64(0x000000d6499e376b))
139139    {
140140        // CIC-NUS-6103
141        //printf("CIC-NUS-6103 detected\n");
141        printf("CIC-NUS-6103 detected\n");
142142        // crc_seed = 0x78;
143143        pif_ram[0x24] = 0x00;
144144        pif_ram[0x25] = 0x02;
r14481r14482
148148    else if (boot_checksum == U64(0x0000011a4a1604b6))
149149    {
150150        // CIC-NUS-6105
151        //printf("CIC-NUS-6105 detected\n");
151        printf("CIC-NUS-6105 detected\n");
152152        // crc_seed = 0x91;
153153
154154        // first_rsp = 0;
r14481r14482
160160    else if (boot_checksum == U64(0x000000d6d5de4ba0))
161161    {
162162        // CIC-NUS-6106
163        //printf("CIC-NUS-6106 detected\n");
163        printf("CIC-NUS-6106 detected\n");
164164        // crc_seed = 0x85;
165165        pif_ram[0x24] = 0x00;
166166        pif_ram[0x25] = 0x02;
r14481r14482
169169    }
170170    else
171171    {
172        //printf("Unknown BootCode Checksum %08X%08X\n", (UINT32)(boot_checksum>>32),(UINT32)(boot_checksum));
172        printf("Unknown BootCode Checksum %08X%08X\n", (UINT32)(boot_checksum>>32),(UINT32)(boot_checksum));
173173    }
174174}
175175
r14481r14482
350350        case 0x0014/4:
351351            for(i = 0x20; i < (0x20 + data); i++)
352352            {
353                //printf( "%c", is64_buffer[i] );
353                printf( "%c", is64_buffer[i] );
354354                if(is64_buffer[i] == 0x0a)
355355                {
356                    //printf( "%c", 0x0d );
356                    printf( "%c", 0x0d );
357357                }
358358                is64_buffer[i] = 0;
359359            }
r14481r14482
436436
437437   if ((sp_mem_addr & 0xfff) + (sp_dma_length) > 0x1000)
438438   {
439      //printf("sp_dma: dma out of memory area: %08X, %08X\n", sp_mem_addr, sp_dma_length);
439      printf("sp_dma: dma out of memory area: %08X, %08X\n", sp_mem_addr, sp_dma_length);
440440      //fatalerror("sp_dma: dma out of memory area: %08X, %08X\n", sp_mem_addr, sp_dma_length);
441441      sp_dma_length = 0x1000 - (sp_mem_addr & 0xfff);
442442   }
r14481r14482
19801980   n64_periphs *periphs = machine.device<n64_periphs>("rcp");
19811981
19821982   device_image_interface *image = dynamic_cast<device_image_interface *>(periphs->m_nvram_image);
1983   //printf("Saving stuff\n");
1983   //printf("Saving\n");
19841984   UINT8 data[0x30800];
19851985   memcpy(data, n64_sram, 0x20000);
19861986   memcpy(data + 0x20000, periphs->m_save_data.eeprom, 0x800);
src/mame/machine/harddriv.c
r14481r14482
671671}
672672
673673
674
675/*************************************
676 *
677 *  MSP synchronization helpers
678 *
679 *************************************/
680
681static TIMER_CALLBACK( stmsp_sync_update )
682{
683   harddriv_state *state = machine.driver_data<harddriv_state>();
684   int which = param >> 28;
685   offs_t offset = (param >> 16) & 0xfff;
686   UINT16 data = param;
687   state->m_stmsp_sync[which][offset] = data;
688   device_triggerint(state->m_msp);
689}
690
691
692INLINE void stmsp_sync_w(address_space *space, offs_t offset, UINT16 data, UINT16 mem_mask, int which)
693{
694   harddriv_state *state = space->machine().driver_data<harddriv_state>();
695   UINT16 newdata = state->m_stmsp_sync[which][offset];
696   COMBINE_DATA(&newdata);
697
698   /* if being written from the 68000, synchronize on it */
699   if (state->m_hd34010_host_access)
700      space->machine().scheduler().synchronize(FUNC(stmsp_sync_update), newdata | (offset << 16) | (which << 28));
701
702   /* otherwise, just update */
703   else
704      state->m_stmsp_sync[which][offset] = newdata;
705}
706
707
708WRITE16_HANDLER( stmsp_sync0_w )
709{
710   stmsp_sync_w(space, offset, data, mem_mask, 0);
711}
712
713
714WRITE16_HANDLER( stmsp_sync1_w )
715{
716   stmsp_sync_w(space, offset, data, mem_mask, 1);
717}
718
719
720WRITE16_HANDLER( stmsp_sync2_w )
721{
722   stmsp_sync_w(space, offset, data, mem_mask, 2);
723}
724
725
726
727674#if 0
728675#pragma mark -
729676#pragma mark * ADSP BOARD
r14481r14482
18431790}
18441791
18451792
1846READ16_HANDLER( stmsp_speedup_r )
1847{
1848   harddriv_state *state = space->machine().driver_data<harddriv_state>();
1849
1850   /* assumes: stmsp_sync[0] -> $80010, stmsp_sync[1] -> $99680, stmsp_sync[2] -> $99d30 */
1851   if (state->m_stmsp_sync[0][0] == 0 &&      /* 80010 */
1852      state->m_stmsp_sync[0][1] == 0 &&      /* 80020 */
1853      state->m_stmsp_sync[0][2] == 0 &&      /* 80030 */
1854      state->m_stmsp_sync[0][3] == 0 &&      /* 80040 */
1855      state->m_stmsp_sync[0][4] == 0 &&      /* 80050 */
1856      state->m_stmsp_sync[0][5] == 0 &&      /* 80060 */
1857      state->m_stmsp_sync[0][6] == 0 &&      /* 80070 */
1858      state->m_stmsp_sync[1][0] == 0 &&      /* 99680 */
1859      state->m_stmsp_sync[2][0] == 0xffff &&   /* 99d30 */
1860      state->m_stmsp_sync[2][1] == 0xffff &&   /* 99d40 */
1861      state->m_stmsp_sync[2][2] == 0 &&      /* 99d50 */
1862      cpu_get_pc(&space->device()) == 0x3c0)
1863   {
1864      state->m_msp_speedup_count[0]++;
1865      device_spin_until_interrupt(&space->device());
1866   }
1867   return state->m_stmsp_sync[0][1];
1868}
1869
1870
1871
18721793#if 0
18731794#pragma mark -
18741795#pragma mark * ADSP OPTIMIZATIONS
src/mame/includes/harddriv.h
r14481r14482
5353   UINT32 *            m_adsp_pgm_memory;
5454
5555   UINT16 *            m_gsp_protection;
56   UINT16 *            m_stmsp_sync[3];
5756
5857   UINT16 *            m_gsp_speedup_addr[2];
5958   offs_t               m_gsp_speedup_pc;
r14481r14482
215214
216215WRITE16_HANDLER( hdgsp_protection_w );
217216
218WRITE16_HANDLER( stmsp_sync0_w );
219WRITE16_HANDLER( stmsp_sync1_w );
220WRITE16_HANDLER( stmsp_sync2_w );
221217
222218/* ADSP board */
223219READ16_HANDLER( hd68k_adsp_program_r );
r14481r14482
290286/* MSP optimizations */
291287READ16_HANDLER( hdmsp_speedup_r );
292288WRITE16_HANDLER( hdmsp_speedup_w );
293READ16_HANDLER( stmsp_speedup_r );
294289
295290/* ADSP optimizations */
296291READ16_HANDLER( hdadsp_speedup_r );
src/mame/video/nmk16.c
r14481r14482
425425
426426// manybloc uses extra flip bits on the sprites, but these break other games
427427
428static void nmk16_draw_sprites(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int priority)
428static inline void nmk16_draw_sprite(nmk16_state *state, running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int priority, UINT16 *spr)
429429{
430  if ((spr[0] & 0x0001))
431  {
432    int sx    = (spr[4] & 0x1FF) + state->m_videoshift;
433    int sy    =  spr[6] & 0x1FF;
434    int code  =  spr[3];
435    int color =  spr[7];
436    int w     =  spr[1] & 0x00F;
437    int h     = (spr[1] & 0x0F0) >> 4;
438    int pri   = (spr[0] & 0x0C0) >> 6;
439    int xx,yy,x;
440    int delta = 16;
441
442    if(pri != priority)
443      return;
444
445    if (flip_screen_get(machine))
446    {
447      sx = 368 - sx;
448      sy = 240 - sy;
449      delta = -16;
450    }
451
452    yy = h;
453    do
454    {
455      x = sx;
456      xx = w;
457      do
458      {
459        drawgfx_transpen(bitmap,cliprect,machine.gfx[2],
460            code,
461            color,
462            flip_screen_get(machine), flip_screen_get(machine),
463            ((x + 16) & 0x1FF) - 16,sy & 0x1FF,15);
464        code++;
465        x += delta;
466      } while (--xx >= 0);
467
468      sy += delta;
469    } while (--yy >= 0);
470  }
471}
472
473static inline void nmk16_draw_sprite_flipsupported(nmk16_state *state, running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int priority, UINT16 *spr)
474{
475  if ((spr[0] & 0x0001))
476  {
477    int sx    = (spr[4] & 0x1FF) + state->m_videoshift;
478    int sy    =  spr[6] & 0x1FF;
479    int code  =  spr[3];
480    int color =  spr[7];
481    int w     =  spr[1] & 0x00F;
482    int h     = (spr[1] & 0x0F0) >> 4;
483    int pri   = (spr[0] & 0x0C0) >> 6;
484    int flipy = (spr[1] & 0x200) >> 9;
485    int flipx = (spr[1] & 0x100) >> 8;
486
487    int xx,yy,x;
488    int delta = 16;
489
490    if(pri != priority)
491      return;
492
493    flipx ^= flip_screen_get(machine);
494    flipy ^= flip_screen_get(machine);
495
496    if (flip_screen_get(machine))
497    {
498      sx = 368 - sx;
499      sy = 240 - sy;
500      delta = -16;
501    }
502
503    yy = h;
504    sy += flipy ? (delta*h) : 0;
505    do
506    {
507      x = sx + (flipx ? (delta*w) : 0);
508      xx = w;
509      do
510      {
511        drawgfx_transpen(bitmap,cliprect,machine.gfx[2],
512            code,
513            color,
514            flipx, flipy,
515            ((x + 16) & 0x1FF) - 16,sy & 0x1FF,15);
516        code++;
517        x += delta * (flipx ? -1 : 1);
518      } while (--xx >= 0);
519      sy += delta * (flipy ? -1 : 1);
520    } while (--yy >= 0);
521  }
522}
523
524static void nmk16_draw_sprites2(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int *swaptbl)
525{
430526   nmk16_state *state = machine.driver_data<nmk16_state>();
431   int offs;
527   int i, l, prio;
432528
433   for (offs = 0;offs < 0x1000/2;offs += 8)
529  // Priority level (0x10 levels, 4 sub-levels, 0x10 sprites each)
530   for ( i = 0; i < 0x10; i++ )
434531   {
435      if ((state->m_spriteram_old2[offs] & 0x0001))
436      {
437         int sx = (state->m_spriteram_old2[offs+4] & 0x1ff) + state->m_videoshift;
438         int sy = (state->m_spriteram_old2[offs+6] & 0x1ff);
439         int code = state->m_spriteram_old2[offs+3];
440         int color = state->m_spriteram_old2[offs+7];
441         int w = (state->m_spriteram_old2[offs+1] & 0x0f);
442         int h = ((state->m_spriteram_old2[offs+1] & 0xf0) >> 4);
443         int pri = (state->m_spriteram_old2[offs] & 0xc0) >> 6;
444         int xx,yy,x;
445         int delta = 16;
532    // Sub-priority level (4 levels)
533    for ( prio = 3; prio >= 0; prio-- )
534    {
535      // Sprite
536      for ( l = 0; l < 0x10; l++ )
537      {
538        nmk16_draw_sprite(state, machine, bitmap, cliprect, prio, state->m_spriteram_old2 + ((swaptbl[i] + l) * 8));
539      }
540    }
541   }
542}
446543
447         if(pri != priority)
448            continue;
544static void nmk16_draw_sprites2_flipsupported(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int *swaptbl)
545{
546   nmk16_state *state = machine.driver_data<nmk16_state>();
547   int i, l, prio;
449548
450         if (flip_screen_get(machine))
451         {
452            sx = 368 - sx;
453            sy = 240 - sy;
454            delta = -16;
455         }
549  // Priority level (0x10 levels, 4 sub-levels, 0x10 sprites each)
550   for ( i = 0; i < 0x10; i++ )
551   {
552    // Sub-priority level (4 levels)
553    for ( prio = 3; prio >= 0; prio-- )
554    {
555      // Sprite
556      for ( l = 0; l < 0x10; l++ )
557      {
558        nmk16_draw_sprite_flipsupported(state, machine, bitmap, cliprect, prio, state->m_spriteram_old2 + ((swaptbl[i] + l) * 8));
559      }
560    }
561   }
562}
456563
457         yy = h;
458         do
459         {
460            x = sx;
461            xx = w;
462            do
463            {
464               drawgfx_transpen(bitmap,cliprect,machine.gfx[2],
465                     code,
466                     color,
467                     flip_screen_get(machine), flip_screen_get(machine),
468                     ((x + 16) & 0x1ff) - 16,sy & 0x1ff,15);
469               code++;
470               x += delta;
471            } while (--xx >= 0);
564static void nmk16_draw_sprites(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int priority)
565{
566   nmk16_state *state = machine.driver_data<nmk16_state>();
567   int offs;
472568
473            sy += delta;
474         } while (--yy >= 0);
475      }
569   for (offs = 0;offs < 0x1000/2;offs += 8)
570   {
571      nmk16_draw_sprite(state, machine, bitmap, cliprect, priority, state->m_spriteram_old2 + offs);
476572   }
477573}
478574
r14481r14482
485581   {
486582      if (state->m_spriteram_old2[offs] & 0x0001)
487583      {
488         int sx = (state->m_spriteram_old2[offs+4] & 0x1ff) + state->m_videoshift;
489         int sy = (state->m_spriteram_old2[offs+6] & 0x1ff);
490         int code = state->m_spriteram_old2[offs+3];
491         int color = state->m_spriteram_old2[offs+7];
492         int w = (state->m_spriteram_old2[offs+1] & 0x0f);
493         int h = ((state->m_spriteram_old2[offs+1] & 0xf0) >> 4);
494         int pri = (state->m_spriteram_old2[offs] & 0xc0) >> 6;
495         int flipy= ((state->m_spriteram_old2[offs+1] & 0x0200) >> 9);
496         int flipx = ((state->m_spriteram_old2[offs+1] & 0x0100) >> 8);
497
498         int xx,yy,x;
499         int delta = 16;
500
501         if(pri != priority)
502            continue;
503
504         flipx ^= flip_screen_get(machine);
505         flipy ^= flip_screen_get(machine);
506
507         if (flip_screen_get(machine))
508         {
509            sx = 368 - sx;
510            sy = 240 - sy;
511            delta = -16;
512         }
513
514         yy = h;
515         sy+=flipy?(delta*h):0;
516         do
517         {
518            x = sx+(flipx?(delta*w):0);
519
520
521            xx = w;
522            do
523            {
524               drawgfx_transpen(bitmap,cliprect,machine.gfx[2],
525                     code,
526                     color,
527                     flipx, flipy,
528                     ((x + 16) & 0x1ff) - 16,sy & 0x1ff,15);
529
530               code++;
531               x +=delta * ( flipx?-1:1 );
532
533
534            } while (--xx >= 0);
535            sy += delta * ( flipy?-1:1);
536
537         } while (--yy >= 0);
584         nmk16_draw_sprite_flipsupported(state, machine, bitmap, cliprect, priority, state->m_spriteram_old2 + offs);
538585      }
539586   }
540587}
541588
542
543589SCREEN_UPDATE_IND16( macross )
544590{
545591   nmk16_state *state = screen.machine().driver_data<nmk16_state>();
r14481r14482
547593
548594   state->m_bg_tilemap0->draw(bitmap, cliprect, 0,0);
549595
550   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,3);
551   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,2);
552   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,1);
553   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,0);
596   static int macross_swaptbl[0x10] = {
597   0x00, 0x80, 0x20, 0xA0, 0x40, 0xC0, 0x60, 0xE0,
598   0x10, 0x90, 0x30, 0xB0, 0x50, 0xD0, 0x70, 0xF0,
599   };
600   nmk16_draw_sprites2(screen.machine(), bitmap,cliprect, macross_swaptbl);
554601
555602   state->m_tx_tilemap->draw(bitmap, cliprect, 0,0);
556603   return 0;
r14481r14482
565612
566613   state->m_bg_tilemap0->draw(bitmap, cliprect, 0,0);
567614
568   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,3);
569   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,2);
570   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,1);
571   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,0);
615   // TODO: Fix this swap table; it's currently incorrect
616   static int tdragon_swaptbl[0x10] = {
617   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
618   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
619   };
620   nmk16_draw_sprites2(screen.machine(), bitmap,cliprect, tdragon_swaptbl);
572621
573622   state->m_tx_tilemap->draw(bitmap, cliprect, 0,0);
574623   return 0;
r14481r14482
583632
584633   state->m_bg_tilemap0->draw(bitmap, cliprect, 0,0);
585634
586   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,3);
635   // TODO: Fix this swap table; it's currently incorrect
636   static int hachamf_swaptbl[0x10] = {
637   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
638   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
639   };
640   nmk16_draw_sprites2(screen.machine(), bitmap,cliprect, hachamf_swaptbl);
641/*   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,3);
587642   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,2);
588643   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,1);
589   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,0);
644   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,0);*/
590645
591646   state->m_tx_tilemap->draw(bitmap, cliprect, 0,0);
592647   return 0;
r14481r14482
618673   state->m_bg_tilemap0->set_scrollx(0,tharrier_scroll);
619674   state->m_bg_tilemap0->draw(bitmap, cliprect, 0,0);
620675
621   nmk16_draw_sprites_flipsupported(screen.machine(), bitmap,cliprect,3);
622   nmk16_draw_sprites_flipsupported(screen.machine(), bitmap,cliprect,2);
623   nmk16_draw_sprites_flipsupported(screen.machine(), bitmap,cliprect,1);
624   nmk16_draw_sprites_flipsupported(screen.machine(), bitmap,cliprect,0);
676   // TODO: Fix this swap table; it's currently incorrect
677   static int tharrier_swaptbl[0x10] = {
678   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
679   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
680   };
681   nmk16_draw_sprites2_flipsupported(screen.machine(), bitmap,cliprect, tharrier_swaptbl);
625682
626683   state->m_tx_tilemap->draw(bitmap, cliprect, 0,0);
627684   return 0;
r14481r14482
696753      bg_tilemap->draw(bitmap, cliprect, 0,0);
697754   }
698755
699   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,3);
700   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,2);
701   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,1);
702   nmk16_draw_sprites(screen.machine(), bitmap,cliprect,0);
756   static int gunnail_swaptbl[0x10] = {
757   0x00, 0x80, 0x20, 0xA0, 0x40, 0xC0, 0x60, 0xE0,
758   0x10, 0x90, 0x30, 0xB0, 0x50, 0xD0, 0x70, 0xF0,
759   };
760   nmk16_draw_sprites2(screen.machine(), bitmap,cliprect, gunnail_swaptbl);
703761
704762   state->m_tx_tilemap->set_scrollx(0,-state->m_videoshift);
705763   state->m_tx_tilemap->draw(bitmap, cliprect, 0,0);
src/mame/drivers/mpu4.c
r14481r14482
1088710887   ROM_LOAD( "sv_20a__.4_1", 0x0000, 0x020000, CRC(0e790ae8) SHA1(48f055f3f1f5d3392b7fba1c5c30624c1f230327) )
1088810888   ROM_LOAD( "sv_20sb_.4_1", 0x0000, 0x020000, CRC(e88c1c29) SHA1(49d180068e4ae9cb65a58e65b4e1ac4d6657ae1d) )
1088910889   ROM_LOAD( "svi20___.4_1", 0x0000, 0x020000, CRC(643037ed) SHA1(d4063faba3069625474dd761f9ad2dcf2f710a19) )
10890   ROM_LOAD( "sinbadbwb1_1game.bin", 0x0000, 0x020000, CRC(cfe152a7) SHA1(b8ecfa8b763d04515b65eb902c18dba7198191c3) )
1089010891
1089110892   ROM_REGION( 0x180000, "msm6376", ROMREGION_ERASE00 )
10892   /* missing? */
10893   //These were with the last listed set, though I have no reason to believe they aren't valid for all BwB Sinbad games
10894   ROM_LOAD( "sinbadbwb1_2snd.bin", 0x000000, 0x080000, CRC(2ee60ce6) SHA1(865860639e8471f97ace0beac2f4c7fddb8ca97c) )
10895   ROM_LOAD( "sinbadbwb1_3snd.bin", 0x000000, 0x080000, CRC(7701e5cc) SHA1(4f9ff91f2b6b15a9c08396b52fc8509ba476ed8d) )
1089310896ROM_END
1089410897
1089510898
src/mame/drivers/model2.c
r14481r14482
2727    srallyc
2828    skytargt
2929    dynamcop
30    dynabb
30    dynabb97
3131    lastbrnj/lastbrnx
3232    skisuprg
3333
r14481r14482
42974297   ROM_LOAD("mpr-19750.24s", 0xc00000, 0x400000, CRC(cd95d0bf) SHA1(40e2a2980c89049c339fefd48bf7aac79962cd2e) )
42984298ROM_END
42994299
4300
43014300ROM_START( doaa ) /* Dead or Alive Revision A, Model 2A */
43024301   ROM_REGION( 0x200000, "maincpu", 0 ) // i960 program
43034302   ROM_LOAD32_WORD("epr-19310a.12", 0x000000, 0x080000, CRC(06486f7a) SHA1(b3e14103570e5f45aed16e1c158e469bc85002ae) )
r14481r14482
44544453   ROM_LOAD("mpr-18653.34", 0x400000, 0x400000, CRC(9ec3e7bf) SHA1(197bc8adc823e93128c1cebf69361a7c7297f808))
44554454ROM_END
44564455
4457
44584456ROM_START( vonj ) /* Virtual On Cyber Troopers Revision B (Japan), Model 2B */
44594457   ROM_REGION( 0x200000, "maincpu", 0 ) // i960 program
44604458   ROM_LOAD32_WORD("epr-18664b.15", 0x000000, 0x080000, CRC(27d0172c) SHA1(f3bcae9898c7d656eccb4d2546c9bb93daaefbb7) )
r14481r14482
45674565   ROM_LOAD("mpr-18065.34", 0x400000, 0x200000, CRC(046b55fe) SHA1(2db7eabf4318881a67b10dba24f6f0cd68940ace) )
45684566ROM_END
45694567
4570ROM_START( dynabb ) /* Dynamite Baseball '97 Revision A, Model 2B */
4568ROM_START( dynabb ) /* Dynamite Baseball, Model 2B */
45714569   ROM_REGION( 0x200000, "maincpu", 0 ) // i960 program
4570   ROM_LOAD32_WORD("epr-19170.15", 0x000000, 0x080000, CRC(e00eb49e) SHA1(20975d892cf1c9f50605238d6ab41d79ece39f69) )
4571   ROM_LOAD32_WORD("epr-19171.16", 0x000002, 0x080000, CRC(9878d67d) SHA1(d3350546b7e0e6fe8bb2f9d1a91475655f931b8b) )
4572   ROM_LOAD32_WORD("epr-19168.13", 0x100000, 0x080000, CRC(041da66b) SHA1(4a58153baf5f0b34e054bf23e519edcf364a9336) )
4573   ROM_LOAD32_WORD("epr-19169.14", 0x100002, 0x080000, CRC(91a5acef) SHA1(2520a3e4ff15e4d583861ba656570abca5f7c611) )
4574
4575   ROM_REGION32_LE( 0x2000000, "user1", 0 ) // Data
4576   ROM_LOAD32_WORD("mpr-19178.11", 0x0000000, 0x400000, CRC(0d621e21) SHA1(31adc229258a5d468ff80d789c59bd8a6777f900) )
4577   ROM_LOAD32_WORD("mpr-19179.12", 0x0000002, 0x400000, CRC(337a4ec2) SHA1(77d7d186344715237895ac1ed0ab219fcc340a7e) )
4578   ROM_LOAD32_WORD("mpr-19176.9",  0x0800000, 0x400000, CRC(2c4e90f5) SHA1(8d5ed0b26e79dd6476282bc69cb27b42381635f2) )
4579   ROM_LOAD32_WORD("mpr-19177.10", 0x0800002, 0x400000, CRC(b0f1e512) SHA1(81e4124ac7766c7ea6bac7e7f4db110783394ae3) )
4580   ROM_LOAD32_WORD("mpr-19174.7",  0x1000000, 0x400000, CRC(057e5200) SHA1(dd07eb438d91a8132789154a633fb6ec4e2ef0d1) )
4581   ROM_LOAD32_WORD("mpr-19175.8",  0x1000002, 0x400000, CRC(85254156) SHA1(aae9531980d1b394d86e285c00c7384601875470) )
4582   ROM_LOAD32_WORD("mpr-19172.5",  0x1800000, 0x400000, CRC(9214aaaf) SHA1(769ad943ca90f0f3cc81f00e7a8cca95c660d266) )
4583   ROM_LOAD32_WORD("mpr-19173.6",  0x1800002, 0x400000, CRC(31adbeed) SHA1(3984be892f0dce21c8d423dda055ef7e57df4d4e) )
4584
4585   ROM_REGION( 0x800000, "user2", 0 ) // Models
4586   ROM_LOAD32_WORD("mpr-19180.17", 0x000000, 0x400000, CRC(d2e311a5) SHA1(83fb31c6ad7c32f1a7bcf870edb2719653c3db97) )
4587   ROM_LOAD32_WORD("mpr-19181.21", 0x000002, 0x400000, CRC(09a86c33) SHA1(30601c5b00fa3c9db815f60a0de16576e34b8c42) )
4588
4589   ROM_REGION( 0x800000, "user3", 0 ) // Textures
4590   ROM_LOAD32_WORD("mpr-19183.27", 0x000000, 0x400000, CRC(5e29074b) SHA1(f4dfa396653aeb649ec170c9584ea1a74377929a) )
4591   ROM_LOAD32_WORD("mpr-19182.25", 0x000002, 0x400000, CRC(c899923d) SHA1(15cc86c885329227d3c19e9837363eaf6c38829b) )
4592
4593   ROM_REGION( 0x800000, "user5", ROMREGION_ERASE00 ) // Coprocessor Data ROM
4594
4595   ROM_REGION( 0x100000, "audiocpu", 0 ) // Sound program
4596   ROM_LOAD16_WORD_SWAP("epr-19184.31", 0x080000,  0x80000, CRC(c013a163) SHA1(c564df8295e3c19082ead0eb22478dc651e0b430) )
4597
4598   ROM_REGION( 0x600000, "scsp", 0 ) // Samples
4599   ROM_LOAD("mpr-19185.32", 0x000000, 0x200000, CRC(5175b7d8) SHA1(bed43db286703e95cc8025013b2d129598faab3c) )
4600   ROM_LOAD("mpr-19186.33", 0x200000, 0x200000, CRC(f23440b5) SHA1(9bb862d61ed079cb3eb0bd7a37b19c6134859b99) )
4601   ROM_LOAD("mpr-19187.34", 0x400000, 0x200000, CRC(20918769) SHA1(90951bd61654d39537c54325b6e157a019edcda8) )
4602ROM_END
4603
4604ROM_START( dynabb97 ) /* Dynamite Baseball 97 Revision A, Model 2B */
4605   ROM_REGION( 0x200000, "maincpu", 0 ) // i960 program
45724606   ROM_LOAD32_WORD("epr-19833a.15", 0x000000, 0x080000, CRC(d99ed1b2) SHA1(b04613d564c04c35feafccad56ed85810d894185) )
45734607   ROM_LOAD32_WORD("epr-19834a.16", 0x000002, 0x080000, CRC(24192bb1) SHA1(c535ab4b38ffd42f03eed6a5a1706e867eaccd67) )
45744608   ROM_LOAD32_WORD("epr-19831a.13", 0x100000, 0x080000, CRC(0527ea40) SHA1(8e80e2627aafe395d8ced4a97ba50cd9a781fb45) )
r14481r14482
45914625   ROM_LOAD32_WORD("mpr-19846.22", 0x800002, 0x400000, CRC(fe53cd17) SHA1(58eab07976972917c345a8d3a50ff1e96e5fa798) )
45924626
45934627   ROM_REGION( 0x800000, "user3", 0 ) // Textures
4594   ROM_LOAD32_WORD("mpr-19848.27", 0x0000000, 0x400000, CRC(4c0526b7) SHA1(e8db7125be8a052e41a00c69cc08ca0d75b3b96f) )
4595   ROM_LOAD32_WORD("mpr-19847.25", 0x0000002, 0x400000, CRC(fe55edbd) SHA1(b0b6135b23349d7d6ae007002d8df83748cab7b1) )
4628   ROM_LOAD32_WORD("mpr-19848.27", 0x000000, 0x400000, CRC(4c0526b7) SHA1(e8db7125be8a052e41a00c69cc08ca0d75b3b96f) )
4629   ROM_LOAD32_WORD("mpr-19847.25", 0x000002, 0x400000, CRC(fe55edbd) SHA1(b0b6135b23349d7d6ae007002d8df83748cab7b1) )
45964630
45974631   ROM_REGION( 0x800000, "user5", ROMREGION_ERASE00 ) // Coprocessor Data ROM
45984632
r14481r14482
46004634   ROM_LOAD16_WORD_SWAP("epr-19849.31", 0x080000,  0x80000, CRC(b0d5bff0) SHA1(1fb824adaf3ed330a8039be726a87eb85c00abd7) )
46014635
46024636   ROM_REGION( 0x800000, "scsp", 0 ) // Samples
4603   ROM_LOAD("mpr-19880.32", 0x000000, 0x200000, CRC(e1fd27bf) SHA1(a7189ad398138a91f96b192cb7c112c0301dcda4) )
4604   ROM_LOAD("mpr-19850.33", 0x200000, 0x200000, CRC(dc644077) SHA1(8765bdb1d471dbeea065a97ae131f2d8f78aa13d) )
4605   ROM_LOAD("mpr-19851.34", 0x400000, 0x200000, CRC(cfda4efd) SHA1(14d55f127da6673c538c2ef9be34a4e02ca449f3) )
4637   ROM_LOAD("mpr-19850.32", 0x000000, 0x200000, CRC(e1fd27bf) SHA1(a7189ad398138a91f96b192cb7c112c0301dcda4) )
4638   ROM_LOAD("mpr-19851.33", 0x200000, 0x200000, CRC(dc644077) SHA1(8765bdb1d471dbeea065a97ae131f2d8f78aa13d) )
4639   ROM_LOAD("mpr-19852.34", 0x400000, 0x200000, CRC(cfda4efd) SHA1(14d55f127da6673c538c2ef9be34a4e02ca449f3) )
46064640   ROM_LOAD("mpr-19853.35", 0x600000, 0x200000, CRC(cfc64857) SHA1(cf51fafb3d45bf799b9ccb407bee862e15c95981) )
46074641ROM_END
46084642
r14481r14482
52215255GAME( 1996, sgt24h,          0, model2b, srallyc, sgt24h, ROT0, "Jaleco", "Super GT 24h", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
52225256GAME( 1996, von,             0, model2b, model2, 0,       ROT0, "Sega", "Virtual On Cyber Troopers (US, Revision B)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
52235257GAME( 1996, vonj,          von, model2b, model2, 0,       ROT0, "Sega", "Virtual On Cyber Troopers (Japan, Revision B)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
5224GAME( 1997, dynabb,          0, model2b, model2, 0,       ROT0, "Sega", "Dynamite Baseball '97 (Revision A)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
5258GAME( 1996, dynabb,          0, model2b, model2, 0,       ROT0, "Sega", "Dynamite Baseball", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
5259GAME( 1997, dynabb97,        0, model2b, model2, 0,       ROT0, "Sega", "Dynamite Baseball 97 (Revision A)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
52255260GAME( 1997, zerogun,         0, model2b, model2, zerogun, ROT0, "Psikyo", "Zero Gunner (Export, Model 2B)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
52265261GAME( 1997, zerogunj,  zerogun, model2b, model2, zerogun, ROT0, "Psikyo", "Zero Gunner (Japan, Model 2B)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
52275262GAME( 1998, dynamcopb,dynamcop, model2b, model2, genprot, ROT0, "Sega", "Dynamite Cop (Export, Model 2B)", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS )
src/mame/drivers/jpmimpct.c
r14481r14482
37873787   ROM_LOAD16_BYTE( "7606.bin", 0x000000, 0x020000, CRC(90dae2a6) SHA1(38b790a3eb2aad3d2c039b27c18a1331b5c57b46) )
37883788
37893789   ROM_REGION( 0x80000, "upd", ROMREGION_ERASE00 )
3790   /* missing? */
3790   ROM_LOAD( "popoli_snd.bin", 0x000000, 0x080000, CRC(e982a788) SHA1(3c6aed29892011c3d7d076ea9bef5882f7ded055) )
37913791ROM_END
37923792
37933793
src/mame/drivers/kinst.c
r14481r14482
166166static MACHINE_START( kinst )
167167{
168168   kinst_state *state = machine.driver_data<kinst_state>();
169   /* set the fastest DRC options */
170   mips3drc_set_options(machine.device("maincpu"), MIPS3DRC_FASTEST_OPTIONS);
171
172   /* configure fast RAM regions for DRC */
173   mips3drc_add_fastram(machine.device("maincpu"), 0x08000000, 0x087fffff, FALSE, state->m_rambase2);
174   mips3drc_add_fastram(machine.device("maincpu"), 0x00000000, 0x0007ffff, FALSE, state->m_rambase);
175   mips3drc_add_fastram(machine.device("maincpu"), 0x1fc00000, 0x1fc7ffff, TRUE,  state->m_rombase);
176}
177
178
179
180/*************************************
181 *
182 *  Machine init
183 *
184 *************************************/
185
186static MACHINE_RESET( kinst )
187{
188   kinst_state *state = machine.driver_data<kinst_state>();
169189   device_t *ide = machine.device("ide");
170190   UINT8 *features = ide_get_features(ide,0);
171191
r14481r14482
198218      features[14*2+1] = 0x41;
199219   }
200220
201   /* set the fastest DRC options */
202   mips3drc_set_options(machine.device("maincpu"), MIPS3DRC_FASTEST_OPTIONS);
203
204   /* configure fast RAM regions for DRC */
205   mips3drc_add_fastram(machine.device("maincpu"), 0x08000000, 0x087fffff, FALSE, state->m_rambase2);
206   mips3drc_add_fastram(machine.device("maincpu"), 0x00000000, 0x0007ffff, FALSE, state->m_rambase);
207   mips3drc_add_fastram(machine.device("maincpu"), 0x1fc00000, 0x1fc7ffff, TRUE,  state->m_rombase);
208}
209
210
211
212/*************************************
213 *
214 *  Machine init
215 *
216 *************************************/
217
218static MACHINE_RESET( kinst )
219{
220   kinst_state *state = machine.driver_data<kinst_state>();
221221   /* set a safe base location for video */
222222   state->m_video_base = &state->m_rambase[0x30000/4];
223223}
src/mame/drivers/vamphalf.c
r14481r14482
15811581   ROM_LOAD( "qs1001a",  0x000000, 0x80000, CRC(d13c6407) SHA1(57b14f97c7d4f9b5d9745d3571a0b7115fbe3176) )
15821582ROM_END
15831583
1584ROM_START( wyvernwga )
1585   ROM_REGION32_BE( 0x100000, "user1", ROMREGION_ERASE00 ) /* Hyperstone CPU Code */
1586   ROM_LOAD( "rom1.rom", 0x000000, 0x080000, CRC(586881fd) SHA1(d335bbd91def8fa4935eb2375c9b00471a1f40eb) )
1587   ROM_LOAD( "rom2.rom", 0x080000, 0x080000, CRC(938049ec) SHA1(cc10944c99ceb388dd4aafc93377c40540861d14) )
1588
1589   ROM_REGION( 0x020000, "audiocpu", 0 ) /* QDSP ('51) Code */
1590   ROM_LOAD( "u7", 0x0000, 0x20000, CRC(00a3f705) SHA1(f0a6bafd16bea53d4c05c8cc108983cbd41e5757) )
1591
1592   ROM_REGION( 0x1000000, "gfx1", 0 )  /* gfx data */
1593   ROM_LOAD32_WORD( "roml00", 0x000000, 0x200000, CRC(fb3541b6) SHA1(4f569ac7bde92c5febf005ab73f76552421ec223) )
1594   ROM_LOAD32_WORD( "romh00", 0x000002, 0x200000, CRC(516aca48) SHA1(42cf5678eb4c0ee7da2ab0bd66e4e34b2735c75a) )
1595   ROM_LOAD32_WORD( "roml01", 0x400000, 0x200000, CRC(1c764f95) SHA1(ba6ac1376e837b491bc0269f2a1d10577a3d40cb) )
1596   ROM_LOAD32_WORD( "romh01", 0x400002, 0x200000, CRC(fee42c63) SHA1(a27b5cbca0defa9be85fee91dde1273f445d3372) )
1597   ROM_LOAD32_WORD( "roml02", 0x800000, 0x200000, CRC(fc846707) SHA1(deaee15ab71927f644dcf576959e2ceaa55bfd44) )
1598   ROM_LOAD32_WORD( "romh02", 0x800002, 0x200000, CRC(86141c7d) SHA1(22a82cc7d44d655b03867503a83e81f7c82d6c91) )
1599   ROM_LOAD32_WORD( "roml03", 0xc00000, 0x200000, CRC(b10bf37c) SHA1(6af835b1e2573f0bb2c17057e016a7aecc8fcde8) )
1600   ROM_LOAD32_WORD( "romh03", 0xc00002, 0x200000, CRC(e01c2a92) SHA1(f53c2db92d62f595d473b1835c46d426f0dbe6b3) )
1601
1602   ROM_REGION( 0x200000, "sfx", 0 ) /* Music data / QDSP samples (SFX) */
1603   ROM_LOAD( "romsnd.u15a",  0x000000, 0x200000, CRC(fc89eedc) SHA1(2ce28bdb773cfa5b5660e4c0a9ef454cb658f2da) )
1604
1605   ROM_REGION( 0x080000, "wavetable", 0 ) /* QDSP wavetable rom */
1606   ROM_LOAD( "qs1001a",  0x000000, 0x80000, CRC(d13c6407) SHA1(57b14f97c7d4f9b5d9745d3571a0b7115fbe3176) )
1607ROM_END
1608
15841609/*
15851610
15861611Mission Craft
r14481r14482
20682093
20692094static READ32_HANDLER( wyvernwg_speedup_r )
20702095{
2096   int pc = cpu_get_pc(&space->device());
2097
20712098   vamphalf_state *state = space->machine().driver_data<vamphalf_state>();
2072   if(cpu_get_pc(&space->device()) == 0x10758 )
2099   if(pc == 0x10758)
20732100   {
20742101      if(irq_active(space))
20752102         device_spin_until_interrupt(&space->device());
r14481r14482
20802107   return state->m_wram32[0x00b56fc/4];
20812108}
20822109
2110static READ32_HANDLER( wyvernwga_speedup_r )
2111{
2112   int pc = cpu_get_pc(&space->device());
2113
2114   vamphalf_state *state = space->machine().driver_data<vamphalf_state>();
2115   if(pc == 0x10758)
2116   {
2117      if(irq_active(space))
2118         device_spin_until_interrupt(&space->device());
2119      else
2120         device_eat_cycles(&space->device(), 50);
2121   }
2122
2123   return state->m_wram32[0x00b74f8/4];
2124}
2125
2126
2127
20832128static READ32_HANDLER( finalgdr_speedup_r )
20842129{
20852130   vamphalf_state *state = space->machine().driver_data<vamphalf_state>();
r14481r14482
22672312{
22682313   vamphalf_state *state = machine.driver_data<vamphalf_state>();
22692314   machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x00b56fc, 0x00b56ff, FUNC(wyvernwg_speedup_r) );
2315   machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x00b74f8, 0x00b74fb, FUNC(wyvernwga_speedup_r) );
22702316
22712317   state->m_palshift = 0;
22722318   state->m_flip_bit = 1;
r14481r14482
23792425GAME( 2001, finalgdr, 0,        finalgdr, finalgdr, finalgdr, ROT0,   "SemiCom",           "Final Godori (Korea, version 2.20.5915)", 0 )
23802426GAME( 2001, mrkicker, 0,        mrkicker, finalgdr, mrkicker, ROT0,   "SemiCom",           "Mr. Kicker", GAME_NOT_WORKING ) // game stops booting / working properly after you get a high score, or if you don't have a default eeprom with 'valid data.  It's never worked properly, CPU core issue?
23812427GAME( 2001, toyland,  0,        coolmini, common,   toyland,  ROT0,   "SemiCom",           "Toy Land Adventure", 0 )
2382GAME( 2001, wyvernwg, 0,        wyvernwg, common,   wyvernwg, ROT270, "SemiCom (Game Vision license)", "Wyvern Wings", GAME_NO_SOUND )
2428GAME( 2001, wyvernwg, 0,        wyvernwg, common,   wyvernwg, ROT270, "SemiCom (Game Vision license)", "Wyvern Wings (set 1)", GAME_NO_SOUND )
2429GAME( 2001, wyvernwga,wyvernwg, wyvernwg, common,   wyvernwg, ROT270, "SemiCom (Game Vision license)", "Wyvern Wings (set 2)", GAME_NO_SOUND )
23832430GAME( 2001, aoh,      0,        aoh,      aoh,      aoh,      ROT0,   "Unico",             "Age Of Heroes - Silkroad 2 (v0.63 - 2001/02/07)", 0 )
23842431GAME( 2001, boonggab, 0,        boonggab, boonggab, boonggab, ROT270, "Taff System",      "Boong-Ga Boong-Ga (Spank'em!)", 0 )
src/mame/drivers/bfm_sc2.c
r14481r14482
49304930   ROM_REGION( 0x10000, "maincpu", 0 )
49314931   ROM_LOAD( "alongtheprom.bin", 0x0000, 0x010000, CRC(0f212ba9) SHA1(34dfe67f8cbdf1cba806dcc7a3e872a8b59747d3) )
49324932
4933   ROM_REGION( 0x20000, "matrix", 0 )
4934   ROM_LOAD("alongthepromdot.bin",  0x00000, 0x10000, CRC(b5a96f4d) SHA1(716dda738e8437b13cb72a6b071e0898abceb647))
4935
49334936   ROM_REGION( 0x200000, "upd", ROMREGION_ERASE00 )
49344937   ROM_LOAD( "alongthepromsnd.bin", 0x0000, 0x040000, CRC(380f56af) SHA1(9125c09e6585e6f4a2de9ea8715371662245aa9a) )
49354938ROM_END
r14481r14482
54775480GAME( 199?, sc2rock      , 0         ,  scorpion2      , drwho      , drwho      , 0,       "Global",   "How Big's Your Rock (Global) (Scorpion 2/3)", GAME_FLAGS)
54785481GAME( 199?, sc2call      , 0         ,  scorpion2      , drwho      , drwho      , 0,       "Global",   "It's Your Call (Global) (Scorpion 2/3)", GAME_FLAGS)
54795482
5480GAME( 199?, sc2prom      , 0         ,  scorpion2      , drwho      , drwho      , 0,       "BFM",   "Along The Prom (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
54815483GAME( 199?, sc2payr      , 0         ,  scorpion2      , drwho      , drwho      , 0,       "BFM/Mazooma",   "Pay Roll Casino (Bellfruit/Mazooma) (Scorpion 2/3)", GAME_FLAGS)
54825484
54835485GAME( 199?, sc2bar7      , 0         ,  scorpion2      , drwho      , drwho      , 0,       "Concept",   "Bar 7 (Concept)", GAME_FLAGS)
r14481r14482
55255527GAME( 199?, sc2cops      , 0         ,  scorpion2_dm01   , drwho      , drwho      , 0,       "BFM",      "Cops 'n' Robbers (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
55265528GAME( 199?, sc2copcl   , 0         ,  scorpion2_dm01   , drwho      , drwho      , 0,       "BFM",      "Cops 'n' Robbers Club (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
55275529GAME( 199?, sc2copdc   , 0         ,  scorpion2_dm01   , drwho      , drwho      , 0,       "BFM",      "Cops 'n' Robbers Club Deluxe (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
5530GAME( 199?, sc2prom      , 0         ,  scorpion2_dm01   , drwho      , drwho      , 0,       "BFM",      "Along The Prom (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
55285531GAME( 199?, sc2prem      , 0         ,  scorpion2_dm01   , drwho      , drwho      , 0,       "BFM",      "Premier Club Manager (Bellfruit) (Scorpion 2/3)", GAME_FLAGS)
55295532
src/mame/drivers/aleck64.c
r14481r14482
800800   62500000         /* system clock */
801801};
802802
803static INTERRUPT_GEN( n64_vblank )
804{
805   signal_rcp_interrupt(device->machine(), VI_INTERRUPT);
806}
807
808803static MACHINE_CONFIG_START( aleck64, n64_state )
809804
810805   /* basic machine hardware */
811806   MCFG_CPU_ADD("maincpu", VR4300BE, 93750000)
812807   MCFG_CPU_CONFIG(vr4300_config)
813808   MCFG_CPU_PROGRAM_MAP(n64_map)
814   MCFG_CPU_VBLANK_INT("screen", n64_vblank)
815809
816810   MCFG_CPU_ADD("rsp", RSP, 62500000)
817811   MCFG_CPU_CONFIG(n64_rsp_config)
src/mame/drivers/seicross.c
r14481r14482
408408   MCFG_CPU_IO_MAP(main_portmap)
409409   MCFG_CPU_VBLANK_INT("screen", vblank_irq)
410410
411   MCFG_CPU_ADD("mcu", NSC8105, 6000000)   /* ??? */
411   MCFG_CPU_ADD("mcu", NSC8105, 3072000)   /* ??? */
412412   MCFG_CPU_PROGRAM_MAP(mcu_nvram_map)
413413
414414   MCFG_QUANTUM_TIME(attotime::from_hz(1200))   /* 20 CPU slices per frame - an high value to ensure proper */
src/mame/drivers/cps3.c
r14481r14482
5454From late 1996 to 1999 Capcom developed another hardware platform to rival the CPS2 System and called
5555it CP SYSTEM III. Only 6 games were produced. Here's a detailed table of all known releases until now:
5656
57                                                           |--------------- Cart ----------------|  |--------------- CD --------------|
58Game                                                 Year  Part #     Label      Region  CD  NO CD  Part #      Catalog #   Label        Revision
59---------------------------------------------------  ----  ---------  ---------  ------  --  -----  ----------  ----------  -----------  --------
60Warzard                                              1996  WZD96a00F  CP300000G  JAPAN   X          CAP-WZD000  CAP-WZD-3   CAP-WZD-3    961023
61Warzard                                                    WZD96a00F  CP300000G  JAPAN   X          CAP-WZD000  CAP-WZD-5   CAP-WZD-5    961121
62Red Earth                                                  WZD96aA0F  CP3000B0G  EUROPE  X          CAP-WZD0A0  CAP-WZD-3   CAP-WZD-3    961023
63Red Earth                                                  WZD96aA0F  CP3000B0G  EUROPE  X          CAP-WZD0A0  CAP-WZD-5   CAP-WZD-5    961121
64Red Earth                                                  WZD96aA0F  CP3000H0G  MEXICO* X          CAP-WZD0A0  CAP-WZD-3   CAP-WZD-3    961023
65Red Earth                                                  WZD96aA0F  CP3000H0G  MEXICO* X          CAP-WZD0A0  CAP-WZD-5   CAP-WZD-5    961121
66Red Earth                                                  WZD96aA0F  CP3000U0G  USA*    X          CAP-WZD0A0  CAP-WZD-3   CAP-WZD-3    961023
67Red Earth                                                  WZD96aA0F  CP3000U0G  USA*    X          CAP-WZD0A0  CAP-WZD-5   CAP-WZD-5    961121
57                                                           |--------------- Cart ----------------|  |--------------- CD ---------------|
58Game                                                 Year  Part #     Label      Region  CD  NO CD  Part #      Catalog #    Label        Revision
59---------------------------------------------------  ----  ---------  ---------  ------  --  -----  ----------  -----------  -----------  --------
60Warzard                                              1996  WZD96a00F  CP300000G  JAPAN   X          CAP-WZD000  CAP-WZD-3    CAP-WZD-3    961023
61Warzard                                                    WZD96a00F  CP300000G  JAPAN   X          CAP-WZD000  CAP-WZD-5    CAP-WZD-5    961121
62Red Earth                                                  WZD96aA0F  CP3000B0G  EUROPE  X          CAP-WZD0A0  CAP-WZD-3    CAP-WZD-3    961023
63Red Earth                                                  WZD96aA0F  CP3000B0G  EUROPE  X          CAP-WZD0A0  CAP-WZD-5    CAP-WZD-5    961121
64Red Earth                                                  WZD96aA0F  CP3000H0G  MEXICO* X          CAP-WZD0A0  CAP-WZD-3    CAP-WZD-3    961023
65Red Earth                                                  WZD96aA0F  CP3000H0G  MEXICO* X          CAP-WZD0A0  CAP-WZD-5    CAP-WZD-5    961121
66Red Earth                                                  WZD96aA0F  CP3000U0G  USA*    X          CAP-WZD0A0  CAP-WZD-3    CAP-WZD-3    961023
67Red Earth                                                  WZD96aA0F  CP3000U0G  USA*    X          CAP-WZD0A0  CAP-WZD-5    CAP-WZD-5    961121
6868
69Street Fighter III: New Generation                   1997  SF397200F  CP300000G  JAPAN   X          CAP-SF3000  CAP-SF3-3   CAP-SF3-3    970204
70Street Fighter III: New Generation                         SF397200F  CP300000G  JAPAN   X          CAP-SF3000  ?           ?            970312*
71Street Fighter III: New Generation                         SF397200F  CP300000G  JAPAN   X          CAP-SF3000  ?           ?            970403*
72Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                           970204
73Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                           970312*
74Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                           970403*
75Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  CAP-SF3-3   CAP-SF3-3    970204
76Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  ?           ?            970312*
77Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  ?           ?            970403*
78Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  CAP-SF3-3   CAP-SF3-3    970204
79Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  ?           ?            970312*
80Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  ?           ?            970403*
69Street Fighter III: New Generation                   1997  SF397200F  CP300000G  JAPAN   X          CAP-SF3000  CAP-SF3-3    CAP-SF3-3    970204
70Street Fighter III: New Generation                         SF397200F  CP300000G  JAPAN   X          CAP-SF3000  ?            ?            970312*
71Street Fighter III: New Generation                         SF397200F  CP300000G  JAPAN   X          CAP-SF3000  ?            ?            970403*
72Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                            970204
73Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                            970312*
74Street Fighter III: New Generation                         SF3972A0F  CP3000C0G  ASIA        X                                            970403*
75Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  CAP-SF3-3    CAP-SF3-3    970204
76Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  ?            ?            970312*
77Street Fighter III: New Generation                         SF3972A0F  CP3000H0G  MEXICO  X          CAP-SF30A0  ?            ?            970403*
78Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  CAP-SF3-3    CAP-SF3-3    970204
79Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  ?            ?            970312*
80Street Fighter III: New Generation                         SF3972A0F  CP3000U0G  USA     X          CAP-SF30A0  ?            ?            970403*
8181
82Street Fighter III 2nd Impact: Giant Attack          1997  3GA97a00F  CP300000G  JAPAN   X          CAP-3GA000  CAP-3GA000  CAP-3GA-1    970930
83Street Fighter III 2nd Impact: Giant Attack                3GA97a00F  CP300000G  JAPAN   X          CAP-3GA000  ?           ?            971016*
84Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000C0G  ASIA        X                                           970930
85Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000C0G  ASIA        X                                           971016*
86Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000U0G  USA     X          CAP-3GA0A0  CAP-3GA000  CAP-3GA-1    970930
87Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000U0G  USA     X          CAP-3GA0A0  ?           ?            971016*
82Street Fighter III 2nd Impact: Giant Attack          1997  3GA97a00F  CP300000G  JAPAN   X          CAP-3GA000  CAP-3GA000   CAP-3GA-1    970930
83Street Fighter III 2nd Impact: Giant Attack                3GA97a00F  CP300000G  JAPAN   X          CAP-3GA000  ?            ?            971016*
84Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000C0G  ASIA        X                                            970930
85Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000C0G  ASIA        X                                            971016*
86Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000U0G  USA     X          CAP-3GA0A0  CAP-3GA000   CAP-3GA-1    970930
87Street Fighter III 2nd Impact: Giant Attack                3GA97aA0F  CP3000U0G  USA     X          CAP-3GA0A0  ?            ?            971016*
8888
89JoJo no Kimyouna Bouken                              1998  JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  CAP-JJK000  CAP-JJK-140  981202
90JoJo no Kimyouna Bouken                                    JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  CAP-JJK-2   CAP-JJK-160  990108
91JoJo no Kimyouna Bouken                                    JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  ?           ?            990128*
92JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                           981202
93JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                           990108
94JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                           990128*
95JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  CAP-JJK000  CAP-JJK-140  981202
96JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  CAP-JJK-2   CAP-JJK-160  990108
97JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  ?           ?            990128*
89JoJo no Kimyouna Bouken                              1998  JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  CAP-JJK000   CAP-JJK-140  981202
90JoJo no Kimyouna Bouken                                    JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  CAP-JJK-2    CAP-JJK-160  990108
91JoJo no Kimyouna Bouken                                    JJK98c00F  CP300000G  JAPAN   X          CAP-JJK000  ?            ?            990128*
92JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                            981202
93JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                            990108
94JoJo's Venture                                             JJK98cA0F  CP3000C0G  ASIA        X                                            990128*
95JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  CAP-JJK000   CAP-JJK-140  981202
96JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  CAP-JJK-2    CAP-JJK-160  990108
97JoJo's Venture                                             JJK98cA0F  CP3000U0G  USA     X          CAP-JJK0A0  ?            ?            990128*
9898
99Street Fighter III 3rd Strike: Fight for the Future  1999  33S99400F  CP300000G  JAPAN*  X          CAP-33S000  CAP-33S-1   CAP-33S-1    990512
100Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN*  X          CAP-33S000  CAP-33S-2   CAP-33S-2    990608
101Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN       X                                           990512
102Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN       X                                           990608
103Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000B0G  EUROPE  X          CAP-33S0A0  CAP-33S-1   CAP-33S-1    990512
104Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000B0G  EUROPE  X          CAP-33S0A0  CAP-33S-2   CAP-33S-2    990608
105Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*   X          CAP-33S0A0  CAP-33S-1   CAP-33S-1    990512
106Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*   X          CAP-33S0A0  CAP-33S-2   CAP-33S-2    990608
107Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*       X                                           990512
108Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*       X                                           990608
109Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000H0G  MEXICO* ?          CAP-33S0A0  CAP-33S-1   CAP-33S-1    990512
110Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000H0G  MEXICO* ?          CAP-33S0A0  CAP-33S-2   CAP-33S-2    990608
111Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000U0G  USA     X          CAP-33S0A0  CAP-33S-1   CAP-33S-1    990512
112Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000U0G  USA     X          CAP-33S0A0  CAP-33S-2   CAP-33S-2    990608
99Street Fighter III 3rd Strike: Fight for the Future  1999  33S99400F  CP300000G  JAPAN*  X          CAP-33S000  CAP-33S-1    CAP-33S-1    990512
100Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN*  X          CAP-33S000  CAP-33S-2    CAP-33S-2    990608
101Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN       X                                            990512
102Street Fighter III 3rd Strike: Fight for the Future        33S99400F  CP300000G  JAPAN       X                                            990608
103Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000B0G  EUROPE  X          CAP-33S0A0  CAP-33S-1    CAP-33S-1    990512
104Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000B0G  EUROPE  X          CAP-33S0A0  CAP-33S-2    CAP-33S-2    990608
105Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*   X          CAP-33S0A0  CAP-33S-1    CAP-33S-1    990512
106Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*   X          CAP-33S0A0  CAP-33S-2    CAP-33S-2    990608
107Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*       X                                            990512
108Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000C0G  ASIA*       X                                            990608
109Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000H0G  MEXICO* ?          CAP-33S0A0  CAP-33S-1    CAP-33S-1    990512
110Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000H0G  MEXICO* ?          CAP-33S0A0  CAP-33S-2    CAP-33S-2    990608
111Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000U0G  USA     X          CAP-33S0A0  CAP-33S-1    CAP-33S-1    990512
112Street Fighter III 3rd Strike: Fight for the Future        33S994A0F  CP3000U0G  USA     X          CAP-33S0A0  CAP-33S-2    CAP-33S-2    990608
113113
114JoJo no Kimyouna Bouken: Miraie no Isan              1999  JJM99900F  CP300000G  JAPAN   X          CAP-JJM000  CAP-JJM-0   CAP-JJM-110  990913
115JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN   X          CAP-JJM000  ?           ?            990927*
116JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN       X                                           990913
117JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN       X                                           990927*
118JoJo's Bizarre Adventure                                   JJM999A0F  CP3000B0G  EUROPE      X                                           990913
119JoJo's Bizarre Adventure                                   JJM999A0F  CP3000B0G  EUROPE      X                                           990927*
114JoJo no Kimyouna Bouken: Miraie no Isan              1999  JJM99900F  CP300000G  JAPAN   X          CAP-JJM000  CAP-JJM-0    CAP-JJM-110  990913
115JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN   X          CAP-JJM000  CAP-JJM-120  CAP-JJM-120  990927
116JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN       X                                            990913
117JoJo no Kimyouna Bouken: Miraie no Isan                    JJM99900F  CP300000G  JAPAN       X                                            990927
118JoJo's Bizarre Adventure                                   JJM999A0F  CP3000B0G  EUROPE      X                                            990913
119JoJo's Bizarre Adventure                                   JJM999A0F  CP3000B0G  EUROPE      X                                            990927
120120
121121* NOT DUMPED but known to exist
122122
r14481r14482
29202920#define SFIII3_990512_CDROM \
29212921   DISK_REGION( "cdrom" ) DISK_IMAGE_READONLY( "cap-33s-1", 0, SHA1(2f4a9006a31903114f9f9dc09465ae253e565c51) ) \
29222922
2923#define JOJOBA_990913_FLASH \
2924   ROM_REGION( 0x200000, "simm1.0", 0 ) ROM_LOAD( "jojoba-simm1.0", 0x00000, 0x200000, CRC(76976231) SHA1(90adde7e5983ec6a4e02789d5cefe9e85c9c52d5) ) \
2925   ROM_REGION( 0x200000, "simm1.1", 0 ) ROM_LOAD( "jojoba-simm1.1", 0x00000, 0x200000, CRC(cedd78e7) SHA1(964988b90a2f14c1da2cfc48d943e16e54da3fd3) ) \
2926   ROM_REGION( 0x200000, "simm1.2", 0 ) ROM_LOAD( "jojoba-simm1.2", 0x00000, 0x200000, CRC(2955b77f) SHA1(2a907a5cd91448bfc420c318584e5ef4bbe55a91) ) \
2927   ROM_REGION( 0x200000, "simm1.3", 0 ) ROM_LOAD( "jojoba-simm1.3", 0x00000, 0x200000, CRC(280139d7) SHA1(b7c28f6f0218688fb873a3106d2f95ea2e1e927c) ) \
2928   ROM_REGION( 0x200000, "simm2.0", 0 ) ROM_LOAD( "jojoba-simm2.0", 0x00000, 0x200000, CRC(305c4914) SHA1(c3a73ffe58f61ab8f1cd9e3f0891037638dc5a9b) ) \
2929   ROM_REGION( 0x200000, "simm2.1", 0 ) ROM_LOAD( "jojoba-simm2.1", 0x00000, 0x200000, CRC(18af4f3b) SHA1(04b8fdf23a782b10c203b111cc634a6d3474044a) ) \
2930   ROM_REGION( 0x200000, "simm2.2", 0 ) ROM_LOAD( "jojoba-simm2.2", 0x00000, 0x200000, CRC(397e5c9e) SHA1(021d86ee66bf951fb6a1dd90fb7007c6865cbb8b) ) \
2931   ROM_REGION( 0x200000, "simm2.3", 0 ) ROM_LOAD( "jojoba-simm2.3", 0x00000, 0x200000, CRC(a9d0a7d7) SHA1(b2cfc0661f8903ddbeea8a604ee8b42097e10ab8) ) \
2923#define JOJOBA_990927_FLASH \
2924   ROM_REGION( 0x200000, "simm1.0", 0 ) ROM_LOAD( "jojoba-simm1.0", 0x00000, 0x200000, CRC(adcd8377) SHA1(f1aacbe061e3bcade5cca34435c3f86aec5f1499) ) \
2925   ROM_REGION( 0x200000, "simm1.1", 0 ) ROM_LOAD( "jojoba-simm1.1", 0x00000, 0x200000, CRC(d7590b59) SHA1(bfee627ebb7cb7b28216527b17e1b06a4e6f19f4) ) \
2926   ROM_REGION( 0x200000, "simm1.2", 0 ) ROM_LOAD( "jojoba-simm1.2", 0x00000, 0x200000, CRC(e62e240b) SHA1(70468cae67c009a80b45954c2a30794577343c77) ) \
2927   ROM_REGION( 0x200000, "simm1.3", 0 ) ROM_LOAD( "jojoba-simm1.3", 0x00000, 0x200000, CRC(c95450c3) SHA1(55616e009b007180d1ac6290c8da44b0d864a494) ) \
2928   ROM_REGION( 0x200000, "simm2.0", 0 ) ROM_LOAD( "jojoba-simm2.0", 0x00000, 0x200000, CRC(535f2eba) SHA1(167bec0dccfc2f91cb10cb1e2631ee619b3eb9fe) ) \
2929   ROM_REGION( 0x200000, "simm2.1", 0 ) ROM_LOAD( "jojoba-simm2.1", 0x00000, 0x200000, CRC(01dd3a01) SHA1(08c462219796baa3ec28d78d038a18187cd838bb) ) \
2930   ROM_REGION( 0x200000, "simm2.2", 0 ) ROM_LOAD( "jojoba-simm2.2", 0x00000, 0x200000, CRC(61432672) SHA1(d0416a75d395926041f90a3d34edb96a080acfd6) ) \
2931   ROM_REGION( 0x200000, "simm2.3", 0 ) ROM_LOAD( "jojoba-simm2.3", 0x00000, 0x200000, CRC(acdc9aca) SHA1(89f77ddd6286709182a676fd9bd6c333a3b16271) ) \
29322932   ROM_REGION( 0x200000, "simm3.0", 0 ) ROM_LOAD( "jojoba-simm3.0", 0x00000, 0x200000, CRC(4d16e111) SHA1(f198007375be65e89856d64ee2b3857a18b4eab8) ) \
29332933   ROM_REGION( 0x200000, "simm3.1", 0 ) ROM_LOAD( "jojoba-simm3.1", 0x00000, 0x200000, CRC(9b3406d3) SHA1(54e90cd334d13e2c74305c6b87ebce1365ef3d59) ) \
29342934   ROM_REGION( 0x200000, "simm3.2", 0 ) ROM_LOAD( "jojoba-simm3.2", 0x00000, 0x200000, CRC(f2414997) SHA1(fb89d5784250538ad17fd527267b513afb6eca20) ) \
r14481r14482
29542954   ROM_REGION( 0x200000, "simm5.6", 0 ) ROM_LOAD( "jojoba-simm5.6", 0x00000, 0x200000, CRC(4fb32906) SHA1(3a5965b3197517932c8aa4c07a6ea6a190a338d7) ) \
29552955   ROM_REGION( 0x200000, "simm5.7", 0 ) ROM_LOAD( "jojoba-simm5.7", 0x00000, 0x200000, CRC(8c8be520) SHA1(c461f3f76a83592b36b29afb316679a7c8972404) ) \
29562956
2957#define JOJOBA_990927_CDROM \
2958   DISK_REGION( "cdrom" ) DISK_IMAGE_READONLY( "cap-jjm-120", 0, SHA1(8628d3fa555fbd5f4121082e925c1834b76c5e65) ) \
2959
2960#define JOJOBA_990913_FLASH \
2961   ROM_REGION( 0x200000, "simm1.0", 0 ) ROM_LOAD( "jojobaa-simm1.0", 0x00000, 0x200000, CRC(76976231) SHA1(90adde7e5983ec6a4e02789d5cefe9e85c9c52d5) ) \
2962   ROM_REGION( 0x200000, "simm1.1", 0 ) ROM_LOAD( "jojobaa-simm1.1", 0x00000, 0x200000, CRC(cedd78e7) SHA1(964988b90a2f14c1da2cfc48d943e16e54da3fd3) ) \
2963   ROM_REGION( 0x200000, "simm1.2", 0 ) ROM_LOAD( "jojobaa-simm1.2", 0x00000, 0x200000, CRC(2955b77f) SHA1(2a907a5cd91448bfc420c318584e5ef4bbe55a91) ) \
2964   ROM_REGION( 0x200000, "simm1.3", 0 ) ROM_LOAD( "jojobaa-simm1.3", 0x00000, 0x200000, CRC(280139d7) SHA1(b7c28f6f0218688fb873a3106d2f95ea2e1e927c) ) \
2965   ROM_REGION( 0x200000, "simm2.0", 0 ) ROM_LOAD( "jojobaa-simm2.0", 0x00000, 0x200000, CRC(305c4914) SHA1(c3a73ffe58f61ab8f1cd9e3f0891037638dc5a9b) ) \
2966   ROM_REGION( 0x200000, "simm2.1", 0 ) ROM_LOAD( "jojobaa-simm2.1", 0x00000, 0x200000, CRC(18af4f3b) SHA1(04b8fdf23a782b10c203b111cc634a6d3474044a) ) \
2967   ROM_REGION( 0x200000, "simm2.2", 0 ) ROM_LOAD( "jojobaa-simm2.2", 0x00000, 0x200000, CRC(397e5c9e) SHA1(021d86ee66bf951fb6a1dd90fb7007c6865cbb8b) ) \
2968   ROM_REGION( 0x200000, "simm2.3", 0 ) ROM_LOAD( "jojobaa-simm2.3", 0x00000, 0x200000, CRC(a9d0a7d7) SHA1(b2cfc0661f8903ddbeea8a604ee8b42097e10ab8) ) \
2969   ROM_REGION( 0x200000, "simm3.0", 0 ) ROM_LOAD( "jojoba-simm3.0",  0x00000, 0x200000, CRC(4d16e111) SHA1(f198007375be65e89856d64ee2b3857a18b4eab8) ) \
2970   ROM_REGION( 0x200000, "simm3.1", 0 ) ROM_LOAD( "jojoba-simm3.1",  0x00000, 0x200000, CRC(9b3406d3) SHA1(54e90cd334d13e2c74305c6b87ebce1365ef3d59) ) \
2971   ROM_REGION( 0x200000, "simm3.2", 0 ) ROM_LOAD( "jojoba-simm3.2",  0x00000, 0x200000, CRC(f2414997) SHA1(fb89d5784250538ad17fd527267b513afb6eca20) ) \
2972   ROM_REGION( 0x200000, "simm3.3", 0 ) ROM_LOAD( "jojoba-simm3.3",  0x00000, 0x200000, CRC(954b9c7d) SHA1(0d64d97167d4e669d7e4f3a388f9d5ec1e18ed42) ) \
2973   ROM_REGION( 0x200000, "simm3.4", 0 ) ROM_LOAD( "jojoba-simm3.4",  0x00000, 0x200000, CRC(625adc1d) SHA1(533d62759ecece10c711d99bfca403e5cba279b5) ) \
2974   ROM_REGION( 0x200000, "simm3.5", 0 ) ROM_LOAD( "jojoba-simm3.5",  0x00000, 0x200000, CRC(20a70bb4) SHA1(3bd8376304ffc974fb8031eac8bebff27969538c) ) \
2975   ROM_REGION( 0x200000, "simm3.6", 0 ) ROM_LOAD( "jojoba-simm3.6",  0x00000, 0x200000, CRC(a10ec5af) SHA1(9b403260e8fbdacaa5369ab79fc05855cc6a6bdb) ) \
2976   ROM_REGION( 0x200000, "simm3.7", 0 ) ROM_LOAD( "jojoba-simm3.7",  0x00000, 0x200000, CRC(0bd0de7a) SHA1(1debecda5f282f2a1dd17e887e522a4d00c5dc9d) ) \
2977   ROM_REGION( 0x200000, "simm4.0", 0 ) ROM_LOAD( "jojoba-simm4.0",  0x00000, 0x200000, CRC(6ea14adc) SHA1(696b2ec66f3c197817a60f507a1b4c78db37f488) ) \
2978   ROM_REGION( 0x200000, "simm4.1", 0 ) ROM_LOAD( "jojoba-simm4.1",  0x00000, 0x200000, CRC(8f4c42fb) SHA1(363d769b0b066ce139125426d2da6dfa15d1eb28) ) \
2979   ROM_REGION( 0x200000, "simm4.2", 0 ) ROM_LOAD( "jojoba-simm4.2",  0x00000, 0x200000, CRC(ef0586d1) SHA1(8fcc350da20e3e59fa76fa14e10f2c47233ba9dc) ) \
2980   ROM_REGION( 0x200000, "simm4.3", 0 ) ROM_LOAD( "jojoba-simm4.3",  0x00000, 0x200000, CRC(93ccc470) SHA1(5d267679e61c0fb592ad5f696d3c06ec1746d0b3) ) \
2981   ROM_REGION( 0x200000, "simm4.4", 0 ) ROM_LOAD( "jojoba-simm4.4",  0x00000, 0x200000, CRC(3d9ec7d2) SHA1(665b867bab928be183c2006527e55f9b8ec4a271) ) \
2982   ROM_REGION( 0x200000, "simm4.5", 0 ) ROM_LOAD( "jojoba-simm4.5",  0x00000, 0x200000, CRC(03e66850) SHA1(8478662dc9db20d9a186d315a883bd1cbb5e5000) ) \
2983   ROM_REGION( 0x200000, "simm4.6", 0 ) ROM_LOAD( "jojoba-simm4.6",  0x00000, 0x200000, CRC(01606ac3) SHA1(ccc74edeca6abdd86fc1cf42ececa1ea393b3261) ) \
2984   ROM_REGION( 0x200000, "simm4.7", 0 ) ROM_LOAD( "jojoba-simm4.7",  0x00000, 0x200000, CRC(36392b87) SHA1(e62080c8461775c1e180400dfb44414679fd0fc1) ) \
2985   ROM_REGION( 0x200000, "simm5.0", 0 ) ROM_LOAD( "jojoba-simm5.0",  0x00000, 0x200000, CRC(2ef8c60c) SHA1(dea87a73a11b8edd27c3c9c5ab2af295cb5508f9) ) \
2986   ROM_REGION( 0x200000, "simm5.1", 0 ) ROM_LOAD( "jojoba-simm5.1",  0x00000, 0x200000, CRC(cf7d7ca6) SHA1(b347707b1e5bc71d28b282273f893592e5f9e333) ) \
2987   ROM_REGION( 0x200000, "simm5.2", 0 ) ROM_LOAD( "jojoba-simm5.2",  0x00000, 0x200000, CRC(b7815bfa) SHA1(0b5a3a2ffe1b3c0ca765dcedc297e78e5928302b) ) \
2988   ROM_REGION( 0x200000, "simm5.3", 0 ) ROM_LOAD( "jojoba-simm5.3",  0x00000, 0x200000, CRC(9bfec049) SHA1(62cc9a1920047863205544b77344ee18f310f084) ) \
2989   ROM_REGION( 0x200000, "simm5.4", 0 ) ROM_LOAD( "jojoba-simm5.4",  0x00000, 0x200000, CRC(d167536b) SHA1(e2637d3486f168ce44e0a00413d38960cb86db4c) ) \
2990   ROM_REGION( 0x200000, "simm5.5", 0 ) ROM_LOAD( "jojoba-simm5.5",  0x00000, 0x200000, CRC(55e7a042) SHA1(c18bda61fa005d9174a27b7b7d324004262a4525) ) \
2991   ROM_REGION( 0x200000, "simm5.6", 0 ) ROM_LOAD( "jojoba-simm5.6",  0x00000, 0x200000, CRC(4fb32906) SHA1(3a5965b3197517932c8aa4c07a6ea6a190a338d7) ) \
2992   ROM_REGION( 0x200000, "simm5.7", 0 ) ROM_LOAD( "jojoba-simm5.7",  0x00000, 0x200000, CRC(8c8be520) SHA1(c461f3f76a83592b36b29afb316679a7c8972404) ) \
2993
29572994#define JOJOBA_990913_CDROM \
29582995   DISK_REGION( "cdrom" ) DISK_IMAGE_READONLY( "cap-jjm-0", 0, SHA1(0678a0baeb853dcff1d230c14f0873cc9f143d7b) ) \
29592996
r14481r14482
31023139   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
31033140   ROM_LOAD( "jojoba_japan.29f400.u2", 0x000000, 0x080000, CRC(3085478c) SHA1(055eab1fc42816f370a44b17fd7e87ffcb10e8b7) )
31043141
3142   JOJOBA_990927_FLASH
3143   JOJOBA_990927_CDROM
3144ROM_END
3145
3146ROM_START( jojobaa )
3147   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
3148   ROM_LOAD( "jojoba_japan.29f400.u2", 0x000000, 0x080000, CRC(3085478c) SHA1(055eab1fc42816f370a44b17fd7e87ffcb10e8b7) )
3149
31053150   JOJOBA_990913_FLASH
31063151   JOJOBA_990913_CDROM
31073152ROM_END
r14481r14482
31553200   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
31563201   ROM_LOAD( "jojoba_japan_nocd.29f400.u2", 0x000000, 0x080000, CRC(4dab19f5) SHA1(ba07190e7662937fc267f07285c51e99a45c061e) )
31573202
3203   JOJOBA_990927_FLASH
3204ROM_END
3205
3206ROM_START( jojobaan )
3207   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
3208   ROM_LOAD( "jojoba_japan_nocd.29f400.u2", 0x000000, 0x080000, CRC(4dab19f5) SHA1(ba07190e7662937fc267f07285c51e99a45c061e) )
3209
31583210   JOJOBA_990913_FLASH
31593211ROM_END
31603212
r14481r14482
31623214   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
31633215   ROM_LOAD( "jojoba_euro_nocd.29f400.u2", 0x000000, 0x080000, CRC(1ee2d679) SHA1(9e129b454a376606b3f7e8aec64de425cf9c635c) )
31643216
3217   JOJOBA_990927_FLASH
3218ROM_END
3219
3220ROM_START( jojobaane )
3221   ROM_REGION32_BE( 0x080000, "user1", 0 ) /* bios region */
3222   ROM_LOAD( "jojoba_euro_nocd.29f400.u2", 0x000000, 0x080000, CRC(1ee2d679) SHA1(9e129b454a376606b3f7e8aec64de425cf9c635c) )
3223
31653224   JOJOBA_990913_FLASH
31663225ROM_END
31673226
r14481r14482
33253384GAME( 1999, sfiii3a,   sfiii3,   sfiii3,   cps3,      sfiii3,   ROT0, "Capcom", "Street Fighter III 3rd Strike: Fight for the Future (Euro 990512)", GAME_IMPERFECT_GRAPHICS )
33263385GAME( 1999, sfiii3u,   sfiii3,   sfiii3,   cps3,      sfiii3,   ROT0, "Capcom", "Street Fighter III 3rd Strike: Fight for the Future (USA 990608)", GAME_IMPERFECT_GRAPHICS )
33273386GAME( 1999, sfiii3au,  sfiii3,   sfiii3,   cps3,      sfiii3,   ROT0, "Capcom", "Street Fighter III 3rd Strike: Fight for the Future (USA 990512)", GAME_IMPERFECT_GRAPHICS )
3328GAME( 1999, jojoba,    0,        jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990913)", GAME_IMPERFECT_GRAPHICS )
3387GAME( 1999, jojoba,    0,        jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990927)", GAME_IMPERFECT_GRAPHICS )
3388GAME( 1999, jojobaa,   jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990913)", GAME_IMPERFECT_GRAPHICS )
33293389
33303390/* NO CD sets */
33313391
r14481r14482
33353395GAME( 1998, jojoan,    jojo,     jojo,     cps3_jojo, jojo,     ROT0, "Capcom", "JoJo's Venture (Asia 981202, NO CD)", GAME_IMPERFECT_GRAPHICS )
33363396GAME( 1999, sfiii3n,   sfiii3,   sfiii3,   cps3,      sfiii3,   ROT0, "Capcom", "Street Fighter III 3rd Strike: Fight for the Future (Japan 990608, NO CD)", GAME_IMPERFECT_GRAPHICS )
33373397GAME( 1999, sfiii3an,  sfiii3,   sfiii3,   cps3,      sfiii3,   ROT0, "Capcom", "Street Fighter III 3rd Strike: Fight for the Future (Japan 990512, NO CD)", GAME_IMPERFECT_GRAPHICS )
3338GAME( 1999, jojoban,   jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990913, NO CD)", GAME_IMPERFECT_GRAPHICS )
3339GAME( 1999, jojobane,  jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo's Bizarre Adventure (Euro 990913, NO CD)", GAME_IMPERFECT_GRAPHICS )
3398GAME( 1999, jojoban,   jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990927, NO CD)", GAME_IMPERFECT_GRAPHICS )
3399GAME( 1999, jojobaan,  jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo no Kimyouna Bouken: Miraie no Isan (Japan 990913, NO CD)", GAME_IMPERFECT_GRAPHICS )
3400GAME( 1999, jojobane,  jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo's Bizarre Adventure (Euro 990927, NO CD)", GAME_IMPERFECT_GRAPHICS )
3401GAME( 1999, jojobaane, jojoba,   jojoba,   cps3_jojo, jojoba,   ROT0, "Capcom", "JoJo's Bizarre Adventure (Euro 990913, NO CD)", GAME_IMPERFECT_GRAPHICS )
src/mame/drivers/proconn.c
r14481r14482
361361   ROM_LOAD( "943a20pn.250", 0x0000, 0x010000, CRC(a6f86f67) SHA1(43b96e2866099af6693aaf03313e119474180934) )
362362   ROM_LOAD( "f-wheel.bin", 0x0000, 0x010000, CRC(ecce8953) SHA1(d90a203e3009be73d456a1f028ffe88754175514) )
363363   ROM_LOAD( "fortunewheel6.bin", 0x0000, 0x010000, CRC(fa95bf1b) SHA1(e22b6979f01ff545c47fdc58600a42b78ecea731) )
364   ROM_LOAD( "943a206n.258", 0x0000, 0x010000, CRC(3ef23263) SHA1(40fb4399e4ac34fcb52aaca6ec19a38723bc8031) )//6GBP
364365
365366   ROM_REGION( 0x80000, "snd", 0 )
366367   ROM_LOAD( "943snd1.000", 0x000000, 0x020000, CRC(6b4223a7) SHA1(7af5779ef0309fef40b930f522e962708bd25930) )
r14481r14482
604605   ROM_REGION( 0x80000, "altrevs", 0 )
605606   ROM_LOAD( "treasuretrail.bin", 0x0000, 0x010000, CRC(2be4e149) SHA1(d8cd8f9196b7f2131c78e3e00384872d3ecc0f5f) )
606607   ROM_LOAD( "ttrail 10_93.bin", 0x0000, 0x010000, CRC(88f97fff) SHA1(e6954030e13cc069e561f3a4729eca077ca8df20) )
608   ROM_LOAD( "bifi-projectcoin.bin", 0x0000, 0x010000, CRC(463dd269) SHA1(da647f5942491f574aec17e6fdd99f75641ff332) )
607609ROM_END
608610
609611ROM_START( pr_trpx )
r14481r14482
653655   ROM_LOAD( "up&underprojectcoin.bin", 0x0000, 0x010000, CRC(053a394f) SHA1(8d7e55092dfba2ce49ee009ed388be027be2ff28) )
654656ROM_END
655657
658ROM_START( pr_qksht )
659   ROM_REGION( 0x80000, "maincpu", 0 )
660   ROM_LOAD( "quickshot27256.bin", 0x0000, 0x008000, CRC(44188ee9) SHA1(a48807252a3fe3aeacbf2e6d2691bdeafc90e249) ) // Should be 10000?
661ROM_END
656662
657663
658664DRIVER_INIT( proconn )
r14481r14482
699705GAME( 199?, pr_medl         ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Medalist (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
700706GAME( 199?, pr_megmn      ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Mega Money (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
701707GAME( 199?, pr_nudxs      ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Nudge XS (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
708GAME( 199?, pr_qksht      ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Maygay", "Quickshot (Maygay) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
702709GAME( 199?, pr_rags         ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Rags To Riches (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
703710GAME( 199?, pr_reflx      ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Reflex (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
704711GAME( 199?, pr_roadr      ,0         ,proconn   ,proconn   ,proconn   ,ROT0   ,"Project", "Road Riot (Project) (PROCONN)",GAME_IS_SKELETON_MECHANICAL )
src/mame/drivers/sms.c
r14481r14482
220220#include "machine/nvram.h"
221221
222222
223class sms_state : public driver_device
223class smsmfg_state : public driver_device
224224{
225225public:
226   sms_state(const machine_config &mconfig, device_type type, const char *tag)
226   smsmfg_state(const machine_config &mconfig, device_type type, const char *tag)
227227      : driver_device(mconfig, type, tag) { }
228228
229229   UINT8 m_communication_port[4];
r14481r14482
252252
253253static READ8_HANDLER(link_r)
254254{
255   sms_state *state = space->machine().driver_data<sms_state>();
255   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
256256   switch(offset)
257257   {
258258      case 0:
r14481r14482
269269
270270static WRITE8_HANDLER(link_w)
271271{
272   sms_state *state = space->machine().driver_data<sms_state>();
272   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
273273   switch(offset)
274274   {
275275      case 0:
r14481r14482
285285
286286static READ8_HANDLER(z80_8088_r)
287287{
288   sms_state *state = space->machine().driver_data<sms_state>();
288   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
289289   return state->m_communication_port_status;
290290}
291291
292292static READ8_HANDLER(p03_r)
293293{
294   sms_state *state = space->machine().driver_data<sms_state>();
294   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
295295   switch(offset)
296296   {
297297      case 0:
r14481r14482
306306
307307static WRITE8_HANDLER(p03_w)
308308{
309   sms_state *state = space->machine().driver_data<sms_state>();
309   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
310310   switch(offset)
311311   {
312312      case 0:
r14481r14482
434434
435435static WRITE8_HANDLER(video_w)
436436{
437   sms_state *state = space->machine().driver_data<sms_state>();
437   smsmfg_state *state = space->machine().driver_data<smsmfg_state>();
438438   state->m_vid_regs[offset] = data;
439439   if ( offset == 5 )
440440   {
r14481r14482
464464
465465static VIDEO_START( sms )
466466{
467   sms_state *state = machine.driver_data<sms_state>();
467   smsmfg_state *state = machine.driver_data<smsmfg_state>();
468468   machine.primary_screen->register_screen_bitmap(state->m_bitmap);
469469
470470   state_save_register_global_array(machine, state->m_vid_regs);
r14481r14482
473473
474474static SCREEN_UPDATE_IND16( sms )
475475{
476   sms_state *state = screen.machine().driver_data<sms_state>();
476   smsmfg_state *state = screen.machine().driver_data<smsmfg_state>();
477477   copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
478478   return 0;
479479}
r14481r14482
531531
532532static MACHINE_START( sms )
533533{
534   sms_state *state = machine.driver_data<sms_state>();
534   smsmfg_state *state = machine.driver_data<smsmfg_state>();
535535   memory_configure_bank(machine, "bank1", 0, 16, machine.region("questions")->base(), 0x4000);
536536
537537   state_save_register_global(machine, state->m_communication_port_status);
r14481r14482
540540
541541static MACHINE_START( sureshot )
542542{
543   sms_state *state = machine.driver_data<sms_state>();
543   smsmfg_state *state = machine.driver_data<smsmfg_state>();
544544   state_save_register_global(machine, state->m_communication_port_status);
545545   state_save_register_global_array(machine, state->m_communication_port);
546546}
547547
548548static MACHINE_RESET( sms )
549549{
550   sms_state *state = machine.driver_data<sms_state>();
550   smsmfg_state *state = machine.driver_data<smsmfg_state>();
551551   state->m_communication_port_status = 0;
552552}
553553
554static MACHINE_CONFIG_START( sms, sms_state )
554static MACHINE_CONFIG_START( sms, smsmfg_state )
555555   MCFG_CPU_ADD("maincpu", I8088, XTAL_24MHz/8)
556556   MCFG_CPU_PROGRAM_MAP(sms_map)
557557
src/mame/drivers/harddriv.c
r14481r14482
968968   PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)   /* up/down */
969969
970970   PORT_START("12BADC2")      /* b80000 - 12 bit ADC 2 */
971   PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)  PORT_NAME("Collective") PORT_REVERSE   /* collective */
971   PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Z ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)  PORT_NAME("Collective") PORT_REVERSE   /* collective */
972972
973973   PORT_START("12BADC3")      /* b80000 - 12 bit ADC 3 */
974   PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)  PORT_NAME("Rudder")   /* rudder */
974   PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)  PORT_NAME("Rudder") PORT_PLAYER(2)   /* rudder */
975975
976976   PORT_INCLUDE( atarijsa_iii )      /* audio board port */
977977   /* steeltal has its own coins */
r14481r14482
41804180   else
41814181      state->m_m68k_slapstic_base = state->m_maincpu->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0xe0000, 0xfffff, FUNC(st68k_protosloop_r), FUNC(st68k_protosloop_w));
41824182
4183   /* synchronization */
4184   state->m_stmsp_sync[0] = &state->m_msp_ram[TOWORD(0x80010)];
4185   state->m_msp->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x80010, 0x8007f, FUNC(stmsp_sync0_w));
4186   state->m_stmsp_sync[1] = &state->m_msp_ram[TOWORD(0x99680)];
4187   state->m_msp->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x99680, 0x9968f, FUNC(stmsp_sync1_w));
4188   state->m_stmsp_sync[2] = &state->m_msp_ram[TOWORD(0x99d30)];
4189   state->m_msp->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x99d30, 0x99d4f, FUNC(stmsp_sync2_w));
4190
41914183   /* set up protection hacks */
41924184   state->m_gsp_protection = state->m_gsp->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xfff965d0, 0xfff965df, FUNC(hdgsp_protection_w));
41934185
4194   /* set up msp speedup handlers */
4195   state->m_msp->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x80020, 0x8002f, FUNC(stmsp_speedup_r));
4196
41974186   /* set up adsp speedup handlers */
41984187   state->m_adsp->memory().space(AS_DATA)->install_legacy_read_handler(0x1fff, 0x1fff, FUNC(hdadsp_speedup_r));
41994188   state->m_adsp->memory().space(AS_DATA)->install_legacy_read_handler(0x1f99, 0x1f99, FUNC(hdds3_speedup_r));
src/mame/drivers/taitogn.c
r14481r14482
451451   taitogn_state *state = space->machine().driver_data<taitogn_state>();
452452
453453   if(offset >= 0x140 && offset <= 0x144) {
454      UINT8 key[5];
454      dynamic_buffer key;
455455      int pos = (offset - 0x140)*2;
456456      UINT8 v, k;
457457      if(ACCESSING_BITS_16_23) {
r14481r14482
459459         pos++;
460460      } else
461461         v = data;
462      chd_get_metadata(get_disk_handle(space->machine(), ":card"), HARD_DISK_KEY_METADATA_TAG, 0, key, 5, 0, 0, 0);
463      k = pos < 5 ? key[pos] : 0;
462      get_disk_handle(space->machine(), ":card")->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, key);
463      k = pos < key.count() ? key[pos] : 0;
464464      if(v == k)
465465         state->m_locked &= ~(1 << pos);
466466      else
r14481r14482
889889   psx_sio_install_handler(machine, 0, sio_pad_handler);
890890   state->m_dip_timer = machine.scheduler().timer_alloc( FUNC(dip_timer_fired), NULL );
891891
892   UINT32 metalength;
892893   memset(state->m_cis, 0xff, 512);
893894   if (get_disk_handle(machine, ":card") != NULL)
894      chd_get_metadata(get_disk_handle(machine, ":card"), PCMCIA_CIS_METADATA_TAG, 0, state->m_cis, 512, 0, 0, 0);
895      get_disk_handle(machine, ":card")->read_metadata(PCMCIA_CIS_METADATA_TAG, 0, state->m_cis, 512, metalength);
895896}
896897
897898static DRIVER_INIT( coh3002t_mp )
src/mame/drivers/decocass.c
r14481r14482
1717    Early boardset: (1980-1983) (proms unknown for this boardset, no schematics for this boardset)
1818    One RMS-3 pcb with a 6502 processor, two ay-3-8910s, and one 2716 eprom holding the audio bios. (audio)
1919    One DSP-3 pcb with a 6502 processor, two 2716 eproms (main processor and bios, graphics, dipswitches?)
20    One BIO-3 pcb with an 8041 MCU (cassette control)
20    One BIO-3 pcb with an 8041 MCU (DECO Cassette control)
2121    TODO: get more info about this older boardset: D. Widel has some info about it on his page at http://www.widel.com/stuff/decopin.htm
2222
2323    Later boardset: (1984 onward, schematic is dated 10/83)
2424    One DE-0097C-0 RMS-8 pcb with a 6502 processor, two ay-3-8910s, two eproms (2716 and 2732) plus one prom, and 48k worth of 4116 16kx1 DRAMs; the 6502 processor has its own 4K of SRAM. (audio processor and RAM, Main processor's dram, dipswitches)
2525    One DE-0096C-0 DSP-8 board with a 'DECO 222' custom on it (labeled '8049 // C10707-2') which appears to really be a 'cleverly' disguised 6502, and two proms, plus 4K of sram, and three hm2511-1 1kx1 srams. (main processor and graphics)
26    One DE-0098C-0 B10-8 (BIO-8 on schematics) board with an 8041, an analog devices ADC0908 8-bit adc, and 4K of SRAM on it (cassette control, inputs)
26    One DE-0098C-0 B10-8 (BIO-8 on schematics) board with an 8041, an analog devices ADC0908 8-bit adc, and 4K of SRAM on it (DECO Cassette control, inputs)
2727
2828
2929    The actual cassettes use a custom player hooked to the BIO board, and are roughly microcassette form factor, but are larger and will not fit in a conventional microcassette player.
r14481r14482
12841284ROM_END
12851285
12861286/* The Following use Dongle Type 4 (unknown part number?)
1287    (dongle data probably differs for each game, but only one is known using it atm) */
1287    (dongle data is used for most of the graphics) */
12881288
12891289ROM_START( cscrtry )
12901290   DECOCASS_BIOS_B_ROMS
r14481r14482
13061306   ROM_LOAD( "cscrtry2.cas",  0x0000, 0x8000, CRC(04597842) SHA1(7f1fc3e06b61df880debe9056bdfbbb8600af739) )
13071307ROM_END
13081308
1309ROM_START( cgsumo )
1310   DECOCASS_BIOS_A_ROMS
1311
1312   ROM_REGION( 0x08000, "dongle", 0 )     /* dongle data */
1313   ROM_LOAD( "dp-141a.pro",  0x0000, 0x8000, CRC(bc379d2c) SHA1(bab19dcb6d68fdbd547ebab1598353f436321157) )
1314
1315   ROM_REGION( 0x10000, "cassette", 0 )     /* (max) 64k for cassette image */
1316   ROM_LOAD( "dt-141[1a]ext.bin",  0x0000, 0x10000, CRC(20c2e86a) SHA1(a18248ba00b847a09df0bea7752a21162af8af76) )
1317ROM_END
1318
13091319/* The Following use Dongle Type 5 (unknown part number?)
13101320    (dongle data not read)       */
13111321
r14481r14482
14001410   state->save_pointer(NAME(state->m_decrypted2), romlength);
14011411}
14021412
1413/* -- */ GAME( 1981, decocass, 0,        decocass, decocass, decocass, ROT270, "Data East Corporation", "DECO Cassette System", GAME_IS_BIOS_ROOT )
1414/* -- */ GAME( 1981, ctsttape, decocass, ctsttape, decocass, decocass, ROT270, "Data East Corporation", "Test Tape (DECO Cassette)", 0 )
1415/* 01 */ GAME( 1980, chwy,     decocass, chwy,     decocass, decocass, ROT270, "Data East Corporation", "Highway Chase (DECO Cassette)", 0 )
1416/* 02 */ // 1980.12 Sengoku Ninjatai
1417/* 03 */ // 1981.01 Manhattan
1418/* 04 */ GAME( 1981, cterrani, decocass, cterrani, cterrani, decocass, ROT270, "Data East Corporation", "Terranean (DECO Cassette)", 0 )
1419/* 05 */ // 1981.?? Missile Sprinter
1420/* 06 */ // 1980.12 Nebula
1421/* 07 */ GAME( 1981, castfant, decocass, castfant, decocass, decocass, ROT270, "Data East Corporation", "Astro Fantasia (DECO Cassette)", 0 )
1422/* 08 */ // 1981.03 The Tower
1423/* 09 */ GAME( 1981, csuperas, decocass, csuperas, csuperas, decocass, ROT270, "Data East Corporation", "Super Astro Fighter (DECO Cassette)", 0 )
1424/* 10 */ // 1981.?? Ocean to Ocean (medal)
1425/* 11 */ GAME( 1981, clocknch, decocass, clocknch, clocknch, decocass, ROT270, "Data East Corporation", "Lock'n'Chase (DECO Cassette)", 0 )
1426/* 12 */ // 1981.08 Flash Boy/DECO Kid
1427/* 13 */ GAME( 1981, cprogolf, decocass, cprogolf, cprogolf, decocass, ROT270, "Data East Corporation", "Tournament Pro Golf (DECO Cassette)", 0 )
1428/* 14 */ // 1981.06 DS Telejan
1429/* 15 */ GAME( 1981, cluckypo, decocass, cluckypo, decocass, decocass, ROT270, "Data East Corporation", "Lucky Poker (DECO Cassette)", 0 )
1430/* 16 */ GAME( 1981, ctisland, decocass, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (DECO Cassette, set 1)", 0 )
1431       GAME( 1981, ctisland2,ctisland, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (DECO Cassette, set 2)", 0 )
1432       GAME( 1981, ctisland3,ctisland, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (DECO Cassette, set 3)", GAME_NOT_WORKING ) /* Different Bitswap? */
1433/* 17 */ // 1981.10 Bobbitto
1434/* 18 */ GAME( 1982, cexplore, decocass, cexplore, cexplore, decocass, ROT270, "Data East Corporation", "Explorer (DECO Cassette)", GAME_NOT_WORKING )
1435/* 19 */ GAME( 1982, cdiscon1, decocass, cdiscon1, decocass, decocass, ROT270, "Data East Corporation", "Disco No.1 (DECO Cassette)", 0 )
1436       GAME( 1982, csweetht, cdiscon1, cdiscon1, decocass, decocass, ROT270, "Data East Corporation", "Sweet Heart (DECO Cassette)", 0 )
1437/* 20 */ GAME( 1982, ctornado, decocass, ctornado, ctornado, decocass, ROT270, "Data East Corporation", "Tornado (DECO Cassette)", 0 )
1438/* 21 */ GAME( 1982, cmissnx,  decocass, cmissnx,  cmissnx,  decocass, ROT270, "Data East Corporation", "Mission-X (DECO Cassette)", 0 )
1439/* 22 */ GAME( 1982, cptennis, decocass, cptennis, decocass, decocass, ROT270, "Data East Corporation", "Pro Tennis (DECO Cassette)", 0 )
1440/* 23 */ // 1982.?? 18 Hole Pro Golf
1441/* 24 */ // 1982.07 Tsumego Kaisyou
1442/* 25 */ // 1982.10 Angler Dangler? (fishing)
1443/* 26 */ GAME( 1983, cbtime,   decocass, cbtime,   cbtime,   decocass, ROT270, "Data East Corporation", "Burger Time (DECO Cassette)", 0 )
1444/* 27 */ GAME( 1982, cburnrub, decocass, cburnrub, decocass, decocass, ROT270, "Data East Corporation", "Burnin' Rubber (DECO Cassette, set 1)", 0 )
1445       GAME( 1982, cburnrub2,cburnrub, cburnrub, decocass, decocass, ROT270, "Data East Corporation", "Burnin' Rubber (DECO Cassette, set 2)", 0 )
1446       GAME( 1982, cbnj,     cburnrub, cbnj,     decocass, decocass, ROT270, "Data East Corporation", "Bump 'n' Jump (DECO Cassette)", 0 )
1447/* 28 */ GAME( 1983, cgraplop, decocass, cgraplop, cgraplop, decocass, ROT270, "Data East Corporation", "Cluster Buster / Graplop (DECO Cassette, set 1)", 0 )
1448       GAME( 1983, cgraplop2,cgraplop, cgraplop2,cgraplop, decocass, ROT270, "Data East Corporation", "Cluster Buster / Graplop (DECO Cassette, set 2)", GAME_NOT_WORKING )
1449/* 29 */ GAME( 1983, clapapa,  decocass, clapapa,  decocass, decocass, ROT270, "Data East Corporation", "Rootin' Tootin' / La-Pa-Pa (DECO Cassette)" , 0) /* Displays 'La-Pa-Pa during attract */
1450        GAME( 1983, clapapa2, clapapa,  clapapa,  decocass, decocass, ROT270, "Data East Corporation", "Rootin' Tootin' (DECO Cassette)" , 0) /* Displays 'Rootin' Tootin' during attract */
1451/* 30 */ // 1983.03 Skater
1452/* 31 */ GAME( 1983, cprobowl, decocass, cprobowl, decocass, decocass, ROT270, "Data East Corporation", "Pro Bowling (DECO Cassette)", 0 )
1453/* 32 */ GAME( 1983, cnightst, decocass, cnightst, cnightst, decocass, ROT270, "Data East Corporation", "Night Star (DECO Cassette, set 1)", 0 )
1454       GAME( 1983, cnightst2,cnightst, cnightst, cnightst, decocass, ROT270, "Data East Corporation", "Night Star (DECO Cassette, set 2)", 0 )
1455/* 33 */ GAME( 1983, cpsoccer, decocass, cpsoccer, cpsoccer, decocass, ROT270, "Data East Corporation", "Pro Soccer (DECO Cassette)", 0 )
1456       GAME( 1983, cpsoccerj,cpsoccer, cpsoccer, cpsoccer, decocass, ROT270, "Data East Corporation", "Pro Soccer (DECO Cassette, Japan)", 0 )
1457/* 34 */ // 1983.09 Super Doubles Tennis
1458/* 35 */ GAME( 1985, cflyball, decocass, cflyball, decocass, decocass, ROT270, "Data East Corporation", "Flying Ball (DECO Cassette)", 0 )
1459/* 36 */ // 1984.04 Genesis/Boomer Rang'r
1460/* 37 */ GAME( 1983, czeroize, decocass, czeroize, decocass, decocass, ROT270, "Data East Corporation", "Zeroize (DECO Cassette)", 0 )
1461/* 38 */ GAME( 1984, cscrtry,  decocass, cscrtry,  cscrtry,  decocass, ROT270, "Data East Corporation", "Scrum Try (DECO Cassette, set 1)", 0 )
1462       GAME( 1984, cscrtry2, cscrtry,  cscrtry,  cscrtry,  decocass, ROT270, "Data East Corporation", "Scrum Try (DECO Cassette, set 2)", 0 )
1463/* 39 */ GAME( 1984, cppicf,   decocass, cppicf,   decocass, decocass, ROT270, "Data East Corporation", "Peter Pepper's Ice Cream Factory (DECO Cassette, set 1)", 0 )
1464       GAME( 1984, cppicf2,  cppicf,   cppicf,   decocass, decocass, ROT270, "Data East Corporation", "Peter Pepper's Ice Cream Factory (DECO Cassette, set 2)", 0 )
1465/* 40 */ GAME( 1984, cfghtice, decocass, cfghtice, cfghtice, decocass, ROT270, "Data East Corporation", "Fighting Ice Hockey (DECO Cassette)", 0 )
1466/* 41 */ GAME( 1984, cgsumo,   decocass, cscrtry,  cscrtry,  decocass, ROT270, "Data East Corporation", "Oozumou - The Grand Sumo (DECO Cassette)", 0 )
1467/* 42 */ // 1984.08 Hellow Gateball // not a typo, this is official spelling
1468/* 43 */ // 1984.08 Yellow Cab
1469/* 44 */ GAME( 1985, cbdash,   decocass, cbdash,   cbdash,   decocass, ROT270, "Data East Corporation", "Boulder Dash (DECO Cassette)", 0 )
14031470
1404         GAME( 1981, decocass, 0, decocass, decocass, decocass, ROT270, "Data East Corporation", "DECO Cassette System", GAME_IS_BIOS_ROOT )
1405         GAME( 1981, ctsttape, decocass, ctsttape, decocass, decocass, ROT270, "Data East Corporation", "Test Tape (Cassette)", 0 )
1406/* 01 */ GAME( 1980, chwy,     decocass, chwy,     decocass, decocass, ROT270, "Data East Corporation", "Highway Chase (Cassette)", 0 )
1407/* 04 */ GAME( 1981, cterrani, decocass, cterrani, cterrani, decocass, ROT270, "Data East Corporation", "Terranean (Cassette)", 0 )
1408/* 07 */ GAME( 1981, castfant, decocass, castfant, decocass, decocass, ROT270, "Data East Corporation", "Astro Fantasia (Cassette)", 0 )
1409/* 09 */ GAME( 1981, csuperas, decocass, csuperas, csuperas, decocass, ROT270, "Data East Corporation", "Super Astro Fighter (Cassette)", 0 )
1410/* 11 */ GAME( 1981, clocknch, decocass, clocknch, clocknch, decocass, ROT270, "Data East Corporation", "Lock'n'Chase (Cassette)", 0 )
1411/* 13 */ GAME( 1981, cprogolf, decocass, cprogolf, cprogolf, decocass, ROT270, "Data East Corporation", "Tournament Pro Golf (Cassette)", 0 )
1412/* 15 */ GAME( 1981, cluckypo, decocass, cluckypo, decocass, decocass, ROT270, "Data East Corporation", "Lucky Poker (Cassette)", 0 )
1413/* 16 */ GAME( 1981, ctisland, decocass, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (Cassette, set 1)", 0 )
1414/* 16 */ GAME( 1981, ctisland2,ctisland, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (Cassette, set 2)", 0 )
1415/* 16 */ GAME( 1981, ctisland3,ctisland, ctisland, decocass, decocrom, ROT270, "Data East Corporation", "Treasure Island (Cassette, set 3)", GAME_NOT_WORKING ) /* Different Bitswap? */
1416/* 18 */ GAME( 1982, cexplore, decocass, cexplore, cexplore, decocass, ROT270, "Data East Corporation", "Explorer (Cassette)", GAME_NOT_WORKING )
1417/* 19 */ GAME( 1982, cdiscon1, decocass, cdiscon1, decocass, decocass, ROT270, "Data East Corporation", "Disco No.1 (Cassette)", 0 )
1418/* 19 */ GAME( 1982, csweetht, cdiscon1, cdiscon1, decocass, decocass, ROT270, "Data East Corporation", "Sweet Heart (Cassette)", 0 )
1419/* 20 */ GAME( 1982, ctornado, decocass, ctornado, ctornado, decocass, ROT270, "Data East Corporation", "Tornado (Cassette)", 0 )
1420/* 21 */ GAME( 1982, cmissnx,  decocass, cmissnx,  cmissnx,  decocass, ROT270, "Data East Corporation", "Mission-X (Cassette)", 0 )
1421/* 22 */ GAME( 1982, cptennis, decocass, cptennis, decocass, decocass, ROT270, "Data East Corporation", "Pro Tennis (Cassette)", 0 )
1422/* 26 */ GAME( 1983, cbtime,   decocass, cbtime,   cbtime,   decocass, ROT270, "Data East Corporation", "Burger Time (Cassette)", 0 )
1423/* 27 */ GAME( 1982, cburnrub, decocass, cburnrub, decocass, decocass, ROT270, "Data East Corporation", "Burnin' Rubber (Cassette, set 1)", 0 )
1424/* 27 */ GAME( 1982, cburnrub2,cburnrub, cburnrub, decocass, decocass, ROT270, "Data East Corporation", "Burnin' Rubber (Cassette, set 2)", 0 )
1425/* 27 */ GAME( 1982, cbnj,     cburnrub, cbnj,     decocass, decocass, ROT270, "Data East Corporation", "Bump 'n' Jump (Cassette)", 0 )
1426/* 28 */ GAME( 1983, cgraplop, decocass, cgraplop, cgraplop, decocass, ROT270, "Data East Corporation", "Cluster Buster / Graplop (Cassette, set 1)", 0 )
1427/* 28 */ GAME( 1983, cgraplop2,cgraplop, cgraplop2,cgraplop, decocass, ROT270, "Data East Corporation", "Cluster Buster / Graplop (Cassette, set 2)", GAME_NOT_WORKING )
1428/* 29 */ GAME( 1983, clapapa,  decocass, clapapa,  decocass, decocass, ROT270, "Data East Corporation", "Rootin' Tootin' / La-Pa-Pa (Cassette)" , 0) /* Displays 'La-Pa-Pa during attract */
1429/* 29 */ GAME( 1983, clapapa2, clapapa,  clapapa,  decocass, decocass, ROT270, "Data East Corporation", "Rootin' Tootin' (Cassette)" , 0) /* Displays 'Rootin' Tootin' during attract */
1430/* 31 */ GAME( 1983, cprobowl, decocass, cprobowl, decocass, decocass, ROT270, "Data East Corporation", "Pro Bowling (Cassette)", 0 )
1431/* 32 */ GAME( 1983, cnightst, decocass, cnightst, cnightst, decocass, ROT270, "Data East Corporation", "Night Star (Cassette, set 1)", 0 )
1432/* 32 */ GAME( 1983, cnightst2,cnightst, cnightst, cnightst, decocass, ROT270, "Data East Corporation", "Night Star (Cassette, set 2)", 0 )
1433/* 33 */ GAME( 1983, cpsoccer, decocass, cpsoccer, cpsoccer, decocass, ROT270, "Data East Corporation", "Pro Soccer (Cassette)", 0 )
1434/* 33 */ GAME( 1983, cpsoccerj,cpsoccer, cpsoccer, cpsoccer, decocass, ROT270, "Data East Corporation", "Pro Soccer (Cassette, Japan)", 0 )
1435/* 35 */ GAME( 1985, cflyball, decocass, cflyball, decocass, decocass, ROT270, "Data East Corporation", "Flying Ball (Cassette)", 0 )
1436/* 37 */ GAME( 1983, czeroize, decocass, czeroize, decocass, decocass, ROT270, "Data East Corporation", "Zeroize (Cassette)", 0 )
1437/* 38 */ GAME( 1984, cscrtry,  decocass, cscrtry,  cscrtry,  decocass, ROT270, "Data East Corporation", "Scrum Try (Cassette, set 1)", 0 )
1438/* 38 */ GAME( 1984, cscrtry2, cscrtry,  cscrtry,  cscrtry,  decocass, ROT270, "Data East Corporation", "Scrum Try (Cassette, set 2)", 0 )
1439/* 39 */ GAME( 1984, cppicf,   decocass, cppicf,   decocass, decocass, ROT270, "Data East Corporation", "Peter Pepper's Ice Cream Factory (Cassette, set 1)", 0 )
1440/* 39 */ GAME( 1984, cppicf2,  cppicf,   cppicf,   decocass, decocass, ROT270, "Data East Corporation", "Peter Pepper's Ice Cream Factory (Cassette, set 2)", 0 )
1441/* 40 */ GAME( 1984, cfghtice, decocass, cfghtice, cfghtice, decocass, ROT270, "Data East Corporation", "Fighting Ice Hockey (Cassette)", 0 )
1442/* 44 */ GAME( 1985, cbdash,   decocass, cbdash,   cbdash,   decocass, ROT270, "Data East Corporation", "Boulder Dash (Cassette)", 0 )
1471/* UX7 */ // 1984.12 Tokyo MIE Clinic/Tokyo MIE Shinryoujo
1472/* UX8 */ // 1985.01 Tokyo MIE Clinic/Tokyo MIE Shinryoujo Part 2
1473/* UX9 */ // 1985.05 Geinoujin Shikaku Shiken
1474
src/mame/drivers/marineb.c
r14481r14482
743743   ROM_LOAD( "springer.7",    0x1000, 0x1000, CRC(95ab8fc0) SHA1(74dad6fe1edd38b22656cf6cd9e4a57012bf0d60) )
744744
745745   ROM_REGION( 0x4000, "gfx2", 0 )
746   ROM_LOAD( "springer.8",    0x0000, 0x1000, CRC(a54bafdc) SHA1(70f1a9ab116dc2a195aa9026ed1004101897d274) )
746   ROM_LOAD( "springer.9",    0x0000, 0x1000, CRC(fa302775) SHA1(412afdc620be95e70b3b782d1a08e4a46777e710) )
747747                     /* 0x1000-0x1fff empty for my convinience */
748   ROM_LOAD( "springer.9",    0x2000, 0x1000, CRC(fa302775) SHA1(412afdc620be95e70b3b782d1a08e4a46777e710) )
748   ROM_LOAD( "springer.8",    0x2000, 0x1000, CRC(a54bafdc) SHA1(70f1a9ab116dc2a195aa9026ed1004101897d274) )
749749                     /* 0x3000-0x3fff empty for my convinience */
750750
751751   ROM_REGION( 0x0200, "proms", 0 )
src/tools/tools.mak
r14481r14482
8484CHDMANOBJS = \
8585   $(TOOLSOBJ)/chdman.o \
8686
87chdman$(EXE): $(VERSIONOBJ) $(CHDMANOBJS) $(LIBUTIL) $(ZLIB) $(EXPAT) $(FLAC_LIB) $(LIBOCORE)
87chdman$(EXE): $(VERSIONOBJ) $(CHDMANOBJS) $(LIBUTIL) $(ZLIB) $(EXPAT) $(FLAC_LIB) $(7Z_LIB) $(LIBOCORE)
88   $(CC) $(CDEFS) $(CFLAGS) -c $(SRC)/version.c -o $(VERSIONOBJ)
8889   @echo Linking $@...
8990   $(LD) $(LDFLAGS) $^ $(LIBS) $(FLAC_LIB) -o $@
9091
src/tools/chdman.c
r14481r14482
3939#include "corefile.h"
4040#include "chdcd.h"
4141#include "aviio.h"
42#include "avcomp.h"
42#include "avhuff.h"
4343#include "bitmap.h"
4444#include "md5.h"
4545#include "sha1.h"
4646#include "vbiparse.h"
47#include "tagmap.h"
4748#include <stdarg.h>
4849#include <stdlib.h>
4950#include <stdio.h>
r14481r14482
5152#include <ctype.h>
5253#include <new>
5354
54
55/***************************************************************************
56    CONSTANTS & DEFINES
57***************************************************************************/
58
59#define IDE_SECTOR_SIZE         512
60
61#define ENABLE_CUSTOM_CHOMP      0
62
63#define OPERATION_UPDATE      0
64#define OPERATION_MERGE         1
65#define OPERATION_CHOMP         2
66
67#ifdef PTR64
68#define IS_FAKE_AVI_FILE(a)      ((UINT64)(a) <= 2)
55#ifdef _WIN32
56#define NUM_PROCESSORS_SUPPORTED 1
6957#else
70#define IS_FAKE_AVI_FILE(a)      ((UINT32)(a) <= 2)
58#define NUM_PROCESSORS_SUPPORTED 0
7159#endif
72#define AVI_FAKE_FILE_22      ((avi_file *)1)
73#define AVI_FAKE_FILE_32      ((avi_file *)2)
7460
75#define AVI_FAKE_FRAMERATE      29970000
76#define AVI_FAKE_FRAMES         54004
77#define AVI_FAKE_WIDTH         720
78#define AVI_FAKE_HEIGHT         524
79#define AVI_FAKE_CHANNELS      2
80#define AVI_FAKE_SAMPLERATE      48000
8161
62//**************************************************************************
63//  CONSTANTS & DEFINES
64//**************************************************************************
8265
66// default hard disk sector size
67const UINT32 IDE_SECTOR_SIZE = 512;
8368
84/***************************************************************************
85    TYPE DEFINITIONS
86***************************************************************************/
69// temporary input buffer size
70const UINT32 TEMP_BUFFER_SIZE = 32 * 1024 * 1024;
8771
88struct _chd_interface_file
89{
90   osd_file *file;
91   UINT64 length;
92};
72// command modifier
73#define REQUIRED "~"
9374
75// command strings
76#define COMMAND_HELP "help"
77#define COMMAND_INFO "info"
78#define COMMAND_VERIFY "verify"
79#define COMMAND_CREATE_RAW "createraw"
80#define COMMAND_CREATE_HD "createhd"
81#define COMMAND_CREATE_CD "createcd"
82#define COMMAND_CREATE_LD "createld"
83#define COMMAND_EXTRACT_RAW "extractraw"
84#define COMMAND_EXTRACT_HD "extracthd"
85#define COMMAND_EXTRACT_CD "extractcd"
86#define COMMAND_EXTRACT_LD "extractld"
87#define COMMAND_COPY "copy"
88#define COMMAND_ADD_METADATA "addmeta"
89#define COMMAND_DEL_METADATA "delmeta"
9490
91// option strings
92#define OPTION_INPUT "input"
93#define OPTION_OUTPUT "output"
94#define OPTION_OUTPUT_BIN "outputbin"
95#define OPTION_OUTPUT_FORCE "force"
96#define OPTION_INPUT_START_BYTE "inputstartbyte"
97#define OPTION_INPUT_START_HUNK "inputstarthunk"
98#define OPTION_INPUT_START_FRAME "inputstartframe"
99#define OPTION_INPUT_LENGTH_BYTES "inputbytes"
100#define OPTION_INPUT_LENGTH_HUNKS "inputhunks"
101#define OPTION_INPUT_LENGTH_FRAMES "inputframes"
102#define OPTION_HUNK_SIZE "hunksize"
103#define OPTION_UNIT_SIZE "unitsize"
104#define OPTION_COMPRESSION "compression"
105#define OPTION_INPUT_PARENT "inputparent"
106#define OPTION_OUTPUT_PARENT "outputparent"
107#define OPTION_IDENT "ident"
108#define OPTION_CHS "chs"
109#define OPTION_SECTOR_SIZE "sectorsize"
110#define OPTION_TAG "tag"
111#define OPTION_INDEX "index"
112#define OPTION_VALUE_TEXT "valuetext"
113#define OPTION_VALUE_FILE "valuefile"
114#define OPTION_NO_CHECKSUM "nochecksum"
115#define OPTION_VERBOSE "verbose"
116#define OPTION_FIX "fix"
117#define OPTION_NUMPROCESSORS "numprocessors"
95118
96/***************************************************************************
97    FUNCTION PROTOTYPES
98***************************************************************************/
99119
100static chd_error chdman_compress_file(chd_file *chd, const char *rawfile, UINT32 offset);
101static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 totalhunks);
102static chd_error chdman_clone_metadata(chd_file *source, chd_file *dest);
103120
121//**************************************************************************
122//  FUNCTION PROTOTYPES
123//**************************************************************************
104124
125typedef tagmap_t<astring *> parameters_t;
105126
106/***************************************************************************
107    GLOBAL VARIABLES
108***************************************************************************/
127static void report_error(int error, const char *format, ...);
128static void do_info(parameters_t &params);
129static void do_verify(parameters_t &params);
130static void do_create_raw(parameters_t &params);
131static void do_create_hd(parameters_t &params);
132static void do_create_cd(parameters_t &params);
133static void do_create_ld(parameters_t &params);
134static void do_copy(parameters_t &params);
135static void do_extract_raw(parameters_t &params);
136static void do_extract_cd(parameters_t &params);
137static void do_extract_ld(parameters_t &params);
138static void do_add_metadata(parameters_t &params);
139static void do_del_metadata(parameters_t &params);
109140
110static clock_t lastprogress = 0;
111141
112142
143//**************************************************************************
144//  TYPE DEFINITIONS
145//**************************************************************************
113146
114/***************************************************************************
115    IMPLEMENTATION
116***************************************************************************/
147// ======================> option_description
117148
118/*-------------------------------------------------
119    print_big_int - 64-bit int printing with
120    commas
121-------------------------------------------------*/
122
123static void print_big_int(UINT64 intvalue, char *output)
149struct option_description
124150{
125   int chunk;
151   const char *name;
152   const char *shortname;
153   bool parameter;
154   const char *description;
155};
126156
127   chunk = intvalue % 1000;
128   intvalue /= 1000;
129   if (intvalue != 0)
130   {
131      print_big_int(intvalue, output);
132      strcat(output, ",");
133      sprintf(&output[strlen(output)], "%03d", chunk);
134   }
135   else
136      sprintf(&output[strlen(output)], "%d", chunk);
137}
138157
158// ======================> command_description
139159
140/*-------------------------------------------------
141    big_int_string - return a string for a big
142    integer
143-------------------------------------------------*/
144
145static char *big_int_string(UINT64 intvalue)
160struct command_description
146161{
147   static char buffer[256];
148   buffer[0] = 0;
149   print_big_int(intvalue, buffer);
150   return buffer;
151}
162   const char *name;
163   void (*handler)(parameters_t &);
164   const char *description;
165   const char *valid_options[16];
166};
152167
153168
154/*-------------------------------------------------
155    progress - generic progress callback
156-------------------------------------------------*/
169// ======================> avi_info
157170
158static void ATTR_PRINTF(2,3) progress(int forceit, const char *fmt, ...)
171struct avi_info
159172{
160   clock_t curtime = clock();
161   va_list arg;
173   UINT32 fps_times_1million;
174   UINT32 width;
175   UINT32 height;
176   bool interlaced;
177   UINT32 channels;
178   UINT32 rate;
179   UINT32 max_samples_per_frame;
180   UINT32 bytes_per_frame;
181};
162182
163   /* skip if it hasn't been long enough */
164   if (!forceit && curtime - lastprogress < CLOCKS_PER_SEC / 2)
165      return;
166   lastprogress = curtime;
167183
168   /* standard vfprintf stuff here */
169   va_start(arg, fmt);
170   vfprintf(stderr, fmt, arg);
171   fflush(stderr);
172   va_end(arg);
173}
184// ======================> metadata_index_info
174185
175
176/*-------------------------------------------------
177    usage - generic usage error display
178-------------------------------------------------*/
179
180static int usage(void)
186struct metadata_index_info
181187{
182   printf("usage: chdman -info input.chd\n");
183   printf("   or: chdman -createraw inputhd.raw output.chd [inputoffs [hunksize]]\n");
184   printf("   or: chdman -createhd inputhd.raw output.chd [ident.bin] [inputoffs [cylinders heads sectors [sectorsize [hunksize]]]]\n");
185   printf("   or: chdman -createuncomphd inputhd.raw output.chd [ident.bin] [inputoffs [cylinders heads sectors [sectorsize [hunksize]]]]\n");
186   printf("   or: chdman -createblankhd output.chd cylinders heads sectors [sectorsize [hunksize]]\n");
187   printf("   or: chdman -createcd input.(toc/cue/nrg/gdi) output.chd\n");
188   printf("   or: chdman -createav input.avi output.chd [firstframe [numframes]]\n");
189   printf("   or: chdman -copydata input.chd output.chd\n");
190   printf("   or: chdman -extract input.chd output.raw\n");
191   printf("   or: chdman -extractcd input.chd output.(toc/cue) output.bin (if toc, no extension if cue)\n");
192   printf("   or: chdman -extractav input.chd output.avi [firstframe [numframes]]\n");
193   printf("   or: chdman -verify input.chd\n");
194   printf("   or: chdman -verifyfix input.chd\n");
195   printf("   or: chdman -update input.chd output.chd\n");
196   printf("   or: chdman -chomp inout.chd output.chd maxhunk\n");
197   printf("   or: chdman -merge parent.chd diff.chd output.chd\n");
198   printf("   or: chdman -diff parent.chd compare.chd diff.chd\n");
199   printf("   or: chdman -setchs inout.chd cylinders heads sectors\n");
200   printf("   or: chdman -fixavdata inout.chd\n");
201   printf("   or: chdman -addmetabin inout.chd tag [index] sourcefile\n");
202   printf("   or: chdman -addmetatext inout.chd tag [index] sourcefile\n");
203   return 1;
204}
188   chd_metadata_tag   tag;
189   UINT32            index;
190};
205191
206192
207/*-------------------------------------------------
208    get_file_size - get the size of a file
209-------------------------------------------------*/
193// ======================> fatal_error
210194
211static UINT64 get_file_size(const char *filename)
195class fatal_error : public std::exception
212196{
213   osd_file *file;
214   UINT64 filesize = 0;
215   file_error filerr;
197public:
198   fatal_error(int error)
199      : m_error(error) { }
216200
217   filerr = osd_open(filename, OPEN_FLAG_READ, &file, &filesize);
218   if (filerr == FILERR_NONE)
219      osd_close(file);
220   return filesize;
221}
201   int error() const { return m_error; }
222202
203private:
204   int m_error;
205};
223206
224/*-------------------------------------------------
225    guess_chs - given a file and an offset,
226    compute a best guess CHS value set
227-------------------------------------------------*/
228207
229static chd_error guess_chs(const char *filename, int offset, int sectorsize, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps)
230{
231   UINT32 totalsecs, hds, secs;
232   UINT64 filesize;
208// ======================> chd_rawfile_compressor
233209
234   /* if this is a direct physical drive read, handle it specially */
235   if (osd_get_physical_drive_geometry(filename, cylinders, heads, sectors, bps))
236      return CHDERR_NONE;
237
238   /* compute the filesize */
239   filesize = get_file_size(filename);
240   if (filesize <= offset)
241   {
242      fprintf(stderr, "Invalid file '%s'\n", filename);
243      return CHDERR_INVALID_FILE;
244   }
245   filesize -= offset;
246
247   /* validate the size */
248   if (filesize % sectorsize != 0)
249   {
250      fprintf(stderr, "Can't guess CHS values because data size is not divisible by the sector size\n");
251      return CHDERR_INVALID_FILE;
252   }
253   totalsecs = filesize / sectorsize;
254
255   /* now find a valid value */
256   for (secs = 63; secs > 1; secs--)
257      if (totalsecs % secs == 0)
258      {
259         size_t totalhds = totalsecs / secs;
260         for (hds = 16; hds > 1; hds--)
261            if (totalhds % hds == 0)
262            {
263               *cylinders = totalhds / hds;
264               *heads = hds;
265               *sectors = secs;
266               *bps = sectorsize;
267               return CHDERR_NONE;
268            }
269      }
270
271   /* ack, it didn't work! */
272   fprintf(stderr, "Can't guess CHS values because no logical combination works!\n");
273   return CHDERR_INVALID_FILE;
274}
275
276
277/*-------------------------------------------------
278    get_chs_from_ident - extract chs from an ident
279    information, validate it with the file size
280
281    Note: limited to IDE for now
282-------------------------------------------------*/
283
284static chd_error get_chs_from_ident(const char *filename, int offset, const UINT8 *ident, UINT32 identsize, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps)
210class chd_rawfile_compressor : public chd_file_compressor
285211{
286   UINT64 filesize, expected_size;
287
288   filesize = get_file_size(filename);
289   if (filesize <= offset)
212public:
213   // construction/destruction
214   chd_rawfile_compressor(core_file *file, UINT64 offset = 0, UINT64 maxoffset = ~0)
215      : m_file(file),
216        m_offset(offset),
217        m_maxoffset(MIN(maxoffset, (file != NULL) ? core_fsize(file) : 0)) { }
218   
219   // read interface
220   virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length)
290221   {
291      fprintf(stderr, "Invalid file '%s'\n", filename);
292      return CHDERR_INVALID_FILE;
222      offset += m_offset;
223      if (offset >= m_maxoffset)
224         return 0;
225      if (offset + length > m_maxoffset)
226         length = m_maxoffset - offset;
227      core_fseek(m_file, offset, SEEK_SET);
228      return core_fread(m_file, dest, length);
293229   }
294230
295   if (filesize % 512 != 0)
296   {
297      fprintf(stderr, "Can't validate CHS values because data size is not divisible by the sector size\n");
298      return CHDERR_INVALID_FILE;
299   }
231private:
232   // internal state
233   core_file *      m_file;
234   UINT64         m_offset;
235   UINT64         m_maxoffset;
236};
300237
301   if (identsize < 14)
302   {
303      fprintf(stderr, "Error: the ident metadata is too short to include geometry information\n");
304      return CHDERR_INVALID_FILE;
305   }
306238
307   *bps = 512;
308   *cylinders = ((unsigned char)ident[ 2]) | (((unsigned char )ident[ 3]) << 8);
309   *heads     = ((unsigned char)ident[ 6]) | (((unsigned char )ident[ 7]) << 8);
310   *sectors   = ((unsigned char)ident[12]) | (((unsigned char )ident[13]) << 8);
239// ======================> chd_chdfile_compressor
311240
312   expected_size = (UINT64)*cylinders * (UINT64)*heads * (UINT64)*sectors * 512;
313   if (expected_size != filesize - offset)
314   {
315      fprintf(stderr, "Error: Mismatch between the ident CHS data (%u/%u/%u, %u sectors) and the file size (%u sectors)\n",
316            *cylinders, *heads, *sectors, *cylinders * *heads * *sectors,
317            (UINT32)((filesize-offset)/512));
318      return CHDERR_INVALID_FILE;
319   }
320   return CHDERR_NONE;
321}
322
323
324/*-------------------------------------------------
325    do_createhd - create a new compressed hard
326    disk image from a raw file
327-------------------------------------------------*/
328
329static int do_createhd(int argc, char *argv[], int param)
241class chd_chdfile_compressor : public chd_file_compressor
330242{
331   UINT32 guess_cylinders = 0, guess_heads = 0, guess_sectors = 0, guess_sectorsize = 0;
332   UINT32 cylinders, heads, sectors, sectorsize, hunksize, totalsectors, offset;
333   const char *inputfile, *outputfile = NULL;
334   chd_error err = CHDERR_NONE;
335   UINT32 identdatasize = 0;
336   UINT8 *identdata = NULL;
337   chd_file *chd = NULL;
338   char metadata[256];
243public:
244   // construction/destruction
245   chd_chdfile_compressor(chd_file &file, UINT64 offset = 0, UINT64 maxoffset = ~0)
246      : m_file(file),
247        m_offset(offset),
248        m_maxoffset(MIN(maxoffset, file.logical_bytes())) { }
339249
340   /* if a file is provided for argument 4 (ident filename), then shift the remaining arguments down */
341   if (argc >= 5)
250   // read interface   
251   virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length)
342252   {
343      char *scan;
344
345      /* if there are any non-digits in the 'offset', then treat it as a ident file */
346      for (scan = argv[4]; *scan != 0; scan++)
347         if (!isdigit((UINT8)*scan))
348            break;
349      if (*scan != 0)
350      {
351         /* attempt to load the file */
352         file_error filerr = core_fload(argv[4], (void **)&identdata, &identdatasize);
353         if (filerr != FILERR_NONE)
354         {
355            fprintf(stderr, "Error opening ident file '%s'\n", argv[4]);
356            return 1;
357         }
358
359         /* shift the remaining arguments down */
360         if (argc > 5)
361            memmove(&argv[4], &argv[5], (argc - 5) * sizeof(argv[0]));
362         argc--;
363      }
364   }
365
366   /* require 4-5, or 8-10 args total */
367   if (argc != 4 && argc != 5 && argc != 8 && argc != 9 && argc != 10)
368      return usage();
369
370   /* extract the first few parameters */
371   inputfile = argv[2];
372   outputfile = argv[3];
373   offset = (argc >= 5) ? atoi(argv[4]) : (get_file_size(inputfile) % IDE_SECTOR_SIZE);
374
375   /* if less than 8 parameters, we need to guess the CHS values */
376   if (argc < 8)
377   {
378      if (identdata != NULL)
379         err = get_chs_from_ident(inputfile, offset, identdata, identdatasize, &guess_cylinders, &guess_heads, &guess_sectors, &guess_sectorsize);
380      else
381         err = guess_chs(inputfile, offset, IDE_SECTOR_SIZE, &guess_cylinders, &guess_heads, &guess_sectors, &guess_sectorsize);
253      offset += m_offset;
254      if (offset >= m_maxoffset)
255         return 0;
256      if (offset + length > m_maxoffset)
257         length = m_maxoffset - offset;
258      chd_error err = m_file.read_bytes(offset, dest, length);
382259      if (err != CHDERR_NONE)
383         goto cleanup;
260         throw err;
261      return length;
384262   }
385263
386   /* parse the remaining parameters */
387   cylinders = (argc >= 6) ? atoi(argv[5]) : guess_cylinders;
388   heads = (argc >= 7) ? atoi(argv[6]) : guess_heads;
389   sectors = (argc >= 8) ? atoi(argv[7]) : guess_sectors;
390   sectorsize = (argc >= 9) ? atoi(argv[8]) : guess_sectorsize;
391   if (sectorsize == 0) sectorsize = IDE_SECTOR_SIZE;
392   hunksize = (argc >= 10) ? atoi(argv[9]) : (sectorsize > 4096) ? sectorsize : ((4096 / sectorsize) * sectorsize);
393   totalsectors = cylinders * heads * sectors;
264private:
265   // internal state
266   chd_file &      m_file;
267   UINT64         m_offset;
268   UINT64         m_maxoffset;
269};
394270
395   /* print some info */
396   printf("Input file:   %s\n", inputfile);
397   printf("Output file:  %s\n", outputfile);
398   printf("Input offset: %d\n", offset);
399   printf("Cylinders:    %d\n", cylinders);
400   printf("Heads:        %d\n", heads);
401   printf("Sectors:      %d\n", sectors);
402   printf("Bytes/sector: %d\n", sectorsize);
403   printf("Sectors/hunk: %d\n", hunksize / sectorsize);
404   printf("Logical size: %s\n", big_int_string((UINT64)totalsectors * (UINT64)sectorsize));
405271
406   /* create the new hard drive */
407   err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL);
408   if (err != CHDERR_NONE)
409   {
410      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
411      goto cleanup;
412   }
272// ======================> chd_cd_compressor
413273
414   /* open the new hard drive */
415   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
416   if (err != CHDERR_NONE)
274class chd_cd_compressor : public chd_file_compressor
275{
276public:
277   // construction/destruction
278   chd_cd_compressor(cdrom_toc &toc, chdcd_track_input_info &info)
279      : m_file(NULL),
280        m_toc(toc),
281        m_info(info) { }
282       
283   ~chd_cd_compressor()
417284   {
418      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
419      goto cleanup;
285      if (m_file != NULL)
286         core_fclose(m_file);
420287   }
421288
422   /* write the metadata */
423   sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
424   err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
425   if (err != CHDERR_NONE)
289   // read interface   
290   virtual UINT32 read_data(void *_dest, UINT64 offset, UINT32 length)
426291   {
427      fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
428      goto cleanup;
429   }
430
431   /* write the ident if present */
432   if (identdata != NULL)
433   {
434      err = chd_set_metadata(chd, HARD_DISK_IDENT_METADATA_TAG, 0, identdata, identdatasize, CHD_MDFLAGS_CHECKSUM);
435      if (err != CHDERR_NONE)
292      // verify assumptions made below
293      assert(offset % CD_FRAME_SIZE == 0);
294      assert(length % CD_FRAME_SIZE == 0);
295   
296      // initialize destination to 0 so that unused areas are filled
297      UINT8 *dest = reinterpret_cast<UINT8 *>(_dest);
298      memset(dest, 0, length);
299   
300      // find out which track we're starting in
301      UINT64 startoffs = 0;
302      UINT32 length_remaining = length;
303      for (int tracknum = 0; tracknum < m_toc.numtrks; tracknum++)
436304      {
437         fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
438         goto cleanup;
439      }
440   }
441
442   /* compress the hard drive */
443   err = chdman_compress_file(chd, inputfile, offset);
444   if (err != CHDERR_NONE)
445      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
446
447cleanup:
448   /* close everything down */
449   if (chd != NULL)
450      chd_close(chd);
451   if (err != CHDERR_NONE)
452      osd_rmfile(outputfile);
453   if (identdata != NULL)
454      osd_free(identdata);
455   return (err != CHDERR_NONE);
456}
457
458/*-------------------------------------------------
459    do_createhd_uncomp - create a new uncompressed hard
460    disk image from a raw file
461-------------------------------------------------*/
462
463static int do_createhd_uncomp(int argc, char *argv[], int param)
464{
465   UINT32 guess_cylinders = 0, guess_heads = 0, guess_sectors = 0, guess_sectorsize = 0;
466   UINT32 cylinders, heads, sectors, sectorsize, hunksize, totalsectors, offset;
467   const char *inputfile, *outputfile = NULL;
468   chd_error err = CHDERR_NONE;
469   UINT32 identdatasize = 0;
470   UINT8 *identdata = NULL;
471   chd_file *chd = NULL;
472   char metadata[256];
473   chd_header header;
474
475   /* if a file is provided for argument 4 (ident filename), then shift the remaining arguments down */
476   if (argc >= 5)
477   {
478      char *scan;
479
480      /* if there are any non-digits in the 'offset', then treat it as a ident file */
481      for (scan = argv[4]; *scan != 0; scan++)
482         if (!isdigit((UINT8)*scan))
483            break;
484      if (*scan != 0)
485      {
486         /* attempt to load the file */
487         file_error filerr = core_fload(argv[4], (void **)&identdata, &identdatasize);
488         if (filerr != FILERR_NONE)
305         const cdrom_track_info &trackinfo = m_toc.tracks[tracknum];
306         UINT64 endoffs = startoffs + (trackinfo.frames + trackinfo.extraframes) * CD_FRAME_SIZE;
307         if (offset >= startoffs && offset < endoffs)
489308         {
490            fprintf(stderr, "Error opening ident file '%s'\n", argv[4]);
491            return 1;
309            // if we don't already have this file open, open it now
310            if (m_file == NULL || m_lastfile != m_info.track[tracknum].fname)
311            {
312               if (m_file != NULL)
313                  core_fclose(m_file);
314               m_lastfile = m_info.track[tracknum].fname;
315               file_error filerr = core_fopen(m_lastfile, OPEN_FLAG_READ, &m_file);
316               if (filerr != FILERR_NONE)
317                  report_error(1, "Error opening input file (%s)'", m_lastfile.cstr());
318            }
319           
320            // iterate over frames
321            UINT32 bytesperframe = trackinfo.datasize + trackinfo.subsize;
322            UINT64 src_track_start = m_info.track[tracknum].offset;
323            UINT64 src_track_end = src_track_start + bytesperframe * trackinfo.frames;
324            while (length_remaining != 0 && offset < endoffs)
325            {
326               // determine start of current frame
327               UINT64 src_frame_start = src_track_start + ((offset - startoffs) / CD_FRAME_SIZE) * bytesperframe;
328               if (src_frame_start < src_track_end)
329               {
330                  // read it in
331                  core_fseek(m_file, src_frame_start, SEEK_SET);
332                  UINT32 count = core_fread(m_file, dest, bytesperframe);
333                  if (count != bytesperframe)
334                     report_error(1, "Error reading input file (%s)'", m_lastfile.cstr());
335                     
336                  // swap if appropriate
337                  if (m_info.track[tracknum].swap)
338                     for (UINT32 swapindex = 0; swapindex < 2352; swapindex += 2)
339                     {
340                        UINT8 temp = dest[swapindex];
341                        dest[swapindex] = dest[swapindex + 1];
342                        dest[swapindex + 1] = temp;
343                     }
344               }
345               
346               // advance
347               offset += CD_FRAME_SIZE;
348               dest += CD_FRAME_SIZE;
349               length_remaining -= CD_FRAME_SIZE;
350               if (length_remaining == 0)
351                  break;
352            }
492353         }
493
494         /* shift the remaining arguments down */
495         if (argc > 5)
496            memmove(&argv[4], &argv[5], (argc - 5) * sizeof(argv[0]));
497         argc--;
354         
355         // next track starts after the previous one
356         startoffs = endoffs;
498357      }
358      return length - length_remaining;
499359   }
500360
501   /* require 4-5, or 8-10 args total */
502   if (argc != 4 && argc != 5 && argc != 8 && argc != 9 && argc != 10)
503      return usage();
361private:
362   // internal state
363   astring                  m_lastfile;
364   core_file *               m_file;
365   cdrom_toc &               m_toc;
366   chdcd_track_input_info &   m_info;
367};
504368
505   /* extract the first few parameters */
506   inputfile = argv[2];
507   outputfile = argv[3];
508   offset = (argc >= 5) ? atoi(argv[4]) : (get_file_size(inputfile) % IDE_SECTOR_SIZE);
509369
510   /* if less than 8 parameters, we need to guess the CHS values */
511   if (argc < 8)
512   {
513      if (identdata != NULL)
514         err = get_chs_from_ident(inputfile, offset, identdata, identdatasize, &guess_cylinders, &guess_heads, &guess_sectors, &guess_sectorsize);
515      else
516         err = guess_chs(inputfile, offset, IDE_SECTOR_SIZE, &guess_cylinders, &guess_heads, &guess_sectors, &guess_sectorsize);
517      if (err != CHDERR_NONE)
518         goto cleanup;
519   }
370// ======================> chd_avi_compressor
520371
521   /* parse the remaining parameters */
522   cylinders = (argc >= 6) ? atoi(argv[5]) : guess_cylinders;
523   heads = (argc >= 7) ? atoi(argv[6]) : guess_heads;
524   sectors = (argc >= 8) ? atoi(argv[7]) : guess_sectors;
525   sectorsize = (argc >= 9) ? atoi(argv[8]) : guess_sectorsize;
526   if (sectorsize == 0) sectorsize = IDE_SECTOR_SIZE;
527   hunksize = (argc >= 10) ? atoi(argv[9]) : (sectorsize > 4096) ? sectorsize : ((4096 / sectorsize) * sectorsize);
528   totalsectors = cylinders * heads * sectors;
529
530   /* print some info */
531   printf("Input file:   %s\n", inputfile);
532   printf("Output file:  %s\n", outputfile);
533   printf("Input offset: %d\n", offset);
534   printf("Cylinders:    %d\n", cylinders);
535   printf("Heads:        %d\n", heads);
536   printf("Sectors:      %d\n", sectors);
537   printf("Bytes/sector: %d\n", sectorsize);
538   printf("Sectors/hunk: %d\n", hunksize / sectorsize);
539   printf("Logical size: %s\n", big_int_string((UINT64)totalsectors * (UINT64)sectorsize));
540
541   /* create the new hard drive */
542   err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_NONE, NULL);
543   if (err != CHDERR_NONE)
544   {
545      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
546      goto cleanup;
547   }
548
549   /* open the new hard drive */
550   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
551   if (err != CHDERR_NONE)
552   {
553      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
554      goto cleanup;
555   }
556
557   /* write the metadata */
558   sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
559   err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
560   if (err != CHDERR_NONE)
561   {
562      fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
563      goto cleanup;
564   }
565
566   /* write the ident if present */
567   if (identdata != NULL)
568   {
569      err = chd_set_metadata(chd, HARD_DISK_IDENT_METADATA_TAG, 0, identdata, identdatasize, CHD_MDFLAGS_CHECKSUM);
570      if (err != CHDERR_NONE)
571      {
572         fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
573         goto cleanup;
574      }
575   }
576
577   /* compress the hard drive */
578   err = chdman_compress_file(chd, inputfile, offset);
579   if (err != CHDERR_NONE)
580      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
581
582   /* make it writeable */
583   header = *chd_get_header(chd);
584   header.flags |= CHDFLAGS_IS_WRITEABLE;
585   err = chd_set_header_file(chd_core_file(chd), &header);
586   if (err != CHDERR_NONE)
587      fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err));
588
589cleanup:
590   /* close everything down */
591   if (chd != NULL)
592      chd_close(chd);
593   if (err != CHDERR_NONE)
594      osd_rmfile(outputfile);
595   if (identdata != NULL)
596      osd_free(identdata);
597   return (err != CHDERR_NONE);
598}
599
600/*-------------------------------------------------
601    do_createraw - create a new compressed raw
602    image from a raw file
603-------------------------------------------------*/
604
605static int do_createraw(int argc, char *argv[], int param)
372class chd_avi_compressor : public chd_file_compressor
606373{
607   const char *inputfile, *outputfile;
608   UINT32 hunksize, offset;
609   UINT64 logicalbytes;
610   chd_file *chd = NULL;
611   chd_error err;
612
613   /* require 4, 5, or 6 args total */
614   if (argc != 4 && argc != 5 && argc != 6)
615      return usage();
616
617   /* extract the first few parameters */
618   inputfile = argv[2];
619   outputfile = argv[3];
620   offset = (argc >= 5) ? atoi(argv[4]) : 0;
621   hunksize = (argc >= 6) ? atoi(argv[5]) : 4096;
622   logicalbytes = get_file_size(inputfile) - offset;
623
624   /* print some info */
625   printf("Input file:   %s\n", inputfile);
626   printf("Output file:  %s\n", outputfile);
627   printf("Input offset: %d\n", offset);
628   printf("Bytes/hunk:   %d\n", hunksize);
629   printf("Logical size: %s\n", big_int_string(logicalbytes));
630
631   /* create the new CHD */
632   err = chd_create(outputfile, logicalbytes, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL);
633   if (err != CHDERR_NONE)
374public:
375   // construction/destruction
376   chd_avi_compressor(avi_file &file, avi_info &info, UINT32 first_frame, UINT32 num_frames)
377      : m_file(file),
378        m_info(info),
379        m_bitmap(info.width, info.height * (info.interlaced ? 2 : 1)),
380        m_start_frame(first_frame),
381        m_frame_count(num_frames),
382        m_ldframedata(num_frames * VBI_PACKED_BYTES),
383        m_rawdata(info.bytes_per_frame) { }
384     
385   // getters
386   const dynamic_buffer &ldframedata() const { return m_ldframedata; }
387   
388   // read interface   
389   virtual UINT32 read_data(void *_dest, UINT64 offset, UINT32 length)
634390   {
635      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
636      goto cleanup;
637   }
391      UINT8 *dest = reinterpret_cast<UINT8 *>(_dest);
392      int interlace_factor = m_info.interlaced ? 2 : 1;
393      UINT32 length_remaining = length;
638394
639   /* open the new CHD */
640   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
641   if (err != CHDERR_NONE)
642   {
643      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
644      goto cleanup;
645   }
646
647   /* compress the CHD */
648   err = chdman_compress_file(chd, inputfile, offset);
649   if (err != CHDERR_NONE)
650      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
651
652cleanup:
653   /* close everything down */
654   if (chd != NULL)
655      chd_close(chd);
656   if (err != CHDERR_NONE)
657      osd_rmfile(outputfile);
658   return (err != CHDERR_NONE);
659}
660
661
662/*-------------------------------------------------
663    do_createcd - create a new compressed CD
664    image from a raw file
665-------------------------------------------------*/
666
667static int do_createcd(int argc, char *argv[], int param)
668{
669   static chdcd_track_input_info track_info;
670   static cdrom_toc toc;
671   UINT32 hunksize = CD_FRAME_SIZE * CD_FRAMES_PER_HUNK;
672   UINT32 sectorsize = CD_FRAME_SIZE;
673   const char *inputfile, *outputfile;
674   core_file *srcfile = NULL;
675   UINT32 origtotalsectors;
676   chd_file *chd = NULL;
677   UINT8 *cache = NULL;
678   UINT32 totalsectors;
679   double ratio = 1.0;
680   UINT32 totalhunks;
681   file_error filerr;
682   chd_error err;
683   int i;
684
685   /* require 4 args total */
686   if (argc != 4)
687      return usage();
688
689   /* extract the data */
690   inputfile = argv[2];
691   outputfile = argv[3];
692
693   /* clear the TOC */
694   memset(&toc, 0, sizeof(toc));
695
696   /* allocate a cache */
697   cache = (UINT8 *)malloc(hunksize);
698   if (cache == NULL)
699   {
700      fprintf(stderr, "Out of memory allocating temporary buffer\n");
701      err = CHDERR_OUT_OF_MEMORY;
702      goto cleanup;
703   }
704
705   /* setup the CDROM module and get the disc info */
706   err = chdcd_parse_toc(inputfile, &toc, &track_info);
707   if (err != CHDERR_NONE)
708   {
709      fprintf(stderr, "Error reading input file: %s\n", chd_error_string(err));
710      goto cleanup;
711   }
712
713   /* pad each track to a hunk boundry. cdrom.c will deal with this on the read side */
714   for (i = 0; i < toc.numtrks; i++)
715   {
716      int hunks = (toc.tracks[i].frames + CD_FRAMES_PER_HUNK - 1) / CD_FRAMES_PER_HUNK;
717      toc.tracks[i].extraframes = hunks * CD_FRAMES_PER_HUNK - toc.tracks[i].frames;
718   }
719
720
721   /* count up the total number of frames */
722   origtotalsectors = totalsectors = 0;
723   for (i = 0; i < toc.numtrks; i++)
724   {
725      origtotalsectors += toc.tracks[i].frames;
726      totalsectors += toc.tracks[i].frames + toc.tracks[i].extraframes;
727   }
728   printf("\nCD-ROM %s has %d tracks and %d total frames\n", inputfile, toc.numtrks, origtotalsectors);
729
730   /* create the new CHD file */
731   if (param) err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_ZLIB_PLUS_WITH_FLAC, NULL);
732   else err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL);
733   if (err != CHDERR_NONE)
734   {
735      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
736      goto cleanup;
737   }
738
739   /* open the new CHD file */
740   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
741   if (err != CHDERR_NONE)
742   {
743      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
744      goto cleanup;
745   }
746
747   /* write the metadata */
748   err = cdrom_write_metadata(chd, &toc);
749   if (err != CHDERR_NONE)
750   {
751      fprintf(stderr, "Error adding CD-ROM metadata: %s\n", chd_error_string(err));
752      goto cleanup;
753   }
754
755   /* begin state for writing */
756   err = chd_compress_begin(chd);
757   if (err != CHDERR_NONE)
758   {
759      fprintf(stderr, "Error compressing: %s\n", chd_error_string(err));
760      goto cleanup;
761   }
762
763   /* loop over tracks */
764   totalhunks = 0;
765   for (i = 0; i < toc.numtrks; i++)
766   {
767      int frames = 0;
768      int bytespersector = toc.tracks[i].datasize + toc.tracks[i].subsize;
769      int trackhunks = (toc.tracks[i].frames + toc.tracks[i].extraframes) / CD_FRAMES_PER_HUNK;
770      UINT64 sourcefileoffset = track_info.offset[i];
771      int curhunk;
772
773      /* open the input file for this track */
774      filerr = core_fopen(track_info.fname[i], OPEN_FLAG_READ, &srcfile);
775      if (filerr != FILERR_NONE)
776      {
777         fprintf(stderr, "Unable to open file: %s\n", track_info.fname[i]);
778         err = CHDERR_FILE_NOT_FOUND;
779         goto cleanup;
780      }
781
782      printf("Track %02d/%02d (%s:%d,%d frames,%d hunks,swap %d,pregap %d,postgap %d)\n", i+1, toc.numtrks, track_info.fname[i], track_info.offset[i], toc.tracks[i].frames, trackhunks, track_info.swap[i], toc.tracks[i].pregap, toc.tracks[i].postgap);
783
784      /* loop over hunks */
785      for (curhunk = 0; curhunk < trackhunks; curhunk++, totalhunks++)
786      {
787         int secnum;
788
789         progress(FALSE, "Compressing hunk %d/%d... (ratio=%d%%)  \r", totalhunks, chd_get_header(chd)->totalhunks, (int)(ratio * 100));
790
791         /* loop over sectors in this hunk, reading the source data into a fixed start location */
792         /* relative to the start; we zero out the buffer ahead of time to ensure that unpopulated */
793         /* areas are cleared */
794         memset(cache, 0, hunksize);
795         for (secnum = 0; secnum < CD_FRAMES_PER_HUNK; secnum++)
395      // iterate over frames
396      INT32 start_frame = offset / m_info.bytes_per_frame;
397      INT32 end_frame = (offset + length - 1) / m_info.bytes_per_frame;
398      for (INT32 framenum = start_frame; framenum <= end_frame; framenum++)
399         if (framenum < m_frame_count)
796400         {
797            if (frames < toc.tracks[i].frames)
401            // determine effective frame number and first/last samples
402            INT32 effframe = m_start_frame + framenum;
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            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           
406            // loop over channels and read the samples
407            int channels = MIN(m_info.channels, ARRAY_LENGTH(m_audio));
408            INT16 *samplesptr[ARRAY_LENGTH(m_audio)];
409            for (int chnum = 0; chnum < channels; chnum++)
798410            {
799               core_fseek(srcfile, sourcefileoffset, SEEK_SET);
800               core_fread(srcfile, &cache[secnum * CD_FRAME_SIZE], bytespersector);
411               // read the sound samples
412               m_audio[chnum].resize(samples);
413               samplesptr[chnum] = m_audio[chnum];
414               avi_error avierr = avi_read_sound_samples(&m_file, chnum, first_sample, samples, m_audio[chnum]);
415               if (avierr != AVIERR_NONE)
416                  report_error(1, "Error reading audio samples %d-%d from channel %d: %s", first_sample, samples, chnum, avi_error_string(avierr));
417            }
801418
802               if (track_info.swap[i])
803               {
804                  int swapindex;
419            // read the video data
420            avi_error avierr = avi_read_video_frame(&m_file, effframe / interlace_factor, m_bitmap);
421            if (avierr != AVIERR_NONE)
422               report_error(1, "Error reading AVI frame %d: %s", effframe / interlace_factor, avi_error_string(avierr));
423            bitmap_yuy16 subbitmap(&m_bitmap.pix(effframe % interlace_factor), m_bitmap.width(), m_bitmap.height() / interlace_factor, m_bitmap.rowpixels() * interlace_factor);
805424
806                  for (swapindex = 0; swapindex < 2352; swapindex += 2 )
807                  {
808                     int swapoffset = ( secnum * CD_FRAME_SIZE ) + swapindex;
809
810                     int swaptemp = cache[ swapoffset ];
811                     cache[ swapoffset ] = cache[ swapoffset + 1 ];
812                     cache[ swapoffset + 1 ] = swaptemp;
813                  }
814               }
425            // update metadata for this frame
426            if (m_info.height == 524/2 || m_info.height == 624/2)
427            {
428               vbi_metadata vbi;
429               vbi_parse_all(&subbitmap.pix16(0), subbitmap.rowpixels(), subbitmap.width(), 8, &vbi);
430               vbi_metadata_pack(&m_ldframedata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
815431            }
816432
817            sourcefileoffset += bytespersector;
818            frames++;
433            // assemble the data into final form
434            avhuff_error averr = avhuff_encoder::assemble_data(m_rawdata, m_rawdata.count(), subbitmap, channels, samples, samplesptr);
435            if (averr != AVHERR_NONE)
436               report_error(1, "Error assembling data for frame %d", framenum);
437            UINT32 rawsize = avhuff_encoder::raw_data_size(m_rawdata);
438            if (rawsize < m_rawdata.count())
439               memset(&m_rawdata[rawsize], 0, m_rawdata.count() - rawsize);
440           
441            // copy to the destination
442            UINT64 start_offset = UINT64(framenum) * UINT64(m_info.bytes_per_frame);
443            UINT64 end_offset = start_offset + m_info.bytes_per_frame;
444            UINT32 bytes_to_copy = MIN(length_remaining, end_offset - offset);
445            memcpy(dest, &m_rawdata[offset - start_offset], bytes_to_copy);
446           
447            // advance
448            offset += bytes_to_copy;
449            dest += bytes_to_copy;
450            length_remaining -= bytes_to_copy;
819451         }
820452
821         int is_half_hunk = 0;
822         if ((curhunk == trackhunks-1) && (toc.tracks[i].extraframes>3))
823            is_half_hunk = 1;
824
825
826         /* compress the current hunk */
827
828         err = chd_compress_hunk(chd, cache, &ratio, is_half_hunk);
829         if (err != CHDERR_NONE)
830         {
831            fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
832            goto cleanup;
833         }
834      }
835
836      /* close the file */
837      core_fclose(srcfile);
838      srcfile = NULL;
453      return length;
839454   }
840455
841   /* cleanup */
842   err = chd_compress_finish(chd, TRUE);
843   if (err != CHDERR_NONE)
844      fprintf(stderr, "Error during compression finalization: %s\n", chd_error_string(err));
845   else
846      progress(TRUE, "Compression complete ... final ratio = %d%%            \n", (int)(100.0 * ratio));
456private:
457   // internal state
458   avi_file &               m_file;
459   avi_info &               m_info;
460   bitmap_yuy16            m_bitmap;
461   UINT32                  m_start_frame;
462   UINT32                  m_frame_count;
463   dynamic_array<INT16>      m_audio[8];
464   dynamic_buffer            m_ldframedata;
465   dynamic_buffer            m_rawdata;
466};
847467
848cleanup:
849   if (cache != NULL)
850      free(cache);
851   if (srcfile != NULL)
852      core_fclose(srcfile);
853   if (chd != NULL)
854      chd_close(chd);
855   if (err != CHDERR_NONE)
856      osd_rmfile(outputfile);
857   return (err != CHDERR_NONE);
858}
859468
860469
861/*-------------------------------------------------
862    read_avi_frame - read an AVI frame
863-------------------------------------------------*/
470//**************************************************************************
471//  GLOBAL VARIABLES
472//**************************************************************************
864473
865static avi_error read_avi_frame(avi_file *avi, UINT32 framenum, UINT32 first_sample, bitmap_yuy16 &fullbitmap, int interlaced, av_codec_compress_config *avconfig)
866{
867   const avi_movie_info *info = avi_get_movie_info(avi);
868   int interlace_factor = interlaced ? 2 : 1;
869   avi_error avierr = AVIERR_NONE;
870   int chnum;
474// timing
475static clock_t lastprogress = 0;
871476
872   /* loop over channels and read the samples */
873   for (chnum = 0; chnum < info->audio_channels; chnum++)
874   {
875      /* read the sound samples */
876      avierr = avi_read_sound_samples(avi, chnum, first_sample, avconfig->samples, avconfig->audio[chnum]);
877      if (avierr != AVIERR_NONE)
878         goto cleanup;
879   }
880477
881   /* read the video data when we hit a new frame */
882   if (framenum % interlace_factor == 0)
883   {
884      avierr = avi_read_video_frame(avi, framenum / interlace_factor, fullbitmap);
885      if (avierr != AVIERR_NONE)
886         goto cleanup;
887   }
478// default compressors
479static const chd_codec_type s_default_raw_compression[4] = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN };
480static const chd_codec_type s_default_hd_compression[4] = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN };
481static const chd_codec_type s_default_cd_compression[4] = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN, CHD_CODEC_FLAC_BE };
482static const chd_codec_type s_default_ld_compression[4] = { CHD_CODEC_AVHUFF };
888483
889   /* build the fake bitmap */
890   if (!interlaced)
891      avconfig->video.wrap(fullbitmap, fullbitmap.cliprect());
892   else
893      avconfig->video.wrap(&fullbitmap.pix16(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / 2, fullbitmap.rowpixels() * 2);
894484
895cleanup:
896   return avierr;
897}
898
899
900/*-------------------------------------------------
901    fake_avi_frame - fake an AVI frame
902-------------------------------------------------*/
903
904static avi_error fake_avi_frame(avi_file *avi, UINT32 framenum, UINT32 first_sample, bitmap_yuy16 &fullbitmap, int interlaced, av_codec_compress_config *avconfig)
485// descriptions for each option
486static const option_description s_options[] =
905487{
906   static int framecounter = 0;
907   int leftsamp = (framenum % 200 < 10) ? 10000 : 0;
908   int rightsamp = (framenum % 200 >= 100 && framenum % 200 < 110) ? 10000 : 0;
909   int interlace_factor = interlaced ? 2 : 1;
910   int chnum, sampnum, x, y;
911   int whiteflag, line1718;
488   { OPTION_INPUT,             "i",   true, " <filename>: input file name" },
489   { OPTION_INPUT_PARENT,         "ip",   true, " <filename>: parent file name for input CHD" },
490   { OPTION_OUTPUT,            "o",   true, " <filename>: output file name" },
491   { OPTION_OUTPUT_BIN,         "ob",   true, " <filename>: output file name for binary data" },
492   { OPTION_OUTPUT_FORCE,         "f",   false, ": force overwriting an existing file" },
493   { OPTION_OUTPUT_PARENT,         "op",   true, " <filename>: parent file name for output CHD" },
494   { OPTION_INPUT_START_BYTE,      "isb",   true, " <offset>: starting byte offset within the input" },
495   { OPTION_INPUT_START_HUNK,      "ish",   true, " <offset>: starting hunk offset within the input" },
496   { OPTION_INPUT_START_FRAME,      "isf",   true, " <offset>: starting frame within the input" },
497   { OPTION_INPUT_LENGTH_BYTES,   "ib",   true, " <length>: effective length of input in bytes" },
498   { OPTION_INPUT_LENGTH_HUNKS,   "ih",   true, " <length>: effective length of input in hunks" },
499   { OPTION_INPUT_LENGTH_FRAMES,   "if",   true, " <length>: effective length of input in frames" },
500   { OPTION_HUNK_SIZE,            "hs",   true, " <bytes>: size of each hunk, in bytes" },
501   { OPTION_UNIT_SIZE,            "us",   true, " <bytes>: size of each unit, in bytes" },
502   { OPTION_COMPRESSION,         "c",   true, " <none|type1[,type2[,...]]>: which compression codecs to use (up to 4)" },
503   { OPTION_IDENT,               "id",   true, " <filename>: name of ident file to provide CHS information" },
504   { OPTION_CHS,               "chs",   true, " <cylinders,heads,sectors>: specifies CHS values directly" },
505   { OPTION_SECTOR_SIZE,         "ss",   true, " <bytes>: size of each hard disk sector" },
506   { OPTION_TAG,               "t",   true, " <tag>: 4-character tag for metadata" },
507   { OPTION_INDEX,               "ix",   true, " <index>: indexed instance of this metadata tag" },
508   { OPTION_VALUE_TEXT,         "vt",   true, " <text>: text for the metadata" },
509   { OPTION_VALUE_FILE,         "vf",   true, " <file>: file containing data to add" },
510#if NUM_PROCESSORS_SUPPORTED
511   { OPTION_NUMPROCESSORS,         "np",   true, " <processors>: limit the number of processors to use during compression" },
512#endif
513   { OPTION_NO_CHECKSUM,         "nocs",   false, ": do not include this metadata information in the overall SHA-1" },
514   { OPTION_FIX,               "f",   false, ": fix the SHA-1 if it is incorrect" },
515   { OPTION_VERBOSE,            "v",   false, ": output additional information" },
516};
912517
913   /* reset framecounter to 1 on frame 0 */
914   if (framenum == 0)
915      framecounter = 1;
916518
917   /* loop over channels and read the samples */
918   for (chnum = 0; chnum < AVI_FAKE_CHANNELS; chnum++)
919   {
920      int modcheck = AVI_FAKE_SAMPLERATE / ((chnum == 0) ? 110 : 220);
921      int samp = (chnum == 0) ? leftsamp : rightsamp;
922      INT16 *dest = avconfig->audio[chnum];
923
924      /* store them to the audio buffer */
925      for (sampnum = 0; sampnum < avconfig->samples; sampnum++)
926         *dest++ = ((first_sample + sampnum) % modcheck < modcheck / 2) ? samp : -samp;
927   }
928
929   /* determine what metadata we should generate */
930   whiteflag = line1718 = 0;
931   if (framenum < 2)
932   {
933      whiteflag = (framenum == 0);
934      line1718 = 0x88ffff;
935   }
936   else if (framenum >= AVI_FAKE_FRAMES * 2 - 2)
937   {
938      whiteflag = (framenum == AVI_FAKE_FRAMES * 2 - 2);
939      line1718 = 0x80eeee;
940   }
941   else
942   {
943      int effnum = framenum - 2;
944      if (avi == AVI_FAKE_FILE_22 && effnum % 2 == 0)
945         whiteflag = 1;
946      else if (avi == AVI_FAKE_FILE_32 && (effnum % 5 == 0 || effnum % 5 == 2))
947         whiteflag = 1;
948      if (whiteflag)
519// descriptions for each command
520static const command_description s_commands[] =
521{
522   { COMMAND_INFO, do_info, ": displays information about a CHD",
949523      {
950         line1718 = 0xf80000 | (((framecounter / 10000) % 10) << 16) | (((framecounter / 1000) % 10) << 12) |
951                  (((framecounter / 100) % 10) << 8) | (((framecounter / 10) % 10) << 4) | (framecounter % 10);
952         framecounter++;
524         REQUIRED OPTION_INPUT,
525         OPTION_VERBOSE
526      }
527   },
528   
529   { COMMAND_VERIFY, do_verify, ": verifies a CHD's integrity",
530      {
531         REQUIRED OPTION_INPUT,
532         OPTION_INPUT_PARENT
533      }
534   },
535   
536   { COMMAND_CREATE_RAW, do_create_raw, ": create a raw CHD from the input file",
537      {
538         REQUIRED OPTION_OUTPUT,
539         OPTION_OUTPUT_PARENT,
540         OPTION_OUTPUT_FORCE,
541         REQUIRED OPTION_INPUT,
542         OPTION_INPUT_START_BYTE,
543         OPTION_INPUT_START_HUNK,
544         OPTION_INPUT_LENGTH_BYTES,
545         OPTION_INPUT_LENGTH_HUNKS,
546         REQUIRED OPTION_HUNK_SIZE,
547         REQUIRED OPTION_UNIT_SIZE,
548         OPTION_COMPRESSION,
549#if NUM_PROCESSORS_SUPPORTED
550         OPTION_NUMPROCESSORS
551#endif
953552      }
954   }
955
956   /* build the fake bitmap */
957   if (!interlaced)
958      avconfig->video.wrap(fullbitmap, fullbitmap.cliprect());
959   else
960      avconfig->video.wrap(&fullbitmap.pix16(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / 2, fullbitmap.rowpixels() * 2);
961
962   /* loop over the data and copy it to the cache */
963   for (y = 0; y < avconfig->video.height(); y++)
964   {
965      UINT16 *dest = &avconfig->video.pix16(y);
966
967      /* white flag? */
968      if (y == 11 && whiteflag)
553   },
554   
555   { COMMAND_CREATE_HD, do_create_hd, ": create a hard disk CHD from the input file",
969556      {
970         for (x = 0; x < AVI_FAKE_WIDTH; x++)
971            *dest++ = (x > 10 && x < avconfig->video.width() - 10) ? 0xff80 : 0x0080;
557         REQUIRED OPTION_OUTPUT,
558         OPTION_OUTPUT_PARENT,
559         OPTION_OUTPUT_FORCE,
560         OPTION_INPUT,
561         OPTION_INPUT_START_BYTE,
562         OPTION_INPUT_START_HUNK,
563         OPTION_INPUT_LENGTH_BYTES,
564         OPTION_INPUT_LENGTH_HUNKS,
565         OPTION_HUNK_SIZE,
566         OPTION_COMPRESSION,
567         OPTION_IDENT,
568         OPTION_CHS,
569         OPTION_SECTOR_SIZE,
570#if NUM_PROCESSORS_SUPPORTED
571         OPTION_NUMPROCESSORS
572#endif
972573      }
973
974      /* line 17/18 */
975      else if ((y == 17 || y == 18) && line1718 != 0)
574   },
575   
576   { COMMAND_CREATE_CD, do_create_cd, ": create a CD CHD from the input file",
976577      {
977         for (x = 0; x < avconfig->video.width(); x++)
978         {
979            UINT16 pixel = 0x0080;
980            if (x >= 20)
981            {
982               int bitnum = (x - 20) / 28;
983               if (bitnum < 24)
984               {
985                  int bithalf = (x - (bitnum * 28 + 20)) / 14;
986                  if ((line1718 << bitnum) & 0x800000) bithalf ^= 1;
987                  pixel = bithalf ? 0x0080 : 0xff80;
988               }
989            }
990            *dest++ = pixel;
991         }
578         REQUIRED OPTION_OUTPUT,
579         OPTION_OUTPUT_PARENT,
580         OPTION_OUTPUT_FORCE,
581         REQUIRED OPTION_INPUT,
582         OPTION_HUNK_SIZE,
583         OPTION_COMPRESSION,
584#if NUM_PROCESSORS_SUPPORTED
585         OPTION_NUMPROCESSORS
586#endif
992587      }
993
994      /* anything else in VBI-land */
995      else if (y < 22)
588   },
589   
590   { COMMAND_CREATE_LD, do_create_ld, ": create a laserdisc CHD from the input file",
996591      {
997         for (x = 0; x < avconfig->video.width(); x++)
998            *dest++ = 0x0080;
592         REQUIRED OPTION_OUTPUT,
593         OPTION_OUTPUT_PARENT,
594         OPTION_OUTPUT_FORCE,
595         REQUIRED OPTION_INPUT,
596         OPTION_INPUT_START_FRAME,
597         OPTION_INPUT_LENGTH_FRAMES,
598         OPTION_HUNK_SIZE,
599         OPTION_COMPRESSION,
600#if NUM_PROCESSORS_SUPPORTED
601         OPTION_NUMPROCESSORS
602#endif
999603      }
1000
1001      /* everything else */
1002      else
604   },
605   
606   { COMMAND_EXTRACT_RAW, do_extract_raw, ": extract raw file from a CHD input file",
1003607      {
1004         for (x = 0; x < avconfig->video.width(); x++)
1005            *dest++ = framenum;
608         REQUIRED OPTION_OUTPUT,
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,
615         OPTION_INPUT_LENGTH_HUNKS
1006616      }
1007   }
1008
1009   return AVIERR_NONE;
1010}
1011
1012
1013/*-------------------------------------------------
1014    do_createav - create a new A/V file from an
1015    input AVI file and metadata
1016-------------------------------------------------*/
1017
1018static int do_createav(int argc, char *argv[], int param)
1019{
1020   UINT32 fps_times_1million, width, height, interlaced, channels, rate, totalframes;
1021   UINT32 max_samples_per_frame, bytes_per_frame, firstframe, numframes;
1022   av_codec_compress_config avconfig;
1023   const char *inputfile, *outputfile;
1024   const avi_movie_info *info;
1025   UINT8 *ldframedata = NULL;
1026   const chd_header *header;
1027   chd_file *chd = NULL;
1028   avi_file *avi = NULL;
1029   double ratio = 1.0;
1030   char metadata[256];
1031   avi_error avierr;
1032   UINT32 framenum;
1033   chd_error err;
1034   int chnum;
1035
1036   /* require 4-6 args total */
1037   if (argc < 4 || argc > 6)
1038      return usage();
1039
1040   /* extract the first few parameters */
1041   inputfile = argv[2];
1042   outputfile = argv[3];
1043   firstframe = (argc > 4) ? atoi(argv[4]) : 0;
1044   numframes = (argc > 5) ? atoi(argv[5]) : 1000000;
1045
1046   /* print some info */
1047   printf("Input file:   %s\n", inputfile);
1048   printf("Output file:  %s\n", outputfile);
1049
1050   /* special AVI files */
1051   if (strcmp(inputfile, "2:2") == 0 || strcmp(inputfile, "3:2") == 0)
1052   {
1053      /* create a fake handle */
1054      avi = (strcmp(inputfile, "2:2") == 0) ? AVI_FAKE_FILE_22 : AVI_FAKE_FILE_32;
1055
1056      /* fake the movie information */
1057      fps_times_1million = AVI_FAKE_FRAMERATE;
1058      width = AVI_FAKE_WIDTH;
1059      height = AVI_FAKE_HEIGHT;
1060      interlaced = TRUE;
1061      channels = 2;
1062      rate = AVI_FAKE_SAMPLERATE;
1063      totalframes = AVI_FAKE_FRAMES;
1064   }
1065   else
1066   {
1067      /* open the source file */
1068      avierr = avi_open(inputfile, &avi);
1069      if (avierr != AVIERR_NONE)
617   },
618   
619   { COMMAND_EXTRACT_HD, do_extract_raw, ": extract raw hard disk file from a CHD input file",
1070620      {
1071         fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr));
1072         err = CHDERR_INVALID_FILE;
1073         goto cleanup;
621         REQUIRED OPTION_OUTPUT,
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,
628         OPTION_INPUT_LENGTH_HUNKS
1074629      }
1075
1076      /* get the movie information */
1077      info = avi_get_movie_info(avi);
1078      fps_times_1million = (UINT64)info->video_timescale * 1000000 / info->video_sampletime;
1079      width = info->video_width;
1080      height = info->video_height;
1081      interlaced = ((fps_times_1million / 1000000) <= 30) && (height % 2 == 0) && (height > 288);
1082      channels = info->audio_channels;
1083      rate = info->audio_samplerate;
1084      totalframes = info->video_numsamples;
1085   }
1086   numframes = MIN(totalframes - firstframe, numframes);
1087
1088   /* print some of it */
1089   printf("Use frames:   %d-%d\n", firstframe, firstframe + numframes - 1);
1090   printf("Frame rate:   %d.%06d\n", fps_times_1million / 1000000, fps_times_1million % 1000000);
1091   printf("Frame size:   %d x %d %s\n", width, height, interlaced ? "interlaced" : "non-interlaced");
1092   printf("Audio:        %d channels at %d Hz\n", channels, rate);
1093   printf("Total frames: %d (%02d:%02d:%02d)\n", totalframes,
1094         (UINT32)((UINT64)totalframes * 1000000 / fps_times_1million / 60 / 60),
1095         (UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million / 60) % 60),
1096         (UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million) % 60));
1097
1098   /* adjust for interlacing */
1099   if (interlaced)
1100   {
1101      fps_times_1million *= 2;
1102      totalframes *= 2;
1103      height /= 2;
1104      firstframe *= 2;
1105      numframes *= 2;
1106   }
1107
1108   /* allocate space for the frame data */
1109   if (height == 524/2 || height == 624/2)
1110   {
1111      ldframedata = (UINT8 *)malloc(numframes * VBI_PACKED_BYTES);
1112      if (ldframedata == NULL)
630   },
631   
632   { COMMAND_EXTRACT_CD, do_extract_cd, ": extract CD file from a CHD input file",
1113633      {
1114         fprintf(stderr, "Out of memory allocating frame metadata\n");
1115         err = CHDERR_OUT_OF_MEMORY;
1116         goto cleanup;
634         REQUIRED OPTION_OUTPUT,
635         OPTION_OUTPUT_BIN,
636         OPTION_OUTPUT_FORCE,
637         REQUIRED OPTION_INPUT
638         OPTION_INPUT_PARENT,
1117639      }
1118      memset(ldframedata, 0, numframes * VBI_PACKED_BYTES);
1119   }
1120
1121   /* determine the number of bytes per frame */
1122   max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
1123   bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2;
1124
1125   /* allocate a video buffer */
1126   {
1127      bitmap_yuy16 fullbitmap(width, height * (interlaced ? 2 : 1));
1128      avconfig.video.wrap(fullbitmap, fullbitmap.cliprect());
1129
1130      /* allocate audio buffers */
1131      avconfig.channels = channels;
1132      for (chnum = 0; chnum < channels; chnum++)
640   },
641   
642   { COMMAND_EXTRACT_LD, do_extract_ld, ": extract laserdisc AVI from a CHD input file",
1133643      {
1134         avconfig.audio[chnum] = (INT16 *)malloc(max_samples_per_frame * 2);
1135         if (avconfig.audio[chnum] == NULL)
1136         {
1137            fprintf(stderr, "Out of memory allocating temporary audio buffer\n");
1138            err = CHDERR_OUT_OF_MEMORY;
1139            goto cleanup;
1140         }
644         REQUIRED OPTION_OUTPUT,
645         OPTION_OUTPUT_FORCE,
646         REQUIRED OPTION_INPUT,
647         OPTION_INPUT_PARENT,
648         OPTION_INPUT_START_FRAME,
649         OPTION_INPUT_LENGTH_FRAMES
1141650      }
1142
1143      /* create the new CHD */
1144      err = chd_create(outputfile, (UINT64)numframes * (UINT64)bytes_per_frame, bytes_per_frame, CHDCOMPRESSION_AV, NULL);
1145      if (err != CHDERR_NONE)
651   },
652   
653   { COMMAND_COPY, do_copy, ": copy data from one CHD to another of the same type",
1146654      {
1147         fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
1148         goto cleanup;
655         REQUIRED OPTION_OUTPUT,
656         OPTION_OUTPUT_PARENT,
657         OPTION_OUTPUT_FORCE,
658         REQUIRED OPTION_INPUT,
659         OPTION_INPUT_PARENT,
660         OPTION_INPUT_START_BYTE,
661         OPTION_INPUT_START_HUNK,
662         OPTION_INPUT_LENGTH_BYTES,
663         OPTION_INPUT_LENGTH_HUNKS,
664         OPTION_HUNK_SIZE,
665         OPTION_COMPRESSION,
666#if NUM_PROCESSORS_SUPPORTED
667         OPTION_NUMPROCESSORS
668#endif
1149669      }
1150
1151      /* open the new CHD */
1152      err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
1153      if (err != CHDERR_NONE)
670   },
671   
672   { COMMAND_ADD_METADATA, do_add_metadata, ": add metadata to the CHD",
1154673      {
1155         fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
1156         goto cleanup;
674         REQUIRED OPTION_INPUT,
675         REQUIRED OPTION_TAG,
676         OPTION_INDEX,
677         OPTION_VALUE_TEXT,
678         OPTION_VALUE_FILE,
679         OPTION_NO_CHECKSUM
1157680      }
1158      header = chd_get_header(chd);
1159
1160      /* write the metadata */
1161      sprintf(metadata, AV_METADATA_FORMAT, fps_times_1million / 1000000, fps_times_1million % 1000000, width, height, interlaced, channels, rate);
1162      err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
1163      if (err != CHDERR_NONE)
681   },
682   
683   { COMMAND_DEL_METADATA, do_del_metadata, ": remove metadata from the CHD",
1164684      {
1165         fprintf(stderr, "Error adding AV metadata: %s\n", chd_error_string(err));
1166         goto cleanup;
685         REQUIRED OPTION_INPUT,
686         REQUIRED OPTION_TAG,
687         OPTION_INDEX
1167688      }
689   }
690};
1168691
1169      /* begin compressing */
1170      err = chd_compress_begin(chd);
1171      if (err != CHDERR_NONE)
1172         goto cleanup;
1173692
1174      /* loop over source hunks until we run out */
1175      for (framenum = 0; framenum < numframes; framenum++)
1176      {
1177         int effframe = firstframe + framenum;
1178         UINT32 first_sample;
1179693
1180         /* progress */
1181         progress(framenum == 0, "Compressing hunk %d/%d... (ratio=%d%%)  \r", framenum, header->totalhunks, (int)(100.0 * ratio));
694//**************************************************************************
695//  IMPLEMENTATION
696//**************************************************************************
1182697
1183         /* compute the number of samples in this frame */
1184         first_sample = ((UINT64)rate * (UINT64)effframe * (UINT64)1000000 + fps_times_1million - 1) / (UINT64)fps_times_1million;
1185         avconfig.samples = ((UINT64)rate * (UINT64)(effframe + 1) * (UINT64)1000000 + fps_times_1million - 1) / (UINT64)fps_times_1million - first_sample;
698//-------------------------------------------------
699//  report_error - report an error
700//-------------------------------------------------
1186701
1187         /* read the frame into its proper format in the cache */
1188         if (IS_FAKE_AVI_FILE(avi))
1189            avierr = fake_avi_frame(avi, effframe, first_sample, fullbitmap, interlaced, &avconfig);
1190         else
1191            avierr = read_avi_frame(avi, effframe, first_sample, fullbitmap, interlaced, &avconfig);
1192         if (avierr != AVIERR_NONE)
1193         {
1194            fprintf(stderr, "Error reading frame %d from AVI file: %s\n", effframe, avi_error_string(avierr));
1195            err = CHDERR_COMPRESSION_ERROR;
1196         }
702static void report_error(int error, const char *format, ...)
703{
704   // output to stderr
705   va_list arg;
706   va_start(arg, format);
707   vfprintf(stderr, format, arg);
708   fflush(stderr);
709   va_end(arg);
710   fprintf(stderr, "\n");
711   
712   // reset time for progress and return the error
713   lastprogress = 0;
714   throw fatal_error(error);
715}
1197716
1198         /* update metadata for this frame */
1199         if (ldframedata != NULL)
1200         {
1201            /* parse the data and pack it */
1202            vbi_metadata vbi;
1203            vbi_parse_all(&avconfig.video.pix16(0), avconfig.video.rowpixels(), avconfig.video.width(), 8, &vbi);
1204            vbi_metadata_pack(&ldframedata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
1205         }
1206717
1207         /* configure the compressor for this frame */
1208         chd_codec_config(chd, AV_CODEC_COMPRESS_CONFIG, &avconfig);
718//-------------------------------------------------
719//  progress - generic progress callback
720//-------------------------------------------------
1209721
1210         /* append the data */
1211         err = chd_compress_hunk(chd, NULL, &ratio);
1212         if (err != CHDERR_NONE)
1213            goto cleanup;
1214      }
722static void ATTR_PRINTF(2,3) progress(bool forceit, const char *format, ...)
723{
724   // skip if it hasn't been long enough
725   clock_t curtime = clock();
726   if (!forceit && lastprogress != 0 && curtime - lastprogress < CLOCKS_PER_SEC / 2)
727      return;
728   lastprogress = curtime;
1215729
1216      /* write the final metadata */
1217      if (ldframedata != NULL)
1218      {
1219         err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
1220         if (err != CHDERR_NONE)
1221         {
1222            fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
1223            goto cleanup;
1224         }
1225      }
1226
1227      /* finish compression */
1228      err = chd_compress_finish(chd, TRUE);
1229      if (err != CHDERR_NONE)
1230         goto cleanup;
1231      else
1232         progress(TRUE, "Compression complete ... final ratio = %d%%            \n", (int)(100.0 * ratio));
1233   }
1234
1235cleanup:
1236   /* close everything down */
1237   if (avi != NULL && !IS_FAKE_AVI_FILE(avi))
1238      avi_close(avi);
1239   if (chd != NULL)
1240      chd_close(chd);
1241   for (chnum = 0; chnum < ARRAY_LENGTH(avconfig.audio); chnum++)
1242      if (avconfig.audio[chnum] != NULL)
1243         free(avconfig.audio[chnum]);
1244   if (ldframedata != NULL)
1245      free(ldframedata);
1246   if (err != CHDERR_NONE)
1247      osd_rmfile(outputfile);
1248   return (err != CHDERR_NONE);
730   // standard vfprintf stuff here
731   va_list arg;
732   va_start(arg, format);
733   vfprintf(stderr, format, arg);
734   fflush(stderr);
735   va_end(arg);
1249736}
1250737
1251738
1252/*-------------------------------------------------
1253    do_createblankhd - create a new non-compressed
1254    hard disk image, with all hunks filled with 0s
1255-------------------------------------------------*/
739//-------------------------------------------------
740//  print_help - print help for all the commands
741//-------------------------------------------------
1256742
1257static int do_createblankhd(int argc, char *argv[], int param)
743static int print_help(const char *argv0, const char *error = NULL)
1258744{
1259   UINT32 cylinders, heads, sectors, sectorsize, hunksize, totalsectors, hunknum;
1260   const char *outputfile;
1261   chd_file *chd = NULL;
1262   UINT8 *cache = NULL;
1263   char metadata[256];
1264   chd_error err;
745   // print the error message first
746   if (error != NULL)
747      fprintf(stderr, "Error: %s\n\n", error);
1265748
1266   /* require 6, 7, or 8 args total */
1267   if (argc != 6 && argc != 7 && argc != 8)
1268      return usage();
749   // print a summary of each command
750   printf("Usage:\n");
751   for (int cmdnum = 0; cmdnum < ARRAY_LENGTH(s_commands); cmdnum++)
752   {
753      const command_description &desc = s_commands[cmdnum];
754      printf("   %s %s%s\n", argv0, desc.name, desc.description);
755   }
756   printf("\nFor help with any command, run:\n");
757   printf("   %s %s <command>\n", argv0, COMMAND_HELP);
758   return 1;
759}
1269760
1270   /* extract the data */
1271   outputfile = argv[2];
1272   cylinders = atoi(argv[3]);
1273   heads = atoi(argv[4]);
1274   sectors = atoi(argv[5]);
1275   sectorsize = (argc >= 7) ? atoi(argv[6]) : IDE_SECTOR_SIZE;
1276   if (sectorsize == 0) sectorsize = IDE_SECTOR_SIZE;
1277   hunksize = (argc >= 8) ? atoi(argv[7]) : (sectorsize > 4096) ? sectorsize : ((4096 / sectorsize) * sectorsize);
1278   totalsectors = cylinders * heads * sectors;
1279761
1280   /* print some info */
1281   printf("Output file:  %s\n", outputfile);
1282   printf("Cylinders:    %d\n", cylinders);
1283   printf("Heads:        %d\n", heads);
1284   printf("Sectors:      %d\n", sectors);
1285   printf("Bytes/sector: %d\n", sectorsize);
1286   printf("Sectors/hunk: %d\n", hunksize / sectorsize);
1287   printf("Logical size: %s\n", big_int_string((UINT64)totalsectors * (UINT64)sectorsize));
762//-------------------------------------------------
763//  print_help - print help for all a specific
764//  command
765//-------------------------------------------------
1288766
1289   /* create the new hard drive */
1290   err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_NONE, NULL);
1291   if (err != CHDERR_NONE)
1292   {
1293      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
1294      goto cleanup;
1295   }
767static int print_help(const char *argv0, const command_description &desc, const char *error = NULL)
768{
769   // print the error message first
770   if (error != NULL)
771      fprintf(stderr, "Error: %s\n\n", error);
1296772
1297   /* open the new hard drive */
1298   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd);
1299   if (err != CHDERR_NONE)
773   // print usage for this command
774   printf("Usage:\n");
775   printf("   %s %s [options], where valid options are:\n", argv0, desc.name);
776   for (int valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++)
1300777   {
1301      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
1302      goto cleanup;
778      // determine whether we are required
779      const char *option = desc.valid_options[valid];
780      if (option == NULL)
781         break;
782      bool required = (option[0] == REQUIRED[0]);
783      if (required)
784         option++;
785     
786      // find the option
787      for (int optnum = 0; optnum < ARRAY_LENGTH(s_options); optnum++)
788         if (strcmp(option, s_options[optnum].name) == 0)
789         {
790            const option_description &odesc = s_options[optnum];
791            printf("      --%s", odesc.name);
792            if (odesc.shortname != NULL)
793               printf(", -%s", odesc.shortname);
794            printf("%s%s\n", odesc.description, required ? " (required)" : "");
795         }
1303796   }
797   return 1;
798}
1304799
1305   /* write the metadata */
1306   sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
1307   err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
1308   if (err != CHDERR_NONE)
1309   {
1310      fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
1311      goto cleanup;
1312   }
1313800
1314   /* alloc and zero buffer*/
1315   cache = (UINT8 *)malloc(hunksize);
1316   if (cache == NULL)
1317   {
1318      fprintf(stderr, "Error allocating memory buffer\n");
1319      err = CHDERR_OUT_OF_MEMORY;
1320      goto cleanup;
1321   }
1322   memset(cache, 0, hunksize);
801//-------------------------------------------------
802//  big_int_string - create a 64-bit string
803//-------------------------------------------------
1323804
1324   /* Zero every hunk */
1325   for (hunknum = 0; hunknum < chd_get_header(chd)->totalhunks; hunknum++)
805const char *big_int_string(astring &string, UINT64 intvalue)
806{
807   // 0 is a special case
808   if (intvalue == 0)
809      return string.cpy("0");
810   
811   // loop until all chunks are done
812   string.reset();
813   bool first = true;
814   while (intvalue != 0)
1326815   {
1327      /* progress */
1328      progress(hunknum == 0, "Zeroing hunk %d/%d...  \r", hunknum, chd_get_header(chd)->totalhunks);
816      int chunk = intvalue % 1000;
817      intvalue /= 1000;
818     
819      astring insert;
820      insert.format((intvalue != 0) ? "%03d" : "%d", chunk);
1329821
1330      /* write out the data */
1331      err = chd_write(chd, hunknum, cache);
1332      if (err != CHDERR_NONE)
1333      {
1334         fprintf(stderr, "Error writing CHD file: %s\n", chd_error_string(err));
1335         goto cleanup;
1336      }
822      if (!first)
823         string.ins(0, ",");
824      first = false;
825      string.ins(0, insert);
1337826   }
1338   progress(TRUE, "Creation complete!                    \n");
1339
1340cleanup:
1341   /* close everything down */
1342   if (cache != NULL)
1343      free(cache);
1344   if (chd != NULL)
1345      chd_close(chd);
1346   if (err != CHDERR_NONE)
1347      osd_rmfile(outputfile);
1348   return (err != CHDERR_NONE);
827   return string;
1349828}
1350829
1351830
1352/*-------------------------------------------------
1353    do_copydata - copy all hunks of data from one
1354    CHD file to another. The hunk sizes do not
1355    need to match. If the source is shorter than
1356    the destination, the source data will be
1357    padded with 0s.
1358-------------------------------------------------*/
831//-------------------------------------------------
832//  msf_string_from_frames - output the given
833//  number of frames in M:S:F format
834//-------------------------------------------------
1359835
1360static int do_copydata(int argc, char *argv[], int param)
836const char *msf_string_from_frames(astring &string, UINT32 frames)
1361837{
1362   const char *inputfile, *outputfile;
1363   chd_file *outputchd = NULL;
1364   chd_file *inputchd = NULL;
1365   chd_error err;
838   return string.format("%02d:%02d:%02d", frames / (75 * 60), (frames / 75) % 60, frames % 75);
839}
1366840
1367   /* require 4 args total */
1368   if (argc != 4)
1369      return usage();
1370841
1371   /* extract the data */
1372   inputfile = argv[2];
1373   outputfile = argv[3];
842//-------------------------------------------------
843//  parse_number - parse a number string with an
844//  optional k/m/g suffix
845//-------------------------------------------------
1374846
1375   /* print some info */
1376   printf("Input file:  %s\n", inputfile);
1377   printf("Output file: %s\n", outputfile);
1378
1379   /* open the src hard drive */
1380   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd);
1381   if (err != CHDERR_NONE)
847UINT64 parse_number(const char *string)
848{
849   // 0-length string is 0
850   int length = strlen(string);
851   if (length == 0)
852      return 0;
853   
854   // scan forward over digits
855   UINT64 result = 0;
856   while (isdigit(*string))
1382857   {
1383      fprintf(stderr, "Error opening src CHD file: %s\n", chd_error_string(err));
1384      goto cleanup;
858      result = (result * 10) + (*string - '0');
859      string++;
1385860   }
1386
1387   /* open the dest hard drive */
1388   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &outputchd);
1389   if (err != CHDERR_NONE)
1390   {
1391      fprintf(stderr, "Error opening dest CHD file: %s\n", chd_error_string(err));
1392      goto cleanup;
1393   }
1394
1395   /* compress the source into the dest */
1396   err = chdman_compress_chd(outputchd, inputchd, 0);
1397   if (err != CHDERR_NONE)
1398      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
1399
1400cleanup:
1401   /* close everything down */
1402   if (outputchd != NULL)
1403      chd_close(outputchd);
1404   if (inputchd != NULL)
1405      chd_close(inputchd);
1406   if (err != CHDERR_NONE)
1407      osd_rmfile(outputfile);
1408   return (err != CHDERR_NONE);
861   
862   // handle multipliers
863   if (*string == 'k' || *string == 'K')
864      result *= 1024;
865   if (*string == 'm' || *string == 'M')
866      result *= 1024 * 1024;
867   if (*string == 'g' || *string == 'G')
868      result *= 1024 * 1024 * 1024;
869   
870   return result;
1409871}
1410872
1411873
1412/*-------------------------------------------------
1413    do_extract - extract a raw file from a
1414    CHD image
1415-------------------------------------------------*/
874//-------------------------------------------------
875//  guess_chs - given a file and an offset,
876//  compute a best guess CHS value set
877//-------------------------------------------------
1416878
1417static int do_extract(int argc, char *argv[], int param)
879static void guess_chs(astring *filename, UINT64 filesize, int sectorsize, UINT32 &cylinders, UINT32 &heads, UINT32 &sectors, UINT32 &bps)
1418880{
1419   const char *inputfile, *outputfile;
1420   core_file *outfile = NULL;
1421   chd_file *infile = NULL;
1422   const chd_header *header;
1423   UINT64 bytesremaining;
1424   void *hunk = NULL;
1425   file_error filerr;
1426   chd_error err;
1427   int hunknum;
881   // if this is a direct physical drive read, handle it specially
882   if (filename != NULL && osd_get_physical_drive_geometry(*filename, &cylinders, &heads, &sectors, &bps))
883      return;
884   
885   // if we have no length to work with, we can't guess
886   if (filesize == 0)
887      report_error(1, "Can't guess CHS values because there is no input file");
1428888
1429   /* require 4 args total */
1430   if (argc != 4)
1431      return usage();
889   // validate the size
890   if (filesize % sectorsize != 0)
891      report_error(1, "Can't guess CHS values because data size is not divisible by %d", sectorsize);
892   ;
1432893
1433   /* extract the data */
1434   inputfile = argv[2];
1435   outputfile = argv[3];
894   // now find a valid value
895   for (UINT32 totalsectors = filesize / sectorsize; ; totalsectors++)
896      for (UINT32 cursectors = 63; cursectors > 1; cursectors--)
897         if (totalsectors % cursectors == 0)
898         {
899            UINT32 totalheads = totalsectors / cursectors;
900            for (UINT32 curheads = 16; curheads > 1; curheads--)
901               if (totalheads % curheads == 0)
902               {
903                  cylinders = totalheads / curheads;
904                  heads = curheads;
905                  sectors = cursectors;
906                  return;
907               }
908         }
1436909
1437   /* print some info */
1438   printf("Input file:   %s\n", inputfile);
1439   printf("Output file:  %s\n", outputfile);
910   // ack, it didn't work!
911   report_error(1, "Can't guess CHS values because no logical combination works!");
912}
1440913
1441   /* get the header */
1442   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &infile);
1443   if (err != CHDERR_NONE)
1444   {
1445      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
1446      goto cleanup;
1447   }
1448   header = chd_get_header(infile);
1449914
1450   /* allocate memory to hold a hunk */
1451   hunk = malloc(header->hunkbytes);
1452   if (hunk == NULL)
1453   {
1454      fprintf(stderr, "Out of memory allocating hunk buffer!\n");
1455      err = CHDERR_OUT_OF_MEMORY;
1456      goto cleanup;
1457   }
915//-------------------------------------------------
916//  parse_input_chd_parameters - parse the
917//  standard set of input CHD parameters
918//-------------------------------------------------
1458919
1459   /* create the output file */
1460   filerr = core_fopen(outputfile, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &outfile);
1461   if (filerr != FILERR_NONE)
920static void parse_input_chd_parameters(const parameters_t &params, chd_file &input_chd, chd_file &input_parent_chd, bool writeable = false)
921{
922   // process input parent file
923   astring *input_chd_parent_str = params.find(OPTION_INPUT_PARENT);
924   if (input_chd_parent_str != NULL)
1462925   {
1463      fprintf(stderr, "Error opening output file '%s'\n", outputfile);
1464      err = CHDERR_CANT_CREATE_FILE;
1465      goto cleanup;
926      chd_error err = input_parent_chd.open(*input_chd_parent_str);
927      if (err != CHDERR_NONE)
928         report_error(1, "Error opening parent CHD file (%s): %s", input_chd_parent_str->cstr(), chd_file::error_string(err));
1466929   }
1467930
1468   /* loop over hunks, reading and writing */
1469   bytesremaining = header->logicalbytes;
1470   for (hunknum = 0; hunknum < header->totalhunks; hunknum++)
931   // process input file
932   astring *input_chd_str = params.find(OPTION_INPUT);
933   if (input_chd_str != NULL)
1471934   {
1472      UINT32 byteswritten, bytes_to_write;
1473
1474      /* progress */
1475      progress(hunknum == 0, "Extracting hunk %d/%d...  \r", hunknum, header->totalhunks);
1476
1477      /* read the hunk into a buffer */
1478      err = chd_read(infile, hunknum, hunk);
935      chd_error err = input_chd.open(*input_chd_str, writeable, input_parent_chd.opened() ? &input_parent_chd : NULL);
1479936      if (err != CHDERR_NONE)
1480      {
1481         fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", hunknum, chd_error_string(err));
1482         goto cleanup;
1483      }
1484
1485      /* write the hunk to the file */
1486      bytes_to_write = MIN(bytesremaining, header->hunkbytes);
1487      core_fseek(outfile, (UINT64)hunknum * (UINT64)header->hunkbytes, SEEK_SET);
1488      byteswritten = core_fwrite(outfile, hunk, bytes_to_write);
1489      if (byteswritten != bytes_to_write)
1490      {
1491         fprintf(stderr, "Error writing hunk %d to output file: %s\n", hunknum, chd_error_string(CHDERR_WRITE_ERROR));
1492         err = CHDERR_WRITE_ERROR;
1493         goto cleanup;
1494      }
1495      bytesremaining -= byteswritten;
937         report_error(1, "Error opening CHD file (%s): %s", input_chd_str->cstr(), chd_file::error_string(err));
1496938   }
1497   progress(TRUE, "Extraction complete!                    \n");
1498
1499cleanup:
1500   /* clean up our mess */
1501   if (outfile != NULL)
1502      core_fclose(outfile);
1503   if (hunk != NULL)
1504      free(hunk);
1505   if (infile != NULL)
1506      chd_close(infile);
1507   if (err != CHDERR_NONE)
1508      osd_rmfile(outputfile);
1509   return (err != CHDERR_NONE);
1510939}
1511940
1512941
1513/*-------------------------------------------------
1514    do_extractcd - extract a CDRDAO .toc/.bin
1515    or CDRWIN .cue/.bin file from a CHD-CD image
1516-------------------------------------------------*/
942//-------------------------------------------------
943//  parse_input_start_end - parse input start/end
944//  parameters in a standard way
945//-------------------------------------------------
1517946
1518static int do_extractcd(int argc, char *argv[], int param)
947static void parse_input_start_end(const parameters_t &params, UINT64 logical_size, UINT32 hunkbytes, UINT32 framebytes, UINT64 &input_start, UINT64 &input_end)
1519948{
1520   const char *inputfile, *outputfile, *outputfile2;
1521   core_file *outfile2 = NULL;
1522   chd_file *inputchd = NULL;
1523   cdrom_file *cdrom = NULL;
1524   FILE *outfile = NULL;
1525   const cdrom_toc *toc;
1526   UINT64 out2offs, discoffs;
1527   file_error filerr;
1528   chd_error err;
1529   int track, cuemode;
949   // process start/end if we were provided an input CHD
950   input_start = 0;
951   input_end = logical_size;
1530952
1531   /* require 5 args total */
1532   if (argc != 5)
1533      return usage();
953   // process input start
954   astring *input_start_byte_str = params.find(OPTION_INPUT_START_BYTE);
955   astring *input_start_hunk_str = params.find(OPTION_INPUT_START_HUNK);
956   astring *input_start_frame_str = params.find(OPTION_INPUT_START_FRAME);
957   if (input_start_byte_str != NULL)
958      input_start = parse_number(*input_start_byte_str);
959   if (input_start_hunk_str != NULL)
960      input_start = parse_number(*input_start_hunk_str) * hunkbytes;
961   if (input_start_frame_str != NULL)
962      input_start = parse_number(*input_start_frame_str) * framebytes;
963   if (input_start >= input_end)
964      report_error(1, "Input start offset greater than input file size");
965   
966   // process input length
967   astring *input_length_bytes_str = params.find(OPTION_INPUT_LENGTH_BYTES);
968   astring *input_length_hunks_str = params.find(OPTION_INPUT_LENGTH_HUNKS);
969   astring *input_length_frames_str = params.find(OPTION_INPUT_LENGTH_FRAMES);
970   UINT64 input_length = input_end;
971   if (input_length_bytes_str != NULL)
972      input_length = parse_number(*input_length_bytes_str);
973   if (input_length_hunks_str != NULL)
974      input_length = parse_number(*input_length_hunks_str) * hunkbytes;
975   if (input_length_frames_str != NULL)
976      input_length = parse_number(*input_length_frames_str) * framebytes;
977   if (input_start + input_length < input_end)
978      input_end = input_start + input_length;
979}
1534980
1535   /* extract the data */
1536   inputfile = argv[2];
1537   outputfile = argv[3];
1538   outputfile2 = argv[4];
1539981
1540   /* print some info */
1541   printf("Input file:   %s\n", inputfile);
1542   printf("Output files:  %s and %s\n", outputfile, outputfile2);
982//-------------------------------------------------
983//  parse_output_chd_parameters - parse the
984//  standard set of output CHD parameters
985//-------------------------------------------------
1543986
1544   /* get the header */
1545   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd);
1546   if (err != CHDERR_NONE)
987static astring *parse_output_chd_parameters(const parameters_t &params, chd_file &output_parent_chd)
988{
989   // process output parent file
990   astring *output_chd_parent_str = params.find(OPTION_OUTPUT_PARENT);
991   if (output_chd_parent_str != NULL)
1547992   {
1548      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
1549      goto cleanup;
993      chd_error err = output_parent_chd.open(*output_chd_parent_str);
994      if (err != CHDERR_NONE)
995         report_error(1, "Error opening parent CHD file (%s): %s", output_chd_parent_str->cstr(), chd_file::error_string(err));
1550996   }
1551997
1552   /* open the CD */
1553   cdrom = cdrom_open(inputchd);
1554   if (cdrom == NULL)
998   // process output file
999   astring *output_chd_str = params.find(OPTION_OUTPUT);
1000   if (output_chd_str != NULL && params.find(OPTION_OUTPUT_FORCE) == NULL)
15551001   {
1556      fprintf(stderr, "Error opening CHD-CD '%s'\n", inputfile);
1557      err = CHDERR_INVALID_FILE;
1558      goto cleanup;
1002      core_file *file;
1003      file_error filerr = core_fopen(*output_chd_str, OPEN_FLAG_READ, &file);
1004      if (filerr == FILERR_NONE)
1005      {
1006         core_fclose(file);
1007         report_error(1, "Error: file already exists (%s)\nUse --force (or -f) to force overwriting", output_chd_str->cstr());
1008      }
15591009   }
1010   return output_chd_str;
1011}
15601012
1561   /* check for CDRWIN format */
1562   cuemode = 0;
1563   if (strstr(outputfile, ".cue"))
1564   {
1565      cuemode = 1;
1566   }
15671013
1568   /* get the TOC data */
1569   toc = cdrom_get_toc(cdrom);
1014//-------------------------------------------------
1015//  parse_hunk_size - parse the hunk_size
1016//  parameter in a standard way
1017//-------------------------------------------------
15701018
1571   /* create the output files */
1572   outfile = fopen(outputfile, "w");
1573   if (outfile == NULL)
1019static void parse_hunk_size(const parameters_t &params, UINT32 required_granularity, UINT32 &hunk_size)
1020{
1021   astring *hunk_size_str = params.find(OPTION_HUNK_SIZE);
1022   if (hunk_size_str != NULL)
15741023   {
1575      fprintf(stderr, "Error opening output file '%s'\n", outputfile);
1576      err = CHDERR_CANT_CREATE_FILE;
1577      goto cleanup;
1024      hunk_size = parse_number(*hunk_size_str);
1025      if (hunk_size < 16 || hunk_size > 1024 * 1024)
1026         report_error(1, "Invalid hunk size");
1027      if (hunk_size % required_granularity != 0)
1028         report_error(1, "Hunk size is not an even multiple of %d", required_granularity);
15781029   }
1030}
15791031
1580   if (!cuemode)
1032
1033//-------------------------------------------------
1034//  parse_compression - parse a standard
1035//  compression parameter string
1036//-------------------------------------------------
1037
1038static void parse_compression(const parameters_t &params, chd_codec_type compression[4])
1039{
1040   // see if anything was specified
1041   astring *compression_str = params.find(OPTION_COMPRESSION);
1042   if (compression_str == NULL)
1043      return;
1044
1045   // special case: 'none'
1046   if (*compression_str == "none")
15811047   {
1582      fprintf(outfile, "CD_ROM\n\n\n");
1048      compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE;
1049      return;
15831050   }
1584
1585   filerr = core_fopen(outputfile2, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &outfile2);
1586   if (filerr != FILERR_NONE)
1051   
1052   // iterate through compressors
1053   int index = 0;
1054   for (int start = 0, end = compression_str->chr(0, ','); index < 4; start = end + 1, end = compression_str->chr(end + 1, ','))
15871055   {
1588      fprintf(stderr, "Error opening output file '%s'\n", outputfile2);
1589      err = CHDERR_CANT_CREATE_FILE;
1590      goto cleanup;
1056      astring name(*compression_str, start, (end == -1) ? -1 : end - start);
1057      if (name.len() != 4)
1058         report_error(1, "Invalid compressor '%s' specified", name.cstr());
1059      chd_codec_type type = CHD_MAKE_TAG(name[0], name[1], name[2], name[3]);
1060      if (!chd_codec_list::codec_exists(type))
1061         report_error(1, "Invalid compressor '%s' specified", name.cstr());
1062      compression[index++] = type;
1063      if (end == -1)
1064         break;
15911065   }
1066}
15921067
1593   /* process away */
1594   out2offs = 0;
1595   discoffs = 0;
1596   for (track = 0; track < toc->numtrks; track++)
1597   {
1598      UINT32 m, s, f, frame, trackframes;
15991068
1600      progress(TRUE, "Extracting track %d...   \r", track+1);
1069//-------------------------------------------------
1070//  parse_numprocessors - handle the numprocessors
1071//  command
1072//-------------------------------------------------
16011073
1602      trackframes = toc->tracks[track].frames;
1074static void parse_numprocessors(const parameters_t &params)
1075{
1076#if NUM_PROCESSORS_SUPPORTED
1077   astring *numprocessors_str = params.find(OPTION_NUMPROCESSORS);
1078   if (numprocessors_str == NULL)
1079      return;
16031080
1604      if (cuemode)
1605      {
1606         char modestr[16];
1081   int count = atoi(*numprocessors_str);
1082   if (count > 0)
1083   {
1084      extern int osd_num_processors;
1085      osd_num_processors = count;
1086   }
1087#endif
1088}
16071089
1608         if (track == 0)
1609         {
1610            fprintf(outfile, "FILE \"%s\" BINARY\n", outputfile2);
1611         }
16121090
1613         switch (toc->tracks[track].trktype)
1614         {
1615            case CD_TRACK_MODE1:
1616            case CD_TRACK_MODE1_RAW:
1617               sprintf(modestr, "MODE1/%04d", toc->tracks[track].datasize);
1618               break;
1091//-------------------------------------------------
1092//  compression_string - create a friendly string
1093//  describing a set of compressors
1094//-------------------------------------------------
16191095
1620            case CD_TRACK_MODE2:
1621            case CD_TRACK_MODE2_FORM1:
1622            case CD_TRACK_MODE2_FORM2:
1623            case CD_TRACK_MODE2_FORM_MIX:
1624            case CD_TRACK_MODE2_RAW:
1625               sprintf(modestr, "MODE2/%04d", toc->tracks[track].datasize);
1626               break;
1096static const char *compression_string(astring &string, chd_codec_type compression[4])
1097{
1098   // output compression types
1099   string.reset();
1100   if (compression[0] == CHD_CODEC_NONE)
1101      return string.cpy("none");
1102   
1103   // iterate over types
1104   for (int index = 0; index < 4; index++)
1105   {
1106      chd_codec_type type = compression[index];
1107      if (type == CHD_CODEC_NONE)
1108         break;
1109      if (index != 0)
1110         string.cat(", ");
1111      string.cat((type >> 24) & 0xff).cat((type >> 16) & 0xff).cat((type >> 8) & 0xff).cat(type & 0xff);
1112      string.cat(" (").cat(chd_codec_list::codec_name(type)).cat(")");
1113   }
1114   return string;
1115}
1116     
16271117
1628            case CD_TRACK_AUDIO:
1629               strcpy(modestr, "AUDIO");
1630               break;
1631         }
1118//-------------------------------------------------
1119//  compress_common - standard compression loop
1120//-------------------------------------------------
16321121
1633         fprintf(outfile, "  TRACK %02d %s\n", track+1, modestr);
1122static void compress_common(chd_file_compressor &chd)
1123{
1124   // begin compressing
1125   chd.compress_begin();
16341126
1635         if (toc->tracks[track].pregap > 0)
1636         {
1637            f = toc->tracks[track].pregap;
1638            s = f / 75;
1639            f %= 75;
1640            m = s / 60;
1641            s %= 60;
1642            fprintf(outfile, "    PREGAP %02d:%02d:%02d\n", m, s, f);
1643         }
1644
1645         f = discoffs;
1646         s = f / 75;
1647         f %= 75;
1648         m = s / 60;
1649         s %= 60;
1650         fprintf(outfile, "    INDEX 01 %02d:%02d:%02d\n", m, s, f);
1651
1652         if (toc->tracks[track].postgap > 0)
1653         {
1654            f = toc->tracks[track].postgap;
1655            s = f / 75;
1656            f %= 75;
1657            m = s / 60;
1658            s %= 60;
1659            fprintf(outfile, "    POSTGAP %02d:%02d:%02d\n", m, s, f);
1660         }
1661      }
1127   // loop until done   
1128   double complete, ratio;
1129   chd_error err;
1130   while ((err = chd.compress_continue(complete, ratio)) == CHDERR_WALKING_PARENT || err == CHDERR_COMPRESSING)
1131      if (err == CHDERR_WALKING_PARENT)
1132         progress(false, "Examining parent, %.1f%% complete...  \r", 100.0 * complete);
16621133      else
1663      {
1664         char modesubmode[64];
1134         progress(false, "Compressing, %.1f%% complete... (ratio=%.1f%%)  \r", 100.0 * complete, 100.0 * ratio);
16651135
1666         fprintf(outfile, "// Track %d\n", track+1);
1136   // handle errors
1137   if (err != CHDERR_NONE)
1138      report_error(1, "Error during compression: %-40s", chd_file::error_string(err));
16671139
1668         /* write out the track type */
1669         if (toc->tracks[track].subtype != CD_SUB_NONE)
1670         {
1671            sprintf(modesubmode, "%s %s", cdrom_get_type_string(toc->tracks[track].trktype), cdrom_get_subtype_string(toc->tracks[track].subtype));
1672         }
1673         else
1674         {
1675            sprintf(modesubmode, "%s", cdrom_get_type_string(toc->tracks[track].trktype));
1676         }
1140   // final progress update
1141   progress(true, "Compression complete ... final ratio = %.1f%%            \n", 100.0 * ratio);
1142}
16771143
1678         fprintf(outfile, "TRACK %s\n", modesubmode);
16791144
1680         /* write out the attributes */
1681         fprintf(outfile, "NO COPY\n");
1682         if (toc->tracks[track].trktype == CD_TRACK_AUDIO)
1683         {
1684            fprintf(outfile, "NO PRE_EMPHASIS\n");
1685            fprintf(outfile, "TWO_CHANNEL_AUDIO\n");
1686         }
1145//-------------------------------------------------
1146//  output_track_metadata - output track metadata
1147//  to a CUE file
1148//-------------------------------------------------
16871149
1688         if (toc->tracks[track].pregap > 0)
1689         {
1690            f = toc->tracks[track].pregap;
1691            s = f / 75;
1692            f %= 75;
1693            m = s / 60;
1694            s %= 60;
1150void output_track_metadata(bool cuemode, core_file *file, int tracknum, const cdrom_track_info &info, const char *filename, UINT32 frameoffs, UINT64 discoffs)
1151{
1152   // CUE mode?
1153   if (cuemode)
1154   {
1155      // first track specifies the file
1156      if (tracknum == 0)
1157         core_fprintf(file, "FILE \"%s\" BINARY\n", filename);
16951158
1696            fprintf(outfile, "ZERO %s %02d:%02d:%02d\n", modesubmode, m, s, f);
1697         }
1159      // determine submode
1160      astring tempstr;
1161      switch (info.trktype)
1162      {
1163         case CD_TRACK_MODE1:
1164         case CD_TRACK_MODE1_RAW:
1165            tempstr.format("MODE1/%04d", info.datasize);
1166            break;
16981167
1699         /* convert to minutes/seconds/frames */
1700         f = trackframes;
1701         s = f / 75;
1702         f %= 75;
1703         m = s / 60;
1704         s %= 60;
1168         case CD_TRACK_MODE2:
1169         case CD_TRACK_MODE2_FORM1:
1170         case CD_TRACK_MODE2_FORM2:
1171         case CD_TRACK_MODE2_FORM_MIX:
1172         case CD_TRACK_MODE2_RAW:
1173            tempstr.format("MODE2/%04d", info.datasize);
1174            break;
17051175
1706         /* all tracks but the first one have a file offset */
1707         if (track > 0)
1708            fprintf(outfile, "DATAFILE \"%s\" #%d %02d:%02d:%02d // length in bytes: %d\n", outputfile2, (UINT32)out2offs, m, s, f, trackframes*(toc->tracks[track].datasize+toc->tracks[track].subsize));
1709         else
1710            fprintf(outfile, "DATAFILE \"%s\" %02d:%02d:%02d // length in bytes: %d\n", outputfile2, m, s, f, trackframes*(toc->tracks[track].datasize+toc->tracks[track].subsize));
1711
1712         /* tracks with pregaps get a START marker too */
1713         if (toc->tracks[track].pregap > 0)
1714         {
1715            f = toc->tracks[track].pregap;
1716            s = f / 75;
1717            f %= 75;
1718            m = s / 60;
1719            s %= 60;
1720
1721            fprintf(outfile, "START %02d:%02d:%02d\n", m, s, f);
1722         }
1723
1724         fprintf(outfile, "\n\n");
1176         case CD_TRACK_AUDIO:
1177            tempstr.cpy("AUDIO");
1178            break;
17251179      }
1180     
1181      // output TRACK entry
1182      core_fprintf(file, "  TRACK %02d %s\n", tracknum + 1, tempstr.cstr());
17261183
1727      /* now write the actual data */
1728      for (frame = 0; frame < trackframes; frame++)
1729      {
1730         UINT8 sector[CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA];
1731         UINT32 byteswritten;
1184      // output PREGAP
1185      if (info.pregap > 0)
1186         core_fprintf(file, "    PREGAP %s\n", msf_string_from_frames(tempstr, info.pregap));
17321187
1733         progress(frame == 0, "Extracting track %d... %d/%d...   \r", track+1, frame, trackframes);
1188      // output track data
1189      core_fprintf(file, "    INDEX 01 %s\n", msf_string_from_frames(tempstr, frameoffs));
17341190
1735         /* read the raw data */
1736         cdrom_read_data(cdrom, cdrom_get_track_start(cdrom, track) + frame, sector, toc->tracks[track].trktype);
1191      // output POSTGAP
1192      if (info.postgap > 0)
1193         core_fprintf(file, "    POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap));
1194   }
1195   
1196   // non-CUE mode
1197   else
1198   {
1199      // header on the first track
1200      if (tracknum == 0)
1201         core_fprintf(file, "CD_ROM\n\n\n");
1202      core_fprintf(file, "// Track %d\n", tracknum + 1);
17371203
1738         /* for CDRWin, audio tracks must be reversed */
1739         if ((cuemode) && (toc->tracks[track].trktype == CD_TRACK_AUDIO))
1740         {
1741            int swapindex;
1204      // write out the track type
1205      astring modesubmode;
1206      if (info.subtype != CD_SUB_NONE)
1207         modesubmode.format("%s %s", cdrom_get_type_string(info.trktype), cdrom_get_subtype_string(info.subtype));
1208      else
1209         modesubmode.format("%s", cdrom_get_type_string(info.trktype));
1210      core_fprintf(file, "TRACK %s\n", modesubmode.cstr());
17421211
1743            for (swapindex = 0; swapindex < toc->tracks[track].datasize; swapindex += 2)
1744            {
1745               UINT8 swaptemp = sector[swapindex];
1746               sector[swapindex] = sector[swapindex+1];
1747               sector[swapindex + 1] = swaptemp;
1748            }
1749         }
1212      // write out the attributes
1213      core_fprintf(file, "NO COPY\n");
1214      if (info.trktype == CD_TRACK_AUDIO)
1215      {
1216         core_fprintf(file, "NO PRE_EMPHASIS\n");
1217         core_fprintf(file, "TWO_CHANNEL_AUDIO\n");
1218      }
17501219
1751         /* write it out */
1752         core_fseek(outfile2, out2offs, SEEK_SET);
1753         byteswritten = core_fwrite(outfile2, sector, toc->tracks[track].datasize);
1754         if (byteswritten != toc->tracks[track].datasize)
1755         {
1756            fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, chd_error_string(CHDERR_WRITE_ERROR));
1757            err = CHDERR_WRITE_ERROR;
1758            goto cleanup;
1759         }
1760         out2offs += toc->tracks[track].datasize;
1761         discoffs++;
1220      // output pregap
1221      astring tempstr;
1222      if (info.pregap > 0)
1223         core_fprintf(file, "ZERO %s %s\n", modesubmode.cstr(), msf_string_from_frames(tempstr, info.pregap));
17621224
1763         /* read the subcode data */
1764         if (toc->tracks[track].subtype != CD_SUB_NONE)
1765         {
1766            cdrom_read_subcode(cdrom, cdrom_get_track_start(cdrom, track) + frame, sector);
1225      // all tracks but the first one have a file offset
1226      if (tracknum > 0)
1227         core_fprintf(file, "DATAFILE \"%s\" #%d %s // length in bytes: %d\n", filename, UINT32(discoffs), msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize));
1228      else
1229         core_fprintf(file, "DATAFILE \"%s\" %s // length in bytes: %d\n", filename, msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize));
17671230
1768            /* write it out */
1769            core_fseek(outfile2, out2offs, SEEK_SET);
1770            byteswritten = core_fwrite(outfile2, sector, toc->tracks[track].subsize);
1771            if (byteswritten != toc->tracks[track].subsize)
1772            {
1773               fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, chd_error_string(CHDERR_WRITE_ERROR));
1774               err = CHDERR_WRITE_ERROR;
1775               goto cleanup;
1776            }
1777            out2offs += toc->tracks[track].subsize;
1778         }
1779      }
1780      progress(TRUE, "Extracting track %d... complete         \n", track+1);
1781   }
1782   progress(TRUE, "Completed!\n");
1231      // tracks with pregaps get a START marker too
1232      if (info.pregap > 0)
1233         core_fprintf(file, "START %s\n", msf_string_from_frames(tempstr, info.pregap));
17831234
1784cleanup:
1785   /* close everything down */
1786   if (outfile != NULL)
1787      fclose(outfile);
1788   if (outfile2 != NULL)
1789      core_fclose(outfile2);
1790   if (cdrom != NULL)
1791      cdrom_close(cdrom);
1792   if (inputchd != NULL)
1793      chd_close(inputchd);
1794   if (err != CHDERR_NONE)
1795      osd_rmfile(outputfile);
1796   return (err != CHDERR_NONE);
1235      core_fprintf(file, "\n\n");
1236   }
17971237}
17981238
17991239
1800/*-------------------------------------------------
1801    do_extractav - extract an AVI file from a
1802    CHD image
1803-------------------------------------------------*/
1240//-------------------------------------------------
1241//  do_info - dump the header information from
1242//  a drive image
1243//-------------------------------------------------
18041244
1805static int do_extractav(int argc, char *argv[], int param)
1245static void do_info(parameters_t &params)
18061246{
1807   int fps, fpsfrac, width, height, interlaced, channels, rate, totalframes;
1808   av_codec_decompress_config avconfig;
1809   const char *inputfile, *outputfile;
1810   UINT32 firstframe, numframes;
1811   UINT32 framenum, numsamples;
1812   UINT32 fps_times_1million;
1813   const chd_header *header;
1814   chd_file *chd = NULL;
1815   avi_file *avi = NULL;
1816   avi_movie_info info;
1817   char metadata[256];
1818   avi_error avierr;
1819   chd_error err;
1820   int chnum;
1247   // parse out input files
1248   chd_file input_parent_chd;
1249   chd_file input_chd;
1250   parse_input_chd_parameters(params, input_chd, input_parent_chd);
18211251
1822   /* require 4-6 args total */
1823   if (argc < 4 || argc > 6)
1824      return usage();
1252   // print filename and version
1253   astring tempstr;
1254   printf("Input file:   %s\n", params.find(OPTION_INPUT)->cstr());
1255   printf("File Version: %d\n", input_chd.version());
1256   if (input_chd.version() < 3)
1257      report_error(1, "Unsupported version (%d); use an older chdman to upgrade to version 3 or later", input_chd.version());
18251258
1826   /* extract the data */
1827   inputfile = argv[2];
1828   outputfile = argv[3];
1829   firstframe = (argc > 4) ? atoi(argv[4]) : 0;
1830   numframes = (argc > 5) ? atoi(argv[5]) : 1000000;
1259   // output cmpression and size information
1260   chd_codec_type compression[4] = { input_chd.compression(0), input_chd.compression(1), input_chd.compression(2), input_chd.compression(3) };
1261   printf("Logical size: %s bytes\n", big_int_string(tempstr, input_chd.logical_bytes()));
1262   printf("Hunk Size:    %s bytes\n", big_int_string(tempstr, input_chd.hunk_bytes()));
1263   printf("Total Hunks:  %s\n", big_int_string(tempstr, input_chd.hunk_count()));
1264   printf("Unit Size:    %s bytes\n", big_int_string(tempstr, input_chd.unit_bytes()));
1265   printf("Total Units:  %s\n", big_int_string(tempstr, input_chd.unit_count()));
1266   printf("Compression:  %s\n", compression_string(tempstr, compression));
1267   printf("CHD size:     %s bytes\n", big_int_string(tempstr, core_fsize(input_chd)));
1268   if (compression[0] != CHD_CODEC_NONE)
1269      printf("Ratio:        %.1f%%\n", 100.0 * double(core_fsize(input_chd)) / double(input_chd.logical_bytes()));
18311270
1832   /* print some info */
1833   printf("Input file:   %s\n", inputfile);
1834   printf("Output file:  %s\n", outputfile);
1835
1836   /* get the header */
1837   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
1838   if (err != CHDERR_NONE)
1271   // add SHA1 output
1272   sha1_t overall = input_chd.sha1();
1273   if (overall != sha1_t::null)
18391274   {
1840      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
1841      goto cleanup;
1275      printf("SHA1:         %s\n", overall.as_string(tempstr));
1276      if (input_chd.version() >= 4)
1277         printf("Data SHA1:    %s\n", input_chd.raw_sha1().as_string(tempstr));
18421278   }
1843   header = chd_get_header(chd);
1279   sha1_t parent = input_chd.parent_sha1();
1280   if (parent != sha1_t::null)
1281      printf("Parent SHA1:  %s\n", parent.as_string(tempstr));
18441282
1845   /* get the metadata */
1846   err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
1847   if (err != CHDERR_NONE)
1283   // print out metadata
1284   dynamic_buffer buffer;
1285   dynamic_array<metadata_index_info> info;
1286   for (int index = 0; ; index++)
18481287   {
1849      fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(err));
1850      goto cleanup;
1851   }
1852
1853   /* extract the info */
1854   if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
1855   {
1856      fprintf(stderr, "Improperly formatted metadata\n");
1857      err = CHDERR_INVALID_METADATA;
1858      goto cleanup;
1859   }
1860   fps_times_1million = fps * 1000000 + fpsfrac;
1861   totalframes = header->totalhunks;
1862
1863   /* adjust for interlacing */
1864   if (interlaced)
1865   {
1866      fps_times_1million /= 2;
1867      height *= 2;
1868      firstframe *= 2;
1869      numframes *= 2;
1870   }
1871   numframes = MIN(totalframes - firstframe, numframes);
1872
1873   /* allocate a video buffer */
1874   {
1875      bitmap_yuy16 fullbitmap(width, height);
1876      avconfig.video.wrap(fullbitmap, fullbitmap.cliprect());
1877
1878      /* allocate audio buffers */
1879      avconfig.maxsamples = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
1880      avconfig.actsamples = &numsamples;
1881      for (chnum = 0; chnum < channels; chnum++)
1882      {
1883         avconfig.audio[chnum] = (INT16 *)malloc(avconfig.maxsamples * 2);
1884         if (avconfig.audio[chnum] == NULL)
1288      // get the indexed metadata item; stop when we hit an error
1289      chd_metadata_tag metatag;
1290      UINT8 metaflags;
1291      chd_error err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index, buffer, metatag, metaflags);
1292      if (err != CHDERR_NONE)
1293         break;
1294     
1295      // determine our index
1296      UINT32 metaindex = ~0;
1297      for (int cur = 0; cur < info.count(); cur++)
1298         if (info[cur].tag == metatag)
18851299         {
1886            fprintf(stderr, "Out of memory allocating temporary audio buffer\n");
1887            err = CHDERR_OUT_OF_MEMORY;
1888            goto cleanup;
1300            metaindex = ++info[cur].index;
1301            break;
18891302         }
1890      }
1891
1892      /* print some of it */
1893      printf("Use frames:   %d-%d\n", firstframe, firstframe + numframes - 1);
1894      printf("Frame rate:   %d.%06d\n", fps_times_1million / 1000000, fps_times_1million % 1000000);
1895      printf("Frame size:   %d x %d %s\n", width, height, interlaced ? "interlaced" : "non-interlaced");
1896      printf("Audio:        %d channels at %d Hz\n", channels, rate);
1897      printf("Total frames: %d (%02d:%02d:%02d)\n", totalframes,
1898            (UINT32)((UINT64)totalframes * 1000000 / fps_times_1million / 60 / 60),
1899            (UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million / 60) % 60),
1900            (UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million) % 60));
1901
1902      /* build up the movie info */
1903      info.video_format = FORMAT_YUY2;
1904      info.video_timescale = fps_times_1million;
1905      info.video_sampletime = 1000000;
1906      info.video_width = width;
1907      info.video_height = height;
1908      info.video_depth = 16;
1909      info.audio_format = 0;
1910      info.audio_timescale = rate;
1911      info.audio_sampletime = 1;
1912      info.audio_channels = channels;
1913      info.audio_samplebits = 16;
1914      info.audio_samplerate = rate;
1915
1916      /* create the output file */
1917      avierr = avi_create(outputfile, &info, &avi);
1918      if (avierr != AVIERR_NONE)
1303     
1304      // if not found, add to our tracking
1305      if (metaindex == ~0)
19191306      {
1920         fprintf(stderr, "Error opening output file '%s': %s\n", outputfile, avi_error_string(avierr));
1921         err = CHDERR_CANT_CREATE_FILE;
1922         goto cleanup;
1307         metadata_index_info curinfo = { metatag, 0 };
1308         info.append(curinfo);
1309         metaindex = 0;
19231310      }
19241311
1925      /* loop over hunks, reading and writing */
1926      for (framenum = 0; framenum < numframes; framenum++)
1927      {
1928         /* progress */
1929         progress(framenum == 0, "Extracting hunk %d/%d...  \r", framenum, numframes);
1312      // print either a string representation or a hex representation of the tag
1313      if (isprint((metatag >> 24) & 0xff) && isprint((metatag >> 16) & 0xff) && isprint((metatag >> 8) & 0xff) && isprint(metatag & 0xff))
1314         printf("Metadata:     Tag='%c%c%c%c'  Index=%d  Length=%d bytes\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff, metaindex, buffer.count());
1315      else
1316         printf("Metadata:     Tag=%08x  Index=%d  Length=%d bytes\n", metatag, metaindex, buffer.count());
1317      printf("              ");
19301318
1931         /* set up the fake bitmap for this frame */
1932         if (!interlaced)
1933            avconfig.video.wrap(fullbitmap, fullbitmap.cliprect());
1934         else
1935            avconfig.video.wrap(&fullbitmap.pix16(framenum % 2), fullbitmap.width(), fullbitmap.height() / 2, fullbitmap.rowpixels() * 2);
1936
1937         /* configure the decompressor for this frame */
1938         chd_codec_config(chd, AV_CODEC_DECOMPRESS_CONFIG, &avconfig);
1939
1940         /* read the hunk into the buffers */
1941         err = chd_read(chd, firstframe + framenum, NULL);
1319      // print up to 60 characters of metadata
1320      UINT32 count = MIN(60, buffer.count());
1321      for (int chnum = 0; chnum < count; chnum++)
1322         printf("%c", isprint(UINT8(buffer[chnum])) ? buffer[chnum] : '.');
1323      printf("\n");
1324   }
1325   
1326   // print compression stats if verbose
1327   if (params.find(OPTION_VERBOSE) != NULL)
1328   {
1329      UINT32 compression_types[10] = { 0 };
1330      for (UINT32 hunknum = 0; hunknum < input_chd.hunk_count(); hunknum++)
1331      {
1332         // get info on this hunk
1333         chd_codec_type codec;
1334         UINT32 compbytes;
1335         chd_error err = input_chd.hunk_info(hunknum, codec, compbytes);
19421336         if (err != CHDERR_NONE)
1337            report_error(1, "Error getting info on hunk %d: %s", hunknum, chd_file::error_string(err));
1338         
1339         // decode into our data
1340         if (codec > CHD_CODEC_MINI)
1341            for (int comptype = 0; comptype < 4; comptype++)
1342               if (codec == input_chd.compression(comptype))
1343               {
1344                  codec = CHD_CODEC_MINI + 1 + comptype;
1345                  break;
1346               }
1347         if (codec > ARRAY_LENGTH(compression_types))
1348            codec = ARRAY_LENGTH(compression_types) - 1;
1349         
1350         // count stats
1351         compression_types[codec]++;
1352      }
1353     
1354      // output the stats
1355      printf("\n");
1356      printf("     Hunks  Percent  Name\n");
1357      printf("----------  -------  ------------------------------------\n");
1358      for (int comptype = 0; comptype < ARRAY_LENGTH(compression_types); comptype++)
1359         if (compression_types[comptype] != 0)
19431360         {
1944            fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", firstframe + framenum, chd_error_string(err));
1945            goto cleanup;
1946         }
1947
1948         /* write audio */
1949         for (chnum = 0; chnum < channels; chnum++)
1950         {
1951            avierr = avi_append_sound_samples(avi, chnum, avconfig.audio[chnum], numsamples, 0);
1952            if (avierr != AVIERR_NONE)
1361            // determine the name
1362            const char *name = "Unknown";
1363            switch (comptype)
19531364            {
1954               fprintf(stderr, "Error writing samples for hunk %d to AVI file: %s\n", firstframe + framenum, avi_error_string(avierr));
1955               goto cleanup;
1365               case CHD_CODEC_NONE:      name = "Uncompressed";               break;
1366               case CHD_CODEC_SELF:      name = "Copy from self";            break;
1367               case CHD_CODEC_PARENT:      name = "Copy from parent";            break;
1368               case CHD_CODEC_MINI:      name = "Legacy 8-byte mini";         break;
1369               default:
1370                  int index = comptype - 1 - CHD_CODEC_MINI;
1371                  if (index < 4)
1372                     name = chd_codec_list::codec_name(input_chd.compression(index));
1373                  break;
19561374            }
1375           
1376            // output the stats
1377            astring tempstr;
1378            printf("%10s   %5.1f%%  %-40s\n",
1379                  big_int_string(tempstr, compression_types[comptype]),
1380                  100.0 * double(compression_types[comptype]) / double(input_chd.hunk_count()),
1381                  name);
19571382         }
1958
1959         /* write video */
1960         if (!interlaced || (firstframe + framenum) % 2 == 1)
1961         {
1962            avierr = avi_append_video_frame(avi, fullbitmap);
1963            if (avierr != AVIERR_NONE)
1964            {
1965               fprintf(stderr, "Error writing video for hunk %d to AVI file: %s\n", firstframe + framenum, avi_error_string(avierr));
1966               goto cleanup;
1967            }
1968         }
1969      }
1970      progress(TRUE, "Extraction complete!                    \n");
19711383   }
1972
1973cleanup:
1974   /* clean up our mess */
1975   if (avi != NULL)
1976      avi_close(avi);
1977   for (chnum = 0; chnum < ARRAY_LENGTH(avconfig.audio); chnum++)
1978      if (avconfig.audio[chnum] != NULL)
1979         free(avconfig.audio[chnum]);
1980   if (chd != NULL)
1981      chd_close(chd);
1982   if (err != CHDERR_NONE)
1983      osd_rmfile(outputfile);
1984   return (err != CHDERR_NONE);
19851384}
19861385
19871386
1988/*-------------------------------------------------
1989    do_verify - validate the MD5/SHA1 on a drive
1990    image
1991-------------------------------------------------*/
1387//-------------------------------------------------
1388//  do_verify - validate the SHA1 on a CHD
1389//-------------------------------------------------
19921390
1993static int do_verify(int argc, char *argv[], int param)
1391static void do_verify(parameters_t &params)
19941392{
1995   chd_verify_result verify;
1996   const char *inputfile;
1997   chd_file *chd = NULL;
1998   chd_header header;
1999   int fixed = FALSE;
2000   chd_error err;
2001   int i;
1393   // parse out input files
1394   chd_file input_parent_chd;
1395   chd_file input_chd;
1396   parse_input_chd_parameters(params, input_chd, input_parent_chd);
20021397
2003   /* require 3 args total */
2004   if (argc != 3)
2005      return usage();
1398   // only makes sense for compressed CHDs with valid SHA1's
1399   if (!input_chd.compressed())
1400      report_error(0, "No verification to be done; CHD is uncompressed");
1401   sha1_t raw_sha1 = (input_chd.version() <= 3) ? input_chd.sha1() : input_chd.raw_sha1();
1402   if (raw_sha1 == sha1_t::null)
1403      report_error(0, "No verification to be done; CHD has no checksum");
20061404
2007   /* extract the data */
2008   inputfile = argv[2];
2009
2010   /* print some info */
2011   printf("Input file:   %s\n", inputfile);
2012
2013   /* open the CHD file */
2014   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
2015   if (err != CHDERR_NONE)
1405   // create an array to read into
1406   dynamic_buffer buffer((TEMP_BUFFER_SIZE / input_chd.hunk_bytes()) * input_chd.hunk_bytes());
1407   
1408   // read all the data and build up an SHA-1
1409   sha1_creator rawsha1;
1410   for (UINT64 offset = 0; offset < input_chd.logical_bytes(); )
20161411   {
2017      fprintf(stderr, "Error opening CHD file: %s\n", chd_error_string(err));
2018      goto cleanup;
2019   }
2020   header = *chd_get_header(chd);
1412      progress(false, "Verifying, %.1f%% complete... \r", 100.0 * double(offset) / double(input_chd.logical_bytes()));
20211413
2022   /* verify the CHD data */
2023   err = chd_verify_begin(chd);
2024   if (err == CHDERR_NONE)
2025   {
2026      UINT32 hunknum;
2027      for (hunknum = 0; hunknum < header.totalhunks; hunknum++)
2028      {
2029         /* progress */
2030         progress(FALSE, "Verifying hunk %d/%d... \r", hunknum, header.totalhunks);
2031
2032         /* verify the data */
2033         err = chd_verify_hunk(chd);
2034         if (err != CHDERR_NONE)
2035            break;
2036      }
2037
2038      /* finish it */
2039      if (err == CHDERR_NONE)
2040         err = chd_verify_finish(chd, &verify);
1414      // determine how much to read
1415      UINT32 bytes_to_read = MIN(buffer.count(), input_chd.logical_bytes() - offset);
1416      chd_error err = input_chd.read_bytes(offset, buffer, bytes_to_read);
1417      if (err != CHDERR_NONE)
1418         report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->cstr(), chd_file::error_string(err));
1419     
1420      // add to the checksum
1421      rawsha1.append(buffer, bytes_to_read);
1422      offset += bytes_to_read;
20411423   }
2042
2043   /* handle errors */
2044   if (err != CHDERR_NONE)
1424   sha1_t computed_sha1 = rawsha1.finish();
1425   
1426   // finish up
1427   if (raw_sha1 != computed_sha1)
20451428   {
2046      if (err == CHDERR_CANT_VERIFY)
2047         fprintf(stderr, "Can't verify this type of image (probably writeable)\n");
2048      else
2049         fprintf(stderr, "\nError during verify: %s\n", chd_error_string(err));
2050      goto cleanup;
2051   }
1429      astring tempstr;
1430      fprintf(stderr, "Error: Raw SHA1 in header = %s\n", raw_sha1.as_string(tempstr));
1431      fprintf(stderr, "              actual SHA1 = %s\n", computed_sha1.as_string(tempstr));
20521432
2053   /* verify the MD5 */
2054   if (header.version <= 3)
2055   {
2056      if (memcmp(header.md5, verify.md5, sizeof(header.md5)) == 0)
2057         printf("MD5 verification successful!\n");
2058      else
1433      // fix it if requested; this also fixes the overall one so we don't need to do any more
1434      if (params.find(OPTION_FIX) != NULL)
20591435      {
2060         fprintf(stderr, "Error: MD5 in header = ");
2061         for (i = 0; i < CHD_MD5_BYTES; i++)
2062            fprintf(stderr, "%02x", header.md5[i]);
2063         fprintf(stderr, "\n");
2064         fprintf(stderr, "          actual MD5 = ");
2065         for (i = 0; i < CHD_MD5_BYTES; i++)
2066            fprintf(stderr, "%02x", verify.md5[i]);
2067         fprintf(stderr, "\n");
2068
2069         /* fix it */
2070         if (param)
2071         {
2072            memcpy(header.md5, verify.md5, sizeof(header.md5));
2073            fixed = TRUE;
2074         }
1436         input_chd.set_raw_sha1(computed_sha1);
1437         printf("SHA-1 updated to correct value in input CHD\n");
20751438      }
20761439   }
2077
2078   /* verify the SHA1 */
2079   if (header.version >= 3)
1440   else
20801441   {
2081      if (memcmp(header.sha1, verify.sha1, sizeof(header.sha1)) == 0)
2082         printf("SHA1 verification successful!\n");
2083      else
1442      printf("Raw SHA1 verification successful!\n");
1443   
1444      // now include the metadata for >= v4
1445      if (input_chd.version() >= 4)
20841446      {
2085         fprintf(stderr, "Error: SHA1 in header = ");
2086         for (i = 0; i < CHD_SHA1_BYTES; i++)
2087            fprintf(stderr, "%02x", header.sha1[i]);
2088         fprintf(stderr, "\n");
2089         fprintf(stderr, "          actual SHA1 = ");
2090         for (i = 0; i < CHD_SHA1_BYTES; i++)
2091            fprintf(stderr, "%02x", verify.sha1[i]);
2092         fprintf(stderr, "\n");
2093
2094         /* fix it */
2095         if (param)
1447         sha1_t computed_overall_sha1 = input_chd.compute_overall_sha1(computed_sha1);
1448         if (input_chd.sha1() == computed_overall_sha1)
1449            printf("Overall SHA1 verification successful!\n");
1450         else
20961451         {
2097            memcpy(header.sha1, verify.sha1, sizeof(header.sha1));
2098            fixed = TRUE;
2099         }
1452            astring tempstr;
1453            fprintf(stderr, "Error: Overall SHA1 in header = %s\n", input_chd.sha1().as_string(tempstr));
1454            fprintf(stderr, "                  actual SHA1 = %s\n", computed_overall_sha1.as_string(tempstr));
21001455
2101         /* verify the raw SHA1 */
2102         if (header.version >= 4)
2103         {
2104            if (memcmp(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1)) != 0)
1456            // fix it if requested
1457            if (params.find(OPTION_FIX) != NULL)
21051458            {
2106               fprintf(stderr, "Error: raw SHA1 in header = ");
2107               for (i = 0; i < CHD_SHA1_BYTES; i++)
2108                  fprintf(stderr, "%02x", header.rawsha1[i]);
2109               fprintf(stderr, "\n");
2110               fprintf(stderr, "          actual raw SHA1 = ");
2111               for (i = 0; i < CHD_SHA1_BYTES; i++)
2112                  fprintf(stderr, "%02x", verify.rawsha1[i]);
2113               fprintf(stderr, "\n");
2114
2115               /* fix it */
2116               if (param)
2117               {
2118                  memcpy(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1));
2119                  fixed = TRUE;
2120               }
1459               input_chd.set_raw_sha1(computed_sha1);
1460               printf("SHA-1 updated to correct value in input CHD\n");
21211461            }
21221462         }
21231463      }
21241464   }
2125
2126   /* close the drive */
2127   chd_close(chd);
2128   chd = NULL;
2129
2130   /* update the header */
2131   if (fixed)
2132   {
2133      err = chd_set_header(inputfile, &header);
2134      if (err != CHDERR_NONE)
2135         fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err));
2136      else
2137         printf("Updated header successfully\n");
2138   }
2139
2140cleanup:
2141   /* close everything down */
2142   if (chd != NULL)
2143      chd_close(chd);
2144   return (err != CHDERR_NONE);
21451465}
21461466
21471467
2148/*-------------------------------------------------
2149    do_fixavdata - fix the AV metadata for an
2150    A/V file
2151-------------------------------------------------*/
1468//-------------------------------------------------
1469//  do_create_raw - create a new compressed raw
1470//  image from a raw file
1471//-------------------------------------------------
21521472
2153static int do_fixavdata(int argc, char *argv[], int param)
1473static void do_create_raw(parameters_t &params)
21541474{
2155   int fps, fpsfrac, width, height, interlaced, channels, rate;
2156   av_codec_decompress_config avconfig;
2157   const char *inputfile;
2158   UINT8 *vbidata = NULL;
2159   int writeable = FALSE;
2160   chd_file *chd = NULL;
2161   bitmap_yuy16 fakebitmap;
2162   char metadata[256];
2163   chd_header header;
2164   UINT32 actlength;
2165   UINT32 framenum;
2166   chd_error err;
2167   int fixframes = 0;
2168   int fixes = 0;
1475   // catch errors so we can close & delete the output file
1476   try
1477   {
1478      // process input file
1479      core_file *input_file = NULL;
1480      astring *input_file_str = params.find(OPTION_INPUT);
1481      if (input_file_str != NULL)
1482      {
1483         file_error filerr = core_fopen(*input_file_str, OPEN_FLAG_READ, &input_file);
1484         if (filerr != FILERR_NONE)
1485            report_error(1, "Unable to open file (%s)", input_file_str->cstr());
1486      }
21691487
2170   /* require 3 args total */
2171   if (argc != 3)
2172      return usage();
1488      // process output CHD
1489      chd_file output_parent;
1490      astring *output_chd_str = parse_output_chd_parameters(params, output_parent);
1491     
1492      // process hunk size
1493      UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : 0;
1494      parse_hunk_size(params, 1, hunk_size);
21731495
2174   /* extract the data */
2175   inputfile = argv[2];
1496      // process unit size
1497      UINT32 unit_size = output_parent.opened() ? output_parent.unit_bytes() : 0;
1498      astring *unit_size_str = params.find(OPTION_UNIT_SIZE);
1499      if (unit_size_str != NULL)
1500      {
1501         unit_size = parse_number(*unit_size_str);
1502         if (hunk_size % unit_size != 0)
1503            report_error(1, "Unit size is not an even divisor of the hunk size");
1504      }
21761505
2177   /* print some info */
2178   printf("Input file:   %s\n", inputfile);
1506      // process input start/end (needs to know hunk_size)
1507      UINT64 input_start;
1508      UINT64 input_end;
1509      parse_input_start_end(params, core_fsize(input_file), hunk_size, hunk_size, input_start, input_end);
1510     
1511      // process compression
1512      chd_codec_type compression[4];
1513      memcpy(compression, s_default_raw_compression, sizeof(compression));
1514      parse_compression(params, compression);
1515     
1516      // process numprocessors
1517      parse_numprocessors(params);
21791518
2180   /* get the header */
2181   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
2182   if (err != CHDERR_NONE)
2183   {
2184      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
2185      goto cleanup;
2186   }
2187   header = *chd_get_header(chd);
1519      // print some info
1520      astring tempstr;
1521      printf("Output CHD:   %s\n", output_chd_str->cstr());
1522      if (output_parent.opened())
1523         printf("Parent CHD:   %s\n", params.find(OPTION_OUTPUT_PARENT)->cstr());
1524      printf("Input file:   %s\n", input_file_str->cstr());
1525      if (input_start != 0 || input_end != core_fsize(input_file))
1526      {
1527         printf("Input start:  %s\n", big_int_string(tempstr, input_start));
1528         printf("Input length: %s\n", big_int_string(tempstr, input_end - input_start));
1529      }
1530      printf("Compression:  %s\n", compression_string(tempstr, compression));
1531      printf("Hunk size:    %s\n", big_int_string(tempstr, hunk_size));
1532      printf("Logical size: %s\n", big_int_string(tempstr, input_end - input_start));
21881533
2189   /* get the metadata */
2190   err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
2191   if (err != CHDERR_NONE)
2192   {
2193      fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(err));
2194      goto cleanup;
2195   }
1534      // create the new CHD
1535      chd_rawfile_compressor chd(input_file, input_start, input_end);
1536      chd_error err;
1537      if (output_parent.opened())
1538         err = chd.create(*output_chd_str, input_end - input_start, hunk_size, compression, output_parent);
1539      else
1540         err = chd.create(*output_chd_str, input_end - input_start, hunk_size, unit_size, compression);
1541      if (err != CHDERR_NONE)
1542         report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err));
1543     
1544      // if we have a parent, copy forward all the metadata
1545      if (output_parent.opened())
1546         chd.clone_all_metadata(output_parent);
21961547
2197   /* extract the info */
2198   if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
2199   {
2200      fprintf(stderr, "Improperly formatted metadata\n");
2201      err = CHDERR_INVALID_METADATA;
2202      goto cleanup;
1548      // compress it generically
1549      compress_common(chd);
22031550   }
2204
2205   /* allocate space for the frame data */
2206   if ((height != 524/2 && height != 624/2) || !interlaced)
1551   catch (...)
22071552   {
2208      fprintf(stderr, "This file does not need VBI metadata\n");
2209      err = CHDERR_INVALID_METADATA;
2210      goto cleanup;
1553      // delete the output file
1554      astring *output_chd_str = params.find(OPTION_OUTPUT);
1555      if (output_chd_str != NULL)
1556         osd_rmfile(*output_chd_str);
1557      throw;
22111558   }
1559}
22121560
2213   /* allocate a video buffer */
2214   {
2215      bitmap_yuy16 fullbitmap(width, height);
2216      avconfig.video.wrap(fullbitmap, fullbitmap.cliprect());
22171561
2218      /* allocate memory for VBI data */
2219      vbidata = (UINT8 *)malloc(header.totalhunks * VBI_PACKED_BYTES);
2220      if (vbidata == NULL)
1562//-------------------------------------------------
1563//  do_create_hd - create a new compressed hard
1564//  disk image from a raw file
1565//-------------------------------------------------
1566
1567static void do_create_hd(parameters_t &params)
1568{
1569   // catch errors so we can close & delete the output file
1570   try
1571   {
1572      // process input file
1573      core_file *input_file = NULL;
1574      astring *input_file_str = params.find(OPTION_INPUT);
1575      if (input_file_str != NULL)
22211576      {
2222         fprintf(stderr, "Out of memory allocating VBI data\n");
2223         err = CHDERR_OUT_OF_MEMORY;
2224         goto cleanup;
1577         file_error filerr = core_fopen(*input_file_str, OPEN_FLAG_READ, &input_file);
1578         if (filerr != FILERR_NONE)
1579            report_error(1, "Unable to open file (%s)", input_file_str->cstr());
22251580      }
2226
2227      /* read the metadata */
2228      err = chd_get_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, &actlength, NULL, NULL);
2229      if (err != CHDERR_NONE)
1581     
1582      // process output CHD
1583      chd_file output_parent;
1584      astring *output_chd_str = parse_output_chd_parameters(params, output_parent);
1585     
1586      // process sectorsize
1587      UINT32 sector_size = output_parent.opened() ? output_parent.unit_bytes() : IDE_SECTOR_SIZE;
1588      astring *sectorsize_str = params.find(OPTION_SECTOR_SIZE);
1589      if (sectorsize_str != NULL)
22301590      {
2231         fprintf(stderr, "Error getting VBI metadata: %s\n", chd_error_string(err));
2232         memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
2233         fixes++;
1591         if (output_parent.opened())
1592            report_error(1, "Sector size does not apply when creating a diff from the parent");
1593         sector_size = parse_number(*sectorsize_str);
22341594      }
2235      if (actlength != header.totalhunks * VBI_PACKED_BYTES)
1595     
1596      // process hunk size (needs to know sector_size)
1597      UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : MAX((4096 / sector_size) * sector_size, sector_size);
1598      parse_hunk_size(params, sector_size, hunk_size);
1599     
1600      // process input start/end (needs to know hunk_size)
1601      UINT64 input_start;
1602      UINT64 input_end;
1603      parse_input_start_end(params, core_fsize(input_file), hunk_size, hunk_size, input_start, input_end);
1604     
1605      // process compression
1606      chd_codec_type compression[4];
1607      memcpy(compression, s_default_hd_compression, sizeof(compression));
1608      if (input_file == NULL)
1609         compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE;
1610      parse_compression(params, compression);
1611      if (input_file == NULL && compression[0] != CHD_CODEC_NONE)
1612         report_error(1, "Blank hard disks must be uncompressed");
1613
1614      // process numprocessors
1615      parse_numprocessors(params);
1616
1617      // process chs
1618      UINT32 cylinders = 0;
1619      UINT32 heads = 0;
1620      UINT32 sectors = 0;
1621      astring *chs_str = params.find(OPTION_CHS);
1622      if (chs_str != NULL)
22361623      {
2237         fprintf(stderr, "VBI metadata incorrect size\n");
2238         memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
2239         fixes++;
1624         if (output_parent.opened())
1625            report_error(1, "CHS does not apply when creating a diff from the parent");
1626         if (sscanf(*chs_str, "%d,%d,%d", &cylinders, &heads, &sectors) != 3)
1627            report_error(1, "Invalid CHS string; must be of the form <cylinders>,<heads>,<sectors>");
22401628      }
22411629
2242      /* loop over hunks, reading */
2243      for (framenum = 0; framenum < header.totalhunks; framenum++)
1630      // process ident
1631      dynamic_buffer identdata;
1632      if (output_parent.opened())
1633         output_parent.read_metadata(HARD_DISK_IDENT_METADATA_TAG, 0, identdata);
1634      astring *ident_str = params.find(OPTION_IDENT);
1635      if (ident_str != NULL)
22441636      {
2245         vbi_metadata origvbi;
2246         vbi_metadata vbi;
2247         UINT32 vbiframe;
1637         // load the file
1638         file_error filerr = core_fload(*ident_str, identdata);
1639         if (filerr != FILERR_NONE)
1640            report_error(1, "Error reading ident file (%s)", ident_str->cstr());
22481641
2249         /* progress */
2250         progress(framenum == 0, "Processing hunk %d/%d...  \r", framenum, header.totalhunks);
2251
2252         /* set up the fake bitmap for this frame */
2253         avconfig.video.wrap(fullbitmap, fullbitmap.cliprect());
2254
2255         /* configure the decompressor for this frame */
2256         chd_codec_config(chd, AV_CODEC_DECOMPRESS_CONFIG, &avconfig);
2257
2258         /* read the hunk into the buffers */
2259         err = chd_read(chd, framenum, NULL);
2260         if (err != CHDERR_NONE)
1642         // must be at least 14 bytes; extract CHS data from there
1643         if (identdata.count() < 14)
1644            report_error(1, "Ident file '%s' is invalid (too short)", ident_str->cstr());
1645         cylinders = (identdata[3] << 8) | identdata[2];
1646         heads = (identdata[7] << 8) | identdata[6];
1647         sectors = (identdata[13] << 8) | identdata[12];
1648      }
1649     
1650      // extract geometry from the parent if we have one
1651      if (output_parent.opened() && cylinders == 0)
1652      {
1653         astring metadata;
1654         if (output_parent.read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) != CHDERR_NONE)
1655            report_error(1, "Unable to find hard disk metadata in parent CHD");
1656         if (sscanf(metadata, HARD_DISK_METADATA_FORMAT, &cylinders, &heads, &sectors, &sector_size) != 4)
1657            report_error(1, "Error parsing hard disk metadata in parent CHD");
1658      }
1659     
1660      // if no CHS values, try to guess them
1661      if (cylinders == 0)
1662      {
1663         if (input_file == NULL && input_end - input_start == 0)
1664            report_error(1, "Blank hard drives must specify either a length or a set of CHS values");
1665         guess_chs(input_file_str, input_end - input_start, sector_size, cylinders, heads, sectors, sector_size);
1666      }
1667      UINT32 totalsectors = cylinders * heads * sectors;
1668     
1669      // print some info
1670      astring tempstr;
1671      printf("Output CHD:   %s\n", output_chd_str->cstr());
1672      if (output_parent.opened())
1673         printf("Parent CHD:   %s\n", params.find(OPTION_OUTPUT_PARENT)->cstr());
1674      if (input_file != NULL)
1675      {
1676         printf("Input file:   %s\n", input_file_str->cstr());
1677         if (input_start != 0 || input_end != core_fsize(input_file))
22611678         {
2262            fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", framenum, chd_error_string(err));
2263            goto cleanup;
1679            printf("Input start:  %s\n", big_int_string(tempstr, input_start));
1680            printf("Input length: %s\n", big_int_string(tempstr, input_end - input_start));
22641681         }
2265
2266         /* unpack the current data for this frame */
2267         vbi_metadata_unpack(&origvbi, &vbiframe, &vbidata[framenum * VBI_PACKED_BYTES]);
2268
2269         /* parse the video data */
2270         vbi_parse_all(&avconfig.video.pix16(0), avconfig.video.rowpixels(), avconfig.video.width(), 8, &vbi);
2271
2272         /* verify the data */
2273         if (vbiframe != 0 || origvbi.white != 0 || origvbi.line16 != 0 || origvbi.line17 != 0 || origvbi.line18 != 0 || origvbi.line1718 != 0)
2274         {
2275            int errors = 0;
2276
2277            if (vbiframe != framenum)
2278            {
2279               fprintf(stderr, "%d:Frame mismatch in VBI data (%d, should be %d)\n", framenum, vbiframe, framenum);
2280               errors++;
2281            }
2282            if (vbi.white != origvbi.white)
2283            {
2284               fprintf(stderr, "%d:White flag mismatch in VBI data (%d, should be %d)\n", framenum, origvbi.white, vbi.white);
2285               errors++;
2286            }
2287            if (vbi.line16 != origvbi.line16)
2288            {
2289               fprintf(stderr, "%d:Line 16 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line16, vbi.line16);
2290               errors++;
2291            }
2292            if (vbi.line17 != origvbi.line17)
2293            {
2294               fprintf(stderr, "%d:Line 17 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line17, vbi.line17);
2295               errors++;
2296            }
2297            if (vbi.line18 != origvbi.line18)
2298            {
2299               fprintf(stderr, "%d:Line 18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line18, vbi.line18);
2300               errors++;
2301            }
2302            if (vbi.line1718 != origvbi.line1718)
2303            {
2304               fprintf(stderr, "%d:Line 17/18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line1718, vbi.line1718);
2305               errors++;
2306            }
2307            fixes += errors;
2308            fixframes += (errors != 0);
2309         }
2310
2311         /* pack the new data */
2312         vbi_metadata_pack(&vbidata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
23131682      }
2314      progress(TRUE, "Processing complete!                                     \n");
1683      printf("Compression:  %s\n", compression_string(tempstr, compression));
1684      printf("Cylinders:    %d\n", cylinders);
1685      printf("Heads:        %d\n", heads);
1686      printf("Sectors:      %d\n", sectors);
1687      printf("Bytes/sector: %d\n", sector_size);
1688      printf("Sectors/hunk: %d\n", hunk_size / sector_size);
1689      printf("Logical size: %s\n", big_int_string(tempstr, UINT64(totalsectors) * UINT64(sector_size)));
23151690
2316      /* print final results */
2317      if (fixes == 0)
2318         printf("\nNo fixes required\n");
1691      // create the new hard drive
1692      chd_rawfile_compressor chd(input_file, input_start, input_end);
1693      chd_error err;
1694      if (output_parent.opened())
1695         err = chd.create(*output_chd_str, UINT64(totalsectors) * UINT64(sector_size), hunk_size, compression, output_parent);
23191696      else
2320         printf("\nFound %d errors on %d frames\n", fixes, fixframes);
1697         err = chd.create(*output_chd_str, UINT64(totalsectors) * UINT64(sector_size), hunk_size, sector_size, compression);
1698      if (err != CHDERR_NONE)
1699         report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err));
23211700
2322      /* close the drive */
2323      chd_close(chd);
2324      chd = NULL;
1701      // add the standard hard disk metadata
1702      astring metadata;
1703      metadata.format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sector_size);
1704      err = chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
1705      if (err != CHDERR_NONE)
1706         report_error(1, "Error adding hard disk metadata: %s", chd_file::error_string(err));
23251707
2326      /* apply fixes */
2327      if (fixes > 0)
1708      // write the ident if present
1709      if (identdata.count() > 0)
23281710      {
2329         /* mark the CHD writeable */
2330         header.flags |= CHDFLAGS_IS_WRITEABLE;
2331         err = chd_set_header(inputfile, &header);
1711         err = chd.write_metadata(HARD_DISK_IDENT_METADATA_TAG, 0, identdata);
23321712         if (err != CHDERR_NONE)
2333            fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err));
2334         header.flags &= ~CHDFLAGS_IS_WRITEABLE;
2335         writeable = TRUE;
2336
2337         /* open the file */
2338         err = chd_open(inputfile, CHD_OPEN_READWRITE, NULL, &chd);
2339         if (err != CHDERR_NONE)
2340         {
2341            fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
2342            goto cleanup;
2343         }
2344
2345         /* write new metadata */
2346         err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
2347         if (err != CHDERR_NONE)
2348         {
2349            fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
2350            goto cleanup;
2351         }
2352         else
2353            printf("Updated metadata written successfully\n");
2354
2355         /* allow cleanup code to close the file and revert the header */
1713            report_error(1, "Error adding hard disk metadata: %s", chd_file::error_string(err));
23561714      }
2357   }
23581715
2359cleanup:
2360   /* clean up our mess */
2361   if (vbidata != NULL)
2362      free(vbidata);
2363   if (chd != NULL)
2364      chd_close(chd);
2365   if (writeable)
2366      chd_set_header(inputfile, &header);
2367   return (err != CHDERR_NONE);
1716      // compress it generically
1717      if (input_file != NULL)
1718         compress_common(chd);
1719   }
1720   catch (...)
1721   {
1722      // delete the output file
1723      astring *output_chd_str = params.find(OPTION_OUTPUT);
1724      if (output_chd_str != NULL)
1725         osd_rmfile(*output_chd_str);
1726      throw;
1727   }
23681728}
23691729
23701730
2371/*-------------------------------------------------
2372    do_info - dump the header information from
2373    a drive image
2374-------------------------------------------------*/
1731//-------------------------------------------------
1732//  do_create_cd - create a new compressed CD
1733//  image from a raw file
1734//-------------------------------------------------
23751735
2376static int do_info(int argc, char *argv[], int param)
1736static void do_create_cd(parameters_t &params)
23771737{
2378   const char *inputfile;
2379   chd_file *chd = NULL;
2380   UINT8 metadata[256];
2381   chd_header header;
2382   chd_error err;
2383   int i, j;
1738   // catch errors so we can close & delete the output file
1739   try
1740   {
1741      // process input file
1742      chdcd_track_input_info track_info;
1743      cdrom_toc toc = { 0 };
1744      astring *input_file_str = params.find(OPTION_INPUT);
1745      if (input_file_str != NULL)
1746      {
1747         chd_error err = chdcd_parse_toc(*input_file_str, toc, track_info);
1748         if (err != CHDERR_NONE)
1749            report_error(1, "Error parsing input file (%s: %s\n", input_file_str->cstr(), chd_file::error_string(err));
1750      }
1751     
1752      // process output CHD
1753      chd_file output_parent;
1754      astring *output_chd_str = parse_output_chd_parameters(params, output_parent);
23841755
2385   /* require 3 args total */
2386   if (argc != 3)
2387      return usage();
1756      // process hunk size
1757      UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : CD_FRAMES_PER_HUNK * CD_FRAME_SIZE;
1758      parse_hunk_size(params, CD_FRAME_SIZE, hunk_size);
1759     
1760      // process compression
1761      chd_codec_type compression[4];
1762      memcpy(compression, s_default_cd_compression, sizeof(compression));
1763      parse_compression(params, compression);
23881764
2389   /* extract the data */
2390   inputfile = argv[2];
1765      // process numprocessors
1766      parse_numprocessors(params);
23911767
2392   /* print some info */
2393   printf("Input file:   %s\n", inputfile);
1768      // pad each track to a 4-frame boundry. cdrom.c will deal with this on the read side
1769      UINT32 origtotalsectors = 0;
1770      UINT32 totalsectors = 0;
1771      for (int tracknum = 0; tracknum < toc.numtrks; tracknum++)
1772      {
1773         cdrom_track_info &trackinfo = toc.tracks[tracknum];
1774         int padded = (trackinfo.frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING;
1775         trackinfo.extraframes = padded * CD_TRACK_PADDING - trackinfo.frames;
1776         origtotalsectors += trackinfo.frames;
1777         totalsectors += trackinfo.frames + trackinfo.extraframes;
1778      }
23941779
2395   /* get the header */
2396   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
2397   if (err != CHDERR_NONE)
2398   {
2399      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
2400      goto cleanup;
2401   }
2402   header = *chd_get_header(chd);
1780      // print some info
1781      astring tempstr;
1782      printf("Output CHD:   %s\n", output_chd_str->cstr());
1783      if (output_parent.opened())
1784         printf("Parent CHD:   %s\n", params.find(OPTION_OUTPUT_PARENT)->cstr());
1785      printf("Input file:   %s\n", input_file_str->cstr());
1786      printf("Input tracks: %d\n", toc.numtrks);
1787      printf("Input length: %s\n", msf_string_from_frames(tempstr, origtotalsectors));
1788      printf("Compression:  %s\n", compression_string(tempstr, compression));
1789      printf("Logical size: %s\n", big_int_string(tempstr, UINT64(totalsectors) * CD_FRAME_SIZE));
24031790
2404   /* print the info */
2405   printf("Header Size:  %d bytes\n", header.length);
2406   printf("File Version: %d\n", header.version);
2407   printf("Flags:        %s, %s\n",
2408         (header.flags & CHDFLAGS_HAS_PARENT) ? "HAS_PARENT" : "NO_PARENT",
2409         (header.flags & CHDFLAGS_IS_WRITEABLE) ? "WRITEABLE" : "READ_ONLY");
2410   printf("Compression:  %s\n", chd_get_codec_name(header.compression));
2411   printf("Hunk Size:    %d bytes\n", header.hunkbytes);
2412   printf("Total Hunks:  %d\n", header.totalhunks);
2413   printf("Logical size: %s bytes\n", big_int_string(header.logicalbytes));
2414   if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version <= 3)
2415      printf("MD5:          %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2416            header.md5[0], header.md5[1], header.md5[2], header.md5[3],
2417            header.md5[4], header.md5[5], header.md5[6], header.md5[7],
2418            header.md5[8], header.md5[9], header.md5[10], header.md5[11],
2419            header.md5[12], header.md5[13], header.md5[14], header.md5[15]);
2420   if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version >= 3)
2421      printf("SHA1:         %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2422            header.sha1[0], header.sha1[1], header.sha1[2], header.sha1[3],
2423            header.sha1[4], header.sha1[5], header.sha1[6], header.sha1[7],
2424            header.sha1[8], header.sha1[9], header.sha1[10], header.sha1[11],
2425            header.sha1[12], header.sha1[13], header.sha1[14], header.sha1[15],
2426            header.sha1[16], header.sha1[17], header.sha1[18], header.sha1[19]);
2427   if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version >= 4)
2428   {
2429      printf("Raw SHA1:     %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2430            header.rawsha1[0], header.rawsha1[1], header.rawsha1[2], header.rawsha1[3],
2431            header.rawsha1[4], header.rawsha1[5], header.rawsha1[6], header.rawsha1[7],
2432            header.rawsha1[8], header.rawsha1[9], header.rawsha1[10], header.rawsha1[11],
2433            header.rawsha1[12], header.rawsha1[13], header.rawsha1[14], header.rawsha1[15],
2434            header.rawsha1[16], header.rawsha1[17], header.rawsha1[18], header.rawsha1[19]);
2435   }
2436   if (header.flags & CHDFLAGS_HAS_PARENT)
2437   {
2438      printf("Parent MD5:   %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2439            header.parentmd5[0], header.parentmd5[1], header.parentmd5[2], header.parentmd5[3],
2440            header.parentmd5[4], header.parentmd5[5], header.parentmd5[6], header.parentmd5[7],
2441            header.parentmd5[8], header.parentmd5[9], header.parentmd5[10], header.parentmd5[11],
2442            header.parentmd5[12], header.parentmd5[13], header.parentmd5[14], header.parentmd5[15]);
2443      if (header.version >= 3)
2444         printf("Parent SHA1:  %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2445               header.parentsha1[0], header.parentsha1[1], header.parentsha1[2], header.parentsha1[3],
2446               header.parentsha1[4], header.parentsha1[5], header.parentsha1[6], header.parentsha1[7],
2447               header.parentsha1[8], header.parentsha1[9], header.parentsha1[10], header.parentsha1[11],
2448               header.parentsha1[12], header.parentsha1[13], header.parentsha1[14], header.parentsha1[15],
2449               header.parentsha1[16], header.parentsha1[17], header.parentsha1[18], header.parentsha1[19]);
2450   }
1791      // create the new hard drive
1792      chd_cd_compressor chd(toc, track_info);
1793      chd_error err;
1794      if (output_parent.opened())
1795         err = chd.create(*output_chd_str, UINT64(totalsectors) * UINT64(CD_FRAME_SIZE), hunk_size, compression, output_parent);
1796      else
1797         err = chd.create(*output_chd_str, UINT64(totalsectors) * UINT64(CD_FRAME_SIZE), hunk_size, CD_FRAME_SIZE, compression);
1798      if (err != CHDERR_NONE)
1799         report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err));
24511800
2452   /* print out metadata */
2453   for (i = 0; ; i++)
2454   {
2455      UINT32 metatag, metasize;
2456
2457      /* get the indexed metadata item; stop when we hit an error */
2458      err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, i, metadata, sizeof(metadata), &metasize, &metatag, NULL);
1801      // add the standard CD metadata; we do this even if we have a parent because it might be different
1802      err = cdrom_write_metadata(&chd, &toc);
24591803      if (err != CHDERR_NONE)
2460         break;
1804         report_error(1, "Error adding CD metadata: %s", chd_file::error_string(err));
24611805
2462      /* print either a string representation or a hex representation of the tag */
2463      if (isprint((metatag >> 24) & 0xff) && isprint((metatag >> 16) & 0xff) && isprint((metatag >> 8) & 0xff) && isprint(metatag & 0xff))
2464         printf("Metadata:     Tag='%c%c%c%c'    Length=%d\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff, metasize);
2465      else
2466         printf("Metadata:     Tag=%08x  Length=%d\n", metatag, metasize);
2467      printf("              ");
2468
2469      /* print up to 60 characters of metadata */
2470      metasize = MIN(60, metasize);
2471      for (j = 0; j < metasize; j++)
2472         printf("%c", isprint(metadata[j]) ? metadata[j] : '.');
2473      printf("\n");
1806      // compress it generically
1807      compress_common(chd);
24741808   }
2475
2476cleanup:
2477   /* close everything down */
2478   if (chd != NULL)
2479      chd_close(chd);
2480   return (err != CHDERR_NONE);
1809   catch (...)
1810   {
1811      // delete the output file
1812      astring *output_chd_str = params.find(OPTION_OUTPUT);
1813      if (output_chd_str != NULL)
1814         osd_rmfile(*output_chd_str);
1815      throw;
1816   }
24811817}
24821818
24831819
2484/*-------------------------------------------------
2485    handle_custom_chomp - custom chomp a file
2486-------------------------------------------------*/
1820//-------------------------------------------------
1821//  do_create_ld - create a new A/V file from an
1822//  input AVI file and metadata
1823//-------------------------------------------------
24871824
2488#if ENABLE_CUSTOM_CHOMP
2489static chd_error handle_custom_chomp(const char *name, chd_file *chd, UINT32 *maxhunk)
1825static void do_create_ld(parameters_t &params)
24901826{
2491   const chd_header *header = chd_get_header(chd);
2492   int sectors_per_hunk = (header->hunkbytes / IDE_SECTOR_SIZE);
2493   chd_error err = CHDERR_INVALID_DATA;
2494   UINT8 *temp = NULL;
2495
2496   /* allocate memory to hold a hunk */
2497   temp = malloc(header->hunkbytes);
2498   if (temp == NULL)
1827   // catch errors so we can close & delete the output file
1828   try
24991829   {
2500      err = CHDERR_OUT_OF_MEMORY;
2501      goto cleanup;
2502   }
2503
2504   /* check for midway */
2505   if (strcmp(name, "midway") == 0)
2506   {
2507      UINT32 maxsector = 0;
2508      UINT32 numparts;
2509      chd_error err;
2510      int i;
2511
2512      /* read sector 0 */
2513      err = chd_read(chd, 0, temp);
2514      if (err != CHDERR_NONE)
1830      // process input file
1831      avi_file *input_file = NULL;
1832      astring *input_file_str = params.find(OPTION_INPUT);
1833      if (input_file_str != NULL)
25151834      {
2516         fprintf(stderr, "Error reading hunk 0\n");
2517         goto cleanup;
1835         avi_error avierr = avi_open(*input_file_str, &input_file);
1836         if (avierr != AVIERR_NONE)
1837            report_error(1, "Error opening AVI file (%s): %s\n", input_file_str->cstr(), avi_error_string(avierr));
25181838      }
1839      const avi_movie_info *aviinfo = avi_get_movie_info(input_file);
1840     
1841      // process output CHD
1842      chd_file output_parent;
1843      astring *output_chd_str = parse_output_chd_parameters(params, output_parent);
1844     
1845      // process input start/end
1846      UINT64 input_start;
1847      UINT64 input_end;
1848      parse_input_start_end(params, aviinfo->video_numsamples, 0, 1, input_start, input_end);
1849     
1850      // determine parameters of the incoming video stream
1851      avi_info info;
1852      info.fps_times_1million = UINT64(aviinfo->video_timescale) * 1000000 / aviinfo->video_sampletime;
1853      info.width = aviinfo->video_width;
1854      info.height = aviinfo->video_height;
1855      info.interlaced = ((info.fps_times_1million / 1000000) <= 30) && (info.height % 2 == 0) && (info.height > 288);
1856      info.channels = aviinfo->audio_channels;
1857      info.rate = aviinfo->audio_samplerate;
25191858
2520      /* look for the signature */
2521      if (temp[0] != 0x54 || temp[1] != 0x52 || temp[2] != 0x41 || temp[3] != 0x50)
2522         goto cleanup;
2523
2524      /* determine the number of partitions */
2525      numparts = temp[4] | (temp[5] << 8) | (temp[6] << 16) | (temp[7] << 24);
2526      printf("%d partitions\n", numparts);
2527
2528      /* get the partition information for each one and track the maximum referenced sector */
2529      for (i = 0; i < numparts; i++)
1859      // adjust for interlacing
1860      if (info.interlaced)
25301861      {
2531         UINT32 pstart = temp[i*12 + 8] | (temp[i*12 + 9] << 8) | (temp[i*12 + 10] << 16) | (temp[i*12 + 11] << 24);
2532         UINT32 psize  = temp[i*12 + 12] | (temp[i*12 + 13] << 8) | (temp[i*12 + 14] << 16) | (temp[i*12 + 15] << 24);
2533         UINT32 pflags = temp[i*12 + 16] | (temp[i*12 + 17] << 8) | (temp[i*12 + 18] << 16) | (temp[i*12 + 19] << 24);
2534         printf("  %2d. %7d - %7d (%X)\n", i, pstart, pstart + psize - 1, pflags);
2535         if (i != 0 && pstart + psize > maxsector)
2536            maxsector = pstart + psize;
1862         info.fps_times_1million *= 2;
1863         info.height /= 2;
1864         input_start *= 2;
1865         input_end *= 2;
25371866      }
25381867
2539      /* the maximum hunk is the one that contains the last sector */
2540      *maxhunk = (maxsector + sectors_per_hunk - 1) / sectors_per_hunk;
2541      printf("Maximum hunk: %d\n", *maxhunk);
1868      // determine the number of bytes per frame
1869      info.max_samples_per_frame = (UINT64(info.rate) * 1000000 + info.fps_times_1million - 1) / info.fps_times_1million;
1870      info.bytes_per_frame = avhuff_encoder::raw_data_size(info.width, info.height, info.channels, info.max_samples_per_frame);
1871     
1872      // process hunk size
1873      UINT32 hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : info.bytes_per_frame;
1874      parse_hunk_size(params, info.bytes_per_frame, hunk_size);
1875     
1876      // process compression
1877      chd_codec_type compression[4];
1878      memcpy(compression, s_default_ld_compression, sizeof(compression));
1879      parse_compression(params, compression);
25421880
2543      /* warn if there will be no effect */
2544      if (*maxhunk >= header->totalhunks)
2545      {
2546         printf("Warning: chomp will have no effect\n");
2547         *maxhunk = header->totalhunks;
2548      }
2549   }
1881      // process numprocessors
1882      parse_numprocessors(params);
25501883
2551   /* check for atari */
2552   if (strcmp(name, "atari") == 0)
2553   {
2554      UINT32 sectors[4];
2555      UINT8 *data;
2556      int i, maxdiff;
1884      // print some info
1885      astring tempstr;
1886      printf("Output CHD:   %s\n", output_chd_str->cstr());
1887      if (output_parent.opened())
1888         printf("Parent CHD:   %s\n", params.find(OPTION_OUTPUT_PARENT)->cstr());
1889      printf("Input file:   %s\n", input_file_str->cstr());
1890      if (input_start != 0 && input_end != aviinfo->video_numsamples)
1891         printf("Input start:  %s\n", big_int_string(tempstr, input_start));
1892      printf("Input length: %s (%02d:%02d:%02d)\n", big_int_string(tempstr, input_end - input_start),
1893            UINT32((UINT64(input_end - input_start) * 1000000 / info.fps_times_1million / 60 / 60)),
1894            UINT32(((UINT64(input_end - input_start) * 1000000 / info.fps_times_1million / 60) % 60)),
1895            UINT32(((UINT64(input_end - input_start) * 1000000 / info.fps_times_1million) % 60)));
1896      printf("Frame rate:   %d.%06d\n", info.fps_times_1million / 1000000, info.fps_times_1million % 1000000);
1897      printf("Frame size:   %d x %d %s\n", info.width, info.height * (info.interlaced ? 2 : 1), info.interlaced ? "interlaced" : "non-interlaced");
1898      printf("Audio:        %d channels at %d Hz\n", info.channels, info.rate);
1899      printf("Compression:  %s\n", compression_string(tempstr, compression));
1900      printf("Hunk size:    %s\n", big_int_string(tempstr, hunk_size));
1901      printf("Logical size: %s\n", big_int_string(tempstr, UINT64(input_end - input_start) * hunk_size));
1902
1903      // create the new CHD
1904      chd_avi_compressor chd(*input_file, info, input_start, input_end);
25571905      chd_error err;
1906      if (output_parent.opened())
1907         err = chd.create(*output_chd_str, UINT64(input_end - input_start) * hunk_size, hunk_size, compression, output_parent);
1908      else
1909         err = chd.create(*output_chd_str, UINT64(input_end - input_start) * hunk_size, hunk_size, info.bytes_per_frame, compression);
1910      if (err != CHDERR_NONE)
1911         report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err));
25581912
2559      /* read the second sector */
2560      err = chd_read(chd, 0x200 / header->hunkbytes, temp);
1913      // write the core A/V metadata
1914      astring metadata;
1915      metadata.format(AV_METADATA_FORMAT, info.fps_times_1million / 1000000, info.fps_times_1million % 1000000, info.width, info.height, info.interlaced, info.channels, info.rate);
1916      err = chd.write_metadata(AV_METADATA_TAG, 0, metadata);
25611917      if (err != CHDERR_NONE)
2562      {
2563         fprintf(stderr, "Error reading sector 1\n");
2564         goto cleanup;
2565      }
2566      data = &temp[0x200 % header->hunkbytes];
1918         report_error(1, "Error adding AV metadata: %s\n", chd_file::error_string(err));
25671919
2568      /* look for the signature */
2569      if (data[0] != 0x0d || data[1] != 0xf0 || data[2] != 0xed || data[3] != 0xfe)
2570         goto cleanup;
2571
2572      /* loop over 4 partitions and compute the number of sectors in each */
2573      for (i = 0; i < 4; i++)
2574         sectors[i] = data[i*4+0x40] | (data[i*4+0x41] << 8) | (data[i*4+0x42] << 16) | (data[i*4+0x43] << 24);
2575      maxdiff = sectors[2] - sectors[1];
2576      if (sectors[3] - sectors[2] > maxdiff)
2577         maxdiff = sectors[3] - sectors[2];
2578      if (sectors[0] != 8)
2579         goto cleanup;
2580
2581      /* the maximum hunk is the end of the fourth copy of the data */
2582      *maxhunk = (sectors[3] + maxdiff + sectors_per_hunk - 1) / sectors_per_hunk;
2583      printf("Maximum hunk: %d\n", *maxhunk);
2584
2585      /* warn if there will be no effect */
2586      if (*maxhunk >= header->totalhunks)
1920      // create the compressor and then run it generically
1921      compress_common(chd);
1922     
1923      // write the final LD metadata
1924      if (info.height == 524/2 || info.height == 624/2)
25871925      {
2588         fprintf(stderr, "Warning: chomp will have no effect\n");
2589         *maxhunk = header->totalhunks;
1926         err = chd.write_metadata(AV_LD_METADATA_TAG, 0, chd.ldframedata());
1927         if (err != CHDERR_NONE)
1928            report_error(1, "Error adding AVLD metadata: %s\n", chd_file::error_string(err));
25901929      }
25911930   }
2592
2593   /* if we fall through, there was no error */
2594   err = CHDERR_NONE;
2595
2596cleanup:
2597   if (temp != NULL)
2598      free(temp);
2599   if (err == CHDERR_INVALID_DATA)
2600      fprintf(stderr, "Error: unable to identify file or compute chomping size.\n");
2601   return err;
1931   catch (...)
1932   {
1933      // delete the output file
1934      astring *output_chd_str = params.find(OPTION_OUTPUT);
1935      if (output_chd_str != NULL)
1936         osd_rmfile(*output_chd_str);
1937      throw;
1938   }
26021939}
2603#endif
26041940
26051941
2606/*-------------------------------------------------
2607    do_merge_update_chomp - merge a parent and its
2608    child together (also works for update & chomp)
2609-------------------------------------------------*/
1942//-------------------------------------------------
1943//  do_copy - create a new CHD with data from
1944//  another CHD
1945//-------------------------------------------------
26101946
2611static int do_merge_update_chomp(int argc, char *argv[], int param)
1947static void do_copy(parameters_t &params)
26121948{
2613   const char *parentfile, *inputfile, *outputfile;
2614   const chd_header *inputheader;
2615   chd_file *parentchd = NULL;
2616   chd_file *outputchd = NULL;
2617   chd_file *inputchd = NULL;
2618   UINT32 maxhunk = ~0;
2619   chd_error err;
2620
2621   /* require 4-5 args total */
2622   if (param == OPERATION_UPDATE && argc != 4)
2623      return usage();
2624   if ((param == OPERATION_MERGE || param == OPERATION_CHOMP) && argc != 5)
2625      return usage();
2626
2627   /* extract the data */
2628   if (param == OPERATION_MERGE)
1949   // catch errors so we can close & delete the output file
1950   try
26291951   {
2630      parentfile = argv[2];
2631      inputfile = argv[3];
2632      outputfile = argv[4];
2633   }
2634   else
2635   {
2636      parentfile = NULL;
2637      inputfile = argv[2];
2638      outputfile = argv[3];
2639      if (param == OPERATION_CHOMP)
2640         maxhunk = atoi(argv[4]);
2641   }
1952      // parse out input files
1953      chd_file input_parent_chd;
1954      chd_file input_chd;
1955      parse_input_chd_parameters(params, input_chd, input_parent_chd);
26421956
2643   /* print some info */
2644   if (parentfile != NULL)
2645   {
2646      printf("Parent file:  %s\n", parentfile);
2647      printf("Diff file:    %s\n", inputfile);
2648   }
2649   else
2650      printf("Input file:   %s\n", inputfile);
2651   printf("Output file:  %s\n", outputfile);
2652   if (param == OPERATION_CHOMP)
2653      printf("Maximum hunk: %d\n", maxhunk);
1957      // parse out input start/end
1958      UINT64 input_start;
1959      UINT64 input_end;
1960      parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end);
26541961
2655   /* open the parent CHD */
2656   if (parentfile != NULL)
2657   {
2658      err = chd_open(parentfile, CHD_OPEN_READ, NULL, &parentchd);
2659      if (err != CHDERR_NONE)
1962      // process output CHD
1963      chd_file output_parent;
1964      astring *output_chd_str = parse_output_chd_parameters(params, output_parent);
1965     
1966      // process hunk size
1967      UINT32 hunk_size = input_chd.hunk_bytes();
1968      parse_hunk_size(params, 1, hunk_size);
1969      if (hunk_size % input_chd.hunk_bytes() != 0 && input_chd.hunk_bytes() % hunk_size != 0)
1970         report_error(1, "Hunk size is not an even multiple or divisor of input hunk size");
1971     
1972      // process compression; we default to our current preferences using metadata to pick the type
1973      chd_codec_type compression[4];
26601974      {
2661         fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, chd_error_string(err));
2662         goto cleanup;
1975         dynamic_buffer metadata;
1976         if (input_chd.read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) == CHDERR_NONE)
1977            memcpy(compression, s_default_hd_compression, sizeof(compression));
1978         else if (input_chd.read_metadata(AV_METADATA_TAG, 0, metadata) == CHDERR_NONE)
1979            memcpy(compression, s_default_ld_compression, sizeof(compression));
1980         else if (input_chd.read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
1981                input_chd.read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
1982                input_chd.read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE)
1983            memcpy(compression, s_default_cd_compression, sizeof(compression));
1984         else
1985            memcpy(compression, s_default_raw_compression, sizeof(compression));
26631986      }
2664   }
1987      parse_compression(params, compression);
26651988
2666   /* open the diff CHD */
2667   err = chd_open(inputfile, CHD_OPEN_READ, parentchd, &inputchd);
2668   if (err != CHDERR_NONE)
2669   {
2670      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
2671      goto cleanup;
2672   }
2673   inputheader = chd_get_header(inputchd);
1989      // process numprocessors
1990      parse_numprocessors(params);
26741991
2675#if ENABLE_CUSTOM_CHOMP
2676   /* if we're chomping with a auto parameter, now is the time to figure it out */
2677   if (param == OPERATION_CHOMP && maxhunk == 0)
2678      if (handle_custom_chomp(argv[4], inputchd, &maxhunk) != CHDERR_NONE)
2679         return 1;
2680#endif
1992      // print some info
1993      astring tempstr;
1994      printf("Output CHD:   %s\n", output_chd_str->cstr());
1995      if (output_parent.opened())
1996         printf("Parent CHD:   %s\n", params.find(OPTION_OUTPUT_PARENT)->cstr());
1997      printf("Input CHD:    %s\n", params.find(OPTION_INPUT)->cstr());
1998      if (input_start != 0 || input_end != input_chd.logical_bytes())
1999      {
2000         printf("Input start:  %s\n", big_int_string(tempstr, input_start));
2001         printf("Input length: %s\n", big_int_string(tempstr, input_end - input_start));
2002      }
2003      printf("Compression:  %s\n", compression_string(tempstr, compression));
2004      printf("Hunk size:    %s\n", big_int_string(tempstr, hunk_size));
2005      printf("Logical size: %s\n", big_int_string(tempstr, input_end - input_start));
26812006
2682   /* create the new merged CHD */
2683   err = chd_create(outputfile, inputheader->logicalbytes, inputheader->hunkbytes, inputheader->compression, NULL);
2684   if (err != CHDERR_NONE)
2685   {
2686      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
2687      goto cleanup;
2688   }
2007      // create the new CHD
2008      chd_chdfile_compressor chd(input_chd, input_start, input_end);
2009      chd_error err;
2010      if (output_parent.opened())
2011         err = chd.create(*output_chd_str, input_end - input_start, hunk_size, compression, output_parent);
2012      else
2013         err = chd.create(*output_chd_str, input_end - input_start, hunk_size, input_chd.unit_bytes(), compression);
2014      if (err != CHDERR_NONE)
2015         report_error(1, "Error creating CHD file (%s): %s", output_chd_str->cstr(), chd_file::error_string(err));
26892016
2690   /* open the new CHD */
2691   err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &outputchd);
2692   if (err != CHDERR_NONE)
2693   {
2694      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
2695      goto cleanup;
2017      // clone all the metadata, upgrading where appropriate
2018      dynamic_buffer metadata;
2019      chd_metadata_tag metatag;
2020      UINT8 metaflags;
2021      UINT32 index = 0;
2022      bool redo_cd = false;
2023      for (err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags); err == CHDERR_NONE; err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags))
2024      {
2025         // if this is an old CD-CHD tag, note that we want to re-do it
2026         if (metatag == CDROM_OLD_METADATA_TAG || metatag == CDROM_TRACK_METADATA_TAG)
2027         {
2028            redo_cd = true;
2029            continue;
2030         }
2031         
2032         // otherwise, clone it
2033         err = chd.write_metadata(metatag, CHDMETAINDEX_APPEND, metadata);
2034         if (err != CHDERR_NONE)
2035            report_error(1, "Error writing cloned metadata: %s", chd_file::error_string(err));
2036      }
2037     
2038      // if we need to re-do the CD metadata, do it now
2039      if (redo_cd)
2040      {
2041         cdrom_file *cdrom = cdrom_open(&input_chd);
2042         if (cdrom == NULL)
2043            report_error(1, "Error upgrading CD metadata");
2044         const cdrom_toc *toc = cdrom_get_toc(cdrom);
2045         err = cdrom_write_metadata(&chd, toc);
2046         if (err != CHDERR_NONE)
2047            report_error(1, "Error writing upgraded CD metadata: %s", chd_file::error_string(err));
2048      }
2049     
2050      // compress it generically
2051      compress_common(chd);
26962052   }
2697
2698   /* clone the metadata from the input file (which should have inherited from the parent) */
2699   err = chdman_clone_metadata(inputchd, outputchd);
2700   if (err != CHDERR_NONE)
2053   catch (...)
27012054   {
2702      fprintf(stderr, "Error cloning metadata: %s\n", chd_error_string(err));
2703      goto cleanup;
2055      // delete the output file
2056      astring *output_chd_str = params.find(OPTION_OUTPUT);
2057      if (output_chd_str != NULL)
2058         osd_rmfile(*output_chd_str);
2059      throw;
27042060   }
2705
2706   /* do the compression; our interface will route reads for us */
2707   err = chdman_compress_chd(outputchd, inputchd, (param == OPERATION_CHOMP) ? (maxhunk + 1) : 0);
2708   if (err != CHDERR_NONE)
2709      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
2710
2711cleanup:
2712   /* close everything down */
2713   if (outputchd != NULL)
2714      chd_close(outputchd);
2715   if (inputchd != NULL)
2716      chd_close(inputchd);
2717   if (parentchd != NULL)
2718      chd_close(parentchd);
2719   if (err != CHDERR_NONE)
2720      osd_rmfile(outputfile);
2721   return (err != CHDERR_NONE);
27222061}
27232062
27242063
2725/*-------------------------------------------------
2726    do_diff - generate a difference between two
2727    CHD files
2728-------------------------------------------------*/
2064//-------------------------------------------------
2065//  do_extract_raw - extract a raw file from a
2066//  CHD image
2067//-------------------------------------------------
27292068
2730static int do_diff(int argc, char *argv[], int param)
2069static void do_extract_raw(parameters_t &params)
27312070{
2732   const char *parentfile = NULL, *inputfile = NULL, *outputfile = NULL;
2733   chd_file *parentchd = NULL;
2734   chd_file *outputchd = NULL;
2735   chd_file *inputchd = NULL;
2736   chd_error err;
2071   // catch errors so we can close & delete the output file
2072   astring *output_file_str = params.find(OPTION_OUTPUT);
2073   core_file *output_file = NULL;
2074   try
2075   {
2076      // parse out input files
2077      chd_file input_parent_chd;
2078      chd_file input_chd;
2079      parse_input_chd_parameters(params, input_chd, input_parent_chd);
27372080
2738   /* require 5 args total */
2739   if (argc != 5)
2740      return usage();
2081      // parse out input start/end
2082      UINT64 input_start;
2083      UINT64 input_end;
2084      parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end);
2085     
2086      // process output file
2087      if (output_file_str != NULL)
2088      {
2089         file_error filerr = core_fopen(*output_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &output_file);
2090         if (filerr != FILERR_NONE)
2091            report_error(1, "Unable to open file (%s)", output_file_str->cstr());
2092      }
27412093
2742   /* extract the data */
2743   parentfile = argv[2];
2744   inputfile = argv[3];
2745   outputfile = argv[4];
2094      // print some info
2095      astring tempstr;
2096      printf("Output File:  %s\n", output_file_str->cstr());
2097      printf("Input CHD:    %s\n", params.find(OPTION_INPUT)->cstr());
2098      if (input_start != 0 || input_end != input_chd.logical_bytes())
2099      {
2100         printf("Input start:  %s\n", big_int_string(tempstr, input_start));
2101         printf("Input length: %s\n", big_int_string(tempstr, input_end - input_start));
2102      }
27462103
2747   /* print some info */
2748   printf("Parent file:  %s\n", parentfile);
2749   printf("Input file:   %s\n", inputfile);
2750   printf("Diff file:    %s\n", outputfile);
2104      // copy all data
2105      dynamic_buffer buffer((TEMP_BUFFER_SIZE / input_chd.hunk_bytes()) * input_chd.hunk_bytes());
2106      for (UINT64 offset = input_start; offset < input_end; )
2107      {
2108         progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(offset - input_start) / double(input_end - input_start));
27512109
2752   /* open the soon-to-be-parent CHD */
2753   err = chd_open(parentfile, CHD_OPEN_READ, NULL, &parentchd);
2754   if (err != CHDERR_NONE)
2755   {
2756      fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, chd_error_string(err));
2757      goto cleanup;
2758   }
2110         // determine how much to read
2111         UINT32 bytes_to_read = MIN(buffer.count(), input_end - offset);
2112         chd_error err = input_chd.read_bytes(offset, buffer, bytes_to_read);
2113         if (err != CHDERR_NONE)
2114            report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->cstr(), chd_file::error_string(err));
2115         
2116         // write to the output
2117         UINT32 count = core_fwrite(output_file, buffer, bytes_to_read);
2118         if (count != bytes_to_read)
2119            report_error(1, "Error writing to file; check disk space (%s)", output_file_str->cstr());
27592120
2760   /* open the input CHD */
2761   err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd);
2762   if (err != CHDERR_NONE)
2763   {
2764      fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
2765      goto cleanup;
2121         // advance
2122         offset += bytes_to_read;
2123      }
2124     
2125      // finish up
2126      core_fclose(output_file);
2127      printf("Extraction complete                                    \n");
27662128   }
2767
2768   /* create the new CHD as a diff against the parent */
2769   err = chd_create(outputfile, 0, 0, chd_get_header(parentchd)->compression, parentchd);
2770   if (err != CHDERR_NONE)
2129   catch (...)
27712130   {
2772      fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err));
2773      goto cleanup;
2131      // delete the output file
2132      if (output_file != NULL)
2133         core_fclose(output_file);
2134      osd_rmfile(*output_file_str);
2135      throw;
27742136   }
2775
2776   /* open the new CHD */
2777   err = chd_open(outputfile, CHD_OPEN_READWRITE, parentchd, &outputchd);
2778   if (err != CHDERR_NONE)
2779   {
2780      fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err));
2781      goto cleanup;
2782   }
2783
2784   /* do the compression; our interface will route reads for us */
2785   err = chdman_compress_chd(outputchd, inputchd, 0);
2786   if (err != CHDERR_NONE)
2787      fprintf(stderr, "Error during compression: %s\n", chd_error_string(err));
2788
2789cleanup:
2790   /* close everything down */
2791   if (outputchd != NULL)
2792      chd_close(outputchd);
2793   if (inputchd != NULL)
2794      chd_close(inputchd);
2795   if (parentchd != NULL)
2796      chd_close(parentchd);
2797   if (err != CHDERR_NONE)
2798      osd_rmfile(outputfile);
2799   return (err != CHDERR_NONE);
28002137}
28012138
28022139
2803/*-------------------------------------------------
2804    do_setchs - change the CHS values on a hard
2805    disk image
2806-------------------------------------------------*/
2140//-------------------------------------------------
2141//  do_extract_cd - extract a CD file from a
2142//  CHD image
2143//-------------------------------------------------
28072144
2808static int do_setchs(int argc, char *argv[], int param)
2145static void do_extract_cd(parameters_t &params)
28092146{
2810   int oldcyls, oldhds, oldsecs, oldsecsize;
2811   UINT8 was_readonly = FALSE;
2812   UINT64 old_logicalbytes;
2813   const char *inoutfile;
2814   chd_file *chd = NULL;
2815   int cyls, hds, secs;
2816   char metadata[256];
2817   chd_header header;
2818   chd_error err;
2819
2820   /* require 6 args total */
2821   if (argc != 6)
2822      return usage();
2823
2824   /* extract the data */
2825   inoutfile = argv[2];
2826   cyls = atoi(argv[3]);
2827   hds = atoi(argv[4]);
2828   secs = atoi(argv[5]);
2829
2830   /* print some info */
2831   printf("Input file:   %s\n", inoutfile);
2832   printf("Cylinders:    %d\n", cyls);
2833   printf("Heads:        %d\n", hds);
2834   printf("Sectors:      %d\n", secs);
2835
2836   /* open the file read-only and get the header */
2837   err = chd_open(inoutfile, CHD_OPEN_READ, NULL, &chd);
2838   if (err != CHDERR_NONE)
2147   // catch errors so we can close & delete the output file
2148   astring *output_file_str = params.find(OPTION_OUTPUT);
2149   astring *output_bin_file_str = params.find(OPTION_OUTPUT_BIN);
2150   core_file *output_bin_file = NULL;
2151   core_file *output_toc_file = NULL;
2152   try
28392153   {
2840      fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, chd_error_string(err));
2841      goto cleanup;
2842   }
2843   header = *chd_get_header(chd);
2844   chd_close(chd);
2845   chd = NULL;
2154      // parse out input files
2155      chd_file input_parent_chd;
2156      chd_file input_chd;
2157      parse_input_chd_parameters(params, input_chd, input_parent_chd);
28462158
2847   /* if the drive is not writeable, note that, and make it so */
2848   if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
2849   {
2850      was_readonly = TRUE;
2851      header.flags |= CHDFLAGS_IS_WRITEABLE;
2159      // further process input file
2160      cdrom_file *cdrom = cdrom_open(&input_chd);
2161      if (cdrom == NULL)
2162         report_error(1, "Unable to recognize CHD file as a CD");
2163      const cdrom_toc *toc = cdrom_get_toc(cdrom);
2164     
2165      // process output file
2166      if (output_file_str != NULL)
2167      {
2168         file_error filerr = core_fopen(*output_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, &output_toc_file);
2169         if (filerr != FILERR_NONE)
2170            report_error(1, "Unable to open file (%s)", output_file_str->cstr());
2171      }
2172      bool cuemode = (output_file_str->find(".cue") != -1);
28522173
2853      /* write the new header */
2854      err = chd_set_header(inoutfile, &header);
2855      if (err != CHDERR_NONE)
2174      // process output BIN file
2175      astring default_name(*output_file_str);
2176      int chop = default_name.rchr(0, '.');
2177      if (chop != -1)
2178         default_name.substr(0, chop);
2179      default_name.cat(".bin");
2180      if (output_bin_file_str == NULL)
2181         output_bin_file_str = &default_name;
28562182      {
2857         fprintf(stderr, "Error making CHD file writeable: %s\n", chd_error_string(err));
2858         goto cleanup;
2183         file_error filerr = core_fopen(*output_bin_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &output_bin_file);
2184         if (filerr != FILERR_NONE)
2185            report_error(1, "Unable to open file (%s)", output_bin_file_str->cstr());
28592186      }
2860   }
28612187
2862   /* open the file read/write */
2863   err = chd_open(inoutfile, CHD_OPEN_READWRITE, NULL, &chd);
2864   if (err != CHDERR_NONE)
2865   {
2866      fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, chd_error_string(err));
2867      goto cleanup;
2868   }
2188      // print some info
2189      astring tempstr;
2190      printf("Output TOC:   %s\n", output_file_str->cstr());
2191      printf("Output Data:  %s\n", output_bin_file_str->cstr());
2192      printf("Input CHD:    %s\n", params.find(OPTION_INPUT)->cstr());
28692193
2870   /* get the hard disk metadata */
2871   err = chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
2872   if (err != CHDERR_NONE || sscanf(metadata, HARD_DISK_METADATA_FORMAT, &oldcyls, &oldhds, &oldsecs, &oldsecsize) != 4)
2873   {
2874      fprintf(stderr, "CHD file '%s' is not a hard disk!\n", inoutfile);
2875      err = CHDERR_INVALID_FILE;
2876      goto cleanup;
2877   }
2194      // determine total frames
2195      UINT64 total_bytes = 0;
2196      for (int tracknum = 0; tracknum < toc->numtrks; tracknum++)
2197         total_bytes += toc->tracks[tracknum].frames * (toc->tracks[tracknum].datasize + toc->tracks[tracknum].subsize);
2198     
2199      // iterate over tracks and copy all data
2200      UINT64 outputoffs = 0;
2201      UINT32 discoffs = 0;
2202      dynamic_buffer buffer;
2203      for (int tracknum = 0; tracknum < toc->numtrks; tracknum++)
2204      {
2205         // output the metadata about the track to the TOC file
2206         const cdrom_track_info &trackinfo = toc->tracks[tracknum];
2207         output_track_metadata(cuemode, output_toc_file, tracknum, trackinfo, *output_bin_file_str, discoffs, outputoffs);
28782208
2879   /* write our own */
2880   sprintf(metadata, HARD_DISK_METADATA_FORMAT, cyls, hds, secs, oldsecsize);
2881   err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
2882   if (err != CHDERR_NONE)
2883   {
2884      fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
2885      goto cleanup;
2886   }
2209         // resize the buffer for the track
2210         UINT32 output_frame_size = trackinfo.datasize + ((trackinfo.subtype != CD_SUB_NONE) ? trackinfo.subsize : 0);
2211         buffer.resize((TEMP_BUFFER_SIZE / output_frame_size) * output_frame_size);
2212         
2213         // now read and output the actual data
2214         UINT32 bufferoffs = 0;
2215         for (int frame = 0; frame < trackinfo.frames; frame++)
2216         {
2217            progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(outputoffs) / double(total_bytes));
28872218
2888   /* get the header and compute the new logical size */
2889   header = *chd_get_header(chd);
2890   old_logicalbytes = header.logicalbytes;
2891   header.logicalbytes = (UINT64)cyls * (UINT64)hds * (UINT64)secs * (UINT64)oldsecsize;
2219            // read the data
2220            cdrom_read_data(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype);
28922221
2893   /* close the file */
2894   chd_close(chd);
2895   chd = NULL;
2222            // for CDRWin, audio tracks must be reversed
2223            if (cuemode && (trackinfo.trktype == CD_TRACK_AUDIO))
2224               for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2)
2225               {
2226                  UINT8 swaptemp = buffer[bufferoffs + swapindex];
2227                  buffer[bufferoffs + swapindex] = buffer[bufferoffs + swapindex + 1];
2228                  buffer[bufferoffs + swapindex + 1] = swaptemp;
2229               }
2230            bufferoffs += trackinfo.datasize;
2231            discoffs++;
28962232
2897   /* restore the read-only state */
2898   if (was_readonly)
2899      header.flags &= ~CHDFLAGS_IS_WRITEABLE;
2233            // read the subcode data
2234            if (trackinfo.subtype != CD_SUB_NONE)
2235            {
2236               cdrom_read_subcode(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs]);
2237               bufferoffs += trackinfo.subsize;
2238            }
29002239
2901   /* set the new logical size */
2902   if (header.logicalbytes != old_logicalbytes || was_readonly)
2903   {
2904      err = chd_set_header(inoutfile, &header);
2905      if (err != CHDERR_NONE)
2906         fprintf(stderr, "Error writing new header to CHD file: %s\n", chd_error_string(err));
2240            // write it out if we need to
2241            if (bufferoffs == buffer.count() || frame == trackinfo.frames - 1)
2242            {
2243               core_fseek(output_bin_file, outputoffs, SEEK_SET);
2244               UINT32 byteswritten = core_fwrite(output_bin_file, buffer, bufferoffs);
2245               if (byteswritten != bufferoffs)
2246                  report_error(1, "Error writing frame %d to file (%s): %s\n", frame, output_file_str->cstr(), chd_file::error_string(CHDERR_WRITE_ERROR));
2247               outputoffs += bufferoffs;
2248               bufferoffs = 0;
2249            }
2250         }
2251      }
2252     
2253      // finish up
2254      core_fclose(output_bin_file);
2255      core_fclose(output_toc_file);
2256      printf("Extraction complete                                    \n");
29072257   }
2908
2909   /* print a warning if the size is different */
2910   if (header.logicalbytes < old_logicalbytes)
2911      fprintf(stderr, "WARNING: new size is smaller; run chdman -update to reclaim empty space\n");
2912   else if (header.logicalbytes > old_logicalbytes)
2913      fprintf(stderr, "WARNING: new size is larger; run chdman -update to account for new empty space\n");
2914
2915cleanup:
2916   if (chd != NULL)
2917      chd_close(chd);
2918   if (err != CHDERR_NONE && was_readonly)
2258   catch (...)
29192259   {
2920      header.flags &= ~CHDFLAGS_IS_WRITEABLE;
2921      chd_set_header(inoutfile, &header);
2260      // delete the output files
2261      if (output_bin_file != NULL)
2262         core_fclose(output_bin_file);
2263      if (output_toc_file != NULL)
2264         core_fclose(output_toc_file);
2265      osd_rmfile(*output_bin_file_str);
2266      osd_rmfile(*output_file_str);
2267      throw;
29222268   }
2923   return (err != CHDERR_NONE);
29242269}
29252270
29262271
2927/*-------------------------------------------------
2928    do_addmeta - add metadata to a CHD from a
2929    file
2930-------------------------------------------------*/
2272//-------------------------------------------------
2273//  do_extract_ld - extract an AVI file from a
2274//  CHD image
2275//-------------------------------------------------
29312276
2932static int do_addmeta(int argc, char *argv[], int param)
2277static void do_extract_ld(parameters_t &params)
29332278{
2934   const char *inoutfile, *srcfile, *tagstring;
2935   UINT8 was_readonly = FALSE;
2936   UINT8 *metadata = NULL;
2937   chd_file *chd = NULL;
2938   chd_header header;
2939   file_error filerr;
2940   UINT32 metalength;
2941   UINT32 metaindex;
2942   UINT32 metatag;
2943   chd_error err;
2944
2945   /* require 5 or 6 args total */
2946   if (argc != 5 && argc != 6)
2947      return usage();
2948
2949   /* extract the data */
2950   inoutfile = argv[2];
2951   tagstring = argv[3];
2952   if (argc == 5)
2279   // catch errors so we can close & delete the output file
2280   astring *output_file_str = params.find(OPTION_OUTPUT);
2281   avi_file *output_file = NULL;
2282   try
29532283   {
2954      metaindex = 0;
2955      srcfile = argv[4];
2956   }
2957   else
2958   {
2959      metaindex = atoi(argv[4]);
2960      srcfile = argv[5];
2961   }
2284      // parse out input files
2285      chd_file input_parent_chd;
2286      chd_file input_chd;
2287      parse_input_chd_parameters(params, input_chd, input_parent_chd);
29622288
2963   /* verify the tag */
2964   if (strlen(tagstring) > 4)
2965   {
2966      fprintf(stderr, "Invalid tag '%s'; must be 4 characters or less\n", tagstring);
2967      return CHDERR_INVALID_PARAMETER;
2968   }
2969   metatag = ((tagstring[0] == 0) ? ' ' : tagstring[0]) << 24;
2970   metatag |= ((tagstring[1] == 0) ? ' ' : tagstring[1]) << 16;
2971   metatag |= ((tagstring[2] == 0) ? ' ' : tagstring[2]) << 8;
2972   metatag |= ((tagstring[3] == 0) ? ' ' : tagstring[3]) << 0;
2289      // read core metadata
2290      astring metadata;
2291      chd_error err = input_chd.read_metadata(AV_METADATA_TAG, 0, metadata);
2292      if (err != CHDERR_NONE)
2293         report_error(1, "Unable to find A/V metadata in the input CHD");
29732294
2974   /* print some info */
2975   printf("Input file:   %s\n", inoutfile);
2976   printf("Tag:          '%c%c%c%c'\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff);
2977   printf("Index:        %d\n", metaindex);
2978   printf("Source file:  %s\n", srcfile);
2295      // parse the metadata
2296      UINT32 fps_times_1million;
2297      UINT32 max_samples_per_frame;
2298      UINT32 frame_bytes;
2299      int width;
2300      int height;
2301      int interlaced;
2302      int channels;
2303      int rate;
2304      {
2305         int fps;
2306         int fpsfrac;
2307         if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
2308            report_error(1, "Improperly formatted A/V metadata found");
2309         fps_times_1million = fps * 1000000 + fpsfrac;
2310      }
2311      int interlace_factor = interlaced ? 2 : 1;
29792312
2980   /* open the file read-only and get the header */
2981   err = chd_open(inoutfile, CHD_OPEN_READ, NULL, &chd);
2982   if (err != CHDERR_NONE)
2983   {
2984      fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, chd_error_string(err));
2985      goto cleanup;
2986   }
2987   header = *chd_get_header(chd);
2988   chd_close(chd);
2989   chd = NULL;
2313      // determine key parameters and validate
2314      max_samples_per_frame = (UINT64(rate) * 1000000 + fps_times_1million - 1) / fps_times_1million;
2315      frame_bytes = avhuff_encoder::raw_data_size(width, height, channels, max_samples_per_frame);
2316      if (frame_bytes != input_chd.hunk_bytes())
2317         report_error(1, "Frame size does not match hunk size for this CHD");
2318     
2319      // parse out input start/end
2320      UINT64 input_start;
2321      UINT64 input_end;
2322      parse_input_start_end(params, input_chd.hunk_count() / interlace_factor, 0, 1, input_start, input_end);
2323      input_start *= interlace_factor;
2324      input_end *= interlace_factor;
29902325
2991   /* if the drive is not writeable, note that, and make it so */
2992   if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
2993   {
2994      was_readonly = TRUE;
2995      header.flags |= CHDFLAGS_IS_WRITEABLE;
2326      // build up the movie info
2327      avi_movie_info info;
2328      info.video_format = FORMAT_YUY2;
2329      info.video_timescale = fps_times_1million / interlace_factor;
2330      info.video_sampletime = 1000000;
2331      info.video_width = width;
2332      info.video_height = height * interlace_factor;
2333      info.video_depth = 16;
2334      info.audio_format = 0;
2335      info.audio_timescale = rate;
2336      info.audio_sampletime = 1;
2337      info.audio_channels = channels;
2338      info.audio_samplebits = 16;
2339      info.audio_samplerate = rate;
29962340
2997      /* write the new header */
2998      err = chd_set_header(inoutfile, &header);
2999      if (err != CHDERR_NONE)
2341      // process output file
2342      if (output_file_str != NULL)
30002343      {
3001         fprintf(stderr, "Error making CHD file writeable: %s\n", chd_error_string(err));
3002         goto cleanup;
2344         avi_error avierr = avi_create(*output_file_str, &info, &output_file);
2345         if (avierr != AVIERR_NONE)
2346            report_error(1, "Unable to open file (%s)", output_file_str->cstr());
30032347      }
3004   }
30052348
3006   /* open the file read/write */
3007   err = chd_open(inoutfile, CHD_OPEN_READWRITE, NULL, &chd);
3008   if (err != CHDERR_NONE)
3009   {
3010      fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, chd_error_string(err));
3011      goto cleanup;
3012   }
2349      // print some info
2350      astring tempstr;
2351      printf("Output File:  %s\n", output_file_str->cstr());
2352      printf("Input CHD:    %s\n", params.find(OPTION_INPUT)->cstr());
2353      if (input_start != 0 || input_end != input_chd.hunk_count())
2354      {
2355         printf("Input start:  %s\n", big_int_string(tempstr, input_start));
2356         printf("Input length: %s\n", big_int_string(tempstr, input_end - input_start));
2357      }
30132358
3014   /* attempt to open the source file */
3015   filerr = core_fload(srcfile, (void **)&metadata, &metalength);
3016   if (filerr != FILERR_NONE)
3017   {
3018      fprintf(stderr, "Error opening source file '%s'\n", srcfile);
3019      err = CHDERR_FILE_NOT_FOUND;
3020      goto cleanup;
3021   }
3022
3023   /* if it's text, strip any trailing Ctrl-Z and CR/LF and add a trailing NULL */
3024   if (param)
3025   {
3026      metadata = (UINT8 *)realloc(metadata, metalength + 1);
3027      if (metadata == NULL)
2359      // create the codec configuration
2360      avhuff_decompress_config avconfig;
2361      dynamic_array<INT16> audio_data[16];
2362      UINT32 actsamples;
2363      avconfig.maxsamples = max_samples_per_frame;
2364      avconfig.actsamples = &actsamples;
2365      for (int chnum = 0; chnum < ARRAY_LENGTH(audio_data); chnum++)
30282366      {
3029         fprintf(stderr, "Out of memory preparing metadata\n");
3030         err = CHDERR_OUT_OF_MEMORY;
3031         goto cleanup;
2367         audio_data[chnum].resize(max_samples_per_frame);
2368         avconfig.audio[chnum] = audio_data[chnum];
30322369      }
3033      metadata[metalength++] = 0;
3034      while (metalength > 0 && (metadata[metalength - 2] == 0x0a || metadata[metalength - 2] == 0x0d || metadata[metalength - 2] == 0x1a))
3035         metadata[--metalength] = 0;
3036   }
2370     
2371      // iterate over frames
2372      bitmap_yuy16 fullbitmap(width, height * interlace_factor);
2373      for (int framenum = input_start; framenum < input_end; framenum++)
2374      {
2375         progress(framenum == 0, "Extracting, %.1f%% complete...  \r", 100.0 * double(framenum - input_start) / double(input_end - input_start));
30372376
3038   /* write the new metadata */
3039   err = chd_set_metadata(chd, metatag, metaindex, metadata, metalength, CHD_MDFLAGS_CHECKSUM);
3040   if (err != CHDERR_NONE)
3041   {
3042      fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
3043      goto cleanup;
3044   }
3045   header = *chd_get_header(chd);
2377         // set up the fake bitmap for this frame
2378         avconfig.video.wrap(&fullbitmap.pix(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / interlace_factor, fullbitmap.rowpixels() * interlace_factor);
2379         input_chd.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig);
2380         
2381         // read the hunk into the buffers
2382         chd_error err = input_chd.read_hunk(framenum, NULL);
2383         if (err != CHDERR_NONE)
2384            report_error(1, "Error reading hunk %d from CHD file (%s): %s\n", framenum, params.find(OPTION_INPUT)->cstr(), chd_file::error_string(err));
30462385
3047   /* close the file */
3048   chd_close(chd);
3049   chd = NULL;
2386         // write audio
2387         for (int chnum = 0; chnum < channels; chnum++)
2388         {
2389            avi_error avierr = avi_append_sound_samples(output_file, chnum, avconfig.audio[chnum], actsamples, 0);
2390            if (avierr != AVIERR_NONE)
2391               report_error(1, "Error writing samples for hunk %d to file (%s): %s\n", framenum, output_file_str->cstr(), avi_error_string(avierr));
2392         }
30502393
3051   /* restore the read-only state */
3052   if (was_readonly)
3053   {
3054      header.flags &= ~CHDFLAGS_IS_WRITEABLE;
3055      err = chd_set_header(inoutfile, &header);
3056      if (err != CHDERR_NONE)
3057         fprintf(stderr, "Error writing new header to CHD file: %s\n", chd_error_string(err));
3058   }
3059   if (err == CHDERR_NONE)
3060      printf("Metadata added successfully as %s\n", param ? "text" : "binary");
2394         // write video
2395         if (framenum % interlace_factor == interlace_factor - 1)
2396         {
2397            avi_error avierr = avi_append_video_frame(output_file, fullbitmap);
2398            if (avierr != AVIERR_NONE)
2399               report_error(1, "Error writing video for hunk %d to file (%s): %s\n", framenum, output_file_str->cstr(), avi_error_string(avierr));
2400         }
2401      }
30612402
3062cleanup:
3063   if (metadata != NULL)
3064      osd_free(metadata);
3065   if (chd != NULL)
3066      chd_close(chd);
3067   if (err != CHDERR_NONE && was_readonly)
2403      // close and return
2404      avi_close(output_file);
2405      printf("Extraction complete                                    \n");
2406   }
2407   catch (...)
30682408   {
3069      header.flags &= ~CHDFLAGS_IS_WRITEABLE;
3070      chd_set_header(inoutfile, &header);
2409      // delete the output file
2410      if (output_file != NULL)
2411         avi_close(output_file);
2412      osd_rmfile(*output_file_str);
2413      throw;
30712414   }
3072   return (err != CHDERR_NONE);
30732415}
30742416
30752417
3076/*-------------------------------------------------
3077    chdman_compress_file - compress a regular
3078    file via the compression interfaces
3079-------------------------------------------------*/
2418//-------------------------------------------------
2419//  do_add_metadata - add metadata to a CHD from a
2420//  file
2421//-------------------------------------------------
30802422
3081static chd_error chdman_compress_file(chd_file *chd, const char *rawfile, UINT32 offset)
2423static void do_add_metadata(parameters_t &params)
30822424{
3083   core_file *sourcefile;
3084   const chd_header *header;
3085   UINT64 sourceoffset = 0;
3086   UINT8 *cache = NULL;
3087   double ratio = 1.0;
3088   file_error filerr;
3089   chd_error err;
3090   int hunknum;
2425   // parse out input files
2426   chd_file input_parent_chd;
2427   chd_file input_chd;
2428   parse_input_chd_parameters(params, input_chd, input_parent_chd, true);
30912429
3092   /* open the raw file */
3093   filerr = core_fopen(rawfile, OPEN_FLAG_READ, &sourcefile);
3094   if (filerr != FILERR_NONE)
2430   // process tag
2431   chd_metadata_tag tag = CHD_MAKE_TAG('?','?','?','?');
2432   astring *tag_str = params.find(OPTION_TAG);
2433   if (tag_str != NULL)
30952434   {
3096      err = CHDERR_FILE_NOT_FOUND;
3097      goto cleanup;
2435      tag_str->cat("    ");
2436      tag = CHD_MAKE_TAG((*tag_str)[0], (*tag_str)[1], (*tag_str)[2], (*tag_str)[3]);
30982437   }
3099
3100   /* get the header */
3101   header = chd_get_header(chd);
3102   cache = (UINT8 *)malloc(header->hunkbytes);
3103   if (cache == NULL)
2438   
2439   // process index
2440   UINT32 index = 0;
2441   astring *index_str = params.find(OPTION_INDEX);
2442   if (index_str != NULL)
2443      index = atoi(*index_str);
2444   
2445   // process text input
2446   astring *text_str = params.find(OPTION_VALUE_TEXT);
2447   astring text;
2448   if (text_str != NULL)
31042449   {
3105      err = CHDERR_OUT_OF_MEMORY;
3106      goto cleanup;
2450      text = *text_str;
2451      if (text[0] == '"' && text[text.len() - 1] == '"')
2452         text.substr(1, text.len() - 2);
31072453   }
3108
3109   /* begin compressing */
3110   err = chd_compress_begin(chd);
3111   if (err != CHDERR_NONE)
3112      goto cleanup;
3113
3114   /* loop over source hunks until we run out */
3115   for (hunknum = 0; hunknum < header->totalhunks; hunknum++)
2454   
2455   // process file input
2456   astring *file_str = params.find(OPTION_VALUE_FILE);
2457   dynamic_buffer file;
2458   if (file_str != NULL)
31162459   {
3117      UINT32 bytesread;
3118
3119      /* progress */
3120      progress(hunknum == 0, "Compressing hunk %d/%d... (ratio=%d%%)  \r", hunknum, header->totalhunks, (int)(100.0 * ratio));
3121
3122      /* read the data */
3123      core_fseek(sourcefile, sourceoffset + offset, SEEK_SET);
3124      bytesread = core_fread(sourcefile, cache, header->hunkbytes);
3125      if (bytesread < header->hunkbytes)
3126         memset(&cache[bytesread], 0, header->hunkbytes - bytesread);
3127
3128      /* append the data */
3129      err = chd_compress_hunk(chd, cache, &ratio);
3130      if (err != CHDERR_NONE)
3131         goto cleanup;
3132
3133      /* prepare for the next hunk */
3134      sourceoffset += header->hunkbytes;
2460      file_error filerr = core_fload(*file_str, file);
2461      if (filerr != FILERR_NONE)
2462         report_error(1, "Error reading metadata file (%s)", file_str->cstr());
31352463   }
2464   
2465   // make sure we have one or the other
2466   if (text_str == NULL && file_str == NULL)
2467      report_error(1, "Error: missing either --valuetext/-vt or --valuefile/-vf parameters");
2468   if (text_str != NULL && file_str != NULL)
2469      report_error(1, "Error: both --valuetext/-vt or --valuefile/-vf parameters specified; only one permitted");
2470   
2471   // process no checksum
2472   UINT8 flags = CHD_MDFLAGS_CHECKSUM;
2473   if (params.find(OPTION_NO_CHECKSUM) != NULL)
2474      flags &= ~CHD_MDFLAGS_CHECKSUM;
2475   
2476   // print some info
2477   astring tempstr;
2478   printf("Input file:   %s\n", params.find(OPTION_INPUT)->cstr());
2479   printf("Tag:          %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff);
2480   printf("Index:        %d\n", index);
2481   if (text_str != NULL)
2482      printf("Text:         %s\n", text.cstr());
2483   else
2484      printf("Data:         %s (%d bytes)\n", file_str->cstr(), file.count());
31362485
3137   /* finish compression */
3138   err = chd_compress_finish(chd, TRUE);
2486   // write the metadata
2487   chd_error err;
2488   if (text_str != NULL)
2489      err = input_chd.write_metadata(tag, index, text, flags);
2490   else
2491      err = input_chd.write_metadata(tag, index, file, flags);
31392492   if (err != CHDERR_NONE)
3140      goto cleanup;
3141
3142   /* final progress update */
3143   progress(TRUE, "Compression complete ... final ratio = %d%%            \n", (int)(100.0 * ratio));
3144
3145cleanup:
3146   if (sourcefile != NULL)
3147      core_fclose(sourcefile);
3148   if (cache != NULL)
3149      free(cache);
3150   return err;
2493      report_error(1, "Error adding metadata: %s", chd_file::error_string(err));
2494   else
2495      printf("Metadata added\n");
31512496}
31522497
31532498
3154/*-------------------------------------------------
3155    chdman_compress_chd - (re)compress a CHD file
3156    via the compression interfaces
3157-------------------------------------------------*/
2499//-------------------------------------------------
2500//  do_del_metadata - remove metadata from a CHD
2501//-------------------------------------------------
31582502
3159static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 totalhunks)
2503static void do_del_metadata(parameters_t &params)
31602504{
3161   const chd_header *source_header;
3162   const chd_header *header;
3163   UINT8 *source_cache = NULL;
3164   UINT64 source_offset = 0;
3165   UINT32 source_bytes = 0;
3166   UINT8 *cache = NULL;
3167   double ratio = 1.0;
3168   chd_error err, verifyerr;
3169   int hunknum;
2505   // parse out input files
2506   chd_file input_parent_chd;
2507   chd_file input_chd;
2508   parse_input_chd_parameters(params, input_chd, input_parent_chd, true);
31702509
3171   /* get the header */
3172   header = chd_get_header(chd);
3173   cache = (UINT8 *)malloc(header->hunkbytes);
3174   if (cache == NULL)
2510   // process tag
2511   chd_metadata_tag tag = CHD_MAKE_TAG('?','?','?','?');
2512   astring *tag_str = params.find(OPTION_TAG);
2513   if (tag_str != NULL)
31752514   {
3176      err = CHDERR_OUT_OF_MEMORY;
3177      goto cleanup;
2515      tag_str->cat("    ");
2516      tag = CHD_MAKE_TAG((*tag_str)[0], (*tag_str)[1], (*tag_str)[2], (*tag_str)[3]);
31782517   }
2518   
2519   // process index
2520   UINT32 index = 0;
2521   astring *index_str = params.find(OPTION_INDEX);
2522   if (index_str != NULL)
2523      index = atoi(*index_str);
2524   
2525   // print some info
2526   astring tempstr;
2527   printf("Input file:   %s\n", params.find(OPTION_INPUT)->cstr());
2528   printf("Tag:          %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff);
2529   printf("Index:        %d\n", index);
31792530
3180   /* get the source CHD header */
3181   source_header = chd_get_header(source);
3182   source_cache = (UINT8 *)malloc(source_header->hunkbytes);
3183   if (source_cache == NULL)
3184   {
3185      err = CHDERR_OUT_OF_MEMORY;
3186      goto cleanup;
3187   }
3188
3189   /* begin compressing */
3190   err = chd_compress_begin(chd);
2531   // write the metadata
2532   chd_error err = input_chd.delete_metadata(tag, index);
31912533   if (err != CHDERR_NONE)
3192      goto cleanup;
2534      report_error(1, "Error removing metadata: %s", chd_file::error_string(err));
2535   else
2536      printf("Metadata removed\n");
2537}
31932538
3194   /* also begin verifying the source driver */
3195   verifyerr = chd_verify_begin(source);
31962539
3197   /* a zero count means the natural number */
3198   if (totalhunks == 0)
3199      totalhunks = source_header->totalhunks;
2540//-------------------------------------------------
2541//  main - entry point
2542//-------------------------------------------------
32002543
3201   /* loop over source hunks until we run out */
3202   for (hunknum = 0; hunknum < totalhunks; hunknum++)
3203   {
3204      UINT32 bytesremaining = header->hunkbytes;
3205      UINT8 *dest = cache;
2544int CLIB_DECL main(int argc, char *argv[])
2545{
2546   // print the header
2547   extern const char build_version[];
2548   printf("chdman - MAME Compressed Hunks of Data (CHD) manager %s\n", build_version);
32062549
3207      /* progress */
3208      progress(hunknum == 0, "Compressing hunk %d/%d... (ratio=%d%%)  \r", hunknum, totalhunks, (int)(100.0 * ratio));
3209
3210      /* read the data */
3211      while (bytesremaining > 0)
2550   // handle help specially
2551   if (argc < 2)
2552      return print_help(argv[0]);
2553   int argnum = 1;
2554   const char *command = argv[argnum++];
2555   bool help = (strcmp(command, COMMAND_HELP) == 0);
2556   if (help)
2557   {
2558      if (argc <= 2)
2559         return print_help(argv[0]);
2560      command = argv[argnum++];
2561   }
2562   
2563   // iterate over commands to find our match
2564   for (int cmdnum = 0; cmdnum < ARRAY_LENGTH(s_commands); cmdnum++)
2565      if (strcmp(command, s_commands[cmdnum].name) == 0)
32122566      {
3213         /* if we have data in the buffer, copy it */
3214         if (source_bytes > 0)
3215         {
3216            UINT32 bytestocopy = MIN(bytesremaining, source_bytes);
3217            memcpy(dest, &source_cache[source_header->hunkbytes - source_bytes], bytestocopy);
3218            dest += bytestocopy;
3219            source_bytes -= bytestocopy;
3220            bytesremaining -= bytestocopy;
3221         }
2567         const command_description &desc = s_commands[cmdnum];
2568     
2569         // print help if that was requested
2570         if (help)
2571            return print_help(argv[0], desc);
32222572
3223         /* otherwise, read in another hunk of the source */
3224         else
2573         // otherwise, verify the parameters
2574         tagmap_t<astring *> parameters;
2575         while (argnum < argc)
32252576         {
3226            /* verify the next hunk */
3227            if (verifyerr == CHDERR_NONE)
3228               err = chd_verify_hunk(source);
2577            // should be an option name
2578            const char *arg = argv[argnum++];
2579            if (arg[0] != '-')
2580               return print_help(argv[0], desc, "Expected option, not parameter");
32292581
3230            /* then read it (should be the same) */
3231            err = chd_read(source, source_offset / source_header->hunkbytes, source_cache);
3232            if (err != CHDERR_NONE)
3233               memset(source_cache, 0, source_header->hunkbytes);
3234            source_bytes = source_header->hunkbytes;
3235            source_offset += source_bytes;
3236         }
3237      }
2582            // iterate over valid options
2583            int valid;
2584            for (valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++)
2585            {
2586               // reduce to the option name
2587               const char *validname = desc.valid_options[valid];
2588               if (validname == NULL)
2589                  break;
2590               if (*validname == REQUIRED[0])
2591                  validname++;
32382592
3239      /* append the data */
3240      err = chd_compress_hunk(chd, cache, &ratio);
3241      if (err != CHDERR_NONE)
3242         goto cleanup;
3243   }
2593               // find the matching option description
2594               int optnum;
2595               for (optnum = 0; optnum < ARRAY_LENGTH(s_options); optnum++)
2596                  if (strcmp(s_options[optnum].name, validname) == 0)
2597                     break;
2598               assert(optnum != ARRAY_LENGTH(s_options));
32442599
3245   /* if we read all the source data, verify the checksums */
3246   if (verifyerr == CHDERR_NONE && source_offset >= source_header->logicalbytes)
3247   {
3248      static const UINT8 empty_checksum[CHD_SHA1_BYTES] = { 0 };
3249      chd_verify_result verify;
3250      int i;
2600               // do we match?
2601               const option_description &odesc = s_options[optnum];
2602               if ((arg[1] == '-' && strcmp(odesc.name, &arg[2]) == 0) ||
2603                  (arg[1] != '-' && odesc.shortname != NULL && strcmp(odesc.shortname, &arg[1]) == 0))
2604               {
2605                  // if we need a parameter, consume it
2606                  const char *param = "";
2607                  if (odesc.parameter)
2608                  {
2609                     if (argnum >= argc || argv[argnum][0] == '-')
2610                        return print_help(argv[0], desc, "Option is missing parameter");
2611                     param = argv[argnum++];
2612                  }
2613                 
2614                  // add to the map
2615                  if (parameters.add(odesc.name, new astring(param)) == TMERR_DUPLICATE)
2616                     return print_help(argv[0], desc, "Multiple parameters of the same type specified");
2617                  break;
2618               }
2619            }
32512620
3252      /* get the final values */
3253      err = chd_verify_finish(source, &verify);
3254
3255      /* check the MD5 */
3256      if (memcmp(source_header->md5, empty_checksum, CHD_MD5_BYTES) != 0)
3257      {
3258         if (memcmp(source_header->md5, verify.md5, CHD_MD5_BYTES) != 0)
3259         {
3260            progress(TRUE, "WARNING: expected input MD5 = ");
3261            for (i = 0; i < CHD_MD5_BYTES; i++)
3262               progress(TRUE, "%02x", source_header->md5[i]);
3263            progress(TRUE, "\n");
3264
3265            progress(TRUE, "                 actual MD5 = ");
3266            for (i = 0; i < CHD_MD5_BYTES; i++)
3267               progress(TRUE, "%02x", verify.md5[i]);
3268            progress(TRUE, "\n");
2621            // if not valid, error
2622            if (valid == ARRAY_LENGTH(desc.valid_options))
2623               return print_help(argv[0], desc, "Option not valid for this command");
32692624         }
3270         else
3271            progress(TRUE, "Input MD5 verified                            \n");
3272      }
3273
3274      /* check the SHA1 */
3275      if (memcmp(source_header->sha1, empty_checksum, CHD_SHA1_BYTES) != 0)
3276      {
3277         if (memcmp(source_header->sha1, verify.sha1, CHD_SHA1_BYTES) != 0)
2625         
2626         // make sure we got all our required parameters
2627         for (int valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++)
32782628         {
3279            progress(TRUE, "WARNING: expected input SHA1 = ");
3280            for (i = 0; i < CHD_SHA1_BYTES; i++)
3281               progress(TRUE, "%02x", source_header->sha1[i]);
3282            progress(TRUE, "\n");
3283
3284            progress(TRUE, "                 actual SHA1 = ");
3285            for (i = 0; i < CHD_SHA1_BYTES; i++)
3286               progress(TRUE, "%02x", verify.sha1[i]);
3287            progress(TRUE, "\n");
2629            const char *validname = desc.valid_options[valid];
2630            if (validname == NULL)
2631               break;
2632            if (*validname == REQUIRED[0] && parameters.find(++validname) == NULL)
2633               return print_help(argv[0], desc, "Required parameters missing");
32882634         }
3289         else
3290            progress(TRUE, "Input SHA1 verified                            \n");
3291      }
3292   }
3293
3294   /* finish compression */
3295   err = chd_compress_finish(chd, !(source_header->flags & CHDFLAGS_IS_WRITEABLE));
3296   if (err != CHDERR_NONE)
3297      goto cleanup;
3298
3299   /* final progress update */
3300   progress(TRUE, "Compression complete ... final ratio = %d%%            \n", (int)(100.0 * ratio));
3301
3302cleanup:
3303   if (source_cache != NULL)
3304      free(source_cache);
3305   if (cache != NULL)
3306      free(cache);
3307   return err;
3308}
3309
3310
3311/*-------------------------------------------------
3312    chdman_clone_metadata - clone the metadata from
3313    one CHD to a second
3314-------------------------------------------------*/
3315
3316static chd_error chdman_clone_metadata(chd_file *source, chd_file *dest)
3317{
3318   const chd_header *header = chd_get_header(source);
3319   UINT8 metabuffer[MAX(4096, sizeof(cdrom_toc))];
3320   UINT32 metatag, metasize, metaindex;
3321   UINT8 metaflags;
3322   chd_error err;
3323
3324   /* clone the metadata */
3325   for (metaindex = 0; ; metaindex++)
3326   {
3327      /* fetch the next piece of metadata */
3328      err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, metabuffer, sizeof(metabuffer), &metasize, &metatag, &metaflags);
3329      if (err != CHDERR_NONE)
3330      {
3331         if (err == CHDERR_METADATA_NOT_FOUND)
3332            err = CHDERR_NONE;
3333         break;
3334      }
3335
3336      /* promote certain bits of metadata to checksummed for older CHDs */
3337      if (header->version <= 3)
3338      {
3339         if (metatag == HARD_DISK_METADATA_TAG || metatag == CDROM_OLD_METADATA_TAG ||
3340             metatag == CDROM_TRACK_METADATA_TAG || metatag == AV_METADATA_TAG ||
3341             metatag == CDROM_TRACK_METADATA2_TAG || metatag == AV_LD_METADATA_TAG)
2635         
2636         // all clear, run the command
2637         try
33422638         {
3343            metaflags |= CHD_MDFLAGS_CHECKSUM;
2639            (*s_commands[cmdnum].handler)(parameters);
2640            return 0;
33442641         }
3345
3346         /* convert old-style CD-ROM data to newer */
3347         if (metatag == CDROM_OLD_METADATA_TAG)
2642         catch (fatal_error &err)
33482643         {
3349            cdrom_toc *toc = (cdrom_toc *)metabuffer;
3350            err = cdrom_parse_metadata(source, toc);
3351            if (err == CHDERR_NONE)
3352               err = cdrom_write_metadata(dest, toc);
3353            if (err == CHDERR_NONE)
3354               continue;
2644            return err.error();
33552645         }
3356      }
3357
3358      /* if that fit, just write it back from the temporary buffer */
3359      if (metasize <= sizeof(metabuffer))
3360      {
3361         /* write it to the target */
3362         err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, metabuffer, metasize, metaflags);
3363         if (err != CHDERR_NONE)
3364            break;
3365      }
3366
3367      /* otherwise, allocate a bigger temporary buffer */
3368      else
3369      {
3370         UINT8 *allocbuffer = (UINT8 *)malloc(metasize);
3371         if (allocbuffer == NULL)
2646         catch (std::bad_alloc &)
33722647         {
3373            err = CHDERR_OUT_OF_MEMORY;
3374            break;
2648            fprintf(stderr, "Out of memory\n");
2649            return 1;
33752650         }
3376
3377         /* re-read the whole thing */
3378         err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, allocbuffer, metasize, &metasize, &metatag, &metaflags);
3379         if (err != CHDERR_NONE)
2651         catch (...)
33802652         {
3381            free(allocbuffer);
3382            break;
2653            fprintf(stderr, "Unhandled exception\n");
2654            return 1;
33832655         }
3384
3385         /* write it to the target */
3386         err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, allocbuffer, metasize, metaflags);
3387         free(allocbuffer);
3388         if (err != CHDERR_NONE)
3389            break;
33902656      }
3391   }
3392   return err;
2657   
2658   // print generic help if nothing found
2659   return print_help(argv[0]);
33932660}
3394
3395
3396/*-------------------------------------------------
3397    main - entry point
3398-------------------------------------------------*/
3399
3400int CLIB_DECL main(int argc, char *argv[])
3401{
3402   static const struct
3403   {
3404      const char *   option;
3405      int (*callback)(int argc, char *argv[], int param);
3406      int param;
3407   } option_list[] =
3408   {
3409      { "-createhd",      do_createhd, 0 },
3410      { "-createuncomphd",   do_createhd_uncomp, 0 },
3411      { "-createraw",      do_createraw, 0 },
3412      { "-createcd",      do_createcd, 0 },
3413//      { "-createcdflac",  do_createcd, 1 },
3414      { "-createblankhd",   do_createblankhd, 0 },
3415      { "-createav",      do_createav, 0 },
3416      { "-copydata",      do_copydata, 0 },
3417      { "-extract",      do_extract, 0 },
3418      { "-extractcd",      do_extractcd, 0 },
3419      { "-extractav",      do_extractav, 0 },
3420      { "-verify",      do_verify, 0 },
3421      { "-verifyfix",      do_verify, 1 },
3422      { "-update",      do_merge_update_chomp, OPERATION_UPDATE },
3423      { "-chomp",         do_merge_update_chomp, OPERATION_CHOMP },
3424      { "-info",         do_info, 0 },
3425      { "-merge",         do_merge_update_chomp, OPERATION_MERGE },
3426      { "-diff",         do_diff, 0 },
3427      { "-setchs",      do_setchs, 0 },
3428      { "-fixavdata",      do_fixavdata, 0 },
3429      { "-addmetatext",   do_addmeta, TRUE },
3430      { "-addmetabin",    do_addmeta, FALSE },
3431   };
3432   extern const char build_version[];
3433   int i;
3434
3435   /* print the header */
3436   printf("chdman - MAME Compressed Hunks of Data (CHD) manager %s\n", build_version);
3437
3438   /* require at least 1 argument */
3439   if (argc < 2)
3440      return usage();
3441
3442   /* handle the appropriate command */
3443   for (i = 0; i < ARRAY_LENGTH(option_list); i++)
3444      if (strcmp(argv[1], option_list[i].option) == 0)
3445         return (*option_list[i].callback)(argc, argv, option_list[i].param);
3446
3447   return usage();
3448}
src/osd/sdl/README_SDL13.txt
r14481r14482
1======================================================================================
2SDLMAME only supports SDL hg revisions up to 4464
3
4Every revision after 4464 has multi-mice/multi-keyboard ripped out.
5Revisions >= 4465 will not work with SDLMAME.
6
7To build a version suitable for SDLMAME, use ...
8
9hg clone http://hg.libsdl.org/SDL
10hg update 4464
11sh autogen.sh
12./configure --prefix=/usr/local/sdl13 --enable-maintainer-mode --disable-video-directfb --disable-fusionsound
13
14Know caveats: DirectFB is broken (will not compile)
15
16=======================================================================================
17
18
19Warning
20=======
21
22- SDL1.3 still is still under development, the following may or may not
23  work.
24- if you are using wine on unix be sure to disable wintab32.dll
25
26Known bugs:
27===========
28
29* SDL1.3/X11: Some compound keys, e.g. "'" are not supported by SDL driver
30* SDL1.3: sdlvideofps does not take -numscreens>1 into account.
31* SDL1.3/WIN32: crashes with -rd d3d
32* SDL1.3/WIN32: resizing does not work
33     
34Build SDL 1.3 from SVN
35======================
36
37Pull 1.3 from svn. Than
38
39sh autogen.sh
40./configure --prefix=/usr/local/sdl13/ --disable-video-svga --enable-video-directfb --enable-fusionsound
41make
42[sudo] make install
43
44You may leave away the last two enables, if you do not want to play around with directfb - although it is lightning fast now :-)
45
46To build the files in test, do
47
48cd test
49./configure --prefix=/usr/local/sdl13/ --with-sdl-pfx=/usr/local/sdl13
50make
51
52Replace /usr/local/sdl13 above with a safe location, this may as well be a directory in $HOME.
53
54Edit sdl.mak to have
55
56SDL_INSTALL_ROOT = /usr/local/sdl13
57
58That's it.
59
60make
61./mame -video sdl13 -rd opengl dkong
62
63
64All drivers
65===========
66
67should support:
68
69-waitvsync
70-prescale
71-resolution[X]
72-switchres
73-numscreens
74-screen[X]
75
76The following modes are working:
77
78SDL13
79=====
80
81This is driver using SDL texture and line drawing support. It supports
82-prescale, -filter and -waitvsync.  The driver determines which pixel
83formats perform best and converts textures to these pixel formats and at
84the same time performs any necessary rotation. 
85
86Basic usage examples:
87
88X11/opengl: ./mamed -video sdl13 -rd opengl mario
89DFB/DFB:    ./mamed -video sdl13 -rd directfb mario
90WIN32/opengl ./mamed -video sdl13 -rd opengl mario
91
92The performance of the directfb driver depends on the combined
93support of the kernel framebuffer driver and the directfb driver.
94Having loaded radeonfb I get the same performance as with the open source
95radeon X11 driver.
96
97Using the SDL software renderer (preferred is -video soft, thought)
98
99X11,DFB,WIN32 ./mamed -video sdl13 -rd software
100
101Soft:
102=====
103
104./mamed -mt -video soft  -ym none -numscreens 2 mario
105
106OpenGL:
107=======
108
109Plain opengl does work. Anything more advanced like pbo, fbo or glsl will
110most probably not.
111
112   ./mamed -mt -video opengl mario -ym none -nogl_pbo -numscreens 2
113
114YUV - modes:
115============
116
117   ./mamed -mt -video soft -rd software -ym yuy2 -numscreens 2 mario
118
119The "-rd" overwrites the default which is built-in opengl. This renderer
120does not support yuv modes. The software driver does support them non-accelarated.
121This has been left in for the time Xv is once again implemented in SDL.
122
123Using DirectFB, the following should get you going
124
125   ./mamed -mt -video soft -sm yuy2 -vd directfb -rd directfb mario
126   
127for accelerated blitting on the framebuffer - provided directfb supports it.
128At least my Radeon R480 is supported.
129
130-video soft and -scale_mode (-sm)
131=================================
132
133sdlmame supports 7 scale modes using textures in -video soft:
134
135none: All rendering/scaling in software.
136
137hwblit: Rendering in software/scaling with hardware (if supported)
138
139hwbest: Rendering in software/antialiased scaling with hardware (if supported)
140
141yv12, yv12x2, yuy2, yuy2x2:
142Rendering in software / scaling with hardware (if supported)
143
144Whether these are actually hardware accelerated depends on the SDL driver
145and the hardware. The current SDL X11 driver needs opengl for rendering but
146does not support yuv textures. The "to-be-submitted" SDL directfb driver
147supports all above if the hardware supports it. However, only one YUV-texture
148per display is supported. The second window consequently will get "software"
149YUV blitting.
150
151     
src/osd/sdl/README_SDL20.txt
r14481r14482
1======================================================================================
2SDLMAME now supports SDL from version 2.0 on upwards.
3=======================================================================================
4
5
6Warning
7=======
8
9- SDL2.0 still is still under development, the following may or may not
10  work.
11- if you are using wine on unix be sure to disable wintab32.dll
12
13Known bugs:
14===========
15
16* SDL1.3/X11: Some compound keys, e.g. "'" are not supported by SDL driver
17* SDL2.0: sdlvideofps does not take -numscreens>1 into account.
18* SDL1.3/WIN32: crashes with -rd d3d
19* SDL1.3/WIN32: resizing does not work
20     
21Build SDL 2.0 from HG
22======================
23
24Pull 2.0 from hg. Than
25
26sh autogen.sh
27./configure --prefix=/usr/local/sdl13/ --disable-video-svga --enable-video-directfb --enable-fusionsound
28make
29[sudo] make install
30
31You may leave away the last two enables, if you do not want to play around with directfb - although it is lightning fast now :-)
32
33To build the files in test, do
34
35cd test
36./configure --prefix=/usr/local/sdl13/ --with-sdl-pfx=/usr/local/sdl13
37make
38
39Replace /usr/local/sdl13 above with a safe location, this may as well be a directory in $HOME.
40
41Edit sdl.mak to have
42
43SDL_LIBVER = sdl2
44SDL_INSTALL_ROOT = /usr/local/sdl13
45
46That's it.
47
48make
49./mame -video sdl13 -rd opengl dkong
50
51
52All drivers
53===========
54
55should support:
56
57-waitvsync
58-prescale
59-resolution[X]
60-switchres
61-numscreens
62-screen[X]
63
64The following modes are working:
65
66SDL13
67=====
68
69This is driver using SDL texture and line drawing support. It supports
70-prescale, -filter and -waitvsync.  The driver determines which pixel
71formats perform best and converts textures to these pixel formats and at
72the same time performs any necessary rotation. 
73
74Basic usage examples:
75
76X11/opengl: ./mamed -video sdl13 -rd opengl mario
77DFB/DFB:    ./mamed -video sdl13 -vd directfb -rd directfb mario
78
79The performance of the directfb driver depends on the combined
80support of the kernel framebuffer driver and the directfb driver.
81Having loaded radeonfb I get the same performance as with the open source
82radeon X11 driver.
83
84Using the SDL software renderer (preferred is -video soft, thought)
85
86X11,DFB,WIN32 ./mamed -video sdl13 -rd software
87
88Soft:
89=====
90
91./mamed -mt -video soft  -sm none -numscreens 2 mario
92
93OpenGL:
94=======
95
96Plain opengl does work. Anything more advanced like pbo, fbo or glsl will
97most probably not work with more than one screen.
98
99   ./mamed -mt -video opengl mario -nogl_pbo -nogl_vbo -nogl_glsl -numscreens 2
100
101YUV - modes:
102============
103
104   ./mamed -mt -video soft -sm yuy2 mario
105
106Using DirectFB, the following should get you going
107
108   ./mamed -mt -video soft -sm yuy2 -vd directfb -rd directfb mario
109   
110for accelerated blitting on the framebuffer - provided directfb supports it.
111At least my Radeon R480 is supported.
112
113-video soft and -scale_mode (-sm)
114=================================
115
116sdlmame supports 7 scale modes using textures in -video soft:
117
118none: All rendering/scaling in software.
119
120hwblit: Rendering in software/scaling with hardware (if supported)
121
122hwbest: Rendering in software/antialiased scaling with hardware (if supported)
123
124yv12, yv12x2, yuy2, yuy2x2:
125Rendering in software / scaling with hardware (if supported)
126
127Whether these are actually hardware accelerated depends on the SDL driver
128and the hardware. The SDL directfb driver supports all above if the hardware
129supports it. However, only one YUV-texture per display is supported.
130The second window consequently will get "software" YUV blitting.
131
132     
1======================================================================================
2SDLMAME now supports SDL from version 2.0 on upwards.
3=======================================================================================
4 
5 
6Warning
7=======
8 
9- SDL2.0 still is still under development, the following may or may not
10  work.
11- if you are using wine on unix be sure to disable wintab32.dll
12 
13Known bugs:
14===========
15 
16* SDL1.3/X11: Some compound keys, e.g. "'" are not supported by SDL driver
17* SDL2.0: sdlvideofps does not take -numscreens>1 into account.
18* SDL1.3/WIN32: crashes with -rd d3d
19* SDL1.3/WIN32: resizing does not work
20       
21Build SDL 2.0 from HG
22======================
23 
24Pull 2.0 from hg. Than 
25 
26sh autogen.sh
27./configure --prefix=/usr/local/sdl13/ --disable-video-svga --enable-video-directfb --enable-fusionsound
28make 
29[sudo] make install
30 
31You may leave away the last two enables, if you do not want to play around with directfb - although it is lightning fast now :-)
32 
33To build the files in test, do
34 
35cd test
36./configure --prefix=/usr/local/sdl13/ --with-sdl-pfx=/usr/local/sdl13
37make
38 
39Replace /usr/local/sdl13 above with a safe location, this may as well be a directory in $HOME.
40 
41Edit sdl.mak to have
42 
43SDL_LIBVER = sdl2
44SDL_INSTALL_ROOT = /usr/local/sdl13
45 
46That's it.
47 
48make
49./mame -video sdl13 -rd opengl dkong
50 
51 
52All drivers
53===========
54 
55should support:
56 
57-waitvsync
58-prescale
59-resolution[X]
60-switchres
61-numscreens
62-screen[X]
63 
64The following modes are working:
65 
66SDL13
67=====
68 
69This is driver using SDL texture and line drawing support. It supports 
70-prescale, -filter and -waitvsync.  The driver determines which pixel 
71formats perform best and converts textures to these pixel formats and at 
72the same time performs any necessary rotation.   
73 
74Basic usage examples:
75 
76X11/opengl: ./mamed -video sdl13 -rd opengl mario 
77DFB/DFB:    ./mamed -video sdl13 -vd directfb -rd directfb mario 
78 
79The performance of the directfb driver depends on the combined
80support of the kernel framebuffer driver and the directfb driver.
81Having loaded radeonfb I get the same performance as with the open source
82radeon X11 driver.
83 
84Using the SDL software renderer (preferred is -video soft, thought)
85 
86X11,DFB,WIN32 ./mamed -video sdl13 -rd software
87 
88Soft:
89=====
90 
91./mamed -mt -video soft  -sm none -numscreens 2 mario
92 
93OpenGL:
94=======
95 
96Plain opengl does work. Anything more advanced like pbo, fbo or glsl will 
97most probably not work with more than one screen.
98 
99   ./mamed -mt -video opengl mario -nogl_pbo -nogl_vbo -nogl_glsl -numscreens 2
100 
101YUV - modes:
102============
103 
104   ./mamed -mt -video soft -sm yuy2 mario
105 
106Using DirectFB, the following should get you going
107 
108   ./mamed -mt -video soft -sm yuy2 -vd directfb -rd directfb mario
109   
110for accelerated blitting on the framebuffer - provided directfb supports it. 
111At least my Radeon R480 is supported.
112 
113-video soft and -scale_mode (-sm)
114=================================
115 
116sdlmame supports 7 scale modes using textures in -video soft:
117 
118none: All rendering/scaling in software.
119 
120hwblit: Rendering in software/scaling with hardware (if supported)
121 
122hwbest: Rendering in software/antialiased scaling with hardware (if supported)
123 
124yv12, yv12x2, yuy2, yuy2x2: 
125Rendering in software / scaling with hardware (if supported)
126 
127Whether these are actually hardware accelerated depends on the SDL driver
128and the hardware. The SDL directfb driver supports all above if the hardware 
129supports it. However, only one YUV-texture per display is supported. 
130The second window consequently will get "software" YUV blitting.
131 
132     
src/osd/sdl/input.c
r14481r14482
9595   INT32 axes[MAX_AXES];
9696   INT32 buttons[MAX_BUTTONS];
9797   INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
98   INT32 balls[MAX_AXES];
9899};
99100
100101// generic device information
r14481r14482
495496   KE8(F6,         F7,         F8,            F9,         F10,      F11,      F12,      F13         )
496497   KE8(F14,      F15,      NUMLOCKCLEAR,   CAPSLOCK,   SCROLLLOCK,   RSHIFT,      LSHIFT,      RCTRL      )
497498   KE5(LCTRL,      RALT,      LALT,         LGUI,      RGUI)
498   KE(PRINTSCREEN)
499   KE(MENU)
499   KE8(GRAVE,      LEFTBRACKET,RIGHTBRACKET,   SEMICOLON,   APOSTROPHE,   BACKSLASH,   PRINTSCREEN,MENU      )
500500   KE(UNDO)
501501   {-1, ""}
502502};
r14481r14482
541541};
542542#endif
543543
544
545544//============================================================
546545//  INLINE FUNCTIONS
547546//============================================================
r14481r14482
681680static void sdlinput_register_joysticks(running_machine &machine)
682681{
683682   device_info *devinfo;
684   int physical_stick, axis, button, hat, stick;
683   int physical_stick, axis, button, hat, stick, ball;
685684   char tempname[512];
686685   SDL_Joystick *joy;
687686
r14481r14482
709708      devinfo->joystick.device = joy;
710709
711710      mame_printf_verbose("Joystick: %s\n", devinfo->name);
712      mame_printf_verbose("Joystick:   ...  %d axes, %d buttons %d hats\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy));
711      mame_printf_verbose("Joystick:   ...  %d axes, %d buttons %d hats %d balls\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy), SDL_JoystickNumBalls(joy));
713712      mame_printf_verbose("Joystick:   ...  Physical id %d mapped to logical id %d\n", physical_stick, stick);
714713
715714      // loop over all axes
r14481r14482
764763         itemid = (input_item_id) ((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + 4 * hat : ITEM_ID_OTHER_SWITCH);
765764          devinfo->device->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsR[hat]);
766765      }
766
767      // loop over all (track)balls
768      for (ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
769      {
770         int itemid;
771
772         if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
773            itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
774         else
775            itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
776
777         sprintf(tempname, "R%d %s", ball * 2, devinfo->name);
778         devinfo->device->add_item(tempname, (input_item_id) itemid, generic_axis_get_state, &devinfo->joystick.balls[ball * 2]);
779         sprintf(tempname, "R%d %s", ball * 2 + 1, devinfo->name);
780         devinfo->device->add_item(tempname, (input_item_id) (itemid + 1), generic_axis_get_state, &devinfo->joystick.balls[ball * 2 + 1]);
781      }
767782   }
768783   mame_printf_verbose("Joystick: End initialization\n");
769784}
r14481r14482
938953   int line = 1;
939954   int index,i, sk, vk, ak;
940955   char buf[256];
941   char mks[21];
942   char sks[21];
943   char kns[21];
956   char mks[41];
957   char sks[41];
958   char kns[41];
959   int  sdl2section=0;
944960
945961   if (!machine.options().bool_value(SDLOPTION_KEYMAP))
946962      return sdl_key_trans_table;
r14481r14482
960976
961977   while (!feof(keymap_file))
962978   {
963      fgets(buf, 255, keymap_file);
964      if (*buf && buf[0] && buf[0] != '#')
979      char *ret = fgets(buf, 255, keymap_file);
980      if (ret && buf[0] != '\n' && buf[0] != '#')
965981      {
966982         buf[255]=0;
967983         i=strlen(buf);
968984         if (i && buf[i-1] == '\n')
969985            buf[i-1] = 0;
970         mks[0]=0;
971         sks[0]=0;
972         memset(kns, 0, ARRAY_LENGTH(kns));
973         sscanf(buf, "%20s %20s %x %x %20c\n",
974               mks, sks, &vk, &ak, kns);
986         if (strncmp(buf,"[SDL2]",6) == 0)
987         {
988            sdl2section = 1;
989         }
990         else if (((SDLMAME_SDL2) ^ sdl2section) == 0)
991         {
992            mks[0]=0;
993            sks[0]=0;
994            memset(kns, 0, ARRAY_LENGTH(kns));
995            sscanf(buf, "%40s %40s %x %x %40c\n",
996                  mks, sks, &vk, &ak, kns);
975997
976         index=lookup_mame_index(mks);
977         sk = lookup_sdl_code(sks);
998            index=lookup_mame_index(mks);
999            sk = lookup_sdl_code(sks);
9781000
979         if ( sk >= 0 && index >=0)
980         {
981            key_trans_table[index].sdl_key = sk;
982            // vk and ak are not really needed
983            //key_trans_table[index][VIRTUAL_KEY] = vk;
984            //key_trans_table[index][ASCII_KEY] = ak;
985            key_trans_table[index].ui_name = auto_alloc_array(machine, char, strlen(kns)+1);
986            strcpy(key_trans_table[index].ui_name, kns);
987            mame_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
1001            if ( sk >= 0 && index >=0)
1002            {
1003               key_trans_table[index].sdl_key = sk;
1004               // vk and ak are not really needed
1005               //key_trans_table[index][VIRTUAL_KEY] = vk;
1006               //key_trans_table[index][ASCII_KEY] = ak;
1007               key_trans_table[index].ui_name = auto_alloc_array(machine, char, strlen(kns)+1);
1008               strcpy(key_trans_table[index].ui_name, kns);
1009               mame_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
1010            }
1011            else
1012               mame_printf_warning("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
9881013         }
989         else
990            mame_printf_warning("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
9911014      }
9921015      line++;
9931016   }
r14481r14482
14771500               ui_input_push_mouse_move_event(machine, window->target, cx, cy);
14781501         }
14791502         break;
1503      case SDL_JOYBALLMOTION:
1504         devinfo = generic_device_find_index(joystick_list, joy_map.logical[event.jball.which]);
1505         //printf("Ball %d %d\n", event.jball.xrel, event.jball.yrel);
1506         devinfo->joystick.balls[event.jball.ball * 2] = event.jball.xrel * INPUT_RELATIVE_PER_PIXEL;
1507         devinfo->joystick.balls[event.jball.ball * 2 + 1] = event.jball.yrel * INPUT_RELATIVE_PER_PIXEL;
1508         break;
14801509#if (!SDLMAME_SDL2)
14811510      case SDL_APPMOUSEFOCUS:
14821511         app_has_mouse_focus = event.active.gain;
src/osd/sdl/testkeys.c
r14481r14482
1919
2020#include "unicode.h"
2121
22// Check whether SDL has compat interface
23#if defined(SDL_AllocSurface) || (!SDLMAME_SDL2)
24#define SDL_HAS_COMPAT      1
25#else
26#define SDL_HAS_COMPAT      0
27#endif
28
2922typedef struct _key_lookup_table key_lookup_table;
3023
3124struct _key_lookup_table
r14481r14482
3427   const char *name;
3528};
3629
37#if SDL_HAS_COMPAT
3830#if (SDLMAME_SDL2)
3931#define KE(x) { SDL_SCANCODE_ ## x, "SDL_SCANCODE_" #x },
4032#define KE8(A, B, C, D, E, F, G, H) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G) KE(H)
r14481r14482
116108   }
117109   return NULL;
118110}
119#endif // SDL_HAS_COMPAT
120111
121112#ifdef SDLMAME_WIN32
122113int utf8_main(int argc, char *argv[])
r14481r14482
124115int main(int argc, char *argv[])
125116#endif
126117{
127#if SDL_HAS_COMPAT
128118   SDL_Event event;
129119   int quit = 0;
120#if (SDLMAME_SDL2)
121   char lasttext[20] = "";
122#else
130123   char buf[20];
124#endif
131125
132126   if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
133127      fprintf(stderr, "Couldn't initialize SDL: %s\n",
134128                     SDL_GetError());
135129      exit(1);
136130   }
131#if (SDLMAME_SDL2)
132   SDL_CreateWindow("Input Test", 0, 0, 100, 100,0 );
133#else
137134   SDL_SetVideoMode(100, 50, 16, SDL_ANYFORMAT);
138135   SDL_EnableUNICODE(1);
136#endif
139137   while(SDL_PollEvent(&event) || !quit) {
140138      switch(event.type) {
141139      case SDL_QUIT:
r14481r14482
146144            quit=1;
147145         else
148146         {
149            memset(buf, 0, ARRAY_LENGTH(buf));
150            utf8_from_uchar(buf, sizeof(buf), event.key.keysym.unicode);
151            printf("ITEM_ID_XY %s 0x%x 0x%x %s \n",
152147#if (SDLMAME_SDL2)
153                  lookup_key_name(sdl_lookup, event.key.keysym.scancode),
148            printf("ITEM_ID_XY %s 0x%x 0x%x %s\n",
149               lookup_key_name(sdl_lookup, event.key.keysym.scancode),
150               (int) event.key.keysym.scancode,
151               (int) event.key.keysym.unicode,
152               "");
153            lasttext[0] = 0;
154154#else
155                  lookup_key_name(sdl_lookup, event.key.keysym.sym),
155            memset(buf, 0, 19);
156            utf8_from_uchar(buf, sizeof(buf), event.key.keysym.unicode);
157            printf("ITEM_ID_XY %s 0x%x 0x%x %s\n",
158               lookup_key_name(sdl_lookup, event.key.keysym.sym),
159               (int) event.key.keysym.scancode,
160               (int) event.key.keysym.unicode,
161               buf);
156162#endif
157                  (int) event.key.keysym.scancode,
158                  (int) event.key.keysym.unicode,
159                  buf);
160163         }
161164         break;
162165      case SDL_KEYUP:
163         memset(buf, 0, 19);
164         utf8_from_uchar(buf, sizeof(buf), event.key.keysym.unicode);
165         printf("ITEM_ID_XY %s 0x%x 0x%x %s \n",
166166#if (SDLMAME_SDL2)
167         printf("ITEM_ID_XY %s 0x%x 0x%x %s\n",
167168               lookup_key_name(sdl_lookup, event.key.keysym.scancode),
169               (int) event.key.keysym.scancode,
170               (int) event.key.keysym.unicode,
171               lasttext);
168172#else
173         memset(buf, 0, 19);
174         utf8_from_uchar(buf, sizeof(buf), event.key.keysym.unicode);
175         printf("ITEM_ID_XY %s 0x%x 0x%x %s\n",
169176               lookup_key_name(sdl_lookup, event.key.keysym.sym),
170#endif
171177               (int) event.key.keysym.scancode,
172178               (int) event.key.keysym.unicode,
173179               buf);
180#endif
174181         break;
182#if (SDLMAME_SDL2)
183      case SDL_TEXTINPUT:
184         strcpy(lasttext, event.text.text);
185         break;
186#endif
175187      }
176188      event.type = 0;
177189
r14481r14482
181193   }
182194   SDL_Quit();
183195   return(0);
184#else
185   printf("This SDL Version does not support 1.2 compatibility interface.\n");
186   return(1);
187#endif
188196}
189197
src/osd/sdl/sdlinc.h
r14481r14482
1#ifndef _sdlinc_h_
2#define _sdlinc_h_
3
4#if (SDLMAME_SDL2)
5#include <SDL2/SDL.h>
6#include <SDL2/SDL_version.h>
7// on win32 this includes windows.h by itself and breaks us!
8#ifndef SDLMAME_WIN32
9#include <SDL2/SDL_syswm.h>
10#endif
11#else
12#include <SDL/SDL.h>
13#include <SDL/SDL_version.h>
14// on win32 this includes windows.h by itself and breaks us!
15#ifndef SDLMAME_WIN32
16#include <SDL/SDL_syswm.h>
17#endif
18#endif
19
20#endif
1#ifndef _sdlinc_h_
2#define _sdlinc_h_
3 
4#if (SDLMAME_SDL2)
5#include <SDL2/SDL.h>
6#include <SDL2/SDL_version.h>
7// on win32 this includes windows.h by itself and breaks us!
8#ifndef SDLMAME_WIN32
9#include <SDL2/SDL_syswm.h>
10#endif
11#else
12#include <SDL/SDL.h>
13#include <SDL/SDL_version.h>
14// on win32 this includes windows.h by itself and breaks us!
15#ifndef SDLMAME_WIN32
16#include <SDL/SDL_syswm.h>
17#endif
18#endif
19 
20#endif
src/osd/sdl/keymaps/km-de.txt
r14481r14482
1212ITEM_ID_SLASH SDLK_MINUS 0x3d 0x2d -
1313ITEM_ID_Z SDLK_y 0x34 0x79 Y
1414ITEM_ID_Y SDLK_z 0x1d 0x7a Z
15[SDL2]
16ITEM_ID_TILDE SDL_SCANCODE_GRAVE 0x35 0x0 ^
17ITEM_ID_MINUS SDL_SCANCODE_MINUS 0x2d 0x0 ß
18ITEM_ID_EQUALS SDL_SCANCODE_EQUALS 0x2e 0x0 '
19ITEM_ID_OPENBRACE SDL_SCANCODE_LEFTBRACKET 0x2f 0x0 Ü
20ITEM_ID_CLOSEBRACE SDL_SCANCODE_RIGHTBRACKET 0x30 0x0 +
21ITEM_ID_COLON SDL_SCANCODE_SEMICOLON 0x33 0x0 Ö
22ITEM_ID_QUOTE SDL_SCANCODE_APOSTROPHE 0x34 0x0 Ä
23ITEM_ID_BACKSLASH SDL_SCANCODE_BACKSLASH 0x31 0x0 #
24ITEM_ID_SLASH SDL_SCANCODE_SLASH 0x38 0x0 -
25ITEM_ID_Z SDL_SCANCODE_Y 0x34 0x79 Y
26ITEM_ID_Y SDL_SCANCODE_Z 0x1d 0x7a Z
src/osd/windows/wintime.c
r14481r14482
104104
105105osd_ticks_t osd_ticks_per_second(void)
106106{
107   if (ticks_per_second == 0)
108      osd_ticks();
107109   return ticks_per_second;
108110}
109111
src/osd/windows/winwork.c
r14481r14482
321321   if (numprocs == 1)
322322      queue->threads = (flags & WORK_QUEUE_FLAG_IO) ? 1 : 0;
323323
324   // on an n-CPU system, create (n-1) threads for multi queues, and 1 thread for everything else
324   // on an n-CPU system, create n threads for multi queues, and 1 thread for everything else
325325   else
326      queue->threads = (flags & WORK_QUEUE_FLAG_MULTI) ? (numprocs - 1) : 1;
326      queue->threads = (flags & WORK_QUEUE_FLAG_MULTI) ? numprocs : 1;
327     
328   // multi-queues with high frequency items should top out at 4 for now
329   // since we have scaling problems above that
330   if ((flags & WORK_QUEUE_FLAG_HIGH_FREQ) && queue->threads > 1)
331      queue->threads = MIN(queue->threads - 1, 4);
327332
328333   // clamp to the maximum
329334   queue->threads = MIN(queue->threads, WORK_MAX_THREADS);
r14481r14482
706711      int numprocs = 0;
707712
708713      // if the OSDPROCESSORS environment variable is set, use that value if valid
714      // note that we permit more than the real number of processors for testing
709715      procsoverride = _tgetenv(_T("OSDPROCESSORS"));
710716      if (procsoverride != NULL && _stscanf(procsoverride, _T("%d"), &numprocs) == 1 && numprocs > 0)
711         // Be well behaved ...
712717         return MIN(info.dwNumberOfProcessors * 4, numprocs);
713718
714      // max out at 4 for now since scaling above that seems to do poorly
715      return MIN(info.dwNumberOfProcessors, 4);
719      return info.dwNumberOfProcessors;
716720   }
717721}
718722
src/emu/emuopts.c
r14481r14482
374374   }
375375   result = core_options::parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string);
376376   update_slot_options();
377   add_device_options(true);   
378   result = core_options::parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string);
377379   return result;
378380}
379381
r14481r14482
502504      // then add the options
503505      add_device_options(true);
504506      update_slot_options();
507      add_device_options(true);
505508   }
506509}
507510
src/emu/emu.h
r14481r14482
5959#include "profiler.h"
6060
6161// commonly-referenecd utilities imported from lib/util
62#include "chd.h"
6362#include "palette.h"
6463#include "unicode.h"
6564
src/emu/clifront.c
r14481r14482
3838***************************************************************************/
3939
4040#include "emu.h"
41#include "chd.h"
4142#include "emuopts.h"
4243#include "jedparse.h"
4344#include "audit.h"
r14481r14482
149150   m_result = MAMERR_NONE;
150151   try
151152   {
153      // first parse options to be able to get software from it
154      astring option_errors;
155      m_options.parse_command_line(argc, argv, option_errors);
156      if (strlen(m_options.software_name()) > 0)
157      {
158         const game_driver *system = m_options.system();
159         if (system == NULL && strlen(m_options.system_name()) > 0)
160            throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name());
161
162         machine_config config(*system, m_options);
163         software_list_device_iterator iter(config.root_device());
164         if (iter.first() == NULL)
165            throw emu_fatalerror(MAMERR_FATALERROR, "Error: unknown option: %s\n", m_options.software_name());
166
167         bool found = FALSE;
168         for (software_list_device *swlist = iter.first(); swlist != NULL; swlist = iter.next())
169         {
170            software_list *list = software_list_open(m_options, swlist->list_name(), FALSE, NULL);
171            if (list)
172            {
173               software_info *swinfo = software_list_find(list, m_options.software_name(), NULL);
174               if (swinfo != NULL)
175               {
176                  // loop through all parts
177                  for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
178                  {
179                     const char *mount = software_part_get_feature(swpart, "automount");
180                     if (is_software_compatible(swpart, swlist))
181                     {
182                        if (mount == NULL || strcmp(mount,"no") != 0)
183                        {
184                           // search for an image device with the right interface
185                           image_interface_iterator imgiter(config.root_device());
186                           for (device_image_interface *image = imgiter.first(); image != NULL; image = imgiter.next())
187                           {
188                              const char *interface = image->image_interface();
189                              if (interface != NULL)
190                              {
191                                 if (!strcmp(interface, swpart->interface_))
192                                 {
193                                    const char *option = m_options.value(image->brief_instance_name());
194                                    // mount only if not already mounted
195                                    if (strlen(option) == 0)
196                                    {
197                                       astring val;
198                                       val.printf("%s:%s:%s",swlist->list_name(),m_options.software_name(),swpart->name);
199                                       // call this in order to set slot devices according to mounting
200                                       m_options.parse_slot_devices(argc, argv, option_errors, image->instance_name(), val.cstr());
201                                       break;
202                                    }
203                                 }
204                              }
205                           }
206                        }
207                        found = TRUE;
208                     }
209                  }
210               }
211               software_list_close(list);
212            }
213
214            if (found) break;
215         }
216         if (!found)
217         {
218            software_display_matches(config,m_options, NULL,m_options.software_name());
219            throw emu_fatalerror(MAMERR_FATALERROR, "");
220         }
221      }
152222      // parse the command line, adding any system-specific options
153      astring option_errors;
154223      if (!m_options.parse_command_line(argc, argv, option_errors))
155224      {
156225         // if we failed, check for no command and a system name first; in that case error on the name
r14481r14482
178247         const game_driver *system = m_options.system();
179248         if (system == NULL && strlen(m_options.system_name()) > 0)
180249            throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name());
181
182         if (strlen(m_options.software_name()) > 0)
183         {
184            machine_config config(*system, m_options);
185            software_list_device_iterator iter(config.root_device());
186            if (iter.first() == NULL)
187               throw emu_fatalerror(MAMERR_FATALERROR, "Error: unknown option: %s\n", m_options.software_name());
188
189            bool found = FALSE;
190            for (software_list_device *swlist = iter.first(); swlist != NULL; swlist = iter.next())
191            {
192               software_list *list = software_list_open(m_options, swlist->list_name(), FALSE, NULL);
193               if (list)
194               {
195                  software_info *swinfo = software_list_find(list, m_options.software_name(), NULL);
196                  if (swinfo != NULL)
197                  {
198                     // loop through all parts
199                     for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
200                     {
201                        const char *mount = software_part_get_feature(swpart, "automount");
202                        if (is_software_compatible(swpart, swlist))
203                        {
204                           if (mount == NULL || strcmp(mount,"no") != 0)
205                           {
206                              // search for an image device with the right interface
207                              image_interface_iterator imgiter(config.root_device());
208                              for (device_image_interface *image = imgiter.first(); image != NULL; image = imgiter.next())
209                              {
210                                 const char *interface = image->image_interface();
211                                 if (interface != NULL)
212                                 {
213                                    if (!strcmp(interface, swpart->interface_))
214                                    {
215                                       const char *option = m_options.value(image->brief_instance_name());
216                                       // mount only if not already mounted
217                                       if (strlen(option) == 0)
218                                       {
219                                          astring val;
220                                          val.printf("%s:%s:%s",swlist->list_name(),m_options.software_name(),swpart->name);
221                                          // call this in order to set slot devices according to mounting
222                                          m_options.parse_slot_devices(argc, argv, option_errors, image->instance_name(), val.cstr());
223                                          break;
224                                       }
225                                    }
226                                 }
227                              }
228                           }
229                           found = TRUE;
230                        }
231                     }
232                  }
233                  software_list_close(list);
234               }
235
236               if (found) break;
237            }
238            if (!found)
239            {
240               software_display_matches(config,m_options, NULL,m_options.software_name());
241               throw emu_fatalerror(MAMERR_FATALERROR, "");
242            }
243         }
244250         // otherwise just run the game
245251         m_result = mame_execute(m_options, m_osd);
246252      }
r14481r14482
14921498      m_total++;
14931499
14941500      // attempt to open as a CHD; fail if not
1495      chd_file *chd;
1496      chd_error err = chd_open(name, CHD_OPEN_READ, NULL, &chd);
1501      chd_file chd;
1502      chd_error err = chd.open(name);
14971503      if (err != CHDERR_NONE)
14981504      {
14991505         mame_printf_info("NOT A CHD\n");
r14481r14482
15011507         return;
15021508      }
15031509
1504      // fetch the header and close the file
1505      chd_header header = *chd_get_header(chd);
1506      chd_close(chd);
1507
15081510      // error on writable CHDs
1509      if (header.flags & CHDFLAGS_IS_WRITEABLE)
1511      if (!chd.compressed())
15101512      {
15111513         mame_printf_info("is a writeable CHD\n");
15121514         return;
15131515      }
15141516
15151517      // otherwise, get the hash collection for this CHD
1516      static const UINT8 nullhash[20] = { 0 };
15171518      hash_collection hashes;
1519      if (chd.sha1() != sha1_t::null)
1520         hashes.add_from_buffer(hash_collection::HASH_SHA1, chd.sha1().m_raw, sizeof(chd.sha1().m_raw));
15181521
1519      if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
1520         hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
1521
15221522      // determine whether this file exists
1523      int found = find_by_hash(hashes, header.logicalbytes);
1523      int found = find_by_hash(hashes, chd.logical_bytes());
15241524      if (found == 0)
15251525         mame_printf_info("NO MATCH\n");
15261526      else
src/emu/romload.c
r14481r14482
3838   friend class simple_list<open_chd>;
3939
4040public:
41   open_chd(const char *region, emu_file &file, chd_file &chdfile, emu_file *difffile = NULL, chd_file *diffchd = NULL)
41   open_chd(const char *region)
4242      : m_next(NULL),
43        m_region(region),
44        m_origchd(&chdfile),
45        m_origfile(&file),
46        m_diffchd(diffchd),
47        m_difffile(difffile) { }
43        m_region(region) { }
4844
49   ~open_chd()
50   {
51      if (m_diffchd != NULL) chd_close(m_diffchd);
52      global_free(m_difffile);
53      chd_close(m_origchd);
54      global_free(m_origfile);
55   }
56
5745   open_chd *next() const { return m_next; }
5846   const char *region() const { return m_region; }
59   chd_file *chd() const { return (m_diffchd != NULL) ? m_diffchd : m_origchd; }
47   chd_file &chd() { return m_diffchd.opened() ? m_diffchd : m_origchd; }
48   chd_file &orig_chd() { return m_origchd; }
49   chd_file &diff_chd() { return m_diffchd; }
6050
6151private:
6252   open_chd *         m_next;               /* pointer to next in the list */
6353   astring            m_region;            /* disk region we came from */
64   chd_file *         m_origchd;            /* handle to the original CHD */
65   emu_file *         m_origfile;            /* file handle to the original CHD file */
66   chd_file *         m_diffchd;            /* handle to the diff CHD */
67   emu_file *         m_difffile;            /* file handle to the diff CHD file */
54   chd_file         m_origchd;            /* handle to the original CHD */
55   chd_file         m_diffchd;            /* handle to the diff CHD */
6856};
6957
7058
r14481r14482
10593    HELPERS (also used by devimage.c)
10694 ***************************************************************************/
10795
108file_error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file **image_file)
96file_error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file &image_file)
10997{
110   *image_file = global_alloc(emu_file(options.media_path(), OPEN_FLAG_READ));
11198   file_error filerr;
11299
113100   if (location != NULL && strcmp(location, "") != 0)
114      filerr = (*image_file)->open(location, PATH_SEPARATOR, ROM_GETNAME(romp), ext);
101      filerr = image_file.open(location, PATH_SEPARATOR, ROM_GETNAME(romp), ext);
115102   else
116      filerr = (*image_file)->open(ROM_GETNAME(romp), ext);
103      filerr = image_file.open(ROM_GETNAME(romp), ext);
117104
118   if (filerr != FILERR_NONE)
119   {
120      global_free(*image_file);
121      *image_file = NULL;
122   }
123105   return filerr;
124106}
125107
r14481r14482
155137{
156138   for (open_chd *curdisk = machine.romload_data->chd_list.first(); curdisk != NULL; curdisk = curdisk->next())
157139      if (strcmp(curdisk->region(), region) == 0)
158         return curdisk->chd();
140         return &curdisk->chd();
159141   return NULL;
160142}
161143
r14481r14482
165147    file associated with the given region
166148-------------------------------------------------*/
167149
168void set_disk_handle(running_machine &machine, const char *region, emu_file &file, chd_file &chdfile)
150int set_disk_handle(running_machine &machine, const char *region, const char *fullpath)
169151{
170   machine.romload_data->chd_list.append(*global_alloc(open_chd(region, file, chdfile)));
152   open_chd *chd = global_alloc(open_chd(region));
153   chd_error err = chd->orig_chd().open(fullpath);
154   if (err == CHDERR_NONE)
155      machine.romload_data->chd_list.append(*chd);
156   else
157      global_free(chd);
158   return err;
171159}
172160
173161
r14481r14482
1010998    checksum
1011999-------------------------------------------------*/
10121000
1013chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd, const char *locationtag)
1001int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, chd_file &image_chd, const char *locationtag)
10141002{
1003   emu_file image_file(options.media_path(), OPEN_FLAG_READ);
10151004   const rom_entry *region, *rom;
10161005   const rom_source *source;
10171006   file_error filerr;
10181007   chd_error err;
10191008
1020   *image_file = NULL;
1021   *image_chd = NULL;
1022
10231009   /* attempt to open the properly named file, scanning up through parent directories */
10241010   filerr = FILERR_NOT_FOUND;
10251011   for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv))
r14481r14482
11031089   /* did the file open succeed? */
11041090   if (filerr == FILERR_NONE)
11051091   {
1092      astring fullpath(image_file.fullpath());
1093      image_file.close();
1094
11061095      /* try to open the CHD */
1107      err = chd_open_file(**image_file, CHD_OPEN_READ, NULL, image_chd);
1096      err = image_chd.open(fullpath);
11081097      if (err == CHDERR_NONE)
11091098         return err;
1110
1111      /* close the file on failure */
1112      global_free(*image_file);
1113      *image_file = NULL;
11141099   }
11151100   else
11161101      err = CHDERR_FILE_NOT_FOUND;
r14481r14482
11411126                     /* did the file open succeed? */
11421127                     if (filerr == FILERR_NONE)
11431128                     {
1129                        astring fullpath(image_file.fullpath());
1130                        image_file.close();
1131
11441132                        /* try to open the CHD */
1145                        err = chd_open_file(**image_file, CHD_OPEN_READ, NULL, image_chd);
1133                        err = image_chd.open(fullpath);
11461134                        if (err == CHDERR_NONE)
11471135                           return err;
1148
1149                        /* close the file on failure */
1150                        global_free(*image_file);
1151                        *image_file = NULL;
11521136                     }
11531137                  }
11541138   }
1155
11561139   return err;
11571140}
11581141
r14481r14482
11611144    open_disk_diff - open a DISK diff file
11621145-------------------------------------------------*/
11631146
1164static chd_error open_disk_diff(emu_options &options, const rom_entry *romp, chd_file *source, emu_file **diff_file, chd_file **diff_chd)
1147static chd_error open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd)
11651148{
11661149   astring fname(ROM_GETNAME(romp), ".dif");
1167   chd_error err;
11681150
1169   *diff_file = NULL;
1170   *diff_chd = NULL;
1171
11721151   /* try to open the diff */
11731152   LOG(("Opening differencing image file: %s\n", fname.cstr()));
1174   *diff_file = global_alloc(emu_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE));
1175   file_error filerr = (*diff_file)->open(fname);
1176   if (filerr != FILERR_NONE)
1153   emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
1154   file_error filerr = diff_file.open(fname);
1155   if (filerr == FILERR_NONE)
11771156   {
1178      /* didn't work; try creating it instead */
1179      LOG(("Creating differencing image: %s\n", fname.cstr()));
1180      (*diff_file)->set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
1181      filerr = (*diff_file)->open(fname);
1182      if (filerr != FILERR_NONE)
1183      {
1184         err = CHDERR_FILE_NOT_FOUND;
1185         goto done;
1186      }
1157      astring fullpath(diff_file.fullpath());
1158      diff_file.close();
1159   
1160      LOG(("Opening differencing image file: %s\n", fullpath.cstr()));
1161      return diff_chd.open(fullpath, true, &source);
1162   }
1163     
1164   /* didn't work; try creating it instead */
1165   LOG(("Creating differencing image: %s\n", fname.cstr()));
1166   diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
1167   filerr = diff_file.open(fname);
1168   if (filerr == FILERR_NONE)
1169   {
1170      astring fullpath(diff_file.fullpath());
1171      diff_file.close();
11871172
11881173      /* create the CHD */
1189      err = chd_create_file(**diff_file, 0, 0, CHDCOMPRESSION_NONE, source);
1174      LOG(("Creating differencing image file: %s\n", fullpath.cstr()));
1175      chd_codec_type compression[4] = { CHD_CODEC_NONE };
1176      chd_error err = diff_chd.create(fullpath, source.logical_bytes(), source.hunk_bytes(), compression, source);
11901177      if (err != CHDERR_NONE)
1191         goto done;
1178         return err;
1179     
1180      return diff_chd.clone_all_metadata(source);
11921181   }
11931182
1194   LOG(("Opening differencing image file: %s\n", fname.cstr()));
1195   err = chd_open_file(**diff_file, CHD_OPEN_READWRITE, source, diff_chd);
1196   if (err != CHDERR_NONE)
1197      goto done;
1198
1199done:
1200   if ((err != CHDERR_NONE) && (*diff_file != NULL))
1201   {
1202      global_free(*diff_file);
1203      *diff_file = NULL;
1204   }
1205   return err;
1183   return CHDERR_FILE_NOT_FOUND;
12061184}
12071185
12081186
r14481r14482
12191197      /* handle files */
12201198      if (ROMENTRY_ISFILE(romp))
12211199      {
1200         open_chd *chd = global_alloc(open_chd(regiontag));
1201         
12221202         hash_collection hashes(ROM_GETHASHDATA(romp));
1223         chd_header header;
12241203         chd_error err;
12251204
12261205         /* make the filename of the source */
12271206         astring filename(ROM_GETNAME(romp), ".chd");
12281207
12291208         /* first open the source drive */
1230         chd_file *origchd;
1231         emu_file *origfile;
12321209         LOG(("Opening disk image: %s\n", filename.cstr()));
1233         err = open_disk_image(romdata->machine().options(), &romdata->machine().system(), romp, &origfile, &origchd, locationtag);
1210         err = chd_error(open_disk_image(romdata->machine().options(), &romdata->machine().system(), romp, chd->orig_chd(), locationtag));
12341211         if (err != CHDERR_NONE)
12351212         {
12361213            if (err == CHDERR_FILE_NOT_FOUND)
12371214               romdata->errorstring.catprintf("%s NOT FOUND\n", filename.cstr());
12381215            else
1239               romdata->errorstring.catprintf("%s CHD ERROR: %s\n", filename.cstr(), chd_error_string(err));
1216               romdata->errorstring.catprintf("%s CHD ERROR: %s\n", filename.cstr(), chd_file::error_string(err));
12401217
12411218            /* if this is NO_DUMP, keep going, though the system may not be able to handle it */
12421219            if (hashes.flag(hash_collection::FLAG_NO_DUMP))
r14481r14482
12451222               romdata->warnings++;
12461223            else
12471224               romdata->errors++;
1225            global_free(chd);
12481226            continue;
12491227         }
12501228
12511229         /* get the header and extract the SHA1 */
1252         header = *chd_get_header(origchd);
12531230         hash_collection acthashes;
1254         acthashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
1231         acthashes.add_from_buffer(hash_collection::HASH_SHA1, chd->orig_chd().sha1().m_raw, sizeof(chd->orig_chd().sha1().m_raw));
12551232
12561233         /* verify the hash */
12571234         if (hashes != acthashes)
r14481r14482
12671244         }
12681245
12691246         /* if not read-only, make the diff file */
1270         chd_file *diffchd = NULL;
1271         emu_file *difffile = NULL;
12721247         if (!DISK_ISREADONLY(romp))
12731248         {
12741249            /* try to open or create the diff */
1275            err = open_disk_diff(romdata->machine().options(), romp, origchd, &difffile, &diffchd);
1250            err = open_disk_diff(romdata->machine().options(), romp, chd->orig_chd(), chd->diff_chd());
12761251            if (err != CHDERR_NONE)
12771252            {
1278               romdata->errorstring.catprintf("%s DIFF CHD ERROR: %s\n", filename.cstr(), chd_error_string(err));
1253               romdata->errorstring.catprintf("%s DIFF CHD ERROR: %s\n", filename.cstr(), chd_file::error_string(err));
12791254               romdata->errors++;
1255               global_free(chd);
12801256               continue;
12811257            }
12821258         }
12831259
12841260         /* we're okay, add to the list of disks */
12851261         LOG(("Assigning to handle %d\n", DISK_GETINDEX(romp)));
1286         romdata->machine().romload_data->chd_list.append(*global_alloc(open_chd(regiontag, *origfile, *origchd, difffile, diffchd)));
1262         romdata->machine().romload_data->chd_list.append(*chd);
12871263      }
12881264   }
12891265}
src/emu/imagedev/harddriv.c
r14481r14482
146146{
147147   int our_result;
148148
149   our_result = internal_load_hd(NULL);
149   our_result = internal_load_hd();
150150
151151   /* Check if there is an image_load callback defined */
152152   if ( m_device_image_load )
r14481r14482
161161bool harddisk_image_device::call_create(int create_format, option_resolution *create_args)
162162{
163163   int err;
164   char metadata[256];
165164   UINT32 sectorsize, hunksize;
166165   UINT32 cylinders, heads, sectors, totalsectors;
166   astring metadata;
167167
168168   cylinders   = option_resolution_lookup_int(create_args, 'C');
169169   heads      = option_resolution_lookup_int(create_args, 'H');
r14481r14482
174174   totalsectors = cylinders * heads * sectors;
175175
176176   /* create the CHD file */
177   err = chd_create_file(image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_NONE, NULL);
177   chd_codec_type compression[4] = { CHD_CODEC_NONE };
178   err = m_self_chd.create(*image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, sectorsize, compression);
178179   if (err != CHDERR_NONE)
179180      goto error;
180181
181   sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
182   return internal_load_hd(metadata);
182   /* if we created the image and hence, have metadata to set, set the metadata */
183   metadata.format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
184   err = m_self_chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
185   m_self_chd.close();
183186
187   if (err != CHDERR_NONE)
188      goto error;
189
190   return internal_load_hd();
191
184192error:
185193   return IMAGE_INIT_FAIL;
186194}
r14481r14482
201209
202210   if (m_chd != NULL)
203211   {
204      chd_close(m_chd);
212      if (m_self_chd.opened())
213         m_self_chd.close();
205214      m_chd = NULL;
206215   }
207216}
208217
209int harddisk_image_device::internal_load_hd(const char *metadata)
218int harddisk_image_device::internal_load_hd()
210219{
211220   chd_error      err = (chd_error)0;
212221   int            is_writeable;
r14481r14482
220229      do
221230      {
222231         is_writeable = !is_readonly();
223         m_chd = NULL;
224         err = chd_open_file(image_core_file(), is_writeable ? CHD_OPEN_READWRITE : CHD_OPEN_READ, NULL, &m_chd);
232         err = m_self_chd.open(*image_core_file(), is_writeable);
233         if (err == CHDERR_NONE)
234            m_chd = &m_self_chd;
225235
226236         /* special case; if we get CHDERR_FILE_NOT_WRITEABLE, make the
227237             * image read only and repeat */
r14481r14482
233243   if (!m_chd)
234244      goto done;
235245
236   /* if we created the image and hence, have metadata to set, set the metadata */
237   if (metadata)
238   {
239      err = chd_set_metadata(m_chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
240      if (err != CHDERR_NONE)
241         goto done;
242   }
243
244246   /* open the hard disk file */
245247   m_hard_disk_handle = hard_disk_open(m_chd);
246248   if (!m_hard_disk_handle)
r14481r14482
252254      /* if we had an error, close out the CHD */
253255      if (m_chd != NULL)
254256      {
255         chd_close(m_chd);
257         if (m_self_chd.opened())
258            m_self_chd.close();
256259         m_chd = NULL;
257260      }
258261
src/emu/imagedev/chd_cd.c
r14481r14482
129129
130130   if (software_entry() == NULL)
131131   {
132      if (strstr(m_image_name,".chd")) {
133         err = chd_open_file( image_core_file(), CHD_OPEN_READ, NULL, &chd );   /* CDs are never writeable */
132      if (strstr(m_image_name,".chd") && is_loaded()) {
133         err = m_self_chd.open( *image_core_file() );   /* CDs are never writeable */
134134         if ( err )
135135            goto error;
136         chd = &m_self_chd;
136137      }
137138   } else {
138139      chd  = get_disk_handle(device().machine(), device().subtag(tempstring,"cdrom"));
r14481r14482
150151   return IMAGE_INIT_PASS;
151152
152153error:
153   if ( chd )
154      chd_close( chd );
154   if ( chd && chd == &m_self_chd )
155      m_self_chd.close( );
155156   if ( err )
156157      seterror( IMAGE_ERROR_UNSPECIFIED, chd_get_error_string( err ) );
157158   return IMAGE_INIT_FAIL;
src/emu/imagedev/harddriv.h
r14481r14482
6464    virtual void device_config_complete();
6565   virtual void device_start();
6666
67   int internal_load_hd(const char *metadata);
67   int internal_load_hd();
6868
6969   chd_file      *m_chd;
70   chd_file      m_self_chd;
7071   hard_disk_file   *m_hard_disk_handle;
7172
7273   image_device_format m_format;
src/emu/imagedev/chd_cd.h
r14481r14482
5757    virtual void device_config_complete();
5858   virtual void device_start();
5959
60   chd_file   m_self_chd;
6061   cdrom_file   *m_cdrom_handle;
6162   image_device_format m_format;
6263};
src/emu/romload.h
r14481r14482
121121
122122class machine_config;
123123class emu_options;
124class chd_file;
124125
125126typedef device_t rom_source;
126127
r14481r14482
315316/* ----- disk handling ----- */
316317
317318/* open a disk image, searching up the parent and loading by checksum */
318chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd,const char *locationtag);
319int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, chd_file &image_chd, const char *locationtag);
319320
320321/* return a pointer to the CHD file associated with the given region */
321322chd_file *get_disk_handle(running_machine &machine, const char *region);
322323
323324/* set a pointer to the CHD file associated with the given region */
324void set_disk_handle(running_machine &machine, const char *region, emu_file &file, chd_file &chdfile);
325int set_disk_handle(running_machine &machine, const char *region, const char *fullpath);
325326
326327void load_software_part_region(device_t *device, char *swlist, char *swname, rom_entry *start_region);
327328
src/emu/audit.c
r14481r14482
436436   audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_DISK)));
437437
438438   // open the disk
439   emu_file *source_file;
440   chd_file *source;
441   chd_error err = open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, &source_file, &source, NULL);
439   chd_file source;
440   chd_error err = chd_error(open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, source, NULL));
442441
443442   // if we succeeded, get the hashes
444443   if (err == CHDERR_NONE)
445444   {
446      static const UINT8 nullhash[20] = { 0 };
447      chd_header header = *chd_get_header(source);
448445      hash_collection hashes;
449446
450447      // if there's a SHA1 hash, add them to the output hash
451      if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
452         hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
448      if (source.sha1() != sha1_t::null)
449         hashes.add_from_buffer(hash_collection::HASH_SHA1, source.sha1().m_raw, sizeof(source.sha1().m_raw));
453450
454451      // update the actual values
455452      record.set_actual(hashes);
456
457      // close the file and release the source
458      chd_close(source);
459      global_free(source_file);
460453   }
461454
462455   // compute the final status
src/emu/machine/idectrl.c
r14481r14482
14761476               }
14771477               else if (ide->command == IDE_COMMAND_TAITO_GNET_UNLOCK_2)
14781478               {
1479                  UINT8 key[5] = { 0, 0, 0, 0, 0 };
1479                  UINT8 key[5] = { 0 };
14801480                  int i, bad = 0;
14811481                  ide->drive[ide->cur_drive].slot->read_key(key);
14821482
r14481r14482
20732073         mame_printf_debug("CHS: %d %d %d\n", m_num_cylinders, m_num_heads, m_num_sectors);
20742074      }
20752075      // build the features page
2076      if (chd_get_metadata (m_handle, HARD_DISK_IDENT_METADATA_TAG, 0, m_features, IDE_DISK_SECTOR_SIZE, 0, 0, 0) != CHDERR_NONE)
2076      UINT32 metalength;
2077      if (m_handle->read_metadata (HARD_DISK_IDENT_METADATA_TAG, 0, m_features, IDE_DISK_SECTOR_SIZE, metalength) != CHDERR_NONE)
20772078         ide_build_features();
20782079   }   
20792080}
r14481r14482
20842085
20852086void ide_hdd_device::read_key(UINT8 key[])
20862087{
2087   chd_get_metadata(m_handle, HARD_DISK_KEY_METADATA_TAG, 0, key, 5, 0, 0, 0);
2088   UINT32 metalength;
2089   m_handle->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, key, 5, metalength);
20882090}
20892091
20902092//**************************************************************************
r14481r14482
21362138            if (PRINTF_IDE_COMMANDS) printf("CHS: %d %d %d\n", m_num_cylinders, m_num_heads, m_num_sectors);
21372139         }
21382140         // build the features page
2139         if (chd_get_metadata (m_handle, HARD_DISK_IDENT_METADATA_TAG, 0, m_features, IDE_DISK_SECTOR_SIZE, 0, 0, 0) != CHDERR_NONE)
2141         UINT32 metalength;
2142         if (m_handle->read_metadata (HARD_DISK_IDENT_METADATA_TAG, 0, m_features, IDE_DISK_SECTOR_SIZE, metalength) != CHDERR_NONE)
21402143            ide_build_features();
21412144      }
21422145   }
src/emu/machine/laserdsc.c
r14481r14482
3939
4040#include "emu.h"
4141#include "laserdsc.h"
42#include "avcomp.h"
42#include "avhuff.h"
4343#include "vbiparse.h"
4444#include "config.h"
4545#include "render.h"
46#include "chd.h"
4647
4748
4849
r14481r14482
9394     m_overheight(0),
9495     m_overclip(0, -1, 0, -1),
9596     m_disc(NULL),
96     m_vbidata(NULL),
9797     m_width(0),
9898     m_height(0),
9999     m_fps_times_1million(0),
100100     m_samplerate(0),
101101     m_readresult(CHDERR_NONE),
102102     m_chdtracks(0),
103     m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO)),
103104     m_audiosquelch(0),
104105     m_videosquelch(0),
105106     m_fieldnum(0),
r14481r14482
134135
135136laserdisc_device::~laserdisc_device()
136137{
138   osd_work_queue_free(m_work_queue);
137139}
138140
139141
r14481r14482
362364{
363365   // make sure all async operations have completed
364366   if (m_disc != NULL)
365      chd_async_complete(m_disc);
367      osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10);
366368
367369   // free any textures and palettes
368370   if (m_videotex != NULL)
r14481r14482
767769   m_maxtrack = VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS + VIRTUAL_LEAD_OUT_TRACKS;
768770   if (m_disc != NULL)
769771   {
770      // require the A/V codec
771      if (chd_get_header(m_disc)->compression != CHDCOMPRESSION_AV)
772      // require the A/V codec and nothing else
773      if (m_disc->compression(0) != CHD_CODEC_AVHUFF || m_disc->compression(1) != CHD_CODEC_NONE)
772774         throw emu_fatalerror("Laserdisc video must be compressed with the A/V codec!");
773775
774776      // read the metadata
775      char metadata[256];
776      chd_error err = chd_get_metadata(m_disc, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
777      astring metadata;
778      chd_error err = m_disc->read_metadata(AV_METADATA_TAG, 0, metadata);
777779      if (err != CHDERR_NONE)
778780         throw emu_fatalerror("Non-A/V CHD file specified");
779781
r14481r14482
789791         throw emu_fatalerror("Laserdisc video must be interlaced!");
790792
791793      // determine the maximum track and allocate a frame buffer
792      UINT32 totalhunks = chd_get_header(m_disc)->totalhunks;
794      UINT32 totalhunks = m_disc->hunk_count();
793795      m_chdtracks = totalhunks / 2;
794796
795797      // allocate memory for the precomputed per-frame metadata
796      m_vbidata = auto_alloc_array(machine(), UINT8, totalhunks * VBI_PACKED_BYTES);
797      UINT32 vbilength;
798      err = chd_get_metadata(m_disc, AV_LD_METADATA_TAG, 0, m_vbidata, totalhunks * VBI_PACKED_BYTES, &vbilength, NULL, NULL);
799      if (err != CHDERR_NONE || vbilength != totalhunks * VBI_PACKED_BYTES)
798      err = m_disc->read_metadata(AV_LD_METADATA_TAG, 0, m_vbidata);
799      if (err != CHDERR_NONE || m_vbidata.count() != totalhunks * VBI_PACKED_BYTES)
800800         throw emu_fatalerror("Precomputed VBI metadata missing or incorrect size");
801801   }
802802   m_maxtrack = MAX(m_maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + m_chdtracks);
r14481r14482
10111011
10121012   // cheat and look up the metadata we are about to retrieve
10131013   vbi_metadata vbidata = { 0 };
1014   if (m_vbidata != NULL)
1014   if (m_vbidata.count() != 0)
10151015      vbi_metadata_unpack(&vbidata, NULL, &m_vbidata[readhunk * VBI_PACKED_BYTES]);
10161016
10171017   // if we're in the lead-in area, force the VBI data to be standard lead-in
r14481r14482
10401040   frame->m_lastfield = m_curtrack * 2 + m_fieldnum;
10411041
10421042   // set the video target information
1043   m_avconfig.video.wrap(&frame->m_bitmap.pix16(m_fieldnum), frame->m_bitmap.width(), frame->m_bitmap.height() / 2, frame->m_bitmap.rowpixels() * 2);
1043   m_avhuff_config.video.wrap(&frame->m_bitmap.pix16(m_fieldnum), frame->m_bitmap.width(), frame->m_bitmap.height() / 2, frame->m_bitmap.rowpixels() * 2);
10441044
10451045   // set the audio target information
10461046   if (m_audiobufin + m_audiomaxsamples <= m_audiobufsize)
10471047   {
10481048      // if we can fit without wrapping, just read the data directly
1049      m_avconfig.audio[0] = &m_audiobuffer[0][m_audiobufin];
1050      m_avconfig.audio[1] = &m_audiobuffer[1][m_audiobufin];
1049      m_avhuff_config.audio[0] = &m_audiobuffer[0][m_audiobufin];
1050      m_avhuff_config.audio[1] = &m_audiobuffer[1][m_audiobufin];
10511051   }
10521052   else
10531053   {
10541054      // otherwise, read to the beginning of the buffer
1055      m_avconfig.audio[0] = &m_audiobuffer[0][0];
1056      m_avconfig.audio[1] = &m_audiobuffer[1][0];
1055      m_avhuff_config.audio[0] = &m_audiobuffer[0][0];
1056      m_avhuff_config.audio[1] = &m_audiobuffer[1][0];
10571057   }
10581058
10591059   // override if we're not decoding
1060   m_avconfig.maxsamples = m_audiomaxsamples;
1061   m_avconfig.actsamples = &m_audiocursamples;
1060   m_avhuff_config.maxsamples = m_audiomaxsamples;
1061   m_avhuff_config.actsamples = &m_audiocursamples;
10621062   m_audiocursamples = 0;
10631063
10641064   // set the VBI data for the new field from our precomputed data
1065   if (m_vbidata != NULL)
1065   if (m_vbidata.count() != 0)
10661066   {
10671067      UINT32 vbiframe;
10681068      vbi_metadata_unpack(&m_metadata[m_fieldnum], &vbiframe, &m_vbidata[readhunk * VBI_PACKED_BYTES]);
r14481r14482
10791079   m_readresult = CHDERR_FILE_NOT_FOUND;
10801080   if (m_disc != NULL && !m_videosquelch)
10811081   {
1082      m_readresult = chd_codec_config(m_disc, AV_CODEC_DECOMPRESS_CONFIG, &m_avconfig);
1082      m_readresult = m_disc->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &m_avhuff_config);
10831083      if (m_readresult == CHDERR_NONE)
1084         m_readresult = chd_read_async(m_disc, readhunk, NULL);
1084      {
1085         m_queued_hunknum = readhunk;
1086         m_readresult = CHDERR_OPERATION_PENDING;
1087         osd_work_item_queue(m_work_queue, read_async_static, this, WORK_ITEM_FLAG_AUTO_RELEASE);
1088      }
10851089   }
10861090}
10871091
10881092
10891093//-------------------------------------------------
1094//  read_async_static - work item callback for
1095//  asynchronous reads
1096//-------------------------------------------------
1097
1098void *laserdisc_device::read_async_static(void *param, int threadid)
1099{
1100   laserdisc_device &ld = *reinterpret_cast<laserdisc_device *>(param);
1101   ld.m_readresult = ld.m_disc->read_hunk(ld.m_queued_hunknum, NULL);
1102   return NULL;
1103}
1104
1105
1106//-------------------------------------------------
10901107//  process_track_data - process data from a
10911108//  track after it has been read
10921109//-------------------------------------------------
r14481r14482
10951112{
10961113   // wait for the async operation to complete
10971114   if (m_readresult == CHDERR_OPERATION_PENDING)
1098      m_readresult = chd_async_complete(m_disc);
1115      osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10);
1116   assert(m_readresult != CHDERR_OPERATION_PENDING);
10991117
11001118   // remove the video if we had an error
11011119   if (m_readresult != CHDERR_NONE)
1102      m_avconfig.video.reset();
1120      m_avhuff_config.video.reset();
11031121
11041122   // count the field as read if we are successful
1105   if (m_avconfig.video.valid())
1123   if (m_avhuff_config.video.valid())
11061124   {
11071125      m_frame[m_videoindex].m_numfields++;
1108      player_overlay(m_avconfig.video);
1126      player_overlay(m_avhuff_config.video);
11091127   }
11101128
11111129   // pass the audio to the callback
11121130   if (!m_audio_callback.isnull())
1113      m_audio_callback(*this, m_samplerate, m_audiocursamples, m_avconfig.audio[0], m_avconfig.audio[1]);
1131      m_audio_callback(*this, m_samplerate, m_audiocursamples, m_avhuff_config.audio[0], m_avhuff_config.audio[1]);
11141132
11151133   // shift audio data if we read it into the beginning of the buffer
11161134   if (m_audiocursamples != 0 && m_audiobufin != 0)
11171135      for (int chnum = 0; chnum < 2; chnum++)
1118         if (m_avconfig.audio[chnum] == &m_audiobuffer[chnum][0])
1136         if (m_avhuff_config.audio[chnum] == &m_audiobuffer[chnum][0])
11191137         {
11201138            // move data to the end
11211139            int samplesleft = m_audiobufsize - m_audiobufin;
src/emu/machine/laserdsc.h
r14481r14482
4343#define __LASERDSC_H__
4444
4545#include "vbiparse.h"
46#include "avhuff.h"
4647
4748
4849//**************************************************************************
r14481r14482
315316   void vblank_state_changed(screen_device &screen, bool vblank_state);
316317   frame_data &current_frame();
317318   void read_track_data();
319   static void *read_async_static(void *param, int threadid);
318320   void process_track_data();
319321   void config_load(int config_type, xml_data_node *parentnode);
320322   void config_save(int config_type, xml_data_node *parentnode);
r14481r14482
332334
333335   // disc parameters
334336   chd_file *         m_disc;               // handle to the disc itself
335   UINT8 *            m_vbidata;            // pointer to precomputed VBI data
337   dynamic_buffer      m_vbidata;            // pointer to precomputed VBI data
336338   int               m_width;            // width of video
337339   int               m_height;            // height of video
338340   UINT32            m_fps_times_1million;   // frame rate of video
339341   int               m_samplerate;         // audio samplerate
340   chd_error         m_readresult;         // result of the most recent read
342   int               m_readresult;         // result of the most recent read
341343   UINT32            m_chdtracks;         // number of tracks in the CHD
342   av_codec_decompress_config m_avconfig;      // decompression configuration
344   avhuff_decompress_config m_avhuff_config;   // decompression configuration
343345
346   // async operations
347   osd_work_queue *   m_work_queue;         // work queue
348   UINT32            m_queued_hunknum;      // queued hunk
349
344350   // core states
345351   UINT8            m_audiosquelch;         // audio squelch state: bit 0 = audio 1, bit 1 = audio 2
346352   UINT8            m_videosquelch;         // video squelch state: bit 0 = on/off
src/lib/lib7z/LzmaDec.c
r14481r14482
967967  return SZ_OK;
968968}
969969 
970// why isn't there an interface to pass in the properties directly????
971SRes LzmaDec_Allocate_MAME(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
972{
973  SizeT dicBufSize;
974  RINOK(LzmaDec_AllocateProbs2(p, propNew, alloc));
975  dicBufSize = propNew->dicSize;
976  if (p->dic == 0 || dicBufSize != p->dicBufSize)
977  {
978    LzmaDec_FreeDict(p, alloc);
979    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
980    if (p->dic == 0)
981    {
982      LzmaDec_FreeProbs(p, alloc);
983      return SZ_ERROR_MEM;
984    }
985  }
986  p->dicBufSize = dicBufSize;
987  p->prop = *propNew;
988  return SZ_OK;
989}
990 
970991SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
971992    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
972993    ELzmaStatus *status, ISzAlloc *alloc)
src/lib/lib7z/Ppmd7.c
r14481r14482
222010-03-12 : Igor Pavlov : Public domain
33This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
44 
5#include <memory.h>
5#include <string.h>
66 
77#include "Ppmd7.h"
88 
src/lib/lib.mak
r14481r14482
3232
3333UTILOBJS = \
3434   $(LIBOBJ)/util/astring.o \
35   $(LIBOBJ)/util/avcomp.o \
35   $(LIBOBJ)/util/avhuff.o \
3636   $(LIBOBJ)/util/aviio.o \
3737   $(LIBOBJ)/util/bitmap.o \
3838   $(LIBOBJ)/util/cdrom.o \
3939   $(LIBOBJ)/util/chd.o \
4040   $(LIBOBJ)/util/chdcd.o \
41   $(LIBOBJ)/util/chdcodec.o \
4142   $(LIBOBJ)/util/corefile.o \
4243   $(LIBOBJ)/util/corestr.o \
4344   $(LIBOBJ)/util/coreutil.o \
45   $(LIBOBJ)/util/flac.o \
4446   $(LIBOBJ)/util/harddisk.o \
47   $(LIBOBJ)/util/hashing.o \
4548   $(LIBOBJ)/util/huffman.o \
4649   $(LIBOBJ)/util/jedparse.o \
4750   $(LIBOBJ)/util/md5.o \
r14481r14482
7376
7477$(OBJ)/libexpat.a: $(EXPATOBJS)
7578
76$(LIBOBJ)/expat/%.o: $(LIBSRC)/explat/%.c | $(OSPREBUILD)
79$(LIBOBJ)/expat/%.o: $(LIBSRC)/expat/%.c | $(OSPREBUILD)
7780   @echo Compiling $<...
7881   $(CC) $(CDEFS) $(CCOMFLAGS) $(CONLYFLAGS) -c $< -o $@
7982
r14481r14482
273276   $(CC) $(CDEFS) $(CCOMFLAGS) $(CONLYFLAGS) -I$(LIBSRC)/libjpeg -c $< -o $@
274277
275278
279
276280#-------------------------------------------------
277281# libflac library objects
278282#-------------------------------------------------
r14481r14482
303307   $(CC) $(CDEFS) $(FLACOPTS) $(CONLYFLAGS) -I$(LIBSRC)/libflac/include -c $< -o $@
304308
305309
306# LIBFLACPPOBJS = \
307#   $(LIBOBJ)/libflacpp/metadata.o \
308#   $(LIBOBJ)/libflacpp/stream_decoder.o \
309#   $(LIBOBJ)/libflacpp/stream_encoder.o
310310
311# $(OBJ)/libflac++.a: $(LIBFLACPPOBJS)
312
313# $(LIBOBJ)/libflacpp/%.o: $(LIBSRC)/libflac/libflac++/%.cpp | $(OSPREBUILD)
314#    @echo Compiling $<...
315#   $(CC) $(CDEFS) $(FLACOPTS) $(CPPONLYFLAGS) -I$(LIBSRC)/libflac/include -c $< -o $@
316
317
318311#-------------------------------------------------
319312# lib7z library objects
320313#-------------------------------------------------
321314
3227ZOPTS=-D_7ZIP_PPMD_SUPPPORT
3157ZOPTS=-D_7ZIP_PPMD_SUPPPORT -D_7ZIP_ST
323316
324317LIB7ZOBJS = \
325318   $(LIBOBJ)/lib7z/7zBuf.o \
r14481r14482
331324   $(LIBOBJ)/lib7z/CpuArch.o \
332325   $(LIBOBJ)/lib7z/LzmaDec.o \
333326   $(LIBOBJ)/lib7z/Lzma2Dec.o \
327   $(LIBOBJ)/lib7z/LzmaEnc.o \
328   $(LIBOBJ)/lib7z/Lzma2Enc.o \
329   $(LIBOBJ)/lib7z/LzFind.o \
334330   $(LIBOBJ)/lib7z/Bra.o \
335331   $(LIBOBJ)/lib7z/Bra86.o \
336332   $(LIBOBJ)/lib7z/Bcj2.o \
r14481r14482
343339$(LIBOBJ)/lib7z/%.o: $(LIBSRC)/lib7z/%.c | $(OSPREBUILD)
344340   @echo Compiling $<...
345341   $(CC) $(CDEFS) $(7ZOPTS) $(CONLYFLAGS) -I$(LIBSRC)/lib7z/ -c $< -o $@
346
347
348
src/lib/util/avcomp.c
r14481r14482
1/***************************************************************************
2
3    avcomp.c
4
5    Audio/video compression and decompression helpers.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38****************************************************************************
39
40    Each frame is compressed as a unit. The raw data is of the form:
41    (all multibyte values are stored in big-endian format)
42
43        +00 = 'chav' (4 bytes) - fixed header data to identify the format
44        +04 = metasize (1 byte) - size of metadata in bytes (max=255 bytes)
45        +05 = channels (1 byte) - number of audio channels
46        +06 = samples (2 bytes) - number of samples per audio stream
47        +08 = width (2 bytes) - width of video data
48        +0A = height (2 bytes) - height of video data
49        +0C = <metadata> - as raw bytes
50              <audio stream 0> - as signed 16-bit samples
51              <audio stream 1> - as signed 16-bit samples
52              ...
53              <video data> - as a raw array of 8-bit YUY data in (Cb,Y,Cr,Y) order
54
55    When compressed, the data is stored as follows:
56    (all multibyte values are stored in big-endian format)
57
58        +00 = metasize (1 byte) - size of metadata in bytes
59        +01 = channels (1 byte) - number of audio channels
60        +02 = samples (2 bytes) - number of samples per audio stream
61        +04 = width (2 bytes) - width of video data
62        +06 = height (2 bytes) - height of video data
63        +08 = audio huffman size (2 bytes) - size of audio huffman tables
64        +0A = str0size (2 bytes) - compressed size of stream 0
65        +0C = str1size (2 bytes) - compressed size of stream 1
66              ...
67              <metadata> - as raw data
68              <audio huffman table> - Huffman table for audio decoding
69              <audio stream 0 data> - Huffman-compressed deltas
70              <audio stream 1 data> - Huffman-compressed deltas
71              <...>
72              <video huffman tables> - Huffman tables for video decoding
73              <video data> - compressed data
74
75****************************************************************************
76
77    Attempted techniques that have not been worthwhile:
78
79    * Attempted to use integer DCTs from the IJG code; even the "slow"
80      variants produce a lot of error and thus kill our compression ratio,
81      since our compression is based on error not bitrate.
82
83    * Tried various other predictors for the lossless video encoding, but
84      none tended to give any significant gain over predicting the
85      previous pixel.
86
87***************************************************************************/
88
89#include "avcomp.h"
90#include "huffman.h"
91#include "chd.h"
92
93#include <math.h>
94#include <stdlib.h>
95#include <new>
96
97
98/***************************************************************************
99    CONSTANTS
100***************************************************************************/
101
102#define MAX_CHANNELS   4
103
104
105
106/***************************************************************************
107    TYPE DEFINITIONS
108***************************************************************************/
109
110struct avcomp_state
111{
112   avcomp_state()
113      : maxwidth(0),
114        maxheight(0),
115        maxchannels(0),
116        audiodata(NULL),
117        ycontext(NULL),
118        cbcontext(NULL),
119        crcontext(NULL),
120        audiohicontext(NULL),
121        audiolocontext(NULL) { }
122
123   /* video parameters */
124   UINT32            maxwidth, maxheight;
125
126   /* audio parameters */
127   UINT32            maxchannels;
128
129   /* intermediate data */
130   UINT8 *            audiodata;
131
132   /* huffman contexts */
133   huffman_context *   ycontext;
134   huffman_context *   cbcontext;
135   huffman_context *   crcontext;
136   huffman_context *   audiohicontext;
137   huffman_context *   audiolocontext;
138
139   /* configuration data */
140   av_codec_compress_config compress;
141   av_codec_decompress_config decompress;
142};
143
144
145
146/***************************************************************************
147    PROTOTYPES
148***************************************************************************/
149
150/* encoding helpers */
151static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 **source, int sourcexor, UINT8 *dest, UINT8 *sizes);
152static avcomp_error encode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength);
153static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength);
154
155/* decoding helpers */
156static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes);
157static avcomp_error decode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor);
158static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor);
159
160
161
162/***************************************************************************
163    IMPLEMENTATION
164***************************************************************************/
165
166/*-------------------------------------------------
167    avcomp_init - allocate and initialize a
168    new state block for compression or
169    decompression
170-------------------------------------------------*/
171
172avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels)
173{
174   huffman_error hufferr;
175   avcomp_state *state;
176
177   /* error if out of range */
178   if (maxchannels > MAX_CHANNELS)
179      return NULL;
180
181   /* allocate memory for state block */
182   state = new(std::nothrow) avcomp_state;
183   if (state == NULL)
184      return NULL;
185
186   /* compute the core info */
187   state->maxwidth = maxwidth;
188   state->maxheight = maxheight;
189   state->maxchannels = maxchannels;
190
191   /* now allocate data buffers */
192   state->audiodata = new(std::nothrow) UINT8[65536 * state->maxchannels * 2];
193   if (state->audiodata == NULL)
194      goto cleanup;
195
196   /* create huffman contexts */
197   hufferr = huffman_create_context(&state->ycontext, 16);
198   if (hufferr != HUFFERR_NONE)
199      goto cleanup;
200   hufferr = huffman_create_context(&state->cbcontext, 16);
201   if (hufferr != HUFFERR_NONE)
202      goto cleanup;
203   hufferr = huffman_create_context(&state->crcontext, 16);
204   if (hufferr != HUFFERR_NONE)
205      goto cleanup;
206   hufferr = huffman_create_context(&state->audiohicontext, 16);
207   if (hufferr != HUFFERR_NONE)
208      goto cleanup;
209   hufferr = huffman_create_context(&state->audiolocontext, 16);
210   if (hufferr != HUFFERR_NONE)
211      goto cleanup;
212
213   return state;
214
215cleanup:
216   avcomp_free(state);
217   return NULL;
218}
219
220
221/*-------------------------------------------------
222    avcomp_free - free a state block
223-------------------------------------------------*/
224
225void avcomp_free(avcomp_state *state)
226{
227   /* free the data buffers */
228   delete[] state->audiodata;
229
230   /* free the contexts */
231   if (state->ycontext != NULL)
232      huffman_free_context(state->ycontext);
233   if (state->cbcontext != NULL)
234      huffman_free_context(state->cbcontext);
235   if (state->crcontext != NULL)
236      huffman_free_context(state->crcontext);
237   if (state->audiohicontext != NULL)
238      huffman_free_context(state->audiohicontext);
239   if (state->audiolocontext != NULL)
240      huffman_free_context(state->audiolocontext);
241
242   delete state;
243}
244
245
246/*-------------------------------------------------
247    avcomp_config_compress - configure compression
248    parameters
249-------------------------------------------------*/
250
251void avcomp_config_compress(avcomp_state *state, av_codec_compress_config *config)
252{
253   state->compress.video.wrap(config->video, config->video.cliprect());
254   state->compress.channels = config->channels;
255   state->compress.samples = config->samples;
256   memcpy(state->compress.audio, config->audio, sizeof(state->compress.audio));
257   state->compress.metalength = config->metalength;
258   state->compress.metadata = config->metadata;
259}
260
261
262/*-------------------------------------------------
263    avcomp_config_decompress - configure
264    decompression parameters
265-------------------------------------------------*/
266
267void avcomp_config_decompress(avcomp_state *state, av_codec_decompress_config *config)
268{
269   state->decompress.video.wrap(config->video, config->video.cliprect());
270   state->decompress.maxsamples = config->maxsamples;
271   state->decompress.actsamples = config->actsamples;
272   memcpy(state->decompress.audio, config->audio, sizeof(state->decompress.audio));
273   state->decompress.maxmetalength = config->maxmetalength;
274   state->decompress.actmetalength = config->actmetalength;
275   state->decompress.metadata = config->metadata;
276}
277
278
279
280/***************************************************************************
281    ENCODING/DECODING FRONTENDS
282***************************************************************************/
283
284/*-------------------------------------------------
285    avcomp_encode_data - encode a block of data
286    into a compressed data stream
287-------------------------------------------------*/
288
289avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength)
290{
291   const UINT8 *metastart, *videostart, *audiostart[MAX_CHANNELS];
292   UINT32 metasize, channels, samples, width, height;
293   UINT32 audioxor, videoxor, videostride;
294   avcomp_error err;
295   UINT32 dstoffs;
296   int chnum;
297
298   /* extract data from source if present */
299   if (source != NULL)
300   {
301      /* validate the header */
302      if (source[0] != 'c' || source[1] != 'h' || source[2] != 'a' || source[3] != 'v')
303         return AVCERR_INVALID_DATA;
304
305      /* extract info from the header */
306      metasize = source[4];
307      channels = source[5];
308      samples = (source[6] << 8) + source[7];
309      width = (source[8] << 8) + source[9];
310      height = (source[10] << 8) + source[11];
311
312      /* determine the start of each piece of data */
313      source += 12;
314      metastart = source;
315      source += metasize;
316      for (chnum = 0; chnum < channels; chnum++)
317      {
318         audiostart[chnum] = source;
319         source += 2 * samples;
320      }
321      videostart = source;
322
323      /* data is assumed to be big-endian already */
324      audioxor = videoxor = 0;
325      videostride = 2 * width;
326   }
327
328   /* otherwise, extract from the state */
329   else
330   {
331      UINT16 betest = 0;
332
333      /* extract metadata information */
334      metastart = state->compress.metadata;
335      metasize = state->compress.metalength;
336      if ((metastart == NULL && metasize != 0) || (metastart != NULL && metasize == 0))
337         return AVCERR_INVALID_CONFIGURATION;
338
339      /* extract audio information */
340      channels = state->compress.channels;
341      samples = state->compress.samples;
342      for (chnum = 0; chnum < channels; chnum++)
343         audiostart[chnum] = (const UINT8 *)state->compress.audio[chnum];
344
345      /* extract video information */
346      videostart = NULL;
347      videostride = width = height = 0;
348      if (state->compress.video.valid())
349      {
350         videostart = reinterpret_cast<const UINT8 *>(&state->compress.video.pix(0));
351         videostride = state->compress.video.rowpixels() * 2;
352         width = state->compress.video.width();
353         height = state->compress.video.height();
354      }
355
356      /* data is assumed to be native-endian */
357      *(UINT8 *)&betest = 1;
358      audioxor = videoxor = (betest == 1) ? 1 : 0;
359   }
360
361   /* validate the info from the header */
362   if (width > state->maxwidth || height > state->maxheight)
363      return AVCERR_VIDEO_TOO_LARGE;
364   if (channels > state->maxchannels)
365      return AVCERR_AUDIO_TOO_LARGE;
366
367   /* write the basics to the new header */
368   dest[0] = metasize;
369   dest[1] = channels;
370   dest[2] = samples >> 8;
371   dest[3] = samples;
372   dest[4] = width >> 8;
373   dest[5] = width;
374   dest[6] = height >> 8;
375   dest[7] = height;
376
377   /* starting offsets */
378   dstoffs = 10 + 2 * channels;
379
380   /* copy the metadata first */
381   if (metasize > 0)
382   {
383      memcpy(dest + dstoffs, metastart, metasize);
384      dstoffs += metasize;
385   }
386
387   /* encode the audio channels */
388   if (channels > 0)
389   {
390      /* encode the audio */
391      err = encode_audio(state, channels, samples, audiostart, audioxor, dest + dstoffs, &dest[8]);
392      if (err != AVCERR_NONE)
393         return err;
394
395      /* advance the pointers past the data */
396      dstoffs += (dest[8] << 8) + dest[9];
397      for (chnum = 0; chnum < channels; chnum++)
398         dstoffs += (dest[10 + 2 * chnum] << 8) + dest[11 + 2 * chnum];
399   }
400
401   /* encode the video data */
402   if (width > 0 && height > 0)
403   {
404      UINT32 vidlength = 0;
405
406      /* encode the video */
407      err = encode_video(state, width, height, videostart, videostride, videoxor, dest + dstoffs, &vidlength);
408      if (err != AVCERR_NONE)
409         return err;
410
411      /* advance the pointers past the data */
412      dstoffs += vidlength;
413   }
414
415   /* set the total compression */
416   *complength = dstoffs;
417   return AVCERR_NONE;
418}
419
420
421/*-------------------------------------------------
422    avcomp_decode_data - decode both
423    audio and video from a raw data stream
424-------------------------------------------------*/
425
426avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest)
427{
428   UINT8 *metastart, *videostart, *audiostart[MAX_CHANNELS];
429   UINT32 metasize, channels, samples, width, height;
430   UINT32 audioxor, videoxor, videostride;
431   UINT32 srcoffs, totalsize;
432   avcomp_error err;
433   int chnum;
434
435   /* extract info from the header */
436   if (complength < 8)
437      return AVCERR_INVALID_DATA;
438   metasize = source[0];
439   channels = source[1];
440   samples = (source[2] << 8) + source[3];
441   width = (source[4] << 8) + source[5];
442   height = (source[6] << 8) + source[7];
443
444   /* validate the info from the header */
445   if (width > state->maxwidth || height > state->maxheight)
446      return AVCERR_VIDEO_TOO_LARGE;
447   if (channels > state->maxchannels)
448      return AVCERR_AUDIO_TOO_LARGE;
449
450   /* validate that the sizes make sense */
451   if (complength < 10 + 2 * channels)
452      return AVCERR_INVALID_DATA;
453   totalsize = 10 + 2 * channels;
454   totalsize += (source[8] << 8) | source[9];
455   for (chnum = 0; chnum < channels; chnum++)
456      totalsize += (source[10 + 2 * chnum] << 8) | source[11 + 2 * chnum];
457   if (totalsize >= complength)
458      return AVCERR_INVALID_DATA;
459
460   /* starting offsets */
461   srcoffs = 10 + 2 * channels;
462
463   /* if we are decoding raw, set up the output parameters */
464   if (dest != NULL)
465   {
466      /* create a header */
467      dest[0] = 'c';
468      dest[1] = 'h';
469      dest[2] = 'a';
470      dest[3] = 'v';
471      dest[4] = metasize;
472      dest[5] = channels;
473      dest[6] = samples >> 8;
474      dest[7] = samples;
475      dest[8] = width >> 8;
476      dest[9] = width;
477      dest[10] = height >> 8;
478      dest[11] = height;
479
480      /* determine the start of each piece of data */
481      dest += 12;
482      metastart = dest;
483      dest += metasize;
484      for (chnum = 0; chnum < channels; chnum++)
485      {
486         audiostart[chnum] = dest;
487         dest += 2 * samples;
488      }
489      videostart = dest;
490
491      /* data is assumed to be big-endian already */
492      audioxor = videoxor = 0;
493      videostride = 2 * width;
494   }
495
496   /* otherwise, extract from the state */
497   else
498   {
499      UINT16 betest = 0;
500
501      /* determine the start of each piece of data */
502      metastart = state->decompress.metadata;
503      for (chnum = 0; chnum < channels; chnum++)
504         audiostart[chnum] = (UINT8 *)state->decompress.audio[chnum];
505      videostart = (state->decompress.video.valid()) ? reinterpret_cast<UINT8 *>(&state->decompress.video.pix(0)) : NULL;
506      videostride = (state->decompress.video.valid()) ? state->decompress.video.rowpixels() * 2 : 0;
507
508      /* data is assumed to be native-endian */
509      *(UINT8 *)&betest = 1;
510      audioxor = videoxor = (betest == 1) ? 1 : 0;
511
512      /* verify against sizes */
513      if (state->decompress.video.valid() && (state->decompress.video.width() < width || state->decompress.video.height() < height))
514         return AVCERR_VIDEO_TOO_LARGE;
515      for (chnum = 0; chnum < channels; chnum++)
516         if (state->decompress.audio[chnum] != NULL && state->decompress.maxsamples < samples)
517            return AVCERR_AUDIO_TOO_LARGE;
518      if (state->decompress.metadata != NULL && state->decompress.maxmetalength < metasize)
519         return AVCERR_METADATA_TOO_LARGE;
520
521      /* set the output values */
522      if (state->decompress.actsamples != NULL)
523         *state->decompress.actsamples = samples;
524      if (state->decompress.actmetalength != NULL)
525         *state->decompress.actmetalength = metasize;
526   }
527
528   /* copy the metadata first */
529   if (metasize > 0)
530   {
531      if (metastart != NULL)
532         memcpy(metastart, source + srcoffs, metasize);
533      srcoffs += metasize;
534   }
535
536   /* decode the audio channels */
537   if (channels > 0)
538   {
539      /* decode the audio */
540      err = decode_audio(state, channels, samples, source + srcoffs, audiostart, audioxor, &source[8]);
541      if (err != AVCERR_NONE)
542         return err;
543
544      /* advance the pointers past the data */
545      srcoffs += (source[8] << 8) + source[9];
546      for (chnum = 0; chnum < channels; chnum++)
547         srcoffs += (source[10 + 2 * chnum] << 8) + source[11 + 2 * chnum];
548   }
549
550   /* decode the video data */
551   if (width > 0 && height > 0 && videostart != NULL)
552   {
553      /* decode the video */
554      err = decode_video(state, width, height, source + srcoffs, complength - srcoffs, videostart, videostride, videoxor);
555      if (err != AVCERR_NONE)
556         return err;
557   }
558   return AVCERR_NONE;
559}
560
561
562
563/***************************************************************************
564    ENCODING HELPERS
565***************************************************************************/
566
567/*-------------------------------------------------
568    encode_audio - encode raw audio data
569    to the destination
570-------------------------------------------------*/
571
572static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 **source, int sourcexor, UINT8 *dest, UINT8 *sizes)
573{
574   UINT32 size, huffsize, totalsize;
575   huffman_context *contexts[2];
576   huffman_error hufferr;
577   UINT8 *output = dest;
578   int chnum, sampnum;
579   UINT8 *deltabuf;
580
581   /* iterate over channels to compute deltas */
582   deltabuf = state->audiodata;
583   for (chnum = 0; chnum < channels; chnum++)
584   {
585      const UINT8 *srcdata = source[chnum];
586      INT16 prevsample = 0;
587
588      /* extract audio data into hi and lo deltas stored in big-endian order */
589      for (sampnum = 0; sampnum < samples; sampnum++)
590      {
591         INT16 newsample = (srcdata[0 ^ sourcexor] << 8) | srcdata[1 ^ sourcexor];
592         INT16 delta = newsample - prevsample;
593         prevsample = newsample;
594         *deltabuf++ = delta >> 8;
595         *deltabuf++ = delta;
596         srcdata += 2;
597      }
598   }
599
600   /* compute the trees */
601   contexts[0] = state->audiohicontext;
602   contexts[1] = state->audiolocontext;
603   hufferr = huffman_compute_tree_interleaved(2, contexts, state->audiodata, samples * 2, channels, samples * 2, 0);
604   if (hufferr != HUFFERR_NONE)
605      return AVCERR_COMPRESSION_ERROR;
606
607   /* export them to the output */
608   hufferr = huffman_export_tree(state->audiohicontext, output, 256, &size);
609   if (hufferr != HUFFERR_NONE)
610      return AVCERR_COMPRESSION_ERROR;
611   output += size;
612   hufferr = huffman_export_tree(state->audiolocontext, output, 256, &size);
613   if (hufferr != HUFFERR_NONE)
614      return AVCERR_COMPRESSION_ERROR;
615   output += size;
616
617   /* note the size of the two trees */
618   huffsize = output - dest;
619   sizes[0] = huffsize >> 8;
620   sizes[1] = huffsize;
621
622   /* iterate over channels */
623   totalsize = huffsize;
624   for (chnum = 0; chnum < channels; chnum++)
625   {
626      const UINT8 *input = state->audiodata + chnum * samples * 2;
627
628      /* encode the data */
629      hufferr = huffman_encode_data_interleaved(2, contexts, input, samples * 2, 1, 0, 0, output, samples * 2, &size);
630      if (hufferr != HUFFERR_NONE)
631         return AVCERR_COMPRESSION_ERROR;
632      output += size;
633
634      /* store the size of this stream */
635      totalsize += size;
636      if (totalsize >= channels * samples * 2)
637         break;
638      sizes[chnum * 2 + 2] = size >> 8;
639      sizes[chnum * 2 + 3] = size;
640   }
641
642   /* if we ran out of room, throw it all away and just store raw */
643   if (chnum < channels)
644   {
645      memcpy(dest, state->audiodata, channels * samples * 2);
646      size = samples * 2;
647      sizes[0] = sizes[1] = 0;
648      for (chnum = 0; chnum < channels; chnum++)
649      {
650         sizes[chnum * 2 + 2] = size >> 8;
651         sizes[chnum * 2 + 3] = size;
652      }
653   }
654
655   return AVCERR_NONE;
656}
657
658
659/*-------------------------------------------------
660    encode_video - encode raw video data
661    to the destination
662-------------------------------------------------*/
663
664static avcomp_error encode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength)
665{
666   /* only lossless supported at this time */
667   return encode_video_lossless(state, width, height, source, sstride, sxor, dest, complength);
668}
669
670
671/*-------------------------------------------------
672    encode_video_lossless - do a lossless video
673    encoding using deltas and huffman encoding
674-------------------------------------------------*/
675
676static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength)
677{
678   UINT32 srcbytes = width * height * 2;
679   huffman_context *contexts[4];
680   huffman_error hufferr;
681   UINT32 outbytes;
682   UINT8 *output;
683
684   /* set up the output; first byte is 0x80 to indicate lossless encoding */
685   output = dest;
686   *output++ = 0x80;
687
688   /* now encode to the destination using two trees, one for the Y and one for the Cr/Cb */
689   contexts[0] = state->ycontext;
690   contexts[1] = state->cbcontext;
691   contexts[2] = state->ycontext;
692   contexts[3] = state->crcontext;
693
694   /* compute the histograms for the data */
695   hufferr = huffman_deltarle_compute_tree_interleaved(4, contexts, source, width * 2, height, sstride, sxor);
696   if (hufferr != HUFFERR_NONE)
697      return AVCERR_COMPRESSION_ERROR;
698
699   /* export the trees to the data stream */
700   hufferr = huffman_deltarle_export_tree(state->ycontext, output, 256, &outbytes);
701   if (hufferr != HUFFERR_NONE)
702      return AVCERR_COMPRESSION_ERROR;
703   output += outbytes;
704   hufferr = huffman_deltarle_export_tree(state->cbcontext, output, 256, &outbytes);
705   if (hufferr != HUFFERR_NONE)
706      return AVCERR_COMPRESSION_ERROR;
707   output += outbytes;
708   hufferr = huffman_deltarle_export_tree(state->crcontext, output, 256, &outbytes);
709   if (hufferr != HUFFERR_NONE)
710      return AVCERR_COMPRESSION_ERROR;
711   output += outbytes;
712
713   /* encode the data using the trees */
714   hufferr = huffman_deltarle_encode_data_interleaved(4, contexts, source, width * 2, height, sstride, sxor, output, srcbytes, &outbytes);
715   if (hufferr != HUFFERR_NONE)
716      return AVCERR_COMPRESSION_ERROR;
717   output += outbytes;
718
719   /* set the final length */
720   *complength = output - dest;
721   return AVCERR_NONE;
722}
723
724
725
726/***************************************************************************
727    DECODING HELPERS
728***************************************************************************/
729
730/*-------------------------------------------------
731    decode_audio - decode audio from a
732    compressed data stream
733-------------------------------------------------*/
734
735static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes)
736{
737   huffman_context *contexts[2];
738   UINT32 actsize, huffsize;
739   huffman_error hufferr;
740   int chnum, sampnum;
741   UINT16 size;
742
743   /* if no huffman length, just copy the data */
744   size = (sizes[0] << 8) | sizes[1];
745   if (size == 0)
746   {
747      /* loop over channels */
748      for (chnum = 0; chnum < channels; chnum++)
749      {
750         UINT8 *curdest = dest[chnum];
751
752         /* extract the size of this channel */
753         size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
754
755         /* extract data from the deltas */
756         if (dest[chnum] != NULL)
757         {
758            INT16 prevsample = 0;
759            for (sampnum = 0; sampnum < samples; sampnum++)
760            {
761               INT16 delta = (source[0] << 8) | source[1];
762               INT16 newsample = prevsample + delta;
763               prevsample = newsample;
764
765               curdest[0 ^ dxor] = newsample >> 8;
766               curdest[1 ^ dxor] = newsample;
767               source += 2;
768               curdest += 2;
769            }
770         }
771         else
772            source += size;
773      }
774      return AVCERR_NONE;
775   }
776
777   /* extract the huffman trees */
778   hufferr = huffman_import_tree(state->audiohicontext, source, size, &actsize);
779   if (hufferr != HUFFERR_NONE)
780      return AVCERR_INVALID_DATA;
781   source += actsize;
782   huffsize = actsize;
783
784   hufferr = huffman_import_tree(state->audiolocontext, source, size, &actsize);
785   if (hufferr != HUFFERR_NONE)
786      return AVCERR_INVALID_DATA;
787   source += actsize;
788   huffsize += actsize;
789   if (huffsize != size)
790      return AVCERR_INVALID_DATA;
791
792   /* set up the contexts */
793   contexts[0] = state->audiohicontext;
794   contexts[1] = state->audiolocontext;
795
796   /* now loop over channels and decode their data */
797   for (chnum = 0; chnum < channels; chnum++)
798   {
799      /* extract the size of this channel */
800      size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
801
802      /* decode the data */
803      if (dest[chnum] != NULL)
804      {
805         UINT8 *deltabuf = state->audiodata + chnum * samples * 2;
806         hufferr = huffman_decode_data_interleaved(2, contexts, source, size, deltabuf, samples * 2, 1, 0, 0, &actsize);
807         if (hufferr != HUFFERR_NONE || actsize != size)
808            return AVCERR_INVALID_DATA;
809      }
810
811      /* advance */
812      source += size;
813   }
814
815   /* reassemble audio from the deltas */
816   for (chnum = 0; chnum < channels; chnum++)
817      if (dest[chnum] != NULL)
818      {
819         UINT8 *deltabuf = state->audiodata + chnum * samples * 2;
820         UINT8 *curdest = dest[chnum];
821         INT16 prevsample = 0;
822
823         for (sampnum = 0; sampnum < samples; sampnum++)
824         {
825            INT16 delta = (deltabuf[0] << 8) | deltabuf[1];
826            INT16 newsample = prevsample + delta;
827            prevsample = newsample;
828
829            curdest[0 ^ dxor] = newsample >> 8;
830            curdest[1 ^ dxor] = newsample;
831            deltabuf += 2;
832            curdest += 2;
833         }
834      }
835
836   return AVCERR_NONE;
837}
838
839
840/*-------------------------------------------------
841    decode_video - decode video from a
842    compressed data stream
843-------------------------------------------------*/
844
845static avcomp_error decode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor)
846{
847   /* if the high bit of the first byte is set, we decode losslessly */
848   if (source[0] & 0x80)
849      return decode_video_lossless(state, width, height, source, complength, dest, dstride, dxor);
850   else
851      return AVCERR_INVALID_DATA;
852}
853
854
855/*-------------------------------------------------
856    decode_video_lossless - do a lossless video
857    decoding using deltas and huffman encoding
858-------------------------------------------------*/
859
860static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor)
861{
862   const UINT8 *sourceend = source + complength;
863   huffman_context *contexts[4];
864   huffman_error hufferr;
865   UINT32 actsize;
866
867   /* skip the first byte */
868   source++;
869
870   /* import the tables */
871   hufferr = huffman_deltarle_import_tree(state->ycontext, source, sourceend - source, &actsize);
872   if (hufferr != HUFFERR_NONE)
873      return AVCERR_INVALID_DATA;
874   source += actsize;
875   hufferr = huffman_deltarle_import_tree(state->cbcontext, source, sourceend - source, &actsize);
876   if (hufferr != HUFFERR_NONE)
877      return AVCERR_INVALID_DATA;
878   source += actsize;
879   hufferr = huffman_deltarle_import_tree(state->crcontext, source, sourceend - source, &actsize);
880   if (hufferr != HUFFERR_NONE)
881      return AVCERR_INVALID_DATA;
882   source += actsize;
883
884   /* set up the decoding contexts */
885   contexts[0] = state->ycontext;
886   contexts[1] = state->cbcontext;
887   contexts[2] = state->ycontext;
888   contexts[3] = state->crcontext;
889
890   /* decode to the destination */
891   hufferr = huffman_deltarle_decode_data_interleaved(4, contexts, source, sourceend - source, dest, width * 2, height, deststride, destxor, &actsize);
892   if (hufferr != HUFFERR_NONE)
893      return AVCERR_INVALID_DATA;
894   if (actsize != sourceend - source)
895      return AVCERR_INVALID_DATA;
896
897   return AVCERR_NONE;
898}
src/lib/util/avcomp.h
r14481r14482
1/***************************************************************************
2
3    avcomp.h
4
5    Audio/video compression and decompression helpers.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#ifndef __AVCOMP_H__
41#define __AVCOMP_H__
42
43#include "osdcore.h"
44#include "bitmap.h"
45
46
47/***************************************************************************
48    CONSTANTS
49***************************************************************************/
50
51/* errors */
52enum _avcomp_error
53{
54   AVCERR_NONE = 0,
55   AVCERR_INVALID_DATA,
56   AVCERR_VIDEO_TOO_LARGE,
57   AVCERR_AUDIO_TOO_LARGE,
58   AVCERR_METADATA_TOO_LARGE,
59   AVCERR_OUT_OF_MEMORY,
60   AVCERR_COMPRESSION_ERROR,
61   AVCERR_TOO_MANY_CHANNELS,
62   AVCERR_INVALID_CONFIGURATION
63};
64typedef enum _avcomp_error avcomp_error;
65
66/* default decompression parameters */
67#define AVCOMP_ENABLE_META               (1 << 0)
68#define AVCOMP_ENABLE_VIDEO               (1 << 1)
69#define AVCOMP_ENABLE_AUDIO(x)            (1 << (2 + (x)))
70#define AVCOMP_ENABLE_DEFAULT            (~0)
71
72
73
74/***************************************************************************
75    TYPE DEFINITIONS
76***************************************************************************/
77
78/* compression configuration */
79struct av_codec_compress_config
80{
81   av_codec_compress_config()
82      : channels(0),
83        samples(0),
84        metalength(0),
85        metadata(NULL)
86   {
87      memset(audio, 0, sizeof(audio));
88   }
89
90   bitmap_yuy16 video;                  /* pointer to video bitmap */
91   UINT32      channels;               /* number of channels */
92   UINT32      samples;               /* number of samples per channel */
93   INT16 *      audio[16];               /* pointer to individual audio channels */
94   UINT32      metalength;               /* length of metadata */
95   UINT8 *      metadata;               /* pointer to metadata buffer */
96};
97
98
99/* decompression configuration */
100struct av_codec_decompress_config
101{
102   av_codec_decompress_config()
103      : maxsamples(0),
104        actsamples(0),
105        maxmetalength(0),
106        actmetalength(0),
107        metadata(NULL)
108   {
109      memset(audio, 0, sizeof(audio));
110   }
111
112   bitmap_yuy16 video;                  /* pointer to video bitmap */
113   UINT32      maxsamples;               /* maximum number of samples per channel */
114   UINT32 *   actsamples;               /* actual number of samples per channel */
115   INT16 *      audio[16];               /* pointer to individual audio channels */
116   UINT32      maxmetalength;            /* maximum length of metadata */
117   UINT32 *   actmetalength;            /* actual length of metadata */
118   UINT8 *      metadata;               /* pointer to metadata buffer */
119};
120
121
122/* opaque state */
123struct avcomp_state;
124
125
126
127/***************************************************************************
128    PROTOTYPES
129***************************************************************************/
130
131avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels);
132void avcomp_free(avcomp_state *state);
133
134void avcomp_config_compress(avcomp_state *state, av_codec_compress_config *config);
135void avcomp_config_decompress(avcomp_state *state, av_codec_decompress_config *config);
136
137avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength);
138avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest);
139
140#endif
src/lib/util/harddisk.h
r14481r14482
5050    TYPE DEFINITIONS
5151***************************************************************************/
5252
53typedef struct _hard_disk_file hard_disk_file;
53struct hard_disk_file;
5454
55typedef struct _hard_disk_info hard_disk_info;
56struct _hard_disk_info
55struct hard_disk_info
5756{
5857   UINT32         cylinders;
5958   UINT32         heads;
src/lib/util/chd.c
r14481r14482
3838***************************************************************************/
3939
4040#include "chd.h"
41#include "avcomp.h"
42#include "md5.h"
43#include "sha1.h"
41#include "avhuff.h"
42#include "hashing.h"
43#include "flac.h"
4444#include "cdrom.h"
45#include "coretmpl.h"
4546#include <zlib.h>
4647#include <time.h>
4748#include <stddef.h>
4849#include <stdlib.h>
4950#include <new>
5051
51#include "../../lib/libflac/include/flac/all.h"
5252
53//**************************************************************************
54//  CONSTANTS
55//**************************************************************************
5356
54/***************************************************************************
55    DEBUGGING
56***************************************************************************/
57// standard metadata formats
58const char *HARD_DISK_METADATA_FORMAT = "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d";
59const char *CDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d";
60const char *CDROM_TRACK_METADATA2_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d";
61const char *AV_METADATA_FORMAT = "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d";
5762
58#define PRINTF_MAX_HUNK            (0)
63static const UINT32 METADATA_HEADER_SIZE = 16;         // metadata header size
5964
65static const UINT8 V34_MAP_ENTRY_FLAG_TYPE_MASK   = 0x0f;      // what type of hunk
66static const UINT8 V34_MAP_ENTRY_FLAG_NO_CRC = 0x10;      // no CRC is present
6067
6168
62/***************************************************************************
63    CONSTANTS
64***************************************************************************/
6569
66#define MAP_STACK_ENTRIES         512         /* max number of entries to use on the stack */
67#define MAP_ENTRY_SIZE            16         /* V3 and later */
68#define OLD_MAP_ENTRY_SIZE         8         /* V1-V2 */
69#define METADATA_HEADER_SIZE      16         /* metadata header size */
70#define CRCMAP_HASH_SIZE         4095      /* number of CRC hashtable entries */
71
72#define MAP_ENTRY_FLAG_TYPE_MASK   0x0f      /* what type of hunk */
73#define MAP_ENTRY_FLAG_NO_CRC      0x10      /* no CRC is present */
74#define MAP_ENTRY_FLAG_HALF_HUNK   0x20      /* only the first half of this hunk is included in the SHA1 calculation (workaround for CD track padding issue) */
75
76#define MAP_ENTRY_TYPE_INVALID              0x00      /* invalid type */
77#define MAP_ENTRY_TYPE_COMPRESSED           0x01      /* standard compression */
78#define MAP_ENTRY_TYPE_UNCOMPRESSED           0x02      /* uncompressed data */
79#define MAP_ENTRY_TYPE_MINI                 0x03      /* mini: use offset as raw data */
80#define MAP_ENTRY_TYPE_SELF_HUNK           0x04      /* same as another hunk in this file */
81#define MAP_ENTRY_TYPE_PARENT_HUNK           0x05      /* same as a hunk in the parent file */
82#define MAP_ENTRY_TYPE_2ND_COMPRESSED       0x06      /* compressed with secondary algorithm (usually FLAC CDDA) */
83
84#define CHD_V1_SECTOR_SIZE         512         /* size of a "sector" in the V1 header */
85
86#define COOKIE_VALUE            0xbaadf00d
87#define MAX_ZLIB_ALLOCS            64
88
89#define END_OF_LIST_COOKIE         "EndOfListCookie"
90
91#define NO_MATCH               (~0)
92
93
94
95/***************************************************************************
96    MACROS
97***************************************************************************/
98
99#define EARLY_EXIT(x)            do { (void)(x); goto cleanup; } while (0)
100
101
102
103/***************************************************************************
104    TYPE DEFINITIONS
105***************************************************************************/
106
107/* interface to a codec */
108typedef struct _codec_interface codec_interface;
109struct _codec_interface
70// V3-V4 entry types
71enum
11072{
111   UINT32      compression;            /* type of compression */
112   const char *compname;               /* name of the algorithm */
113   UINT8      lossy;                  /* is this a lossy algorithm? */
114   chd_error   (*init)(chd_file *chd);      /* codec initialize */
115   void      (*free)(chd_file *chd);      /* codec free */
116   chd_error   (*compress)(chd_file *chd, const void *src, UINT32 *complen); /* compress data */
117   chd_error   (*decompress)(chd_file *chd, UINT32 complen, void *dst); /* decompress data */
118   chd_error   (*config)(chd_file *chd, int param, void *config); /* configure */
119
120   chd_error   (*secondary_compress)(chd_file *chd, const void *src, UINT32 *complen); /* secondary compress data */
121   chd_error   (*secondary_decompress)(chd_file *chd, UINT32 complen, void *dst); /* secondary decompress data */
122
73   V34_MAP_ENTRY_TYPE_INVALID = 0,            // invalid type
74   V34_MAP_ENTRY_TYPE_COMPRESSED = 1,         // standard compression
75   V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,      // uncompressed data
76   V34_MAP_ENTRY_TYPE_MINI = 3,            // mini: use offset as raw data
77   V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,         // same as another hunk in this file
78   V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         // same as a hunk in the parent file
79   V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6      // compressed with secondary algorithm (usually FLAC CDDA)
12380};
12481
125
126/* a single map entry */
127typedef struct _map_entry map_entry;
128struct _map_entry
82// V5 compression types
83enum
12984{
130   UINT64               offset;         /* offset within the file of the data */
131   UINT32               crc;         /* 32-bit CRC of the data */
132   UINT32               length;         /* length of the data */
133   UINT8               flags;         /* misc flags */
85   // these types are live when running
86   COMPRESSION_TYPE_0 = 0,                  // codec #0
87   COMPRESSION_TYPE_1 = 1,                  // codec #1
88   COMPRESSION_TYPE_2 = 2,                  // codec #2
89   COMPRESSION_TYPE_3 = 3,                  // codec #3
90   COMPRESSION_NONE = 4,                  // no compression; implicit length = hunkbytes
91   COMPRESSION_SELF = 5,                  // same as another block in this chd
92   COMPRESSION_PARENT = 6,                  // same as a hunk's worth of units in the parent chd
93   
94   // these additional pseudo-types are used for compressed encodings:
95   COMPRESSION_RLE_SMALL,                  // start of small RLE run (4-bit length)
96   COMPRESSION_RLE_LARGE,                  // start of large RLE run (8-bit length)
97   COMPRESSION_SELF_0,                     // same as the last COMPRESSION_SELF block
98   COMPRESSION_SELF_1,                     // same as the last COMPRESSION_SELF block + 1
99   COMPRESSION_PARENT_SELF,               // same block in the parent
100   COMPRESSION_PARENT_0,                  // same as the last COMPRESSION_PARENT block
101   COMPRESSION_PARENT_1                  // same as the last COMPRESSION_PARENT block + 1
134102};
135103
136104
137/* simple linked-list of hunks used for our CRC map */
138typedef struct _crcmap_entry crcmap_entry;
139struct _crcmap_entry
140{
141   UINT32               hunknum;      /* hunk number */
142   crcmap_entry *         next;         /* next entry in list */
143};
144105
106//**************************************************************************
107//  TYPE DEFINITIONS
108//**************************************************************************
145109
146/* a single metadata entry */
147typedef struct _metadata_entry metadata_entry;
148struct _metadata_entry
149{
150   UINT64               offset;         /* offset within the file of the header */
151   UINT64               next;         /* offset within the file of the next header */
152   UINT64               prev;         /* offset within the file of the previous header */
153   UINT32               length;         /* length of the metadata */
154   UINT32               metatag;      /* metadata tag */
155   UINT8               flags;         /* flag bits */
156};
110// ======================> metadata_entry
157111
158
159/* internal representation of an open CHD file */
160struct _chd_file
112// description of where a metadata entry lives within the file
113struct chd_file::metadata_entry
161114{
162   UINT32               cookie;         /* cookie, should equal COOKIE_VALUE */
163
164   core_file *            file;         /* handle to the open core file */
165   UINT8               owns_file;      /* flag indicating if this file should be closed on chd_close() */
166   chd_header            header;         /* header, extracted from file */
167
168   chd_file *            parent;         /* pointer to parent file, or NULL */
169
170   map_entry *            map;         /* array of map entries */
171
172   UINT8 *               cache;         /* hunk cache pointer */
173   UINT32               cachehunk;      /* index of currently cached hunk */
174
175   UINT8 *               compare;      /* hunk compare pointer */
176   UINT32               comparehunk;   /* index of current compare data */
177
178   UINT8 *               compressed;      /* pointer to buffer for compressed data */
179   const codec_interface *   codecintf;      /* interface to the codec */
180   void *               codecdata;      /* opaque pointer to codec data */
181
182   crcmap_entry *         crcmap;         /* CRC map entries */
183   crcmap_entry *         crcfree;      /* free list CRC entries */
184   crcmap_entry **         crctable;      /* table of CRC entries */
185
186   UINT32               maxhunk;      /* maximum hunk accessed */
187
188   UINT8               compressing;   /* are we compressing? */
189   struct MD5Context      compmd5;      /* running MD5 during compression */
190   struct sha1_ctx         compsha1;      /* running SHA1 during compression */
191   UINT32               comphunk;      /* next hunk we will compress */
192
193   UINT8               verifying;      /* are we verifying? */
194   struct MD5Context      vermd5;       /* running MD5 during verification */
195   struct sha1_ctx         versha1;      /* running SHA1 during verification */
196   UINT32               verhunk;      /* next hunk we will verify */
197
198   osd_work_queue *      workqueue;      /* pointer to work queue for async operations */
199   osd_work_item *         workitem;      /* active work item, or NULL if none */
200   UINT32               async_hunknum;   /* hunk index for asynchronous operations */
201   void *               async_buffer;   /* buffer pointer for asynchronous operations */
115   UINT64               offset;         // offset within the file of the header
116   UINT64               next;         // offset within the file of the next header
117   UINT64               prev;         // offset within the file of the previous header
118   UINT32               length;         // length of the metadata
119   UINT32               metatag;      // metadata tag
120   UINT8               flags;         // flag bits
202121};
203122
204123
205/* codec-private data for the ZLIB codec */
206typedef struct _zlib_codec_data zlib_codec_data;
207struct _zlib_codec_data
208{
209   z_stream            inflater;
210   z_stream            deflater;
211   UINT32 *            allocptr[MAX_ZLIB_ALLOCS];
212};
124// ======================> metadata_hash
213125
214
215/* codec-private data for the A/V codec */
216struct av_codec_data
126struct chd_file::metadata_hash
217127{
218   avcomp_state *         compstate;
219   av_codec_compress_config compress;
220   av_codec_decompress_config decompress;
128   UINT8                tag[4];         // tag of the metadata in big-endian
129   sha1_t                sha1;         // hash data
221130};
222131
223132
224/* a single metadata hash entry */
225typedef struct _metadata_hash metadata_hash;
226struct _metadata_hash
227{
228   UINT8               tag[4];         /* tag of the metadata in big-endian */
229   UINT8               sha1[CHD_SHA1_BYTES]; /* hash */
230};
231133
134//**************************************************************************
135//  INLINE FUNCTIONS
136//**************************************************************************
232137
138//-------------------------------------------------
139//  be_read - extract a big-endian number from
140//  a byte buffer
141//-------------------------------------------------
233142
234/***************************************************************************
235    GLOBAL VARIABLES
236***************************************************************************/
143inline UINT64 chd_file::be_read(const UINT8 *base, int numbytes)
144{
145   UINT64 result = 0;
146   while (numbytes--)
147      result = (result << 8) | *base++;
148   return result;
149}
237150
238static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
239static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
240151
152//-------------------------------------------------
153//  be_write - write a big-endian number to a byte
154//  buffer
155//-------------------------------------------------
241156
242
243/***************************************************************************
244    PROTOTYPES
245***************************************************************************/
246
247/* internal async operations */
248static void *async_read_callback(void *param, int threadid);
249static void *async_write_callback(void *param, int threadid);
250
251/* internal header operations */
252static chd_error header_validate(const chd_header *header);
253static chd_error header_read(core_file *file, chd_header *header);
254static chd_error header_write(core_file *file, const chd_header *header);
255
256/* internal hunk read/write */
257static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
258static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
259static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UINT8 *src, int is_half_hunk = 0);
260
261/* internal map access */
262static chd_error map_write_initial(core_file *file, chd_file *parent, const chd_header *header);
263static chd_error map_read(chd_file *chd);
264
265/* internal CRC map access */
266static void crcmap_init(chd_file *chd, int prepopulate);
267static void crcmap_add_entry(chd_file *chd, UINT32 hunknum);
268static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const UINT8 *rawdata);
269
270/* metadata management */
271static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
272static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset);
273static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length);
274static chd_error metadata_compute_hash(chd_file *chd, const UINT8 *rawsha1, UINT8 *finalsha1);
275static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2);
276
277/* zlib compression codec */
278static chd_error zlib_codec_init(chd_file *chd);
279static void zlib_codec_free(chd_file *chd);
280static chd_error zlib_codec_compress(chd_file *chd, const void *src, UINT32 *length);
281static chd_error zlib_codec_decompress(chd_file *chd, UINT32 srclength, void *dest);
282static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
283static void zlib_fast_free(voidpf opaque, voidpf address);
284
285/* flac compression codec */
286static chd_error flac_codec_compress(chd_file *chd, const void *src, UINT32 *length, int swap);
287static chd_error flac_codec_compress_normal(chd_file *chd, const void *src, UINT32 *length);
288static chd_error flac_codec_decompress(chd_file *chd, UINT32 srclength, void *dest);
289
290
291/* A/V compression codec */
292static chd_error av_codec_init(chd_file *chd);
293static void av_codec_free(chd_file *chd);
294static chd_error av_codec_compress(chd_file *chd, const void *src, UINT32 *length);
295static chd_error av_codec_decompress(chd_file *chd, UINT32 srclength, void *dest);
296static chd_error av_codec_config(chd_file *chd, int param, void *config);
297static chd_error av_codec_postinit(chd_file *chd);
298
299
300
301/***************************************************************************
302    CODEC INTERFACES
303***************************************************************************/
304
305static const codec_interface codec_interfaces[] =
157inline void chd_file::be_write(UINT8 *base, UINT64 value, int numbytes)
306158{
307   /* "none" or no compression */
159   base += numbytes;
160   while (numbytes--)
308161   {
309      CHDCOMPRESSION_NONE,
310      "none",
311      FALSE,
312      NULL,
313      NULL,
314      NULL,
315      NULL,
316      NULL,
317      NULL,
318      NULL
319   },
162      *--base = value;
163      value >>= 8;
164   }
165}
320166
321   /* standard zlib compression */
322   {
323      CHDCOMPRESSION_ZLIB,
324      "zlib",
325      FALSE,
326      zlib_codec_init,
327      zlib_codec_free,
328      zlib_codec_compress,
329      zlib_codec_decompress,
330      NULL,
331      NULL,
332      NULL
333   },
334167
335   /* zlib+ compression */
336   {
337      CHDCOMPRESSION_ZLIB_PLUS,
338      "zlib+",
339      FALSE,
340      zlib_codec_init,
341      zlib_codec_free,
342      zlib_codec_compress,
343      zlib_codec_decompress,
344      NULL,
345      NULL,
346      NULL
347   },
168//-------------------------------------------------
169//  be_read_sha1 - fetch a sha1_t from a data
170//  stream in bigendian order
171//-------------------------------------------------
348172
349   /* a/v compression */
350   {
351      CHDCOMPRESSION_AV,
352      "A/V",
353      TRUE,
354      av_codec_init,
355      av_codec_free,
356      av_codec_compress,
357      av_codec_decompress,
358      av_codec_config,
359      NULL,
360      NULL
361   },
362
363   /* zlib+ with FLAC compression */
364   {
365      CHDCOMPRESSION_ZLIB_PLUS_WITH_FLAC,
366      "zlib+ with FLAC",
367      FALSE,
368      zlib_codec_init,
369      zlib_codec_free,
370      zlib_codec_compress,
371      zlib_codec_decompress,
372      NULL,
373      flac_codec_compress_normal,
374      flac_codec_decompress,
375   },
376};
377
378
379
380/***************************************************************************
381    INLINE FUNCTIONS
382***************************************************************************/
383
384/*-------------------------------------------------
385    get_bigendian_uint64 - fetch a UINT64 from
386    the data stream in bigendian order
387-------------------------------------------------*/
388
389INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
173inline sha1_t chd_file::be_read_sha1(const UINT8 *base)
390174{
391   return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
392         ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
175   sha1_t result;
176   memcpy(&result.m_raw[0], base, sizeof(result.m_raw));
177   return result;
393178}
394179
395180
396/*-------------------------------------------------
397    put_bigendian_uint64 - write a UINT64 to
398    the data stream in bigendian order
399-------------------------------------------------*/
181//-------------------------------------------------
182//  be_write_sha1 - write a sha1_t to a data
183//  stream in bigendian order
184//-------------------------------------------------
400185
401INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
186inline void chd_file::be_write_sha1(UINT8 *base, sha1_t value)
402187{
403   base[0] = value >> 56;
404   base[1] = value >> 48;
405   base[2] = value >> 40;
406   base[3] = value >> 32;
407   base[4] = value >> 24;
408   base[5] = value >> 16;
409   base[6] = value >> 8;
410   base[7] = value;
188   memcpy(base, &value.m_raw[0], sizeof(value.m_raw));
411189}
412190
413191
414/*-------------------------------------------------
415    get_bigendian_uint32 - fetch a UINT32 from
416    the data stream in bigendian order
417-------------------------------------------------*/
192//-------------------------------------------------
193//  file_read - read from the file at the given
194//  offset; on failure throw an error
195//-------------------------------------------------
418196
419INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
197inline void chd_file::file_read(UINT64 offset, void *dest, UINT32 length)
420198{
421   return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
199   // no file = failure
200   if (m_file == NULL)
201      throw CHDERR_NOT_OPEN;
202   
203   // seek and read
204   core_fseek(m_file, offset, SEEK_SET);
205   UINT32 count = core_fread(m_file, dest, length);
206   if (count != length)
207      throw CHDERR_READ_ERROR;
422208}
423209
424210
425/*-------------------------------------------------
426    put_bigendian_uint32 - write a UINT32 to
427    the data stream in bigendian order
428-------------------------------------------------*/
211//-------------------------------------------------
212//  file_write - write to the file at the given
213//  offset; on failure throw an error
214//-------------------------------------------------
429215
430INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
216inline void chd_file::file_write(UINT64 offset, const void *source, UINT32 length)
431217{
432   base[0] = value >> 24;
433   base[1] = value >> 16;
434   base[2] = value >> 8;
435   base[3] = value;
218   // no file = failure
219   if (m_file == NULL)
220      throw CHDERR_NOT_OPEN;
221   
222   // seek and write
223   core_fseek(m_file, offset, SEEK_SET);
224   UINT32 count = core_fwrite(m_file, source, length);
225   if (count != length)
226      throw CHDERR_WRITE_ERROR;
436227}
437228
438229
439/*-------------------------------------------------
440    get_bigendian_uint16 - fetch a UINT16 from
441    the data stream in bigendian order
442-------------------------------------------------*/
230//-------------------------------------------------
231//  file_append - append to the file at the given
232//  offset, ensuring we start at the given
233//  alignment; on failure throw an error
234//-------------------------------------------------
443235
444INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
236inline UINT64 chd_file::file_append(const void *source, UINT32 length, UINT32 alignment)
445237{
446   return (base[0] << 8) | base[1];
447}
238   // no file = failure
239   if (m_file == NULL)
240      throw CHDERR_NOT_OPEN;
448241
242   // seek to the end and align if necessary
243   core_fseek(m_file, 0, SEEK_END);
244   if (alignment != 0)
245   {
246      UINT64 offset = core_ftell(m_file);
247      UINT32 delta = offset % alignment;
248      if (delta != 0)
249      {
250         // pad with 0's from a local buffer
251         UINT8 buffer[1024];
252         memset(buffer, 0, sizeof(buffer));
253         delta = alignment - delta;
254         while (delta != 0)
255         {
256            UINT32 bytes_to_write = MIN(sizeof(buffer), delta);
257            UINT32 count = core_fwrite(m_file, buffer, bytes_to_write);
258            if (count != length)
259               throw CHDERR_WRITE_ERROR;
260            delta -= bytes_to_write;
261         }
262      }
263   }
449264
450/*-------------------------------------------------
451    put_bigendian_uint16 - write a UINT16 to
452    the data stream in bigendian order
453-------------------------------------------------*/
454
455INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
456{
457   base[0] = value >> 8;
458   base[1] = value;
265   // write the real data
266   UINT64 offset = core_ftell(m_file);
267   UINT32 count = core_fwrite(m_file, source, length);
268   if (count != length)
269      throw CHDERR_READ_ERROR;
270   return offset;
459271}
460272
461273
462/*-------------------------------------------------
463    map_extract - extract a single map
464    entry from the datastream
465-------------------------------------------------*/
274//-------------------------------------------------
275//  bits_for_value - return the number of bits
276//  necessary to represent all numbers 0..value
277//-------------------------------------------------
466278
467INLINE void map_extract(const UINT8 *base, map_entry *entry)
279inline UINT8 chd_file::bits_for_value(UINT64 value)
468280{
469   entry->offset = get_bigendian_uint64(&base[0]);
470   entry->crc = get_bigendian_uint32(&base[8]);
471   entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
472   entry->flags = base[15];
281   UINT8 result = 0;
282   while (value != 0)
283      value >>= 1, result++;
284   return result;
473285}
474286
475287
476/*-------------------------------------------------
477    map_assemble - write a single map
478    entry to the datastream
479-------------------------------------------------*/
480288
481INLINE void map_assemble(UINT8 *base, map_entry *entry)
482{
483   put_bigendian_uint64(&base[0], entry->offset);
484   put_bigendian_uint32(&base[8], entry->crc);
485   put_bigendian_uint16(&base[12], entry->length);
486   base[14] = entry->length >> 16;
487   base[15] = entry->flags;
488}
289//**************************************************************************
290//  CHD FILE MANAGEMENT
291//**************************************************************************
489292
293//-------------------------------------------------
294//  chd_file - constructor
295//-------------------------------------------------
490296
491/*-------------------------------------------------
492    map_extract_old - extract a single map
493    entry in old format from the datastream
494-------------------------------------------------*/
495
496INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
297chd_file::chd_file()
298   : m_file(NULL)
497299{
498   entry->offset = get_bigendian_uint64(&base[0]);
499   entry->crc = 0;
500   entry->length = entry->offset >> 44;
501   entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? MAP_ENTRY_TYPE_UNCOMPRESSED : MAP_ENTRY_TYPE_COMPRESSED);
502#ifdef __MWERKS__
503   entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
504#else
505   entry->offset = (entry->offset << 20) >> 20;
506#endif
300   // reset state
301   memset(m_decompressor, 0, sizeof(m_decompressor));
302   close();
507303}
508304
509305
510/*-------------------------------------------------
511    queue_async_operation - queue a new work
512    item
513-------------------------------------------------*/
306//-------------------------------------------------
307//  ~chd_file - destructor
308//-------------------------------------------------
514309
515INLINE int queue_async_operation(chd_file *chd, osd_work_callback callback)
310chd_file::~chd_file()
516311{
517   /* if no queue yet, create one on the fly */
518   if (chd->workqueue == NULL)
519   {
520      chd->workqueue = osd_work_queue_alloc(WORK_QUEUE_FLAG_IO);
521      if (chd->workqueue == NULL)
522         return FALSE;
523   }
524
525   /* make sure we cleared out the previous item */
526   if (chd->workitem != NULL)
527      return FALSE;
528
529   /* create a new work item to run the job */
530   chd->workitem = osd_work_item_queue(chd->workqueue, callback, chd, 0);
531   if (chd->workitem == NULL)
532      return FALSE;
533
534   return TRUE;
312   // close any open files
313   close();
535314}
536315
537316
538/*-------------------------------------------------
539    wait_for_pending_async - wait for any pending
540    async
541-------------------------------------------------*/
317//-------------------------------------------------
318//  sha1 - return our SHA1 value
319//-------------------------------------------------
542320
543INLINE void wait_for_pending_async(chd_file *chd)
321sha1_t chd_file::sha1()
544322{
545   /* if something is pending, wait for it */
546   if (chd->workitem != NULL)
323   try
547324   {
548      /* 10 seconds should be enough for anything! */
549      int wait_successful = osd_work_item_wait(chd->workitem, 10 * osd_ticks_per_second());
550      if (!wait_successful)
551         osd_break_into_debugger("Pending async operation never completed!");
325      // read the big-endian version
326      UINT8 rawbuf[sizeof(sha1_t)];
327      file_read(m_sha1_offset, rawbuf, sizeof(rawbuf));
328      return be_read_sha1(rawbuf);
552329   }
330   catch (chd_error &)
331   {
332      // on failure, return NULL
333      return sha1_t::null;
334   }
553335}
554336
555337
338//-------------------------------------------------
339//  raw_sha1 - return our raw SHA1 value
340//-------------------------------------------------
556341
557/***************************************************************************
558    CHD FILE MANAGEMENT
559***************************************************************************/
560
561/*-------------------------------------------------
562    chd_create_file - create a new CHD file
563-------------------------------------------------*/
564
565chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent)
342sha1_t chd_file::raw_sha1()
566343{
567   chd_file *newchd = NULL;
568   chd_header header;
569   chd_error err;
570   int intfnum;
571
572   /* verify parameters */
573   if (file == NULL)
574      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
575   if (parent == NULL && (logicalbytes == 0 || hunkbytes == 0))
576      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
577
578   /* verify the compression type */
579   for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
580      if (codec_interfaces[intfnum].compression == compression)
581         break;
582   if (intfnum == ARRAY_LENGTH(codec_interfaces))
583      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
584
585   /* if we have a parent, the sizes come from there */
586   if (parent != NULL)
344   try
587345   {
588      logicalbytes = parent->header.logicalbytes;
589      hunkbytes = parent->header.hunkbytes;
346      // determine offset within the file for data-only
347      if (m_rawsha1_offset == 0)
348         throw CHDERR_UNSUPPORTED_VERSION;
349     
350      // read the big-endian version
351      UINT8 rawbuf[sizeof(sha1_t)];
352      file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf));
353      return be_read_sha1(rawbuf);
590354   }
591
592   /* if we have a parent, it must be V3 or later */
593   if (parent != NULL && parent->header.version < 3)
594      EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
595
596   /* build the header */
597   memset(&header, 0, sizeof(header));
598   header.length = CHD_V4_HEADER_SIZE;
599   header.version = CHD_HEADER_VERSION;
600   header.flags = CHDFLAGS_IS_WRITEABLE;
601   header.compression = compression;
602   header.hunkbytes = hunkbytes;
603   header.totalhunks = (logicalbytes + hunkbytes - 1) / hunkbytes;
604   header.logicalbytes = logicalbytes;
605
606   /* tweaks if there is a parent */
607   if (parent != NULL)
355   catch (chd_error &)
608356   {
609      header.flags |= CHDFLAGS_HAS_PARENT;
610      memcpy(&header.parentmd5[0], &parent->header.md5[0], sizeof(header.parentmd5));
611      memcpy(&header.parentsha1[0], &parent->header.sha1[0], sizeof(header.parentsha1));
357      // on failure, return NULL
358      return sha1_t::null;
612359   }
360}
613361
614   /* validate it */
615   err = header_validate(&header);
616   if (err != CHDERR_NONE)
617      EARLY_EXIT(err);
618362
619   /* write the resulting header */
620   err = header_write(file, &header);
621   if (err != CHDERR_NONE)
622      EARLY_EXIT(err);
363//-------------------------------------------------
364//  parent_sha1 - return our parent's SHA1 value
365//-------------------------------------------------
623366
624   /* create an initial map */
625   err = map_write_initial(file, parent, &header);
626   if (err != CHDERR_NONE)
627      EARLY_EXIT(err);
628
629   /* if we have a parent, clone the metadata */
630   if (parent != NULL)
367sha1_t chd_file::parent_sha1()
368{
369   try
631370   {
632      /* open the new CHD via the standard mechanism */
633      err = chd_open_file(file, CHD_OPEN_READWRITE, parent, &newchd);
634      if (err != CHDERR_NONE)
635         EARLY_EXIT(err);
636
637      /* close the metadata */
638      err = chd_clone_metadata(parent, newchd);
639      if (err != CHDERR_NONE)
640         EARLY_EXIT(err);
641
642      /* close the CHD */
643      chd_close(newchd);
371      // determine offset within the file
372      if (m_parentsha1_offset == 0)
373         throw CHDERR_UNSUPPORTED_VERSION;
374     
375      // read the big-endian version
376      UINT8 rawbuf[sizeof(sha1_t)];
377      file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf));
378      return be_read_sha1(rawbuf);
644379   }
645
646   return CHDERR_NONE;
647
648cleanup:
649   if (newchd != NULL)
650      chd_close(newchd);
651   return err;
380   catch (chd_error &)
381   {
382      // on failure, return NULL
383      return sha1_t::null;
384   }
652385}
653386
654387
655/*-------------------------------------------------
656    chd_open_file - open a CHD file for access
657-------------------------------------------------*/
388//-------------------------------------------------
389//  hunk_info - return information about this
390//  hunk
391//-------------------------------------------------
658392
659chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
393chd_error chd_file::hunk_info(UINT32 hunknum, chd_codec_type &compressor, UINT32 &compbytes)
660394{
661   chd_file *newchd = NULL;
662   chd_error err;
663   int intfnum;
664
665   /* verify parameters */
666   if (file == NULL)
667      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
668
669   /* punt if invalid parent */
670   if (parent != NULL && parent->cookie != COOKIE_VALUE)
671      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
672
673   /* allocate memory for the final result */
674   newchd = (chd_file *)malloc(sizeof(**chd));
675   if (newchd == NULL)
676      EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
677   memset(newchd, 0, sizeof(*newchd));
678   newchd->cookie = COOKIE_VALUE;
679   newchd->parent = parent;
680   newchd->file = file;
681
682   /* now attempt to read the header */
683   err = header_read(newchd->file, &newchd->header);
684   if (err != CHDERR_NONE)
685      EARLY_EXIT(err);
686
687   /* validate the header */
688   err = header_validate(&newchd->header);
689   if (err != CHDERR_NONE)
690      EARLY_EXIT(err);
691
692   /* make sure we don't open a read-only file writeable */
693   if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
694      EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
695
696   /* also, never open an older version writeable */
697   if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
698      EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
699
700   /* if we need a parent, make sure we have one */
701   if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT))
702      EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
703
704   /* make sure we have a valid parent */
705   if (parent != NULL)
395   // error if invalid
396   if (hunknum >= m_hunkcount)
397      return CHDERR_HUNK_OUT_OF_RANGE;
398   
399   // get the map pointer
400   UINT8 *rawmap;
401   switch (m_version)
706402   {
707      /* check MD5 if it isn't empty */
708      if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
709         memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
710         memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
711         EARLY_EXIT(err = CHDERR_INVALID_PARENT);
403      // v3/v4 map entries
404      case 3:
405      case 4:
406         rawmap = m_rawmap + 16 * hunknum;
407         switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK)
408         {
409            case V34_MAP_ENTRY_TYPE_COMPRESSED:
410               compressor = CHD_CODEC_ZLIB;
411               compbytes = be_read(&rawmap[12], 2) + (rawmap[14] << 16);
412               break;
413               
414            case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
415               compressor = CHD_CODEC_NONE;
416               compbytes = m_hunkbytes;
417               break;
418               
419            case V34_MAP_ENTRY_TYPE_MINI:
420               compressor = CHD_CODEC_MINI;
421               compbytes = 0;
422               break;
423           
424            case V34_MAP_ENTRY_TYPE_SELF_HUNK:
425               compressor = CHD_CODEC_SELF;
426               compbytes = 0;
427               break;
712428
713      /* check SHA1 if it isn't empty */
714      if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
715         memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
716         memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
717         EARLY_EXIT(err = CHDERR_INVALID_PARENT);
718   }
429            case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
430               compressor = CHD_CODEC_PARENT;
431               compbytes = 0;
432               break;
433         }
434         break;
435     
436      // v5 map entries
437      case 5:
438         rawmap = m_rawmap + m_mapentrybytes * hunknum;
719439
720   /* now read the hunk map */
721   err = map_read(newchd);
722   if (err != CHDERR_NONE)
723      EARLY_EXIT(err);
440         // uncompressed case
441         if (!compressed())
442         {
443            if (be_read(&rawmap[0], 4) == 0)
444            {
445               compressor = CHD_CODEC_PARENT;
446               compbytes = 0;
447            }
448            else
449            {
450               compressor = CHD_CODEC_NONE;
451               compbytes = m_hunkbytes;
452            }
453            break;
454         }
455         
456         // compressed case
457         switch (rawmap[0])
458         {
459            case COMPRESSION_TYPE_0:
460            case COMPRESSION_TYPE_1:
461            case COMPRESSION_TYPE_2:
462            case COMPRESSION_TYPE_3:
463               compressor = m_compression[rawmap[0]];
464               compbytes = be_read(&rawmap[1], 3);
465               break;
724466
725   /* allocate and init the hunk cache */
726   newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
727   newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
728   if (newchd->cache == NULL || newchd->compare == NULL)
729      EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
730   newchd->cachehunk = ~0;
731   newchd->comparehunk = ~0;
467            case COMPRESSION_NONE:
468               compressor = CHD_CODEC_NONE;
469               compbytes = m_hunkbytes;
470               break;
732471
733   /* allocate the temporary compressed buffer */
734   newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
735   if (newchd->compressed == NULL)
736      EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
737
738   /* find the codec interface */
739   for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
740      if (codec_interfaces[intfnum].compression == newchd->header.compression)
741      {
742         newchd->codecintf = &codec_interfaces[intfnum];
472            case COMPRESSION_SELF:
473               compressor = CHD_CODEC_SELF;
474               compbytes = 0;
475               break;
476               
477            case COMPRESSION_PARENT:
478               compressor = CHD_CODEC_PARENT;
479               compbytes = 0;
480               break;
481         }
743482         break;
744      }
745   if (intfnum == ARRAY_LENGTH(codec_interfaces))
746      EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
747
748   /* initialize the codec */
749   if (newchd->codecintf->init != NULL)
750      err = (*newchd->codecintf->init)(newchd);
751   if (err != CHDERR_NONE)
752      EARLY_EXIT(err);
753
754   /* all done */
755   *chd = newchd;
483   }
756484   return CHDERR_NONE;
757
758cleanup:
759   if (newchd != NULL)
760      chd_close(newchd);
761   return err;
762485}
763486
764487
765/*-------------------------------------------------
766    chd_create - create a CHD file by
767    filename
768-------------------------------------------------*/
488//-------------------------------------------------
489//  set_raw_sha1 - set our SHA1 values
490//-------------------------------------------------
769491
770chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent)
492void chd_file::set_raw_sha1(sha1_t rawdata)
771493{
772   core_file *file = NULL;
773   file_error filerr;
774   chd_error chderr;
775
776   filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
777   if (filerr != FILERR_NONE)
778   {
779      chderr = CHDERR_FILE_NOT_FOUND;
780      goto cleanup;
781   }
782
783   chderr = chd_create_file(file, logicalbytes, hunkbytes, compression, parent);
784   if (chderr != CHDERR_NONE)
785      goto cleanup;
786
787cleanup:
788   if (file != NULL)
789      core_fclose(file);
790   return chderr;
494   // create a big-endian version
495   UINT8 rawbuf[sizeof(sha1_t)];
496   be_write_sha1(rawbuf, rawdata);
497   
498   // write to the header
499   UINT64 offset = (m_rawsha1_offset != 0) ? m_rawsha1_offset : m_sha1_offset;
500   assert(offset != 0);
501   file_write(offset, rawbuf, sizeof(rawbuf));
502   
503   // if we have a separate rawsha1_offset, update the full sha1 as well
504   if (m_rawsha1_offset != 0)
505      metadata_update_hash();
791506}
792507
793508
794/*-------------------------------------------------
795    chd_open - open a CHD file by
796    filename
797-------------------------------------------------*/
509//-------------------------------------------------
510//  set_parent_sha1 - set the parent SHA1 value
511//-------------------------------------------------
798512
799chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
513void chd_file::set_parent_sha1(sha1_t parent)
800514{
801   chd_error err;
802   file_error filerr;
803   core_file *file = NULL;
804   UINT32 openflags;
515   // if no file, fail
516   if (m_file == NULL)
517      throw CHDERR_INVALID_FILE;
805518
806   /* choose the proper mode */
807   switch(mode)
808   {
809      case CHD_OPEN_READ:
810         openflags = OPEN_FLAG_READ;
811         break;
519   // create a big-endian version
520   UINT8 rawbuf[sizeof(sha1_t)];
521   be_write_sha1(rawbuf, parent);
522   
523   // write to the header
524   assert(m_parentsha1_offset != 0);
525   file_write(m_parentsha1_offset, rawbuf, sizeof(rawbuf));
526}
812527
813      case CHD_OPEN_READWRITE:
814         openflags = OPEN_FLAG_READ | OPEN_FLAG_WRITE;
815         break;
816528
817      default:
818         err = CHDERR_INVALID_PARAMETER;
819         goto cleanup;
820   }
529//-------------------------------------------------
530//  create - create a new file with no parent
531//  using an existing opened file handle
532//-------------------------------------------------
821533
822   /* open the file */
823   filerr = core_fopen(filename, openflags, &file);
824   if (filerr != FILERR_NONE)
825   {
826      err = CHDERR_FILE_NOT_FOUND;
827      goto cleanup;
828   }
534chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
535{
536   // make sure we don't already have a file open
537   if (m_file != NULL)
538      return CHDERR_ALREADY_OPEN;
829539
830   /* now open the CHD */
831   err = chd_open_file(file, mode, parent, chd);
832   if (err != CHDERR_NONE)
833      goto cleanup;
540   // set the header parameters
541   m_version = HEADER_VERSION;
542   m_logicalbytes = logicalbytes;
543   m_metaoffset = 0;
544   m_hunkbytes = hunkbytes;
545   m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
546   m_unitbytes = unitbytes;
547   memcpy(m_compression, compression, sizeof(m_compression));
548   m_parent = NULL;
834549
835   /* we now own this file */
836   (*chd)->owns_file = TRUE;
837
838cleanup:
839   if ((err != CHDERR_NONE) && (file != NULL))
840      core_fclose(file);
841   return err;
550   // take ownership of the file
551   m_file = &file;
552   m_owns_file = false;
553   return create_common();
842554}
843555
844556
845/*-------------------------------------------------
846    chd_close - close a CHD file for access
847-------------------------------------------------*/
557//-------------------------------------------------
558//  create - create a new file with a parent
559//  using an existing opened file handle
560//-------------------------------------------------
848561
849void chd_close(chd_file *chd)
562chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
850563{
851   /* punt if NULL or invalid */
852   if (chd == NULL || chd->cookie != COOKIE_VALUE)
853      return;
564   // make sure we don't already have a file open
565   if (m_file != NULL)
566      return CHDERR_ALREADY_OPEN;
854567
855   /* wait for any pending async operations */
856   wait_for_pending_async(chd);
568   // set the header parameters
569   m_version = HEADER_VERSION;
570   m_logicalbytes = logicalbytes;
571   m_metaoffset = 0;
572   m_hunkbytes = hunkbytes;
573   m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
574   m_unitbytes = parent.unit_bytes();
575   memcpy(m_compression, compression, sizeof(m_compression));
576   m_parent = &parent;
857577
858   /* kill the work queue and any work item */
859   if (chd->workitem != NULL)
860      osd_work_item_release(chd->workitem);
861   if (chd->workqueue != NULL)
862      osd_work_queue_free(chd->workqueue);
863
864   /* deinit the codec */
865   if (chd->codecintf != NULL && chd->codecintf->free != NULL)
866      (*chd->codecintf->free)(chd);
867
868   /* free the compressed data buffer */
869   if (chd->compressed != NULL)
870      free(chd->compressed);
871
872   /* free the hunk cache and compare data */
873   if (chd->compare != NULL)
874      free(chd->compare);
875   if (chd->cache != NULL)
876      free(chd->cache);
877
878   /* free the hunk map */
879   if (chd->map != NULL)
880      free(chd->map);
881
882   /* free the CRC table */
883   if (chd->crctable != NULL)
884      free(chd->crctable);
885
886   /* free the CRC map */
887   if (chd->crcmap != NULL)
888      free(chd->crcmap);
889
890   /* close the file */
891   if (chd->owns_file && chd->file != NULL)
892      core_fclose(chd->file);
893
894   if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
895
896   /* free our memory */
897   free(chd);
578   // take ownership of the file
579   m_file = &file;
580   m_owns_file = false;
581   return create_common();
898582}
899583
900584
901/*-------------------------------------------------
902    chd_core_file - return the associated
903    core_file
904-------------------------------------------------*/
585//-------------------------------------------------
586//  create - create a new file with no parent
587//  using a filename
588//-------------------------------------------------
905589
906core_file *chd_core_file(chd_file *chd)
590chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
907591{
908   return chd->file;
909}
592   // make sure we don't already have a file open
593   if (m_file != NULL)
594      return CHDERR_ALREADY_OPEN;
910595
596   // create the new file
597   core_file *file = NULL;
598   file_error filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
599   if (filerr != FILERR_NONE)
600      return CHDERR_FILE_NOT_FOUND;
911601
912/*-------------------------------------------------
913    chd_error_string - return an error string for
914    the given CHD error
915-------------------------------------------------*/
916
917const char *chd_error_string(chd_error err)
918{
919   switch (err)
602   // create the file normally, then claim the file
603   chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression);
604   m_owns_file = true;
605   
606   // if an error happened, close and delete the file
607   if (chderr != CHDERR_NONE)
920608   {
921      case CHDERR_NONE:                  return "no error";
922      case CHDERR_NO_INTERFACE:            return "no drive interface";
923      case CHDERR_OUT_OF_MEMORY:            return "out of memory";
924      case CHDERR_INVALID_FILE:            return "invalid file";
925      case CHDERR_INVALID_PARAMETER:         return "invalid parameter";
926      case CHDERR_INVALID_DATA:            return "invalid data";
927      case CHDERR_FILE_NOT_FOUND:            return "file not found";
928      case CHDERR_REQUIRES_PARENT:         return "requires parent";
929      case CHDERR_FILE_NOT_WRITEABLE:         return "file not writeable";
930      case CHDERR_READ_ERROR:               return "read error";
931      case CHDERR_WRITE_ERROR:            return "write error";
932      case CHDERR_CODEC_ERROR:            return "codec error";
933      case CHDERR_INVALID_PARENT:            return "invalid parent";
934      case CHDERR_HUNK_OUT_OF_RANGE:         return "hunk out of range";
935      case CHDERR_DECOMPRESSION_ERROR:      return "decompression error";
936      case CHDERR_COMPRESSION_ERROR:         return "compression error";
937      case CHDERR_CANT_CREATE_FILE:         return "can't create file";
938      case CHDERR_CANT_VERIFY:            return "can't verify file";
939      case CHDERR_NOT_SUPPORTED:            return "operation not supported";
940      case CHDERR_METADATA_NOT_FOUND:         return "can't find metadata";
941      case CHDERR_INVALID_METADATA_SIZE:      return "invalid metadata size";
942      case CHDERR_UNSUPPORTED_VERSION:      return "unsupported CHD version";
943      case CHDERR_VERIFY_INCOMPLETE:         return "incomplete verify";
944      case CHDERR_INVALID_METADATA:         return "invalid metadata";
945      case CHDERR_INVALID_STATE:            return "invalid state";
946      case CHDERR_OPERATION_PENDING:         return "operation pending";
947      case CHDERR_NO_ASYNC_OPERATION:         return "no async operation in progress";
948      case CHDERR_UNSUPPORTED_FORMAT:         return "unsupported format";
949      default:                        return "undocumented error";
609      core_fclose(file);
610      osd_rmfile(filename);
950611   }
612   return chderr;
951613}
952614
953615
616//-------------------------------------------------
617//  create - create a new file with a parent
618//  using a filename
619//-------------------------------------------------
954620
955/***************************************************************************
956    CHD HEADER MANAGEMENT
957***************************************************************************/
958
959/*-------------------------------------------------
960    chd_get_header - return a pointer to the
961    extracted header data
962-------------------------------------------------*/
963
964const chd_header *chd_get_header(chd_file *chd)
621chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
965622{
966   /* punt if NULL or invalid */
967   if (chd == NULL || chd->cookie != COOKIE_VALUE)
968      return NULL;
623   // make sure we don't already have a file open
624   if (m_file != NULL)
625      return CHDERR_ALREADY_OPEN;
969626
970   return &chd->header;
971}
627   // create the new file
628   core_file *file = NULL;
629   file_error filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
630   if (filerr != FILERR_NONE)
631      return CHDERR_FILE_NOT_FOUND;
972632
973
974/*-------------------------------------------------
975    chd_set_header_file - write the current header to
976    the file
977-------------------------------------------------*/
978
979chd_error chd_set_header_file(core_file *file, const chd_header *header)
980{
981   chd_header oldheader;
982   chd_error err;
983
984   /* validate the header */
985   err = header_validate(header);
986   if (err != CHDERR_NONE)
987      EARLY_EXIT(err);
988
989   /* read the old header */
990   err = header_read(file, &oldheader);
991   if (err != CHDERR_NONE)
992      EARLY_EXIT(err);
993
994   /* make sure we're only making valid changes */
995   if (header->length != oldheader.length)
996      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
997   if (header->version != oldheader.version)
998      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
999   if (header->compression != oldheader.compression)
1000      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1001   if (header->hunkbytes != oldheader.hunkbytes)
1002      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1003   if (header->totalhunks != oldheader.totalhunks)
1004      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1005   if (header->metaoffset != oldheader.metaoffset)
1006      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1007   if (header->obsolete_hunksize != oldheader.obsolete_hunksize)
1008      EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1009
1010   /* write the new header */
1011   err = header_write(file, header);
1012   if (err != CHDERR_NONE)
1013      EARLY_EXIT(err);
1014
1015   return CHDERR_NONE;
1016
1017cleanup:
1018   return err;
633   // create the file normally, then claim the file
634   chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent);
635   m_owns_file = true;
636   
637   // if an error happened, close and delete the file
638   if (chderr != CHDERR_NONE)
639   {
640      core_fclose(file);
641      osd_rmfile(filename);
642   }
643   return chderr;
1019644}
1020645
1021646
1022/*-------------------------------------------------
1023    chd_set_header - write the current
1024    header to the file
1025-------------------------------------------------*/
647//-------------------------------------------------
648//  open - open an existing file for read or
649//  read/write
650//-------------------------------------------------
1026651
1027chd_error chd_set_header(const char *filename, const chd_header *header)
652chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
1028653{
1029   core_file *file = NULL;
1030   file_error filerr;
1031   chd_error err;
654   // make sure we don't already have a file open
655   if (m_file != NULL)
656      return CHDERR_ALREADY_OPEN;
1032657
1033   filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE, &file);
658   // open the file
659   UINT32 openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ;
660   core_file *file = NULL;
661   file_error filerr = core_fopen(filename, openflags, &file);
1034662   if (filerr != FILERR_NONE)
1035   {
1036      err = CHDERR_FILE_NOT_FOUND;
1037      goto cleanup;
1038   }
663      return CHDERR_FILE_NOT_FOUND;
1039664
1040   err = chd_set_header_file(file, header);
665   // now open the CHD
666   chd_error err = open(*file, writeable, parent);
1041667   if (err != CHDERR_NONE)
1042      goto cleanup;
1043
1044cleanup:
1045   if (file != NULL)
668   {
1046669      core_fclose(file);
670      return err;
671   }
672     
673   // we now own this file
674   m_owns_file = true;
1047675   return err;
1048676}
1049677
1050678
679//-------------------------------------------------
680//  open - open an existing file for read or
681//  read/write
682//-------------------------------------------------
1051683
1052/***************************************************************************
1053    CORE DATA READ/WRITE
1054***************************************************************************/
1055
1056/*-------------------------------------------------
1057    chd_read - read a single hunk from the CHD
1058    file
1059-------------------------------------------------*/
1060
1061chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
684chd_error chd_file::open(core_file &file, bool writeable, chd_file *parent)
1062685{
1063   /* punt if NULL or invalid */
1064   if (chd == NULL || chd->cookie != COOKIE_VALUE)
1065      return CHDERR_INVALID_PARAMETER;
686   // make sure we don't already have a file open
687   if (m_file != NULL)
688      return CHDERR_ALREADY_OPEN;
1066689
1067   /* if we're past the end, fail */
1068   if (hunknum >= chd->header.totalhunks)
1069      return CHDERR_HUNK_OUT_OF_RANGE;
1070
1071   /* wait for any pending async operations */
1072   wait_for_pending_async(chd);
1073
1074   /* perform the read */
1075   return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
690   // open the file
691   m_file = &file;
692   m_owns_file = false;
693   m_parent = parent;
694   return open_common(writeable);
1076695}
1077696
1078697
1079/*-------------------------------------------------
1080    chd_read_async - read a single hunk from the
1081    CHD file asynchronously
1082-------------------------------------------------*/
698//-------------------------------------------------
699//  close - close a CHD file for access
700//-------------------------------------------------
1083701
1084chd_error chd_read_async(chd_file *chd, UINT32 hunknum, void *buffer)
702void chd_file::close()
1085703{
1086   /* punt if NULL or invalid */
1087   if (chd == NULL || chd->cookie != COOKIE_VALUE)
1088      return CHDERR_INVALID_PARAMETER;
704   // reset file characteristics
705   if (m_owns_file && m_file != NULL)
706      core_fclose(m_file);
707   m_file = NULL;
708   m_owns_file = false;
709   m_allow_reads = false;
710   m_allow_writes = false;
711   
712   // reset core parameters from the header
713   m_version = HEADER_VERSION;
714   m_logicalbytes = 0;
715   m_mapoffset = 0;
716   m_metaoffset = 0;
717   m_hunkbytes = 0;
718   m_hunkcount = 0;
719   m_unitbytes = 0;
720   m_unitcount = 0;
721   memset(m_compression, 0, sizeof(m_compression));
722   m_parent = NULL;
723   m_parent_missing = false;
1089724
1090   /* if we're past the end, fail */
1091   if (hunknum >= chd->header.totalhunks)
1092      return CHDERR_HUNK_OUT_OF_RANGE;
725   // reset key offsets within the header
726   m_mapoffset_offset = 0;
727   m_metaoffset_offset = 0;
728   m_sha1_offset = 0;
729   m_rawsha1_offset = 0;
730   m_parentsha1_offset = 0;
1093731
1094   /* wait for any pending async operations */
1095   wait_for_pending_async(chd);
732   // reset map information
733   m_mapentrybytes = 0;
734   m_rawmap.reset();
1096735
1097   /* set the async parameters */
1098   chd->async_hunknum = hunknum;
1099   chd->async_buffer = buffer;
736   // reset compression management
737   for (int decompnum = 0; decompnum < ARRAY_LENGTH(m_decompressor); decompnum++)
738   {
739      delete m_decompressor[decompnum];
740      m_decompressor[decompnum] = NULL;
741   }
742   m_compressed.reset();
1100743
1101   /* queue the work item */
1102   if (queue_async_operation(chd, async_read_callback))
1103      return CHDERR_OPERATION_PENDING;
1104
1105   /* if we fail, fall back on the sync version */
1106   return chd_read(chd, hunknum, buffer);
744   // reset caching
745   m_cache.reset();
746   m_cachehunk = ~0;
1107747}
1108748
1109749
1110/*-------------------------------------------------
1111    chd_write - write a single hunk to the CHD
1112    file
1113-------------------------------------------------*/
750//-------------------------------------------------
751//  read - read a single hunk from the CHD file
752//-------------------------------------------------
1114753
1115chd_error chd_write(chd_file *chd, UINT32 hunknum, const void *buffer)
754chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer)
1116755{
1117   /* punt if NULL or invalid */
1118   if (chd == NULL || chd->cookie != COOKIE_VALUE)
1119      return CHDERR_INVALID_PARAMETER;
756   // wrap this for clean reporting
757   try
758   {
759      // punt if no file
760      if (m_file == NULL)
761         throw CHDERR_NOT_OPEN;
762     
763      // return an error if out of range
764      if (hunknum >= m_hunkcount)
765         throw CHDERR_HUNK_OUT_OF_RANGE;
1120766
1121   /* if we're past the end, fail */
1122   if (hunknum >= chd->header.totalhunks)
1123      return CHDERR_HUNK_OUT_OF_RANGE;
767      // get a pointer to the map entry
768      UINT64 blockoffs;
769      UINT32 blocklen;
770      UINT32 blockcrc;
771      UINT8 *rawmap;
772      UINT8 *dest = reinterpret_cast<UINT8 *>(buffer);
773      switch (m_version)
774      {
775         // v3/v4 map entries
776         case 3:
777         case 4:
778            rawmap = m_rawmap + 16 * hunknum;
779            blockoffs = be_read(&rawmap[0], 8);
780            blockcrc = be_read(&rawmap[8], 4);
781            switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK)
782            {
783               case V34_MAP_ENTRY_TYPE_COMPRESSED:
784                  blocklen = be_read(&rawmap[12], 2) + (rawmap[14] << 16);
785                  file_read(blockoffs, m_compressed, blocklen);
786                  m_decompressor[0]->decompress(m_compressed, blocklen, dest, m_hunkbytes);
787                  if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != NULL && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
788                     throw CHDERR_DECOMPRESSION_ERROR;
789                  return CHDERR_NONE;
790                 
791               case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
792                  file_read(blockoffs, dest, m_hunkbytes);
793                  if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
794                     throw CHDERR_DECOMPRESSION_ERROR;
795                  return CHDERR_NONE;
796                 
797               case V34_MAP_ENTRY_TYPE_MINI:
798                  be_write(dest, blockoffs, 8);
799                  for (UINT32 bytes = 8; bytes < m_hunkbytes; bytes++)
800                     dest[bytes] = dest[bytes - 8];
801                  if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
802                     throw CHDERR_DECOMPRESSION_ERROR;
803                  return CHDERR_NONE;
804               
805               case V34_MAP_ENTRY_TYPE_SELF_HUNK:
806                  return read_hunk(blockoffs, dest);
1124807
1125   /* wait for any pending async operations */
1126   wait_for_pending_async(chd);
808               case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
809                  if (m_parent_missing)
810                     throw CHDERR_REQUIRES_PARENT;
811                  return m_parent->read_hunk(blockoffs, dest);
812            }
813            break;
814         
815         // v5 map entries
816         case 5:
817            rawmap = m_rawmap + m_mapentrybytes * hunknum;
1127818
1128   /* then write out the hunk */
1129   return hunk_write_from_memory(chd, hunknum, (const UINT8 *)buffer);
1130}
819            // uncompressed case
820            if (!compressed())
821            {
822               blockoffs = UINT64(be_read(rawmap, 4)) * UINT64(m_hunkbytes);
823               if (blockoffs != 0)
824                  file_read(blockoffs, dest, m_hunkbytes);
825               else if (m_parent_missing)
826                  throw CHDERR_REQUIRES_PARENT;
827               else if (m_parent != NULL)
828                  m_parent->read_hunk(hunknum, dest);
829               else
830                  memset(dest, 0, m_hunkbytes);
831               return CHDERR_NONE;
832            }
833           
834            // compressed case
835            blocklen = be_read(&rawmap[1], 3);
836            blockoffs = be_read(&rawmap[4], 6);
837            blockcrc = be_read(&rawmap[10], 2);
838            switch (rawmap[0])
839            {
840               case COMPRESSION_TYPE_0:
841               case COMPRESSION_TYPE_1:
842               case COMPRESSION_TYPE_2:
843               case COMPRESSION_TYPE_3:
844                  file_read(blockoffs, m_compressed, blocklen);
845                  m_decompressor[rawmap[0]]->decompress(m_compressed, blocklen, dest, m_hunkbytes);
846                  if (!m_decompressor[rawmap[0]]->lossy() && dest != NULL && crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
847                     throw CHDERR_DECOMPRESSION_ERROR;
848                  if (m_decompressor[rawmap[0]]->lossy() && crc16_creator::simple(m_compressed, blocklen) != blockcrc)
849                     throw CHDERR_DECOMPRESSION_ERROR;
850                  return CHDERR_NONE;
1131851
852               case COMPRESSION_NONE:
853                  file_read(blockoffs, dest, m_hunkbytes);
854                  if (crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
855                     throw CHDERR_DECOMPRESSION_ERROR;
856                  return CHDERR_NONE;
1132857
1133/*-------------------------------------------------
1134    chd_write_async - write a single hunk to the
1135    CHD file asynchronously
1136-------------------------------------------------*/
1137
1138chd_error chd_write_async(chd_file *chd, UINT32 hunknum, const void *buffer)
1139{
1140   /* punt if NULL or invalid */
1141   if (chd == NULL || chd->cookie != COOKIE_VALUE)
1142      return CHDERR_INVALID_PARAMETER;
1143
1144   /* if we're past the end, fail */
1145   if (hunknum >= chd->header.totalhunks)
1146      return CHDERR_HUNK_OUT_OF_RANGE;
1147
1148   /* wait for any pending async operations */
1149   wait_for_pending_async(chd);
1150
1151   /* set the async parameters */
1152   chd->async_hunknum = hunknum;
1153   chd->async_buffer = (void *)buffer;
1154
1155   /* queue the work item */
1156   if (queue_async_operation(chd, async_write_callback))
1157      return CHDERR_OPERATION_PENDING;
1158
1159   /* if we fail, fall back on the sync version */
1160   return chd_write(chd, hunknum, buffer);
858               case COMPRESSION_SELF:
859                  return read_hunk(blockoffs, dest);
860                 
861               case COMPRESSION_PARENT:
862                  if (m_parent_missing)
863                     throw CHDERR_REQUIRES_PARENT;
864                  return m_parent->read_bytes(UINT64(blockoffs) * UINT64(m_parent->unit_bytes()), dest, m_hunkbytes);
865            }
866            break;
867      }
868     
869      // if we get here, something was wrong
870      throw CHDERR_READ_ERROR;
871   }
872   
873   // just return errors
874   catch (chd_error &err)
875   {
876      return err;
877   }
1161878}
1162879
1163880
1164/*-------------------------------------------------
1165    chd_async_complete - get the result of a
1166    completed work item and clear it out of the
1167    system
1168-------------------------------------------------*/
881//-------------------------------------------------
882//  write - write a single hunk to the CHD file
883//-------------------------------------------------
1169884
1170chd_error chd_async_complete(chd_file *chd)
885chd_error chd_file::write_hunk(UINT32 hunknum, const void *buffer)
1171886{
1172   void *result;
887   // wrap this for clean reporting
888   try
889   {
890      // punt if no file
891      if (m_file == NULL)
892         throw CHDERR_NOT_OPEN;
1173893
1174   /* if nothing present, return an error */
1175   if (chd->workitem == NULL)
1176      return CHDERR_NO_ASYNC_OPERATION;
894      // return an error if out of range
895      if (hunknum >= m_hunkcount)
896         throw CHDERR_HUNK_OUT_OF_RANGE;
1177897
1178   /* wait for the work to complete */
1179   wait_for_pending_async(chd);
898      // if not writeable, fail
899      if (!m_allow_writes)
900         throw CHDERR_FILE_NOT_WRITEABLE;
1180901
1181   /* get the result and free the work item */
1182   result = osd_work_item_result(chd->workitem);
1183   osd_work_item_release(chd->workitem);
1184   chd->workitem = NULL;
902      // uncompressed writes only via this interface
903      if (compressed())
904         throw CHDERR_FILE_NOT_WRITEABLE;
905     
906      // see if we have allocated the space on disk for this hunk
907      UINT8 *rawmap = m_rawmap + hunknum * 4;
908      UINT32 rawentry = be_read(rawmap, 4);
1185909
1186   return (chd_error)(ptrdiff_t)result;
1187}
1188
1189
1190
1191/***************************************************************************
1192    METADATA MANAGEMENT
1193***************************************************************************/
1194
1195/*-------------------------------------------------
1196    chd_get_metadata - get the indexed metadata
1197    of the given type
1198-------------------------------------------------*/
1199
1200chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
1201{
1202   metadata_entry metaentry;
1203   chd_error err;
1204   UINT32 count;
1205
1206   /* wait for any pending async operations */
1207   wait_for_pending_async(chd);
1208
1209   /* if we didn't find it, just return */
1210   err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
1211   if (err != CHDERR_NONE)
1212   {
1213      /* unless we're an old version and they are requesting hard disk metadata */
1214      if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
910      // if not, allocate one now
911      if (rawentry == 0)
1215912      {
1216         char faux_metadata[256];
1217         UINT32 faux_length;
1218
1219         /* fill in the faux metadata */
1220         sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize);
1221         faux_length = (UINT32)strlen(faux_metadata) + 1;
1222
1223         /* copy the metadata itself */
1224         memcpy(output, faux_metadata, MIN(outputlen, faux_length));
1225
1226         /* return the length of the data and the tag */
1227         if (resultlen != NULL)
1228            *resultlen = faux_length;
1229         if (resulttag != NULL)
1230            *resulttag = HARD_DISK_METADATA_TAG;
1231         return CHDERR_NONE;
913         // append new data to the end of the file, aligning the first chunk
914         rawentry = file_append(buffer, m_hunkbytes, m_hunkbytes) / m_hunkbytes;
915         
916         // write the map entry back
917         be_write(rawmap, rawentry, 4);
918         file_write(m_mapoffset + hunknum * 4, rawmap, 4);
919         
920         // update the cached hunk if we just wrote it
921         if (hunknum == m_cachehunk && buffer != m_cache)
922            memcpy(m_cache, buffer, m_hunkbytes);
1232923      }
924     
925      // otherwise, just overwrite
926      else
927         file_write(UINT64(rawentry) * UINT64(m_hunkbytes), buffer, m_hunkbytes);
928      return CHDERR_NONE;
929   }
930   
931   // just return errors
932   catch (chd_error &err)
933   {
1233934      return err;
1234935   }
1235
1236   /* read the metadata */
1237   outputlen = MIN(outputlen, metaentry.length);
1238   core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
1239   count = core_fread(chd->file, output, outputlen);
1240   if (count != outputlen)
1241      return CHDERR_READ_ERROR;
1242
1243   /* return the length of the data and the tag */
1244   if (resultlen != NULL)
1245      *resultlen = metaentry.length;
1246   if (resulttag != NULL)
1247      *resulttag = metaentry.metatag;
1248   if (resultflags != NULL)
1249      *resultflags = metaentry.flags;
1250   return CHDERR_NONE;
1251936}
1252937
1253938
1254/*-------------------------------------------------
1255    chd_set_metadata - write the indexed metadata
1256    of the given type
1257-------------------------------------------------*/
939//-------------------------------------------------
940//  read_units - read the given number of units
941//  from the CHD
942//-------------------------------------------------
1258943
1259chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen, UINT8 flags)
944chd_error chd_file::read_units(UINT64 unitnum, void *buffer, UINT32 count)
1260945{
1261   UINT8 raw_meta_header[METADATA_HEADER_SIZE];
1262   metadata_entry metaentry = { 0 };
1263   chd_error err;
1264   UINT64 offset;
1265   UINT32 count;
946   return read_bytes(unitnum * UINT64(m_unitbytes), buffer, count * m_unitbytes);
947}
1266948
1267   /* if the disk is an old version, punt */
1268   if (chd->header.version < 3)
1269      return CHDERR_NOT_SUPPORTED;
1270949
1271   /* if the disk isn't writeable, punt */
1272   if (!(chd->header.flags & CHDFLAGS_IS_WRITEABLE))
1273      return CHDERR_FILE_NOT_WRITEABLE;
950//-------------------------------------------------
951//  write_units - write the given number of units
952//  to the CHD
953//-------------------------------------------------
1274954
1275   /* must write at least 1 byte */
1276   if (inputlen < 1)
1277      return CHDERR_INVALID_PARAMETER;
955chd_error chd_file::write_units(UINT64 unitnum, const void *buffer, UINT32 count)
956{
957   return write_bytes(unitnum * UINT64(m_unitbytes), buffer, count * m_unitbytes);
958}
1278959
1279   /* no more than 16MB */
1280   if (inputlen >= 16 * 1024 * 1024)
1281      return CHDERR_INVALID_PARAMETER;
1282960
1283   /* wait for any pending async operations */
1284   wait_for_pending_async(chd);
961//-------------------------------------------------
962//  read_bytes - read from the CHD at a byte level,
963//  using the cache to handle partial hunks
964//-------------------------------------------------
1285965
1286   /* find the entry if it already exists */
1287   err = metadata_find_entry(chd, metatag, metaindex, &metaentry);
1288
1289   /* if it's there and it fits, just overwrite */
1290   if (err == CHDERR_NONE && inputlen <= metaentry.length)
966chd_error chd_file::read_bytes(UINT64 offset, void *buffer, UINT32 bytes)
967{
968   // iterate over hunks
969   UINT32 first_hunk = offset / m_hunkbytes;
970   UINT32 last_hunk = (offset + bytes - 1) / m_hunkbytes;
971   UINT8 *dest = reinterpret_cast<UINT8 *>(buffer);
972   for (UINT32 curhunk = first_hunk; curhunk <= last_hunk; curhunk++)
1291973   {
1292      /* overwrite the original data with our new input data */
1293      core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
1294      count = core_fwrite(chd->file, inputbuf, inputlen);
1295      if (count != inputlen)
974      // determine start/end boundaries
975      UINT32 startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0;
976      UINT32 endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1);
977     
978      // if it's a full block, just read directly from disk unless it's the cached hunk
979      chd_error err = CHDERR_NONE;
980      if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk)
981         err = read_hunk(curhunk, dest);
982     
983      // otherwise, read from the cache
984      else
1296985      {
1297         err = CHDERR_WRITE_ERROR;
1298         goto update;
986         if (curhunk != m_cachehunk)
987         {
988            err = read_hunk(curhunk, m_cache);
989            if (err != CHDERR_NONE)
990               return err;
991            m_cachehunk = curhunk;
992         }
993         memcpy(dest, &m_cache[startoffs], endoffs + 1 - startoffs);
1299994      }
1300995
1301      /* if the lengths don't match, we need to update the length in our header */
1302      if (inputlen != metaentry.length)
1303         err = metadata_set_length(chd, metaentry.offset, inputlen);
1304      goto update;
1305   }
1306
1307   /* if we already have an entry, unlink it */
1308   if (err == CHDERR_NONE)
1309   {
1310      err = metadata_set_previous_next(chd, metaentry.prev, metaentry.next);
996      // handle errors and advance
1311997      if (err != CHDERR_NONE)
1312         goto update;
998         return err;
999      dest += endoffs + 1 - startoffs;
13131000   }
1314
1315   /* now build us a new entry */
1316   put_bigendian_uint32(&raw_meta_header[0], metatag);
1317   put_bigendian_uint32(&raw_meta_header[4], (inputlen & 0x00ffffff) | (flags << 24));
1318   put_bigendian_uint64(&raw_meta_header[8], (err == CHDERR_NONE) ? metaentry.next : 0);
1319
1320   /* write out the new header */
1321   offset = core_fsize(chd->file);
1322   core_fseek(chd->file, offset, SEEK_SET);
1323   count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
1324   if (count != sizeof(raw_meta_header))
1325   {
1326      err = CHDERR_WRITE_ERROR;
1327      goto update;
1328   }
1329
1330   /* follow that with the data */
1331   core_fseek(chd->file, offset + METADATA_HEADER_SIZE, SEEK_SET);
1332   count = core_fwrite(chd->file, inputbuf, inputlen);
1333   if (count != inputlen)
1334   {
1335      err = CHDERR_WRITE_ERROR;
1336      goto update;
1337   }
1338
1339   /* set the previous entry to point to us */
1340   err = metadata_set_previous_next(chd, metaentry.prev, offset);
1341
1342update:
1343   /* update the hash */
1344   if (metadata_compute_hash(chd, chd->header.rawsha1, chd->header.sha1) == CHDERR_NONE)
1345      err = header_write(chd->file, &chd->header);
1346   return err;
1001   return CHDERR_NONE;
13471002}
13481003
13491004
1350/*-------------------------------------------------
1351    chd_clone_metadata - clone the metadata from
1352    one CHD to a second
1353-------------------------------------------------*/
1005//-------------------------------------------------
1006//  write_bytes - write to the CHD at a byte level,
1007//  using the cache to handle partial hunks
1008//-------------------------------------------------
13541009
1355chd_error chd_clone_metadata(chd_file *source, chd_file *dest)
1010chd_error chd_file::write_bytes(UINT64 offset, const void *buffer, UINT32 bytes)
13561011{
1357   UINT32 metatag, metasize, metaindex;
1358   UINT8 metabuffer[1024];
1359   UINT8 metaflags;
1360   chd_error err;
1361
1362   /* clone the metadata */
1363   for (metaindex = 0; ; metaindex++)
1012   // iterate over hunks
1013   UINT32 first_hunk = offset / m_hunkbytes;
1014   UINT32 last_hunk = (offset + bytes - 1) / m_hunkbytes;
1015   const UINT8 *source = reinterpret_cast<const UINT8 *>(buffer);
1016   for (UINT32 curhunk = first_hunk; curhunk <= last_hunk; curhunk++)
13641017   {
1365      /* fetch the next piece of metadata */
1366      err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, metabuffer, sizeof(metabuffer), &metasize, &metatag, &metaflags);
1367      if (err != CHDERR_NONE)
1368      {
1369         if (err == CHDERR_METADATA_NOT_FOUND)
1370            err = CHDERR_NONE;
1371         break;
1372      }
1373
1374      /* if that fit, just write it back from the temporary buffer */
1375      if (metasize <= sizeof(metabuffer))
1376      {
1377         /* write it to the target */
1378         err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, metabuffer, metasize, metaflags);
1379         if (err != CHDERR_NONE)
1380            break;
1381      }
1382
1383      /* otherwise, allocate a bigger temporary buffer */
1018      // determine start/end boundaries
1019      UINT32 startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0;
1020      UINT32 endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1);
1021     
1022      // if it's a full block, just write directly to disk unless it's the cached hunk
1023      chd_error err = CHDERR_NONE;
1024      if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk)
1025         err = write_hunk(curhunk, source);
1026     
1027      // otherwise, write from the cache
13841028      else
13851029      {
1386         UINT8 *allocbuffer = (UINT8 *)malloc(metasize);
1387         if (allocbuffer == NULL)
1030         if (curhunk != m_cachehunk)
13881031         {
1389            err = CHDERR_OUT_OF_MEMORY;
1390            break;
1032            err = read_hunk(curhunk, m_cache);
1033            if (err != CHDERR_NONE)
1034               return err;
1035            m_cachehunk = curhunk;
13911036         }
1392
1393         /* re-read the whole thing */
1394         err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, allocbuffer, metasize, &metasize, &metatag, &metaflags);
1395         if (err != CHDERR_NONE)
1396         {
1397            free(allocbuffer);
1398            break;
1399         }
1400
1401         /* write it to the target */
1402         err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, allocbuffer, metasize, metaflags);
1403         free(allocbuffer);
1404         if (err != CHDERR_NONE)
1405            break;
1037         memcpy(&m_cache[startoffs], source, endoffs + 1 - startoffs);
1038         err = write_hunk(curhunk, m_cache);
14061039      }
1040
1041      // handle errors and advance
1042      if (err != CHDERR_NONE)
1043         return err;
1044      source += endoffs + 1 - startoffs;
14071045   }
1408   return err;
1046   return CHDERR_NONE;
14091047}
14101048
14111049
1050//-------------------------------------------------
1051//  read_metadata - read the indexed metadata
1052//  of the given type
1053//-------------------------------------------------
14121054
1413/***************************************************************************
1414    COMPRESSION MANAGEMENT
1415***************************************************************************/
1416
1417/*-------------------------------------------------
1418    chd_compress_begin - begin compressing data
1419    into a CHD
1420-------------------------------------------------*/
1421
1422chd_error chd_compress_begin(chd_file *chd)
1055chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, astring &output)
14231056{
1424   chd_error err;
1057   // wrap this for clean reporting
1058   try
1059   {
1060      // if we didn't find it, just return
1061      metadata_entry metaentry;
1062      if (!metadata_find(searchtag, searchindex, metaentry))
1063         throw CHDERR_METADATA_NOT_FOUND;
14251064
1426   /* verify parameters */
1427   if (chd == NULL)
1428      return CHDERR_INVALID_PARAMETER;
1429
1430   /* wait for any pending async operations */
1431   wait_for_pending_async(chd);
1432
1433   /* mark the CHD writeable and write the updated header */
1434   chd->header.flags |= CHDFLAGS_IS_WRITEABLE;
1435   err = header_write(chd->file, &chd->header);
1436   if (err != CHDERR_NONE)
1065      // read the metadata
1066      file_read(metaentry.offset + METADATA_HEADER_SIZE, output.stringbuffer(metaentry.length), metaentry.length);
1067      return CHDERR_NONE;
1068   }
1069   
1070   // just return errors
1071   catch (chd_error &err)
1072   {
14371073      return err;
1438
1439   /* create CRC maps for the new CHD and the parent */
1440   crcmap_init(chd, FALSE);
1441   if (chd->parent != NULL)
1442      crcmap_init(chd->parent, TRUE);
1443
1444   /* init the MD5/SHA1 computations */
1445   MD5Init(&chd->compmd5);
1446   sha1_init(&chd->compsha1);
1447   chd->compressing = TRUE;
1448   chd->comphunk = 0;
1449
1450   return CHDERR_NONE;
1074   }
14511075}
14521076
1453
1454/*-------------------------------------------------
1455    chd_compress_hunk - append data to a CHD
1456    that is being compressed
1457-------------------------------------------------*/
1458
1459chd_error chd_compress_hunk(chd_file *chd, const void *data, double *curratio, int is_half_hunk)
1077chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output)
14601078{
1461   UINT32 thishunk = chd->comphunk++;
1462   UINT64 sourceoffset = (UINT64)thishunk * (UINT64)chd->header.hunkbytes;
1463   UINT32 bytestochecksum;
1464   const void *crcdata;
1465   chd_error err;
1466
1467   /* error if in the wrong state */
1468   if (!chd->compressing)
1469      return CHDERR_INVALID_STATE;
1470
1471   /* write out the hunk */
1472   err = hunk_write_from_memory(chd, thishunk, (const UINT8 *)data, is_half_hunk);
1473   if (err != CHDERR_NONE)
1474      return err;
1475
1476   /* if we are lossy, then we need to use the decompressed version in */
1477   /* the cache as our MD5/SHA1 source */
1478   crcdata = (chd->codecintf->lossy || data == NULL) ? chd->cache : data;
1479
1480   /* update the MD5/SHA1 */
1481   bytestochecksum = chd->header.hunkbytes;
1482
1483   if (is_half_hunk)
1079   // wrap this for clean reporting
1080   try
14841081   {
1485      bytestochecksum = bytestochecksum/2;
1486   }
1082      // if we didn't find it, just return
1083      metadata_entry metaentry;
1084      if (!metadata_find(searchtag, searchindex, metaentry))
1085         throw CHDERR_METADATA_NOT_FOUND;
14871086
1488   if (sourceoffset + chd->header.hunkbytes > chd->header.logicalbytes)
1489   {
1490      if (sourceoffset >= chd->header.logicalbytes)
1491         bytestochecksum = 0;
1492      else
1493         bytestochecksum = chd->header.logicalbytes - sourceoffset;
1087      // read the metadata
1088      output.resize(metaentry.length);
1089      file_read(metaentry.offset + METADATA_HEADER_SIZE, output, metaentry.length);
1090      return CHDERR_NONE;
14941091   }
1495   if (bytestochecksum > 0)
1092   
1093   // just return errors
1094   catch (chd_error &err)
14961095   {
1497      MD5Update(&chd->compmd5, (const unsigned char *)crcdata, bytestochecksum);
1498      sha1_update(&chd->compsha1, bytestochecksum, (const UINT8 *)crcdata);
1096      return err;
14991097   }
1098}
15001099
1501   /* update our CRC map */
1502   if ((chd->map[thishunk].flags & MAP_ENTRY_FLAG_TYPE_MASK) != MAP_ENTRY_TYPE_SELF_HUNK &&
1503      (chd->map[thishunk].flags & MAP_ENTRY_FLAG_TYPE_MASK) != MAP_ENTRY_TYPE_PARENT_HUNK)
1504      crcmap_add_entry(chd, thishunk);
1100chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 &resultlen)
1101{
1102   // wrap this for clean reporting
1103   try
1104   {
1105      // if we didn't find it, just return
1106      metadata_entry metaentry;
1107      if (!metadata_find(searchtag, searchindex, metaentry))
1108         throw CHDERR_METADATA_NOT_FOUND;
15051109
1506   /* update the ratio */
1507   if (curratio != NULL)
1110      // read the metadata
1111      resultlen = metaentry.length;
1112      file_read(metaentry.offset + METADATA_HEADER_SIZE, output, MIN(outputlen, resultlen));
1113      return CHDERR_NONE;
1114   }
1115   
1116   // just return errors
1117   catch (chd_error &err)
15081118   {
1509      UINT64 curlength = core_fsize(chd->file);
1510      *curratio = 1.0 - (double)curlength / (double)((UINT64)chd->comphunk * (UINT64)chd->header.hunkbytes);
1119      return err;
15111120   }
1512
1513   return CHDERR_NONE;
15141121}
15151122
1516
1517/*-------------------------------------------------
1518    chd_compress_finish - complete compression of
1519    a CHD
1520-------------------------------------------------*/
1521
1522chd_error chd_compress_finish(chd_file *chd, int write_protect)
1123chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output, chd_metadata_tag &resulttag, UINT8 &resultflags)
15231124{
1524   /* error if in the wrong state */
1525   if (!chd->compressing)
1526      return CHDERR_INVALID_STATE;
1125   // wrap this for clean reporting
1126   try
1127   {
1128      // if we didn't find it, just return
1129      metadata_entry metaentry;
1130      if (!metadata_find(searchtag, searchindex, metaentry))
1131         throw CHDERR_METADATA_NOT_FOUND;
15271132
1528   /* compute the final MD5/SHA1 values */
1529   MD5Final(chd->header.md5, &chd->compmd5);
1530   sha1_final(&chd->compsha1);
1531   sha1_digest(&chd->compsha1, SHA1_DIGEST_SIZE, chd->header.rawsha1);
1532   metadata_compute_hash(chd, chd->header.rawsha1, chd->header.sha1);
1533
1534   /* turn off the writeable flag and re-write the header */
1535   if (chd->header.compression != CHDCOMPRESSION_NONE || write_protect)
1536      chd->header.flags &= ~CHDFLAGS_IS_WRITEABLE;
1537   chd->compressing = FALSE;
1538   return header_write(chd->file, &chd->header);
1133      // read the metadata
1134      output.resize(metaentry.length);
1135      file_read(metaentry.offset + METADATA_HEADER_SIZE, output, metaentry.length);
1136      resulttag = metaentry.metatag;
1137      resultflags = metaentry.flags;
1138      return CHDERR_NONE;
1139   }
1140   
1141   // just return errors
1142   catch (chd_error &err)
1143   {
1144      return err;
1145   }
15391146}
15401147
15411148
1149//-------------------------------------------------
1150//  write_metadata - write the indexed metadata
1151//  of the given type
1152//-------------------------------------------------
15421153
1543/***************************************************************************
1544    VERIFICATION
1545***************************************************************************/
1546
1547/*-------------------------------------------------
1548    chd_verify_begin - begin compressing data
1549    into a CHD
1550-------------------------------------------------*/
1551
1552chd_error chd_verify_begin(chd_file *chd)
1154chd_error chd_file::write_metadata(chd_metadata_tag metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen, UINT8 flags)
15531155{
1554   /* verify parameters */
1555   if (chd == NULL)
1556      return CHDERR_INVALID_PARAMETER;
1156   // wrap this for clean reporting
1157   try
1158   {
1159      // must write at least 1 byte and no more than 16MB
1160      if (inputlen < 1 || inputlen >= 16 * 1024 * 1024)
1161         return CHDERR_INVALID_PARAMETER;
15571162
1558   /* if this is a writeable file image, we can't verify */
1559   if (chd->header.flags & CHDFLAGS_IS_WRITEABLE)
1560      return CHDERR_CANT_VERIFY;
1163      // find the entry if it already exists
1164      metadata_entry metaentry;
1165      bool finished = false;
1166      if (metadata_find(metatag, metaindex, metaentry))
1167      {
1168         // if the new data fits over the old data, just overwrite
1169         if (inputlen <= metaentry.length)
1170         {
1171            file_write(metaentry.offset + METADATA_HEADER_SIZE, inputbuf, inputlen);
15611172
1562   /* wait for any pending async operations */
1563   wait_for_pending_async(chd);
1173            // if the lengths don't match, we need to update the length in our header
1174            if (inputlen != metaentry.length)
1175            {
1176               UINT8 length[3];
1177               be_write(length, inputlen, 3);
1178               file_write(metaentry.offset + 5, length, sizeof(length));
1179            }
1180           
1181            // indicate we did everything
1182            finished = true;
1183         }
1184         
1185         // if it doesn't fit, unlink the current entry
1186         else
1187            metadata_set_previous_next(metaentry.prev, metaentry.next);
1188      }
1189   
1190      // if not yet done, create a new entry and append
1191      if (!finished)
1192      {
1193         // now build us a new entry
1194         UINT8 raw_meta_header[METADATA_HEADER_SIZE];
1195         be_write(&raw_meta_header[0], metatag, 4);
1196         raw_meta_header[4] = flags;
1197         be_write(&raw_meta_header[5], (inputlen & 0x00ffffff) | (flags << 24), 3);
1198         be_write(&raw_meta_header[8], 0, 8);
1199         
1200         // append the new header, then the data
1201         UINT64 offset = file_append(raw_meta_header, sizeof(raw_meta_header));
1202         file_append(inputbuf, inputlen);
15641203
1565   /* init the MD5/SHA1 computations */
1566   MD5Init(&chd->vermd5);
1567   sha1_init(&chd->versha1);
1568   chd->verifying = TRUE;
1569   chd->verhunk = 0;
1204         // set the previous entry to point to us
1205         metadata_set_previous_next(metaentry.prev, offset);
1206      }
15701207
1571   return CHDERR_NONE;
1208      // update the hash
1209      metadata_update_hash();
1210      return CHDERR_NONE;
1211   }
1212   
1213   // return any errors
1214   catch (chd_error &err)
1215   {
1216      return err;
1217   }
15721218}
15731219
15741220
1575/*-------------------------------------------------
1576    chd_verify_hunk - verify the next hunk in
1577    the CHD
1578-------------------------------------------------*/
1221//-------------------------------------------------
1222//  delete_metadata - remove the given metadata
1223//  from the list
1224//-------------------------------------------------
15791225
1580chd_error chd_verify_hunk(chd_file *chd)
1226chd_error chd_file::delete_metadata(chd_metadata_tag metatag, UINT32 metaindex)
15811227{
1582   UINT32 thishunk = chd->verhunk++;
1583   UINT64 hunkoffset = (UINT64)thishunk * (UINT64)chd->header.hunkbytes;
1584   map_entry *entry;
1585   chd_error err;
1586
1587   /* error if in the wrong state */
1588   if (!chd->verifying)
1589      return CHDERR_INVALID_STATE;
1590
1591   /* read the hunk into the cache */
1592   err = hunk_read_into_cache(chd, thishunk);
1593   if (err != CHDERR_NONE)
1228   // wrap this for clean reporting
1229   try
1230   {
1231      // find the entry
1232      metadata_entry metaentry;
1233      if (!metadata_find(metatag, metaindex, metaentry))
1234         throw CHDERR_METADATA_NOT_FOUND;
1235     
1236      // point the previous to the next, unlinking us
1237      metadata_set_previous_next(metaentry.prev, metaentry.next);
1238      return CHDERR_NONE;
1239   }
1240   
1241   // return any errors
1242   catch (chd_error &err)
1243   {
15941244      return err;
1245   }
1246}
15951247
1596   entry = &chd->map[thishunk];
15971248
1598   /* update the MD5/SHA1 */
1599   if (hunkoffset < chd->header.logicalbytes)
1600   {
1601      UINT64 bytestochecksum = MIN(chd->header.hunkbytes, chd->header.logicalbytes - hunkoffset);
1249//-------------------------------------------------
1250//  clone_all_metadata - clone the metadata from
1251//  one CHD to a second
1252//-------------------------------------------------
16021253
1603      if (entry->flags & MAP_ENTRY_FLAG_HALF_HUNK)
1254chd_error chd_file::clone_all_metadata(chd_file &source)
1255{
1256   // wrap this for clean reporting
1257   try
1258   {
1259      // iterate over metadata entries in the source
1260      dynamic_buffer filedata;
1261      metadata_entry metaentry;
1262      for (bool has_data = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); has_data; has_data = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true))
16041263      {
1605         bytestochecksum /= 2;
1264         // read the metadata item
1265         filedata.resize(metaentry.length);
1266         source.file_read(metaentry.offset + METADATA_HEADER_SIZE, filedata, metaentry.length);
1267         
1268         // write it to the destination
1269         chd_error err = write_metadata(metaentry.metatag, -1, filedata, metaentry.length, metaentry.flags);
1270         if (err != CHDERR_NONE)
1271            throw err;
16061272      }
1607
1608      if (bytestochecksum > 0)
1609      {
1610         MD5Update(&chd->vermd5, chd->cache, bytestochecksum);
1611         sha1_update(&chd->versha1, bytestochecksum, chd->cache);
1612      }
1273      return CHDERR_NONE;
16131274   }
1614
1615   /* validate the CRC if we have one */
1616   if (!(entry->flags & MAP_ENTRY_FLAG_NO_CRC) && entry->crc != crc32(0, chd->cache, chd->header.hunkbytes))
1617      return CHDERR_DECOMPRESSION_ERROR;
1618
1619   return CHDERR_NONE;
1275   
1276   // return any errors
1277   catch (chd_error &err)
1278   {
1279      return err;
1280   }
16201281}
16211282
16221283
1623/*-------------------------------------------------
1624    chd_verify_finish - finish verification of
1625    the CHD
1626-------------------------------------------------*/
1284//-------------------------------------------------
1285//  compute_overall_sha1 - iterate through the
1286//  metadata and compute the overall hash of the
1287//  CHD file
1288//-------------------------------------------------
16271289
1628chd_error chd_verify_finish(chd_file *chd, chd_verify_result *result)
1290sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1)
16291291{
1630   /* error if in the wrong state */
1631   if (!chd->verifying)
1632      return CHDERR_INVALID_STATE;
1292   // only works for v4 and above
1293   if (m_version < 4)
1294      return rawsha1;
16331295
1634   /* compute the final MD5 */
1635   MD5Final(result->md5, &chd->vermd5);
1296   // iterate over metadata
1297   dynamic_buffer filedata;
1298   dynamic_array<metadata_hash> hasharray;
1299   metadata_entry metaentry;
1300   for (bool has_data = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); has_data; has_data = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true))
1301   {
1302      // if not checksumming, continue
1303      if ((metaentry.flags & CHD_MDFLAGS_CHECKSUM) == 0)
1304         continue;
16361305
1637   /* compute the final SHA1 */
1638   sha1_final(&chd->versha1);
1639   sha1_digest(&chd->versha1, SHA1_DIGEST_SIZE, result->rawsha1);
1306      // allocate memory and read the data
1307      filedata.resize(metaentry.length);
1308      file_read(metaentry.offset + METADATA_HEADER_SIZE, filedata, metaentry.length);
16401309
1641   /* compute the overall hash including metadata */
1642   metadata_compute_hash(chd, result->rawsha1, result->sha1);
1310      // create an entry for this metadata and add it
1311      metadata_hash hashentry;
1312      be_write(hashentry.tag, metaentry.metatag, 4);
1313      hashentry.sha1 = sha1_creator::simple(filedata, metaentry.length);
1314      hasharray.append(hashentry);
1315   }
16431316
1644   /* return an error */
1645   chd->verifying = FALSE;
1646   return (chd->verhunk < chd->header.totalhunks) ? CHDERR_VERIFY_INCOMPLETE : CHDERR_NONE;
1647}
1317   // sort the array
1318   if (hasharray.count() != 0)
1319      qsort(&hasharray[0], hasharray.count(), sizeof(hasharray[0]), metadata_hash_compare);
16481320
1649
1650
1651/***************************************************************************
1652    CODEC INTERFACES
1653***************************************************************************/
1654
1655/*-------------------------------------------------
1656    chd_codec_config - set internal codec
1657    parameters
1658-------------------------------------------------*/
1659
1660chd_error chd_codec_config(chd_file *chd, int param, void *config)
1661{
1662   /* wait for any pending async operations */
1663   wait_for_pending_async(chd);
1664
1665   /* if the codec has a configuration callback, call through to it */
1666   if (chd->codecintf->config != NULL)
1667      return (*chd->codecintf->config)(chd, param, config);
1668
1669   return CHDERR_INVALID_PARAMETER;
1321   // read the raw data hash from our header and start a new SHA1 with that data
1322   sha1_creator overall_sha1;
1323   overall_sha1.append(&rawsha1, sizeof(rawsha1));
1324   if (hasharray.count() != 0)
1325      overall_sha1.append(&hasharray[0], hasharray.count() * sizeof(hasharray[0]));
1326   return overall_sha1.finish();
16701327}
16711328
16721329
1673/*-------------------------------------------------
1674    chd_get_codec_name - get the name of a
1675    particular codec
1676-------------------------------------------------*/
1330//-------------------------------------------------
1331//  codec_config - set internal codec parameters
1332//-------------------------------------------------
16771333
1678const char *chd_get_codec_name(UINT32 codec)
1334chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *config)
16791335{
1680   int intfnum;
1681
1682   /* look for a matching codec and return its string */
1683   for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
1684      if (codec_interfaces[intfnum].compression == codec)
1685         return codec_interfaces[intfnum].compname;
1686
1687   return "Unknown";
1336   // wrap this for clean reporting
1337   try
1338   {
1339      // find the codec and call its configuration
1340      for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compression); codecnum++)
1341         if (m_compression[codecnum] == codec)
1342         {
1343            m_decompressor[codecnum]->configure(param, config);
1344            return CHDERR_NONE;
1345         }
1346      return CHDERR_INVALID_PARAMETER;
1347   }
1348   
1349   // return any errors
1350   catch (chd_error &err)
1351   {
1352      return err;
1353   }
16881354}
16891355
16901356
1357//-------------------------------------------------
1358//  error_string - return an error string for
1359//  the given CHD error
1360//-------------------------------------------------
16911361
1692/***************************************************************************
1693    INTERNAL ASYNC OPERATIONS
1694***************************************************************************/
1695
1696/*-------------------------------------------------
1697    async_read_callback - asynchronous reading
1698    callback
1699-------------------------------------------------*/
1700
1701static void *async_read_callback(void *param, int threadid)
1362const char *chd_file::error_string(chd_error err)
17021363{
1703   chd_file *chd = (chd_file *)param;
1704   chd_error err;
1705
1706   /* read the hunk into the cache */
1707   err = hunk_read_into_memory(chd, chd->async_hunknum, (UINT8 *)chd->async_buffer);
1708
1709   /* return the error */
1710   return (void *)err;
1364   switch (err)
1365   {
1366      case CHDERR_NONE:                  return "no error";
1367      case CHDERR_NO_INTERFACE:            return "no drive interface";
1368      case CHDERR_OUT_OF_MEMORY:            return "out of memory";
1369      case CHDERR_INVALID_FILE:            return "invalid file";
1370      case CHDERR_INVALID_PARAMETER:         return "invalid parameter";
1371      case CHDERR_INVALID_DATA:            return "invalid data";
1372      case CHDERR_FILE_NOT_FOUND:            return "file not found";
1373      case CHDERR_REQUIRES_PARENT:         return "requires parent";
1374      case CHDERR_FILE_NOT_WRITEABLE:         return "file not writeable";
1375      case CHDERR_READ_ERROR:               return "read error";
1376      case CHDERR_WRITE_ERROR:            return "write error";
1377      case CHDERR_CODEC_ERROR:            return "codec error";
1378      case CHDERR_INVALID_PARENT:            return "invalid parent";
1379      case CHDERR_HUNK_OUT_OF_RANGE:         return "hunk out of range";
1380      case CHDERR_DECOMPRESSION_ERROR:      return "decompression error";
1381      case CHDERR_COMPRESSION_ERROR:         return "compression error";
1382      case CHDERR_CANT_CREATE_FILE:         return "can't create file";
1383      case CHDERR_CANT_VERIFY:            return "can't verify file";
1384      case CHDERR_NOT_SUPPORTED:            return "operation not supported";
1385      case CHDERR_METADATA_NOT_FOUND:         return "can't find metadata";
1386      case CHDERR_INVALID_METADATA_SIZE:      return "invalid metadata size";
1387      case CHDERR_UNSUPPORTED_VERSION:      return "unsupported CHD version";
1388      case CHDERR_VERIFY_INCOMPLETE:         return "incomplete verify";
1389      case CHDERR_INVALID_METADATA:         return "invalid metadata";
1390      case CHDERR_INVALID_STATE:            return "invalid state";
1391      case CHDERR_OPERATION_PENDING:         return "operation pending";
1392      case CHDERR_UNSUPPORTED_FORMAT:         return "unsupported format";
1393      default:                        return "undocumented error";
1394   }
17111395}
17121396
17131397
1714/*-------------------------------------------------
1715    async_write_callback - asynchronous writing
1716    callback
1717-------------------------------------------------*/
17181398
1719static void *async_write_callback(void *param, int threadid)
1720{
1721   chd_file *chd = (chd_file *)param;
1722   chd_error err;
1399//**************************************************************************
1400//  INTERNAL HELPERS
1401//**************************************************************************
17231402
1724   /* write the hunk from memory */
1725   err = hunk_write_from_memory(chd, chd->async_hunknum, (const UINT8 *)chd->async_buffer);
1403//-------------------------------------------------
1404//  guess_unitbytes - for older CHD formats, take
1405//   a guess at the bytes/unit based on metadata
1406//-------------------------------------------------
17261407
1727   /* return the error */
1728   return (void *)err;
1729}
1730
1731
1732
1733/***************************************************************************
1734    INTERNAL HEADER OPERATIONS
1735***************************************************************************/
1736
1737/*-------------------------------------------------
1738    header_validate - check the validity of a
1739    CHD header
1740-------------------------------------------------*/
1741
1742static chd_error header_validate(const chd_header *header)
1408UINT32 chd_file::guess_unitbytes()
17431409{
1744   int intfnum;
1410   // look for hard disk metadata; if found, then the unit size == sector size
1411   astring metadata;
1412   int i0, i1, i2, i3;
1413   if (read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) == CHDERR_NONE && sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
1414      return i3;
17451415
1746   /* require a valid version */
1747   if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1748      return CHDERR_UNSUPPORTED_VERSION;
1749
1750   /* require a valid length */
1751   if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1752      (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1753      (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1754      (header->version == 4 && header->length != CHD_V4_HEADER_SIZE))
1755      return CHDERR_INVALID_PARAMETER;
1756
1757   /* require valid flags */
1758   if (header->flags & CHDFLAGS_UNDEFINED)
1759      return CHDERR_INVALID_PARAMETER;
1760
1761   /* require a supported compression mechanism */
1762   for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
1763      if (codec_interfaces[intfnum].compression == header->compression)
1764         break;
1765   if (intfnum == ARRAY_LENGTH(codec_interfaces))
1766      return CHDERR_INVALID_PARAMETER;
1767
1768   /* require a valid hunksize */
1769   if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
1770      return CHDERR_INVALID_PARAMETER;
1771
1772   /* require a valid hunk count */
1773   if (header->totalhunks == 0)
1774      return CHDERR_INVALID_PARAMETER;
1775
1776   /* require a valid MD5 and/or SHA1 if we're using a parent */
1777   if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
1778      return CHDERR_INVALID_PARAMETER;
1779
1780   /* if we're V3 or later, the obsolete fields must be 0 */
1781   if (header->version >= 3 &&
1782      (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
1783       header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
1784      return CHDERR_INVALID_PARAMETER;
1785
1786   /* if we're pre-V3, the obsolete fields must NOT be 0 */
1787   if (header->version < 3 &&
1788      (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
1789       header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
1790      return CHDERR_INVALID_PARAMETER;
1791
1792   return CHDERR_NONE;
1416   // look for CD-ROM metadata; if found, then the unit size == CD frame size
1417   if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
1418      read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
1419      read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE)
1420      return CD_FRAME_SIZE;
1421   
1422   // otherwise, just map 1:1 with the hunk size
1423   return m_hunkbytes;
17931424}
17941425
17951426
1796/*-------------------------------------------------
1797    header_read - read a CHD header into the
1798    internal data structure
1799-------------------------------------------------*/
1427//-------------------------------------------------
1428//  parse_v3_header - parse the header from a v3
1429//  file and configure core parameters
1430//-------------------------------------------------
18001431
1801static chd_error header_read(core_file *file, chd_header *header)
1432void chd_file::parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1)
18021433{
1803   UINT8 rawheader[CHD_MAX_HEADER_SIZE];
1804   UINT32 count;
1434   // verify header length
1435   if (be_read(&rawheader[8], 4) != V3_HEADER_SIZE)
1436      throw CHDERR_INVALID_FILE;
18051437
1806   /* punt if NULL */
1807   if (header == NULL)
1808      return CHDERR_INVALID_PARAMETER;
1438   // extract core info
1439   m_logicalbytes = be_read(&rawheader[28], 8);
1440   m_mapoffset = 120;
1441   m_metaoffset = be_read(&rawheader[36], 8);
1442   m_hunkbytes = be_read(&rawheader[76], 4);
1443   m_hunkcount = be_read(&rawheader[24], 4);
1444   
1445   // extract parent SHA-1
1446   UINT32 flags = be_read(&rawheader[16], 4);
1447   if ((flags & 2) && m_allow_writes)
1448      throw CHDERR_FILE_NOT_WRITEABLE;
18091449
1810   /* punt if invalid file */
1811   if (file == NULL)
1812      return CHDERR_INVALID_FILE;
1813
1814   /* seek and read */
1815   core_fseek(file, 0, SEEK_SET);
1816   count = core_fread(file, rawheader, sizeof(rawheader));
1817   if (count != sizeof(rawheader))
1818      return CHDERR_READ_ERROR;
1819
1820   /* verify the tag */
1821   if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
1822      return CHDERR_INVALID_DATA;
1823
1824   /* extract the direct data */
1825   memset(header, 0, sizeof(*header));
1826   header->length        = get_bigendian_uint32(&rawheader[8]);
1827   header->version       = get_bigendian_uint32(&rawheader[12]);
1828
1829   /* make sure it's a version we understand */
1830   if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1831      return CHDERR_UNSUPPORTED_VERSION;
1832
1833   /* make sure the length is expected */
1834   if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1835      (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1836      (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1837      (header->version == 4 && header->length != CHD_V4_HEADER_SIZE))
1838      return CHDERR_INVALID_DATA;
1839
1840   /* extract the common data */
1841   header->flags         = get_bigendian_uint32(&rawheader[16]);
1842   header->compression   = get_bigendian_uint32(&rawheader[20]);
1843
1844   /* extract the V1/V2-specific data */
1845   if (header->version < 3)
1450   // determine compression
1451   switch (be_read(&rawheader[20], 4))
18461452   {
1847      int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
1848      header->obsolete_hunksize  = get_bigendian_uint32(&rawheader[24]);
1849      header->totalhunks         = get_bigendian_uint32(&rawheader[28]);
1850      header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
1851      header->obsolete_heads     = get_bigendian_uint32(&rawheader[36]);
1852      header->obsolete_sectors   = get_bigendian_uint32(&rawheader[40]);
1853      memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1854      memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1855      header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
1856      header->hunkbytes = seclen * header->obsolete_hunksize;
1857      header->metaoffset = 0;
1453      case 0:   m_compression[0] = CHD_CODEC_NONE;      break;
1454      case 1:   m_compression[0] = CHD_CODEC_ZLIB;      break;
1455      case 2:   m_compression[0] = CHD_CODEC_ZLIB;      break;
1456      case 3:   m_compression[0] = CHD_CODEC_AVHUFF;   break;
1457      default: throw CHDERR_UNKNOWN_COMPRESSION;
18581458   }
1459   m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
1460   
1461   // describe the format
1462   m_mapoffset_offset = 0;
1463   m_metaoffset_offset = 36;
1464   m_sha1_offset = 80;
1465   m_rawsha1_offset = 0;
1466   m_parentsha1_offset = 100;
1467   
1468   // determine properties of map entries
1469   m_mapentrybytes = 16;
18591470
1860   /* extract the V3-specific data */
1861   else if (header->version == 3)
1862   {
1863      header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
1864      header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1865      header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
1866      memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1867      memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1868      header->hunkbytes    = get_bigendian_uint32(&rawheader[76]);
1869      memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
1870      memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
1871   }
1872
1873   /* extract the V4-specific data */
1874   else
1875   {
1876      header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
1877      header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1878      header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
1879      header->hunkbytes    = get_bigendian_uint32(&rawheader[44]);
1880      memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
1881      memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
1882      memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
1883   }
1884
1885   /* guess it worked */
1886   return CHDERR_NONE;
1471   // extract parent SHA-1
1472   if (flags & 1)
1473      parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
1474   
1475   // guess at the units based on snooping the metadata
1476   m_unitbytes = guess_unitbytes();
1477   m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
18871478}
18881479
18891480
1890/*-------------------------------------------------
1891    header_write - write a CHD header from the
1892    internal data structure
1893-------------------------------------------------*/
1481//-------------------------------------------------
1482//  parse_v4_header - parse the header from a v4
1483//  file and configure core parameters
1484//-------------------------------------------------
18941485
1895static chd_error header_write(core_file *file, const chd_header *header)
1486void chd_file::parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1)
18961487{
1897   UINT8 rawheader[CHD_MAX_HEADER_SIZE];
1898   UINT32 count;
1488   // verify header length
1489   if (be_read(&rawheader[8], 4) != V4_HEADER_SIZE)
1490      throw CHDERR_INVALID_FILE;
18991491
1900   /* punt if NULL */
1901   if (header == NULL)
1902      return CHDERR_INVALID_PARAMETER;
1492   // extract core info
1493   m_logicalbytes = be_read(&rawheader[28], 8);
1494   m_mapoffset = 108;
1495   m_metaoffset = be_read(&rawheader[36], 8);
1496   m_hunkbytes = be_read(&rawheader[44], 4);
1497   m_hunkcount = be_read(&rawheader[24], 4);
1498   
1499   // extract parent SHA-1
1500   UINT32 flags = be_read(&rawheader[16], 4);
1501   if ((flags & 2) && m_allow_writes)
1502      throw CHDERR_FILE_NOT_WRITEABLE;
19031503
1904   /* punt if invalid file */
1905   if (file == NULL)
1906      return CHDERR_INVALID_FILE;
1504   // determine compression
1505   switch (be_read(&rawheader[20], 4))
1506   {
1507      case 0:   m_compression[0] = CHD_CODEC_NONE;      break;
1508      case 1:   m_compression[0] = CHD_CODEC_ZLIB;      break;
1509      case 2:   m_compression[0] = CHD_CODEC_ZLIB;      break;
1510      case 3:   m_compression[0] = CHD_CODEC_AVHUFF;   break;
1511      default: throw CHDERR_UNKNOWN_COMPRESSION;
1512   }
1513   m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
1514   
1515   // describe the format
1516   m_mapoffset_offset = 0;
1517   m_metaoffset_offset = 36;
1518   m_sha1_offset = 48;
1519   m_rawsha1_offset = 88;
1520   m_parentsha1_offset = 68;
1521   
1522   // determine properties of map entries
1523   m_mapentrybytes = 16;
19071524
1908   /* only support writing modern headers */
1909   if (header->version != 4)
1910      return CHDERR_INVALID_PARAMETER;
1911
1912   /* assemble the data */
1913   memset(rawheader, 0, sizeof(rawheader));
1914   memcpy(rawheader, "MComprHD", 8);
1915
1916   put_bigendian_uint32(&rawheader[8],  CHD_V4_HEADER_SIZE);
1917   put_bigendian_uint32(&rawheader[12], header->version);
1918   put_bigendian_uint32(&rawheader[16], header->flags);
1919   put_bigendian_uint32(&rawheader[20], header->compression);
1920   put_bigendian_uint32(&rawheader[24], header->totalhunks);
1921   put_bigendian_uint64(&rawheader[28], header->logicalbytes);
1922   put_bigendian_uint64(&rawheader[36], header->metaoffset);
1923   put_bigendian_uint32(&rawheader[44], header->hunkbytes);
1924   memcpy(&rawheader[48], header->sha1, CHD_SHA1_BYTES);
1925   memcpy(&rawheader[68], header->parentsha1, CHD_SHA1_BYTES);
1926   memcpy(&rawheader[88], header->rawsha1, CHD_SHA1_BYTES);
1927
1928   /* seek and write */
1929   core_fseek(file, 0, SEEK_SET);
1930   count = core_fwrite(file, rawheader, CHD_V4_HEADER_SIZE);
1931   if (count != CHD_V4_HEADER_SIZE)
1932      return CHDERR_WRITE_ERROR;
1933
1934   return CHDERR_NONE;
1525   // extract parent SHA-1
1526   if (flags & 1)
1527      parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
1528   
1529   // guess at the units based on snooping the metadata
1530   m_unitbytes = guess_unitbytes();
1531   m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
19351532}
19361533
19371534
1535//-------------------------------------------------
1536//  parse_v5_header - read the header from a v5
1537//  file and configure core parameters
1538//-------------------------------------------------
19381539
1939/***************************************************************************
1940    INTERNAL HUNK READ/WRITE
1941***************************************************************************/
1942
1943/*-------------------------------------------------
1944    hunk_read_into_cache - read a hunk into
1945    the CHD's hunk cache
1946-------------------------------------------------*/
1947
1948static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
1540void chd_file::parse_v5_header(UINT8 *rawheader, sha1_t &parentsha1)
19491541{
1950   chd_error err;
1542   // verify header length
1543   if (be_read(&rawheader[8], 4) != V5_HEADER_SIZE)
1544      throw CHDERR_INVALID_FILE;
19511545
1952   /* track the max */
1953   if (hunknum > chd->maxhunk)
1954      chd->maxhunk = hunknum;
1546   // extract core info
1547   m_logicalbytes = be_read(&rawheader[32], 8);
1548   m_mapoffset = be_read(&rawheader[40], 8);
1549   m_metaoffset = be_read(&rawheader[48], 8);
1550   m_hunkbytes = be_read(&rawheader[56], 4);
1551   m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
1552   m_unitbytes = be_read(&rawheader[60], 4);
1553   m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
1554   
1555   // determine compression
1556   m_compression[0] = be_read(&rawheader[16], 4);
1557   m_compression[1] = be_read(&rawheader[20], 4);
1558   m_compression[2] = be_read(&rawheader[24], 4);
1559   m_compression[3] = be_read(&rawheader[28], 4);
1560   
1561   // describe the format
1562   m_mapoffset_offset = 40;
1563   m_metaoffset_offset = 48;
1564   m_sha1_offset = 84;
1565   m_rawsha1_offset = 64;
1566   m_parentsha1_offset = 104;
1567   
1568   // determine properties of map entries
1569   m_mapentrybytes = compressed() ? 12 : 4;
19551570
1956   /* if we're already in the cache, we're done */
1957   if (chd->cachehunk == hunknum)
1958      return CHDERR_NONE;
1959   chd->cachehunk = ~0;
1960
1961   /* otherwise, read the data */
1962   err = hunk_read_into_memory(chd, hunknum, chd->cache);
1963   if (err != CHDERR_NONE)
1964      return err;
1965
1966   /* mark the hunk successfully cached in */
1967   chd->cachehunk = hunknum;
1968   return CHDERR_NONE;
1571   // extract parent SHA-1
1572   parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
19691573}
19701574
19711575
1972/*-------------------------------------------------
1973    hunk_read_into_memory - read a hunk into
1974    memory at the given location
1975-------------------------------------------------*/
1576//-------------------------------------------------
1577//  compress_v5_map - compress the v5 map and
1578//  write it to the end of the file
1579//-------------------------------------------------
19761580
1977static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
1581chd_error chd_file::compress_v5_map()
19781582{
1979   map_entry *entry = &chd->map[hunknum];
1980   chd_error err;
1981   UINT32 bytes;
1982
1983   /* return an error if out of range */
1984   if (hunknum >= chd->header.totalhunks)
1985      return CHDERR_HUNK_OUT_OF_RANGE;
1986
1987   /* switch off the entry type */
1988   switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
1583   try
19891584   {
1990      /* compressed data */
1991      case MAP_ENTRY_TYPE_COMPRESSED:
1585      // first get a CRC-16 of the original rawmap
1586      crc16_t mapcrc = crc16_creator::simple(m_rawmap, m_hunkcount * 12);
19921587
1993         /* read it into the decompression buffer */
1994         core_fseek(chd->file, entry->offset, SEEK_SET);
1995         bytes = core_fread(chd->file, chd->compressed, entry->length);
1996         if (bytes != entry->length)
1997            return CHDERR_READ_ERROR;
1588      // create a buffer to hold the RLE data   
1589      dynamic_buffer compression_rle(m_hunkcount);
1590      UINT8 *dest = compression_rle;
1591     
1592      // use a huffman encoder for 16 different codes, maximum length is 8 bits
1593      huffman_encoder<16, 8> encoder;
1594      encoder.histo_reset();
19981595
1999         /* now decompress using the codec */
2000         err = CHDERR_NONE;
2001         if (chd->codecintf->decompress != NULL)
2002            err = (*chd->codecintf->decompress)(chd, entry->length, dest);
2003         if (err != CHDERR_NONE)
2004            return err;
2005         break;
2006
2007      /* uncompressed data */
2008      case MAP_ENTRY_TYPE_UNCOMPRESSED:
2009         core_fseek(chd->file, entry->offset, SEEK_SET);
2010         bytes = core_fread(chd->file, dest, chd->header.hunkbytes);
2011         if (bytes != chd->header.hunkbytes)
2012            return CHDERR_READ_ERROR;
2013         break;
2014
2015      /* mini-compressed data */
2016      case MAP_ENTRY_TYPE_MINI:
2017         put_bigendian_uint64(&dest[0], entry->offset);
2018         for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
2019            dest[bytes] = dest[bytes - 8];
2020         break;
2021
2022      /* self-referenced data */
2023      case MAP_ENTRY_TYPE_SELF_HUNK:
2024         if (chd->cachehunk == entry->offset && dest == chd->cache)
2025            break;
2026         return hunk_read_into_memory(chd, entry->offset, dest);
2027
2028      /* parent-referenced data */
2029      case MAP_ENTRY_TYPE_PARENT_HUNK:
2030         err = hunk_read_into_memory(chd->parent, entry->offset, dest);
2031         if (err != CHDERR_NONE)
2032            return err;
2033         break;
2034
2035      case MAP_ENTRY_TYPE_2ND_COMPRESSED:
2036         /* read it into the decompression buffer */
2037         core_fseek(chd->file, entry->offset, SEEK_SET);
2038         bytes = core_fread(chd->file, chd->compressed, entry->length);
2039         if (bytes != entry->length)
2040            return CHDERR_READ_ERROR;
2041
2042         /* now decompress using the codec */
2043         err = CHDERR_NONE;
2044         if (chd->codecintf->secondary_decompress != NULL)
2045            err = (*chd->codecintf->secondary_decompress)(chd, entry->length, dest);
2046         if (err != CHDERR_NONE)
2047            return err;
2048         break;
2049
2050   }
2051   return CHDERR_NONE;
2052}
2053
2054
2055/*-------------------------------------------------
2056    hunk_write_from_memory - write a hunk from
2057    memory into a CHD
2058-------------------------------------------------*/
2059
2060
2061static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UINT8 *src, int is_half_hunk)
2062{
2063   map_entry *entry = &chd->map[hunknum];
2064   map_entry newentry;
2065   UINT8 fileentry[MAP_ENTRY_SIZE];
2066   const void *data = src;
2067   UINT32 bytes = 0, match;
2068   chd_error err;
2069   bool is_likely_cd = false;
2070   int strategy = 0;
2071
2072   /* track the max */
2073   if (hunknum > chd->maxhunk)
2074      chd->maxhunk = hunknum;
2075
2076   /* first compute the CRC of the original data */
2077    newentry.flags = 0;
2078    newentry.length = 0;
2079    newentry.offset = 0;
2080   newentry.crc = 0;
2081   if (src != NULL)
2082      newentry.crc = crc32(0, &src[0], chd->header.hunkbytes);
2083
2084   /* if we're not a lossy codec, compute the CRC and look for matches */
2085   if (!chd->codecintf->lossy && src != NULL)
2086   {
2087      /* some extra stuff for zlib+ compression */
2088      if (chd->header.compression >= CHDCOMPRESSION_ZLIB_PLUS)
1596      // RLE-compress the compression type since we expect runs of the same
1597      UINT32 max_self = 0;
1598      UINT32 last_self = 0;
1599      UINT64 max_parent = 0;
1600      UINT64 last_parent = 0;
1601      UINT32 max_complen = 0;
1602      UINT8 lastcomp = 0;
1603      int count = 0;
1604      for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
20891605      {
2090         /* see if we can mini-compress first */
2091         for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
2092            if (src[bytes] != src[bytes - 8])
2093               break;
2094
2095         /* if so, we don't need to write any data */
2096         if (bytes == chd->header.hunkbytes)
1606         UINT8 curcomp = m_rawmap[hunknum * 12 + 0];
1607         
1608         // promote self block references to more compact forms
1609         if (curcomp == COMPRESSION_SELF)
20971610         {
2098            newentry.offset = get_bigendian_uint64(&src[0]);
2099            newentry.length = 0;
2100            newentry.flags = MAP_ENTRY_TYPE_MINI;
2101            goto write_entry;
1611            UINT32 refhunk = be_read(&m_rawmap[hunknum * 12 + 4], 6);
1612            if (refhunk == last_self)
1613               curcomp = COMPRESSION_SELF_0;
1614            else if (refhunk == last_self + 1)
1615               curcomp = COMPRESSION_SELF_1;
1616            else
1617               max_self = MAX(max_self, refhunk);
1618            last_self = refhunk;
21021619         }
21031620
2104         /* otherwise, see if we can find a match in the current file */
2105         match = crcmap_find_hunk(chd, hunknum, newentry.crc, &src[0]);
2106         if (match != NO_MATCH)
1621         // promote parent block references to more compact forms
1622         else if (curcomp == COMPRESSION_PARENT)
21071623         {
2108            newentry.offset = match;
2109            newentry.length = 0;
2110            newentry.flags = MAP_ENTRY_TYPE_SELF_HUNK;
2111            goto write_entry;
1624            UINT32 refunit = be_read(&m_rawmap[hunknum * 12 + 4], 6);
1625            if (refunit == (UINT64(hunknum) * UINT64(m_hunkbytes)) / m_unitbytes)
1626               curcomp = COMPRESSION_PARENT_SELF;
1627            else if (refunit == last_parent)
1628               curcomp = COMPRESSION_PARENT_0;
1629            else if (refunit == last_parent + m_hunkbytes / m_unitbytes)
1630               curcomp = COMPRESSION_PARENT_1;
1631            else
1632               max_parent = MAX(max_parent, refunit);
1633            last_parent = refunit;
21121634         }
2113
2114         /* if we have a parent, see if we can find a match in there */
2115         if (chd->header.flags & CHDFLAGS_HAS_PARENT)
1635         
1636         // track maximum compressed length
1637         else if (curcomp >= COMPRESSION_TYPE_0 && curcomp <= COMPRESSION_TYPE_3)
1638            max_complen = MAX(max_complen, be_read(&m_rawmap[hunknum * 12 + 1], 3));
1639         
1640         // track repeats
1641         if (curcomp == lastcomp)
1642            count++;
1643         
1644         // if no repeat, or we're at the end, flush it
1645         if (curcomp != lastcomp || hunknum == m_hunkcount - 1)
21161646         {
2117            match = crcmap_find_hunk(chd->parent, ~0, newentry.crc, &src[0]);
2118            if (match != NO_MATCH)
1647            while (count != 0)
21191648            {
2120               newentry.offset = match;
2121               newentry.length = 0;
2122               newentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
2123               goto write_entry;
1649               if (count < 3)
1650                  encoder.histo_one(*dest++ = lastcomp), count--;
1651               else if (count <= 3+15)
1652               {
1653                  encoder.histo_one(*dest++ = COMPRESSION_RLE_SMALL);
1654                  encoder.histo_one(*dest++ = count - 3);
1655                  count = 0;
1656               }
1657               else
1658               {
1659                  int this_count = MIN(count, 3+16+255);
1660                  encoder.histo_one(*dest++ = COMPRESSION_RLE_LARGE);
1661                  encoder.histo_one(*dest++ = (this_count - 3 - 16) >> 4);
1662                  encoder.histo_one(*dest++ = (this_count - 3 - 16) & 15);
1663                  count -= this_count;
1664               }
21241665            }
1666            if (curcomp != lastcomp)
1667               encoder.histo_one(*dest++ = lastcomp = curcomp);
21251668         }
21261669      }
2127   }
1670     
1671      // compute a tree and export it to the buffer
1672      dynamic_buffer compressed(m_hunkcount * 6);
1673      bitstream_out bitbuf(&compressed[16], compressed.count() - 16);
1674      huffman_error err = encoder.compute_tree_from_histo();
1675      if (err != HUFFERR_NONE)
1676         throw CHDERR_COMPRESSION_ERROR;
1677      err = encoder.export_tree_rle(bitbuf);
1678      if (err != HUFFERR_NONE)
1679         throw CHDERR_COMPRESSION_ERROR;
21281680
2129   if (chd->codecintf->secondary_compress != NULL)
2130   {
2131      if (chd->header.hunkbytes == (CD_MAX_SECTOR_DATA+CD_MAX_SUBCODE_DATA) * CD_FRAMES_PER_HUNK)
2132         is_likely_cd = true;
1681      // encode the data
1682      for (UINT8 *src = compression_rle; src < dest; src++)
1683         encoder.encode_one(bitbuf, *src);
1684     
1685      // determine the number of bits we need to hold the a length
1686      // and a hunk index
1687      UINT8 lengthbits = bits_for_value(max_complen);
1688      UINT8 selfbits = bits_for_value(max_self);
1689      UINT8 parentbits = bits_for_value(max_parent);
21331690
2134      if (is_likely_cd)
1691      // for each compression type, output the relevant data
1692      lastcomp = 0;
1693      count = 0;
1694      UINT8 *src = compression_rle;
1695      UINT64 firstoffs = 0;
1696      for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
21351697      {
2136         int offset = 0;
2137         for (int frames=0;frames<CD_FRAMES_PER_HUNK;frames++)
1698         UINT8 *rawmap = &m_rawmap[hunknum * 12];
1699         UINT32 length = be_read(&rawmap[1], 3);
1700         UINT64 offset = be_read(&rawmap[4], 6);
1701         UINT16 crc = be_read(&rawmap[10], 2);
1702         
1703         // if no count remaining, fetch the next entry
1704         if (count == 0)
21381705         {
2139            int secoff;
2140            for (secoff=0;secoff<CD_MAX_SECTOR_DATA;secoff++)
2141            {
2142               offset++;
2143            }
2144            for (secoff=0;secoff<CD_MAX_SUBCODE_DATA;secoff++)
2145            {
2146               if (src[offset]!=0x00)
2147                  is_likely_cd = false;
2148
2149               offset++;
2150            }
1706            UINT8 val = *src++;
1707            if (val == COMPRESSION_RLE_SMALL)
1708               count = 2 + *src++;
1709            else if (val == COMPRESSION_RLE_LARGE)
1710               count = 2 + 16 + (*src++ << 4), count += *src++;
1711            else
1712               lastcomp = val;
21511713         }
2152      }
2153   }
2154
2155   if (is_likely_cd)
2156   {
2157      err = CHDERR_COMPRESSION_ERROR;
2158
2159      UINT8* tempram = (UINT8 *)malloc(chd->header.hunkbytes);
2160      UINT32 tempbytes = 0;
2161      chd_error temperror = err;
2162      int tempstrategy = 0;
2163
2164      /* try strategy 0 - zlib */
2165      if (chd->codecintf->compress != NULL)
2166      {
2167         err = (*chd->codecintf->compress)(chd, src, &bytes);
2168
2169         /* store current results and errors */
2170         memcpy(tempram, chd->compressed, bytes);
2171         tempbytes = bytes;
2172         temperror = err;
2173         tempstrategy = 0;
2174      }
2175
2176      /* try strategy 1 - flac */
2177      if (chd->codecintf->secondary_compress != NULL)
2178      {
2179         strategy = 1;
2180
2181         err = (*chd->codecintf->secondary_compress)(chd, src, &bytes);
2182
2183         /* check against previous compression attempt if that was successful */
2184         if (temperror == CHDERR_NONE)
1714         else
1715            count--;
1716         
1717         // output additional data needed for this entry
1718         switch (lastcomp)
21851719         {
2186            /* if the previous compression was better, restore that ... */
2187            if (bytes>=tempbytes)
2188            {
2189               strategy = tempstrategy;
2190               memcpy(chd->compressed, tempram, tempbytes);
2191               bytes = tempbytes;
2192               err = temperror;
2193            }
1720            case COMPRESSION_TYPE_0:
1721            case COMPRESSION_TYPE_1:
1722            case COMPRESSION_TYPE_2:
1723            case COMPRESSION_TYPE_3:
1724               assert(length < (1 << lengthbits));
1725               bitbuf.write(length, lengthbits);
1726               bitbuf.write(crc, 16);
1727               if (firstoffs == 0)
1728                  firstoffs = offset;
1729               break;
1730           
1731            case COMPRESSION_NONE:
1732               bitbuf.write(crc, 16);
1733               if (firstoffs == 0)
1734                  firstoffs = offset;
1735               break;
1736           
1737            case COMPRESSION_SELF:
1738               assert(offset < (UINT64(1) << selfbits));
1739               bitbuf.write(offset, selfbits);
1740               break;
1741           
1742            case COMPRESSION_PARENT:
1743               assert(offset < (UINT64(1) << parentbits));
1744               bitbuf.write(offset, parentbits);
1745               break;
1746           
1747            case COMPRESSION_SELF_0:
1748            case COMPRESSION_SELF_1:
1749            case COMPRESSION_PARENT_SELF:
1750            case COMPRESSION_PARENT_0:
1751            case COMPRESSION_PARENT_1:
1752               break;
21941753         }
21951754      }
2196
2197      free(tempram);
1755     
1756      // write the map header
1757      UINT32 complen = bitbuf.flush();
1758      assert(!bitbuf.overflow());
1759      be_write(&compressed[0], complen, 4);
1760      be_write(&compressed[4], firstoffs, 6);
1761      be_write(&compressed[10], mapcrc, 2);
1762      compressed[12] = lengthbits;
1763      compressed[13] = selfbits;
1764      compressed[14] = parentbits;
1765     
1766      // write the result
1767      m_mapoffset = file_append(compressed, complen + 16);
1768     
1769      // then write the map offset
1770      UINT8 rawbuf[sizeof(UINT64)];
1771      be_write(rawbuf, m_mapoffset, 8);
1772      file_write(m_mapoffset_offset, rawbuf, sizeof(rawbuf));
1773      return CHDERR_NONE;
21981774   }
2199   else
1775   catch (chd_error &err)
22001776   {
2201      /* now try compressing the data */
2202      err = CHDERR_COMPRESSION_ERROR;
2203      if (chd->codecintf->compress != NULL)
2204         err = (*chd->codecintf->compress)(chd, src, &bytes);
1777      return err;
22051778   }
1779}
22061780
2207   /* if that worked, and we're lossy, decompress and CRC the result */
2208   if (err == CHDERR_NONE && (chd->codecintf->lossy || src == NULL))
1781
1782//-------------------------------------------------
1783//  decompress_v5_map - decompress the v5 map
1784//-------------------------------------------------
1785
1786void chd_file::decompress_v5_map()
1787{
1788   // if no offset, we haven't written it yet
1789   if (m_mapoffset == 0)
22091790   {
2210      err = (*chd->codecintf->decompress)(chd, bytes, chd->cache);
2211      if (err == CHDERR_NONE)
2212         newentry.crc = crc32(0, chd->cache, chd->header.hunkbytes);
1791      memset(m_rawmap, 0xff, m_rawmap.count());
1792      return;
22131793   }
22141794
2215   /* if we succeeded in compressing the data, replace our data pointer and mark it so */
2216   if (err == CHDERR_NONE)
1795   // read the reader
1796   UINT8 rawbuf[16];
1797   file_read(m_mapoffset, rawbuf, sizeof(rawbuf));
1798   UINT32 mapbytes = be_read(&rawbuf[0], 4);
1799   UINT64 firstoffs = be_read(&rawbuf[4], 6);
1800   UINT16 mapcrc = be_read(&rawbuf[10], 2);
1801   UINT8 lengthbits = rawbuf[12];
1802   UINT8 selfbits = rawbuf[13];
1803   UINT8 parentbits = rawbuf[14];
1804   
1805   // now read the map
1806   dynamic_buffer compressed(mapbytes);
1807   file_read(m_mapoffset + 16, compressed, mapbytes);
1808   bitstream_in bitbuf(compressed, compressed.count());
1809   
1810   // first decode the compression types
1811   huffman_decoder<16, 8> decoder;
1812   huffman_error err = decoder.import_tree_rle(bitbuf);
1813   if (err != HUFFERR_NONE)
1814      throw CHDERR_DECOMPRESSION_ERROR;
1815   UINT8 lastcomp = 0;
1816   int repcount = 0;
1817   for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
22171818   {
2218      data = chd->compressed;
2219      newentry.length = bytes;
2220
2221      if (strategy == 0)
1819      UINT8 *rawmap = &m_rawmap[hunknum * 12];
1820      if (repcount > 0)
1821         rawmap[0] = lastcomp, repcount--;
1822      else
22221823      {
2223         newentry.flags = MAP_ENTRY_TYPE_COMPRESSED;
1824         UINT8 val = decoder.decode_one(bitbuf);
1825         if (val == COMPRESSION_RLE_SMALL)
1826            rawmap[0] = lastcomp, repcount = 2 + decoder.decode_one(bitbuf);
1827         else if (val == COMPRESSION_RLE_LARGE)
1828            rawmap[0] = lastcomp, repcount = 2 + 16 + (decoder.decode_one(bitbuf) << 4), repcount += decoder.decode_one(bitbuf);
1829         else
1830            rawmap[0] = lastcomp = val;
22241831      }
2225      else if (strategy == 1)
1832   }
1833   
1834   // then iterate through the hunks and extract the needed data
1835   UINT64 curoffset = firstoffs;
1836   UINT32 last_self = 0;
1837   UINT64 last_parent = 0;
1838   for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
1839   {
1840      UINT8 *rawmap = &m_rawmap[hunknum * 12];
1841      UINT64 offset = curoffset;
1842      UINT32 length = 0;
1843      UINT16 crc = 0;
1844      switch (rawmap[0])
22261845      {
2227         newentry.flags = MAP_ENTRY_TYPE_2ND_COMPRESSED;
1846         // base types
1847         case COMPRESSION_TYPE_0:
1848         case COMPRESSION_TYPE_1:
1849         case COMPRESSION_TYPE_2:
1850         case COMPRESSION_TYPE_3:
1851            curoffset += length = bitbuf.read(lengthbits);
1852            crc = bitbuf.read(16);
1853            break;
1854         
1855         case COMPRESSION_NONE:
1856            curoffset += length = m_hunkbytes;
1857            crc = bitbuf.read(16);
1858            break;
1859         
1860         case COMPRESSION_SELF:
1861            last_self = offset = bitbuf.read(selfbits);
1862            break;
1863         
1864         case COMPRESSION_PARENT:
1865            offset = bitbuf.read(parentbits);
1866            last_parent = offset;
1867            break;
1868         
1869         // pseudo-types; convert into base types
1870         case COMPRESSION_SELF_1:
1871            last_self++;
1872         case COMPRESSION_SELF_0:
1873            rawmap[0] = COMPRESSION_SELF;
1874            offset = last_self;
1875            break;
1876           
1877         case COMPRESSION_PARENT_SELF:
1878            rawmap[0] = COMPRESSION_PARENT;
1879            last_parent = offset = (UINT64(hunknum) * UINT64(m_hunkbytes)) / m_unitbytes;
1880            break;
1881           
1882         case COMPRESSION_PARENT_1:
1883            last_parent += m_hunkbytes / m_unitbytes;
1884         case COMPRESSION_PARENT_0:
1885            rawmap[0] = COMPRESSION_PARENT;
1886            offset = last_parent;
1887            break;
22281888      }
1889      be_write(&rawmap[1], length, 3);
1890      be_write(&rawmap[4], offset, 6);
1891      be_write(&rawmap[10], crc, 2);
22291892   }
2230
2231   /* otherwise, mark it uncompressed and use the original data */
2232   else
2233   {
2234      newentry.length = chd->header.hunkbytes;
2235      newentry.flags = MAP_ENTRY_TYPE_UNCOMPRESSED;
2236   }
2237
2238
2239   /* if the data doesn't fit into the previous entry, make a new one at the eof */
2240   newentry.offset = entry->offset;
2241   if (newentry.offset == 0 || newentry.length > entry->length)
2242      newentry.offset = core_fsize(chd->file);
2243
2244   /* write the data */
2245   core_fseek(chd->file, newentry.offset, SEEK_SET);
2246   bytes = core_fwrite(chd->file, data, newentry.length);
2247   if (bytes != newentry.length)
2248      return CHDERR_WRITE_ERROR;
2249
2250   /* update the entry in memory */
2251write_entry:
2252
2253   if (is_half_hunk)
2254      newentry.flags |= MAP_ENTRY_FLAG_HALF_HUNK;
2255
2256   *entry = newentry;
2257
2258   /* update the map on file */
2259   map_assemble(&fileentry[0], &chd->map[hunknum]);
2260   core_fseek(chd->file, chd->header.length + hunknum * sizeof(fileentry), SEEK_SET);
2261   bytes = core_fwrite(chd->file, &fileentry[0], sizeof(fileentry));
2262   if (bytes != sizeof(fileentry))
2263      return CHDERR_WRITE_ERROR;
2264
2265   return CHDERR_NONE;
1893   
1894   // verify the final CRC
1895   if (crc16_creator::simple(m_rawmap, m_hunkcount * 12) != mapcrc)
1896      throw CHDERR_DECOMPRESSION_ERROR;
22661897}
1898   
22671899
1900//-------------------------------------------------
1901//  create_common - command path when creating a
1902//  new CHD file
1903//-------------------------------------------------
22681904
2269
2270/***************************************************************************
2271    INTERNAL MAP ACCESS
2272***************************************************************************/
2273
2274/*-------------------------------------------------
2275    map_write_initial - write an initial map to
2276    a new CHD file
2277-------------------------------------------------*/
2278
2279static chd_error map_write_initial(core_file *file, chd_file *parent, const chd_header *header)
1905chd_error chd_file::create_common()
22801906{
2281   UINT8 blank_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
2282   int fullchunks, remainder, count, i, j;
2283   map_entry mapentry;
2284   UINT64 fileoffset;
1907   // wrap in try for proper error handling
1908   try
1909   {
1910      // if we have a parent, it must be V3 or later
1911      if (m_parent != NULL && m_parent->version() < 3)
1912         throw CHDERR_UNSUPPORTED_VERSION;
1913     
1914      // must be an even number of units per hunk
1915      if (m_hunkbytes % m_unitbytes != 0)
1916         throw CHDERR_INVALID_PARAMETER;
1917      if (m_parent != NULL && m_unitbytes != m_parent->unit_bytes())
1918         throw CHDERR_INVALID_PARAMETER;
1919     
1920      // writes are obviously permitted; reads only if uncompressed
1921      m_allow_writes = true;
1922      m_allow_reads = !compressed();
1923   
1924      // verify the compression types
1925      bool found_zero = false;
1926      for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compression); codecnum++)
1927      {
1928         // once we hit an empty slot, all later slots must be empty as well
1929         if (m_compression[codecnum] == CHD_CODEC_NONE)
1930            found_zero = true;
1931         else if (found_zero)
1932            throw CHDERR_INVALID_PARAMETER;
1933         else if (!chd_codec_list::codec_exists(m_compression[codecnum]))
1934            throw CHDERR_UNKNOWN_COMPRESSION;
1935      }
22851936
2286   /* create a mini hunk of 0's */
2287   mapentry.offset = 0;
2288   mapentry.crc = 0;
2289   mapentry.length = 0;
2290   mapentry.flags = MAP_ENTRY_TYPE_MINI | MAP_ENTRY_FLAG_NO_CRC;
2291   for (i = 0; i < MAP_STACK_ENTRIES; i++)
2292      map_assemble(&blank_map_entries[i * MAP_ENTRY_SIZE], &mapentry);
1937      // create our V5 header
1938      assert(m_version == HEADER_VERSION);
1939      UINT8 rawheader[V5_HEADER_SIZE];
1940      memcpy(&rawheader[0], "MComprHD", 8);
1941      be_write(&rawheader[8], V5_HEADER_SIZE, 4);
1942      be_write(&rawheader[12], m_version, 4);
1943      be_write(&rawheader[16], m_compression[0], 4);
1944      be_write(&rawheader[20], m_compression[1], 4);
1945      be_write(&rawheader[24], m_compression[2], 4);
1946      be_write(&rawheader[28], m_compression[3], 4);
1947      be_write(&rawheader[32], m_logicalbytes, 8);
1948      be_write(&rawheader[40], compressed() ? 0 : V5_HEADER_SIZE, 8);
1949      be_write(&rawheader[48], m_metaoffset, 8);
1950      be_write(&rawheader[56], m_hunkbytes, 4);
1951      be_write(&rawheader[60], m_unitbytes, 4);
1952      be_write_sha1(&rawheader[64], sha1_t::null);
1953      be_write_sha1(&rawheader[84], sha1_t::null);
1954      be_write_sha1(&rawheader[104], (m_parent != NULL) ? m_parent->sha1() : sha1_t::null);
22931955
2294   /* prepare to write a blank hunk map immediately following */
2295   fileoffset = header->length;
2296   fullchunks = header->totalhunks / MAP_STACK_ENTRIES;
2297   remainder = header->totalhunks % MAP_STACK_ENTRIES;
2298
2299   /* first write full chunks of blank entries */
2300   for (i = 0; i < fullchunks; i++)
2301   {
2302      /* parent drives need to be mapped through */
2303      if (parent != NULL)
2304         for (j = 0; j < MAP_STACK_ENTRIES; j++)
1956      // write the resulting header
1957      file_write(0, rawheader, sizeof(rawheader));
1958     
1959      // parse it back out to set up fields appropriately
1960      sha1_t parentsha1;
1961      parse_v5_header(rawheader, parentsha1);
1962     
1963      // write out the map (if not compressed)
1964      if (!compressed())
1965      {
1966         UINT32 mapsize = m_mapentrybytes * m_hunkcount;
1967         UINT8 buffer[4096] = { 0 };
1968         UINT64 offset = m_mapoffset;
1969         while (mapsize != 0)
23051970         {
2306            mapentry.offset = i * MAP_STACK_ENTRIES + j;
2307            mapentry.crc = parent->map[i * MAP_STACK_ENTRIES + j].crc;
2308            mapentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
2309            map_assemble(&blank_map_entries[j * MAP_ENTRY_SIZE], &mapentry);
1971            UINT32 bytes_to_write = MIN(mapsize, sizeof(buffer));
1972            file_write(offset, buffer, bytes_to_write);
1973            offset += bytes_to_write;
1974            mapsize -= bytes_to_write;
23101975         }
1976      }
23111977
2312      /* write the chunks */
2313      core_fseek(file, fileoffset, SEEK_SET);
2314      count = core_fwrite(file, blank_map_entries, sizeof(blank_map_entries));
2315      if (count != sizeof(blank_map_entries))
2316         return CHDERR_WRITE_ERROR;
2317      fileoffset += sizeof(blank_map_entries);
1978      // finish opening the file
1979      create_open_common();
23181980   }
2319
2320   /* then write the remainder */
2321   if (remainder > 0)
1981   
1982   // handle errors by closing ourself
1983   catch (chd_error &err)
23221984   {
2323      /* parent drives need to be mapped through */
2324      if (parent != NULL)
2325         for (j = 0; j < remainder; j++)
2326         {
2327            mapentry.offset = i * MAP_STACK_ENTRIES + j;
2328            mapentry.crc = parent->map[i * MAP_STACK_ENTRIES + j].crc;
2329            mapentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
2330            map_assemble(&blank_map_entries[j * MAP_ENTRY_SIZE], &mapentry);
2331         }
2332
2333      /* write the chunks */
2334      core_fseek(file, fileoffset, SEEK_SET);
2335      count = core_fwrite(file, blank_map_entries, remainder * MAP_ENTRY_SIZE);
2336      if (count != remainder * MAP_ENTRY_SIZE)
2337         return CHDERR_WRITE_ERROR;
2338      fileoffset += remainder * MAP_ENTRY_SIZE;
1985      close();
1986      return err;
23391987   }
2340
2341   /* then write a special end-of-list cookie */
2342   memcpy(&blank_map_entries[0], END_OF_LIST_COOKIE, MAP_ENTRY_SIZE);
2343   core_fseek(file, fileoffset, SEEK_SET);
2344   count = core_fwrite(file, blank_map_entries, MAP_ENTRY_SIZE);
2345   if (count != MAP_ENTRY_SIZE)
2346      return CHDERR_WRITE_ERROR;
2347
1988   catch (...)
1989   {
1990      close();
1991      throw;
1992   }
23481993   return CHDERR_NONE;
23491994}
23501995
23511996
2352/*-------------------------------------------------
2353    map_read - read the initial sector map
2354-------------------------------------------------*/
1997//-------------------------------------------------
1998//  open_common - common path when opening an
1999//  existing CHD file for input
2000//-------------------------------------------------
23552001
2356static chd_error map_read(chd_file *chd)
2002chd_error chd_file::open_common(bool writeable)
23572003{
2358   UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
2359   UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
2360   UINT64 fileoffset, maxoffset = 0;
2361   UINT8 cookie[MAP_ENTRY_SIZE];
2362   UINT32 count;
2363   chd_error err;
2364   int i;
2365
2366   /* first allocate memory */
2367   chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
2368   if (!chd->map)
2369      return CHDERR_OUT_OF_MEMORY;
2370
2371   /* read the map entries in in chunks and extract to the map list */
2372   fileoffset = chd->header.length;
2373   for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
2004   // wrap in try for proper error handling
2005   try
23742006   {
2375      /* compute how many entries this time */
2376      int entries = chd->header.totalhunks - i, j;
2377      if (entries > MAP_STACK_ENTRIES)
2378         entries = MAP_STACK_ENTRIES;
2379
2380      /* read that many */
2381      core_fseek(chd->file, fileoffset, SEEK_SET);
2382      count = core_fread(chd->file, raw_map_entries, entries * entrysize);
2383      if (count != entries * entrysize)
2007      // reads are always permitted; writes possibly as well
2008      m_allow_reads = true;
2009      m_allow_writes = writeable;
2010     
2011      // read the raw header
2012      UINT8 rawheader[MAX_HEADER_SIZE];
2013      file_read(0, rawheader, sizeof(rawheader));
2014     
2015      // verify the signature
2016      if (memcmp(rawheader, "MComprHD", 8) != 0)
2017         throw CHDERR_INVALID_FILE;
2018     
2019      // only allow writes to the most recent version
2020      m_version = be_read(&rawheader[12], 4);
2021      if (m_allow_writes && m_version < HEADER_VERSION)
2022         throw CHDERR_UNSUPPORTED_VERSION;
2023     
2024      // read the header if we support it
2025      sha1_t parentsha1 = sha1_t::null;
2026      switch (m_version)
23842027      {
2385         err = CHDERR_READ_ERROR;
2386         goto cleanup;
2028         case 3:      parse_v3_header(rawheader, parentsha1);   break;
2029         case 4:      parse_v4_header(rawheader, parentsha1);   break;
2030         case 5:      parse_v5_header(rawheader, parentsha1);   break;
2031         default:    throw CHDERR_UNSUPPORTED_VERSION;
23872032      }
2388      fileoffset += entries * entrysize;
2389
2390      /* process that many */
2391      if (entrysize == MAP_ENTRY_SIZE)
2033     
2034      // make sure we have a parent if we need one (and don't if we don't)
2035      if (parentsha1 != sha1_t::null)
23922036      {
2393         for (j = 0; j < entries; j++)
2394            map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
2037         if (m_parent == NULL)
2038            m_parent_missing = true;
2039         else if (m_parent->sha1() != parentsha1)
2040            throw CHDERR_INVALID_PARENT;
23952041      }
2396      else
2397      {
2398         for (j = 0; j < entries; j++)
2399            map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
2400      }
2401
2402      /* track the maximum offset */
2403      for (j = 0; j < entries; j++)
2404         if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_COMPRESSED ||
2405            (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_2ND_COMPRESSED ||
2406            (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_UNCOMPRESSED)
2407            maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
2042      else if (parentsha1 == sha1_t::null && m_parent != NULL)
2043         throw CHDERR_INVALID_PARAMETER;
2044     
2045      // finish opening the file
2046      create_open_common();
2047      return CHDERR_NONE;
24082048   }
2409
2410   /* verify the cookie */
2411   core_fseek(chd->file, fileoffset, SEEK_SET);
2412   count = core_fread(chd->file, &cookie, entrysize);
2413   if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
2049   
2050   // handle errors by closing ourself
2051   catch (chd_error &err)
24142052   {
2415      err = CHDERR_INVALID_FILE;
2416      goto cleanup;
2053      close();
2054      return err;
24172055   }
2418
2419   /* verify the length */
2420   if (maxoffset > core_fsize(chd->file))
2421   {
2422      err = CHDERR_INVALID_FILE;
2423      goto cleanup;
2424   }
2425   return CHDERR_NONE;
2426
2427cleanup:
2428   if (chd->map)
2429      free(chd->map);
2430   chd->map = NULL;
2431   return err;
24322056}
24332057
24342058
2059//-------------------------------------------------
2060//  create_open_common - common code for handling
2061//  creation and opening of a file
2062//-------------------------------------------------
24352063
2436/***************************************************************************
2437    INTERNAL CRC MAP ACCESS
2438***************************************************************************/
2439
2440/*-------------------------------------------------
2441    crcmap_init - initialize the CRC map
2442-------------------------------------------------*/
2443
2444static void crcmap_init(chd_file *chd, int prepopulate)
2064void chd_file::create_open_common()
24452065{
2446   int i;
2447
2448   /* if we already have one, bail */
2449   if (chd->crcmap != NULL)
2450      return;
2451
2452   /* reset all pointers */
2453   chd->crcmap = NULL;
2454   chd->crcfree = NULL;
2455   chd->crctable = NULL;
2456
2457   /* allocate a list; one for each hunk */
2458   chd->crcmap = (crcmap_entry *)malloc(chd->header.totalhunks * sizeof(chd->crcmap[0]));
2459   if (chd->crcmap == NULL)
2460      return;
2461
2462   /* allocate a CRC map table */
2463   chd->crctable = (crcmap_entry **)malloc(CRCMAP_HASH_SIZE * sizeof(chd->crctable[0]));
2464   if (chd->crctable == NULL)
2066   // verify the compression types and initialize the codecs
2067   for (int decompnum = 0; decompnum < ARRAY_LENGTH(m_compression); decompnum++)
24652068   {
2466      free(chd->crcmap);
2467      chd->crcmap = NULL;
2468      return;
2069      m_decompressor[decompnum] = chd_codec_list::new_decompressor(m_compression[decompnum], *this);
2070      if (m_decompressor[decompnum] == NULL && m_compression[decompnum] != 0)
2071         throw CHDERR_UNKNOWN_COMPRESSION;
24692072   }
2073   
2074   // read the map; v5+ compressed drives need to read and decompress their map
2075   m_rawmap.resize(m_hunkcount * m_mapentrybytes);
2076   if (m_version >= 5 && compressed())
2077      decompress_v5_map();
2078   else
2079      file_read(m_mapoffset, m_rawmap, m_rawmap.count());
24702080
2471   /* initialize the free list */
2472   for (i = 0; i < chd->header.totalhunks; i++)
2473   {
2474      chd->crcmap[i].next = chd->crcfree;
2475      chd->crcfree = &chd->crcmap[i];
2476   }
2477
2478   /* initialize the table */
2479   memset(chd->crctable, 0, CRCMAP_HASH_SIZE * sizeof(chd->crctable[0]));
2480
2481   /* if we're to prepopulate, go for it */
2482   if (prepopulate)
2483      for (i = 0; i < chd->header.totalhunks; i++)
2484         crcmap_add_entry(chd, i);
2081   // allocate the temporary compressed buffer and a buffer for caching
2082   m_compressed.resize(m_hunkbytes);
2083   m_cache.resize(m_hunkbytes);
24852084}
24862085
24872086
2488/*-------------------------------------------------
2489    crcmap_add_entry - log a CRC entry
2490-------------------------------------------------*/
2087//-------------------------------------------------
2088//  verify_proper_compression_append - verify that
2089//  the given hunk is a proper candidate for
2090//  appending to a compressed CHD
2091//-------------------------------------------------
24912092
2492static void crcmap_add_entry(chd_file *chd, UINT32 hunknum)
2093void chd_file::verify_proper_compression_append(UINT32 hunknum)
24932094{
2494   UINT32 hash = chd->map[hunknum].crc % CRCMAP_HASH_SIZE;
2495   crcmap_entry *crcmap;
2095   // punt if no file
2096   if (m_file == NULL)
2097      throw CHDERR_NOT_OPEN;
24962098
2497   /* pull a free entry off the list */
2498   crcmap = chd->crcfree;
2499   chd->crcfree = crcmap->next;
2099   // return an error if out of range
2100   if (hunknum >= m_hunkcount)
2101      throw CHDERR_HUNK_OUT_OF_RANGE;
25002102
2501   /* set up the entry and link it into the hash table */
2502   crcmap->hunknum = hunknum;
2503   crcmap->next = chd->crctable[hash];
2504   chd->crctable[hash] = crcmap;
2505}
2103   // if not writeable, fail
2104   if (!m_allow_writes)
2105      throw CHDERR_FILE_NOT_WRITEABLE;
25062106
2107   // compressed writes only via this interface
2108   if (!compressed())
2109      throw CHDERR_FILE_NOT_WRITEABLE;
25072110
2508/*-------------------------------------------------
2509    crcmap_verify_hunk_match - verify that a
2510    hunk really matches by doing a byte-for-byte
2511    compare
2512-------------------------------------------------*/
2111   // only permitted to write new blocks
2112   UINT8 *rawmap = &m_rawmap[hunknum * 12];
2113   if (rawmap[0] != 0xff)
2114      throw CHDERR_COMPRESSION_ERROR;
2115   
2116   // if this isn't the first block, only permitted to write immediately
2117   // after the previous one
2118   if (hunknum != 0 && rawmap[-12] == 0xff)
2119      throw CHDERR_COMPRESSION_ERROR;
2120}
2121   
25132122
2514static int crcmap_verify_hunk_match(chd_file *chd, UINT32 hunknum, const UINT8 *rawdata)
2123//-------------------------------------------------
2124//  hunk_write_compressed - write a hunk to a
2125//  compressed CHD, discovering the best
2126//  technique
2127//-------------------------------------------------
2128
2129void chd_file::hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, crc16_t crc16)
25152130{
2516   /* we have a potential match -- better be sure */
2517   /* read the hunk from disk and compare byte-for-byte */
2518   if (hunknum != chd->comparehunk)
2519   {
2520      chd->comparehunk = ~0;
2521      if (hunk_read_into_memory(chd, hunknum, chd->compare) == CHDERR_NONE)
2522         chd->comparehunk = hunknum;
2523   }
2524   return (hunknum == chd->comparehunk && memcmp(rawdata, chd->compare, chd->header.hunkbytes) == 0);
2131   // verify that we are appending properly to a compressed file
2132   verify_proper_compression_append(hunknum);
2133   
2134   // write the final result
2135   UINT64 offset = file_append(compressed, complength);
2136   
2137   // update the map entry
2138   UINT8 *rawmap = &m_rawmap[hunknum * 12];
2139   rawmap[0] = (compression == -1) ? COMPRESSION_NONE : compression;
2140   be_write(&rawmap[1], complength, 3);
2141   be_write(&rawmap[4], offset, 6);
2142   be_write(&rawmap[10], crc16, 2);
25252143}
25262144
25272145
2528/*-------------------------------------------------
2529    crcmap_find_hunk - find a hunk with a matching
2530    CRC in the map
2531-------------------------------------------------*/
2146//-------------------------------------------------
2147//  hunk_copy_from_self - mark a hunk as being a
2148//  copy of another hunk in the same CHD
2149//-------------------------------------------------
25322150
2533static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const UINT8 *rawdata)
2151void chd_file::hunk_copy_from_self(UINT32 hunknum, UINT32 otherhunk)
25342152{
2535   UINT32 lasthunk = (hunknum < chd->header.totalhunks) ? hunknum : chd->header.totalhunks;
2536   int curhunk;
2153   // verify that we are appending properly to a compressed file
2154   verify_proper_compression_append(hunknum);
2155   
2156   // only permitted to reference prior hunks
2157   if (otherhunk >= hunknum)
2158      throw CHDERR_INVALID_PARAMETER;
25372159
2538   /* if we have a CRC map, use that */
2539   if (chd->crctable)
2540   {
2541      crcmap_entry *curentry;
2542      for (curentry = chd->crctable[crc % CRCMAP_HASH_SIZE]; curentry; curentry = curentry->next)
2543      {
2544         curhunk = curentry->hunknum;
2545         if (chd->map[curhunk].crc == crc && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_NO_CRC) && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_HALF_HUNK) && crcmap_verify_hunk_match(chd, curhunk, rawdata))
2546            return curhunk;
2547      }
2548      return NO_MATCH;
2549   }
2550
2551   /* first see if the last match is a valid one */
2552   if (chd->comparehunk < chd->header.totalhunks && chd->map[chd->comparehunk].crc == crc && !(chd->map[chd->comparehunk].flags & MAP_ENTRY_FLAG_NO_CRC) && !(chd->map[chd->comparehunk].flags & MAP_ENTRY_FLAG_HALF_HUNK) &&
2553      memcmp(rawdata, chd->compare, chd->header.hunkbytes) == 0)
2554      return chd->comparehunk;
2555
2556   /* scan through the CHD's hunk map looking for a match */
2557   for (curhunk = 0; curhunk < lasthunk; curhunk++)
2558      if (chd->map[curhunk].crc == crc && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_NO_CRC) && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_HALF_HUNK) && crcmap_verify_hunk_match(chd, curhunk, rawdata))
2559         return curhunk;
2560
2561   return NO_MATCH;
2160   // update the map entry
2161   UINT8 *rawmap = &m_rawmap[hunknum * 12];
2162   rawmap[0] = COMPRESSION_SELF;
2163   be_write(&rawmap[1], 0, 3);
2164   be_write(&rawmap[4], otherhunk, 6);
2165   be_write(&rawmap[10], 0, 2);
25622166}
25632167
25642168
2169//-------------------------------------------------
2170//  hunk_copy_from_parent - mark a hunk as being a
2171//  copy of a hunk from a parent CHD
2172//-------------------------------------------------
25652173
2566/***************************************************************************
2567    INTERNAL METADATA ACCESS
2568***************************************************************************/
2569
2570/*-------------------------------------------------
2571    metadata_find_entry - find a metadata entry
2572-------------------------------------------------*/
2573
2574static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
2174void chd_file::hunk_copy_from_parent(UINT32 hunknum, UINT64 parentunit)
25752175{
2576   /* start at the beginning */
2577   metaentry->offset = chd->header.metaoffset;
2578   metaentry->prev = 0;
2176   // verify that we are appending properly to a compressed file
2177   verify_proper_compression_append(hunknum);
25792178
2580   /* loop until we run out of options */
2581   while (metaentry->offset != 0)
2582   {
2583      UINT8   raw_meta_header[METADATA_HEADER_SIZE];
2584      UINT32   count;
2585
2586      /* read the raw header */
2587      core_fseek(chd->file, metaentry->offset, SEEK_SET);
2588      count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
2589      if (count != sizeof(raw_meta_header))
2590         break;
2591
2592      /* extract the data */
2593      metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
2594      metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
2595      metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
2596
2597      /* flags are encoded in the high byte of length */
2598      metaentry->flags = metaentry->length >> 24;
2599      metaentry->length &= 0x00ffffff;
2600
2601      /* if we got a match, proceed */
2602      if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
2603         if (metaindex-- == 0)
2604            return CHDERR_NONE;
2605
2606      /* no match, fetch the next link */
2607      metaentry->prev = metaentry->offset;
2608      metaentry->offset = metaentry->next;
2609   }
2610
2611   /* if we get here, we didn't find it */
2612   return CHDERR_METADATA_NOT_FOUND;
2179   // update the map entry
2180   UINT8 *rawmap = &m_rawmap[hunknum * 12];
2181   rawmap[0] = COMPRESSION_PARENT;
2182   be_write(&rawmap[1], 0, 3);
2183   be_write(&rawmap[4], parentunit, 6);
2184   be_write(&rawmap[10], 0, 2);
26132185}
26142186
26152187
2616/*-------------------------------------------------
2617    metadata_set_previous_next - set the 'next'
2618    offset of a piece of metadata
2619-------------------------------------------------*/
2188//-------------------------------------------------
2189//  metadata_find - find a metadata entry
2190//-------------------------------------------------
26202191
2621static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset)
2192bool chd_file::metadata_find(chd_metadata_tag metatag, INT32 metaindex, metadata_entry &metaentry, bool resume)
26222193{
2623   UINT8 raw_meta_header[METADATA_HEADER_SIZE];
2624   chd_error err;
2625   UINT32 count;
2626
2627   /* if we were the first entry, make the next entry the first */
2628   if (prevoffset == 0)
2194   // start at the beginning unless we're resuming a previous search
2195   if (!resume)
26292196   {
2630      chd->header.metaoffset = nextoffset;
2631      err = header_write(chd->file, &chd->header);
2632      if (err != CHDERR_NONE)
2633         return err;
2197      metaentry.offset = m_metaoffset;
2198      metaentry.prev = 0;
26342199   }
2635
2636   /* otherwise, update the link in the previous pointer */
26372200   else
26382201   {
2639      /* read the previous raw header */
2640      core_fseek(chd->file, prevoffset, SEEK_SET);
2641      count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
2642      if (count != sizeof(raw_meta_header))
2643         return CHDERR_READ_ERROR;
2644
2645      /* copy our next pointer into the previous->next offset */
2646      put_bigendian_uint64(&raw_meta_header[8], nextoffset);
2647
2648      /* write the previous raw header */
2649      core_fseek(chd->file, prevoffset, SEEK_SET);
2650      count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
2651      if (count != sizeof(raw_meta_header))
2652         return CHDERR_WRITE_ERROR;
2202      metaentry.prev = metaentry.offset;
2203      metaentry.offset = metaentry.next;
26532204   }
26542205
2655   return CHDERR_NONE;
2656}
2657
2658
2659/*-------------------------------------------------
2660    metadata_set_length - set the length field of
2661    a piece of metadata
2662-------------------------------------------------*/
2663
2664static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length)
2665{
2666   UINT8 raw_meta_header[METADATA_HEADER_SIZE];
2667   UINT32 oldlength;
2668   UINT32 count;
2669
2670   /* read the raw header */
2671   core_fseek(chd->file, offset, SEEK_SET);
2672   count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
2673   if (count != sizeof(raw_meta_header))
2674      return CHDERR_READ_ERROR;
2675
2676   /* update the length at offset 4, preserving the flags in the upper byte */
2677   oldlength = get_bigendian_uint32(&raw_meta_header[4]);
2678   length = (length & 0x00ffffff) | (oldlength & 0xff000000);
2679   put_bigendian_uint32(&raw_meta_header[4], length);
2680
2681   /* write the raw header */
2682   core_fseek(chd->file, offset, SEEK_SET);
2683   count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
2684   if (count != sizeof(raw_meta_header))
2685      return CHDERR_WRITE_ERROR;
2686
2687   return CHDERR_NONE;
2688}
2689
2690
2691/*-------------------------------------------------
2692    metadata_compute_hash - compute the SHA1
2693    hash of all metadata that requests it
2694-------------------------------------------------*/
2695
2696static chd_error metadata_compute_hash(chd_file *chd, const UINT8 *rawsha1, UINT8 *finalsha1)
2697{
2698   metadata_hash *hasharray = NULL;
2699   chd_error err = CHDERR_NONE;
2700   struct sha1_ctx sha1;
2701   UINT32 hashindex = 0;
2702   UINT32 hashalloc = 0;
2703   UINT64 offset, next;
2704
2705   /* only works for V4 and above */
2706   if (chd->header.version < 4)
2206   // loop until we run out of options
2207   while (metaentry.offset != 0)
27072208   {
2708      memcpy(finalsha1, rawsha1, SHA1_DIGEST_SIZE);
2709      return CHDERR_NONE;
2710   }
2711
2712   /* loop until we run out of data */
2713   for (offset = chd->header.metaoffset; offset != 0; offset = next)
2714   {
2209      // read the raw header
27152210      UINT8 raw_meta_header[METADATA_HEADER_SIZE];
2716      UINT32 count, metalength, metatag;
2717      UINT8 *tempbuffer;
2718      UINT8 metaflags;
2211      file_read(metaentry.offset, raw_meta_header, sizeof(raw_meta_header));
27192212
2720      /* read the raw header */
2721      core_fseek(chd->file, offset, SEEK_SET);
2722      count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
2723      if (count != sizeof(raw_meta_header))
2724         break;
2213      // extract the data
2214      metaentry.metatag = be_read(&raw_meta_header[0], 4);
2215      metaentry.flags = raw_meta_header[4];
2216      metaentry.length = be_read(&raw_meta_header[5], 3);
2217      metaentry.next = be_read(&raw_meta_header[8], 8);
27252218
2726      /* extract the data */
2727      metatag = get_bigendian_uint32(&raw_meta_header[0]);
2728      metalength = get_bigendian_uint32(&raw_meta_header[4]);
2729      next = get_bigendian_uint64(&raw_meta_header[8]);
2219      // if we got a match, proceed
2220      if (metatag == CHDMETATAG_WILDCARD || metaentry.metatag == metatag)
2221         if (metaindex-- == 0)
2222            return true;
27302223
2731      /* flags are encoded in the high byte of length */
2732      metaflags = metalength >> 24;
2733      metalength &= 0x00ffffff;
2734
2735      /* if not checksumming, continue */
2736      if (!(metaflags & CHD_MDFLAGS_CHECKSUM))
2737         continue;
2738
2739      /* allocate memory */
2740      tempbuffer = (UINT8 *)malloc(metalength);
2741      if (tempbuffer == NULL)
2742      {
2743         err = CHDERR_OUT_OF_MEMORY;
2744         goto cleanup;
2745      }
2746
2747      /* seek and read the metadata */
2748      core_fseek(chd->file, offset + METADATA_HEADER_SIZE, SEEK_SET);
2749      count = core_fread(chd->file, tempbuffer, metalength);
2750      if (count != metalength)
2751      {
2752         free(tempbuffer);
2753         err = CHDERR_READ_ERROR;
2754         goto cleanup;
2755      }
2756
2757      /* compute this entry's hash */
2758      sha1_init(&sha1);
2759      sha1_update(&sha1, metalength, tempbuffer);
2760      sha1_final(&sha1);
2761      free(tempbuffer);
2762
2763      /* expand the hasharray if necessary */
2764      if (hashindex >= hashalloc)
2765      {
2766         hashalloc += 256;
2767         hasharray = (metadata_hash *)realloc(hasharray, hashalloc * sizeof(hasharray[0]));
2768         if (hasharray == NULL)
2769         {
2770            err = CHDERR_OUT_OF_MEMORY;
2771            goto cleanup;
2772         }
2773      }
2774
2775      /* fill in the entry */
2776      put_bigendian_uint32(hasharray[hashindex].tag, metatag);
2777      sha1_digest(&sha1, SHA1_DIGEST_SIZE, hasharray[hashindex].sha1);
2778      hashindex++;
2224      // no match, fetch the next link
2225      metaentry.prev = metaentry.offset;
2226      metaentry.offset = metaentry.next;
27792227   }
27802228
2781   /* sort the array */
2782   qsort(hasharray, hashindex, sizeof(hasharray[0]), metadata_hash_compare);
2783
2784   /* compute the SHA1 of the raw plus the various metadata */
2785   sha1_init(&sha1);
2786   sha1_update(&sha1, CHD_SHA1_BYTES, rawsha1);
2787   sha1_update(&sha1, hashindex * sizeof(hasharray[0]), (const UINT8 *)hasharray);
2788   sha1_final(&sha1);
2789   sha1_digest(&sha1, SHA1_DIGEST_SIZE, finalsha1);
2790
2791cleanup:
2792   if (hasharray != NULL)
2793      free(hasharray);
2794   return err;
2229   // if we get here, we didn't find it
2230   return false;
27952231}
27962232
27972233
2798/*-------------------------------------------------
2799    metadata_hash_compare - compare two hash
2800    entries
2801-------------------------------------------------*/
2234//-------------------------------------------------
2235//  metadata_set_previous_next - set the 'next'
2236//  offset of a piece of metadata
2237//-------------------------------------------------
28022238
2803static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2)
2239void chd_file::metadata_set_previous_next(UINT64 prevoffset, UINT64 nextoffset)
28042240{
2805   return memcmp(elem1, elem2, sizeof(metadata_hash));
2806}
2241   UINT64 offset = 0;
28072242
2808
2809
2810/***************************************************************************
2811    ZLIB COMPRESSION CODEC
2812***************************************************************************/
2813
2814/*-------------------------------------------------
2815    zlib_codec_init - initialize the ZLIB codec
2816-------------------------------------------------*/
2817
2818static chd_error zlib_codec_init(chd_file *chd)
2819{
2820   zlib_codec_data *data;
2821   chd_error err;
2822   int zerr;
2823
2824   /* allocate memory for the 2 stream buffers */
2825   data = (zlib_codec_data *)malloc(sizeof(*data));
2826   if (data == NULL)
2827      return CHDERR_OUT_OF_MEMORY;
2828
2829   /* clear the buffers */
2830   memset(data, 0, sizeof(*data));
2831
2832   /* init the inflater first */
2833   data->inflater.next_in = (Bytef *)data;   /* bogus, but that's ok */
2834   data->inflater.avail_in = 0;
2835   data->inflater.zalloc = zlib_fast_alloc;
2836   data->inflater.zfree = zlib_fast_free;
2837   data->inflater.opaque = data;
2838   zerr = inflateInit2(&data->inflater, -MAX_WBITS);
2839
2840   /* if that worked, initialize the deflater */
2841   if (zerr == Z_OK)
2243   // if we were the first entry, make the next entry the first
2244   if (prevoffset == 0)
28422245   {
2843      data->deflater.next_in = (Bytef *)data;   /* bogus, but that's ok */
2844      data->deflater.avail_in = 0;
2845      data->deflater.zalloc = zlib_fast_alloc;
2846      data->deflater.zfree = zlib_fast_free;
2847      data->deflater.opaque = data;
2848      zerr = deflateInit2(&data->deflater, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
2246      offset = m_metaoffset_offset;
2247      m_metaoffset = nextoffset;
28492248   }
28502249
2851   /* convert errors */
2852   if (zerr == Z_MEM_ERROR)
2853      err = CHDERR_OUT_OF_MEMORY;
2854   else if (zerr != Z_OK)
2855      err = CHDERR_CODEC_ERROR;
2250   // otherwise, update the link in the previous header
28562251   else
2857      err = CHDERR_NONE;
2858
2859   /* handle an error */
2860   if (err == CHDERR_NONE)
2861      chd->codecdata = data;
2862   else
2863      free(data);
2864
2865   return err;
2252      offset = prevoffset + 8;
2253   
2254   // create a big-endian version
2255   UINT8 rawbuf[sizeof(UINT64)];
2256   be_write(rawbuf, nextoffset, 8);
2257   
2258   // write to the header and update our local copy
2259   file_write(offset, rawbuf, sizeof(rawbuf));
28662260}
28672261
28682262
2869/*-------------------------------------------------
2870    zlib_codec_free - free data for the ZLIB
2871    codec
2872-------------------------------------------------*/
2263//-------------------------------------------------
2264//  metadata_update_hash - compute the SHA1
2265//  hash of all metadata that requests it
2266//-------------------------------------------------
28732267
2874static void zlib_codec_free(chd_file *chd)
2268void chd_file::metadata_update_hash()
28752269{
2876   zlib_codec_data *data = (zlib_codec_data *)chd->codecdata;
2270   // only works for V4 and above, and only for compressed CHDs
2271   if (m_version < 4 || !compressed())
2272      return;
28772273
2878   /* deinit the streams */
2879   if (data != NULL)
2880   {
2881      int i;
2882
2883      inflateEnd(&data->inflater);
2884      deflateEnd(&data->deflater);
2885
2886      /* free our fast memory */
2887      for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2888         if (data->allocptr[i])
2889            free(data->allocptr[i]);
2890      free(data);
2891   }
2274   // compute the new overall hash
2275   sha1_t fullsha1 = compute_overall_sha1(raw_sha1());
2276     
2277   // create a big-endian version
2278   UINT8 rawbuf[sizeof(sha1_t)];
2279   be_write_sha1(&rawbuf[0], fullsha1);
2280   
2281   // write to the header
2282   file_write(m_sha1_offset, rawbuf, sizeof(rawbuf));
28922283}
28932284
28942285
2895/*-------------------------------------------------
2896    zlib_codec_compress - compress data using the
2897    ZLIB codec
2898-------------------------------------------------*/
2286//-------------------------------------------------
2287//  metadata_hash_compare - compare two hash
2288//  entries
2289//-------------------------------------------------
28992290
2900static chd_error zlib_codec_compress(chd_file *chd, const void *src, UINT32 *length)
2291int CLIB_DECL chd_file::metadata_hash_compare(const void *elem1, const void *elem2)
29012292{
2902   zlib_codec_data *data = (zlib_codec_data *)chd->codecdata;
2903   int zerr;
2904
2905   /* reset the decompressor */
2906   data->deflater.next_in = (Bytef *)src;
2907   data->deflater.avail_in = chd->header.hunkbytes;
2908   data->deflater.total_in = 0;
2909   data->deflater.next_out = chd->compressed;
2910   data->deflater.avail_out = chd->header.hunkbytes;
2911   data->deflater.total_out = 0;
2912   zerr = deflateReset(&data->deflater);
2913   if (zerr != Z_OK)
2914      return CHDERR_COMPRESSION_ERROR;
2915
2916   /* do it */
2917   zerr = deflate(&data->deflater, Z_FINISH);
2918
2919   /* if we ended up with more data than we started with, return an error */
2920   if (zerr != Z_STREAM_END || data->deflater.total_out >= chd->header.hunkbytes)
2921      return CHDERR_COMPRESSION_ERROR;
2922
2923   /* otherwise, fill in the length and return success */
2924   *length = data->deflater.total_out;
2925   return CHDERR_NONE;
2293   return memcmp(elem1, elem2, sizeof(metadata_hash));
29262294}
29272295
29282296
2929/*-------------------------------------------------
2930    zlib_codec_decompress - decomrpess data using
2931    the ZLIB codec
2932-------------------------------------------------*/
29332297
2934static chd_error zlib_codec_decompress(chd_file *chd, UINT32 srclength, void *dest)
2935{
2936   zlib_codec_data *data = (zlib_codec_data *)chd->codecdata;
2937   int zerr;
2298//**************************************************************************
2299//  CHD COMPRESSOR
2300//**************************************************************************
29382301
2939   /* reset the decompressor */
2940   data->inflater.next_in = chd->compressed;
2941   data->inflater.avail_in = srclength;
2942   data->inflater.total_in = 0;
2943   data->inflater.next_out = (Bytef *)dest;
2944   data->inflater.avail_out = chd->header.hunkbytes;
2945   data->inflater.total_out = 0;
2946   zerr = inflateReset(&data->inflater);
2947   if (zerr != Z_OK)
2948      return CHDERR_DECOMPRESSION_ERROR;
2302//-------------------------------------------------
2303//  chd_file_compressor - constructor
2304//-------------------------------------------------
29492305
2950   /* do it */
2951   zerr = inflate(&data->inflater, Z_FINISH);
2952   if (data->inflater.total_out != chd->header.hunkbytes)
2953      return CHDERR_DECOMPRESSION_ERROR;
2954
2955   return CHDERR_NONE;
2956}
2957
2958
2959/*-------------------------------------------------
2960    zlib_fast_alloc - fast malloc for ZLIB, which
2961    allocates and frees memory frequently
2962-------------------------------------------------*/
2963
2964static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
2306chd_file_compressor::chd_file_compressor()
2307   : m_walking_parent(false),
2308     m_total_in(0),
2309     m_total_out(0),
2310     m_read_queue(NULL),
2311     m_read_queue_offset(0),
2312     m_read_done_offset(0),
2313     m_read_error(false),
2314     m_work_queue(NULL),
2315     m_write_hunk(0)
29652316{
2966   zlib_codec_data *data = (zlib_codec_data *)opaque;
2967   UINT32 *ptr;
2968   int i;
2317   // zap arrays
2318   memset(m_work_item, 0, sizeof(m_work_item));
2319   memset(m_codecs, 0, sizeof(m_codecs));
29692320
2970   /* compute the size, rounding to the nearest 1k */
2971   size = (size * items + 0x3ff) & ~0x3ff;
2972
2973   /* reuse a hunk if we can */
2974   for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2975   {
2976      ptr = data->allocptr[i];
2977      if (ptr && size == *ptr)
2978      {
2979         /* set the low bit of the size so we don't match next time */
2980         *ptr |= 1;
2981         return ptr + 1;
2982      }
2983   }
2984
2985   /* alloc a new one */
2986   ptr = (UINT32 *)malloc(size + sizeof(UINT32));
2987   if (!ptr)
2988      return NULL;
2989
2990   /* put it into the list */
2991   for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2992      if (!data->allocptr[i])
2993      {
2994         data->allocptr[i] = ptr;
2995         break;
2996      }
2997
2998   /* set the low bit of the size so we don't match next time */
2999   *ptr = size | 1;
3000   return ptr + 1;
2321   // allocate work queues
2322   m_read_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_IO);
2323   m_work_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI);
30012324}
30022325
30032326
3004/*-------------------------------------------------
3005    zlib_fast_free - fast free for ZLIB, which
3006    allocates and frees memory frequently
3007-------------------------------------------------*/
2327//-------------------------------------------------
2328//  ~chd_file_compressor - destructor
2329//-------------------------------------------------
30082330
3009static void zlib_fast_free(voidpf opaque, voidpf address)
2331chd_file_compressor::~chd_file_compressor()
30102332{
3011   zlib_codec_data *data = (zlib_codec_data *)opaque;
3012   UINT32 *ptr = (UINT32 *)address - 1;
3013   int i;
3014
3015   /* find the hunk */
3016   for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
3017      if (ptr == data->allocptr[i])
3018      {
3019         /* clear the low bit of the size to allow matches */
3020         *ptr &= ~1;
3021         return;
3022      }
2333   // free the work queues
2334   osd_work_queue_free(m_read_queue);
2335   osd_work_queue_free(m_work_queue);
2336   
2337   // delete allocated arrays
2338   for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_codecs); codecnum++)
2339      delete m_codecs[codecnum];
30232340}
30242341
3025/*-------------------------------------------------
3026    flac_codec_compress - compress data using the
3027    FLAC codec
3028-------------------------------------------------*/
30292342
2343//-------------------------------------------------
2344//  compress_begin - initiate compression
2345//-------------------------------------------------
30302346
3031const int INITIAL_BUFFER_SIZE = 0x20000;
3032const int INITIAL_GROW_SIZE = 0x20000;
3033
3034
3035struct flac_encoder_data
2347void chd_file_compressor::compress_begin()
30362348{
3037   FLAC__int32* pcm;
3038   FLAC__byte* tempbuffer;
3039   UINT8* flac_outputbuffer;
3040   size_t flac_outputbuffer_size;
3041   FLAC__uint64 flac_output_buffer_curpos;
3042   FLAC__uint64 flac_output_buffer_total;
3043};
3044
3045static FLAC__StreamEncoderWriteStatus flac_encoder_write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
3046{
3047   if (((flac_encoder_data*)client_data)->flac_output_buffer_curpos + bytes >= ((flac_encoder_data*)client_data)->flac_outputbuffer_size)
2349   // reset state
2350   m_walking_parent = (m_parent != NULL);
2351   m_total_in = 0;
2352   m_total_out = 0;
2353   m_compsha1.reset();
2354   
2355   // reset our maps
2356   m_parent_map.reset();
2357   m_current_map.reset();
2358   
2359   // reset read state
2360   m_read_queue_offset = 0;
2361   m_read_done_offset = 0;
2362   m_read_error = false;
2363   
2364   // reset work item state
2365   m_work_buffer.resize(hunk_bytes() * (WORK_BUFFER_HUNKS + 1));
2366   m_compressed_buffer.resize(hunk_bytes() * WORK_BUFFER_HUNKS);
2367   for (int itemnum = 0; itemnum < WORK_BUFFER_HUNKS; itemnum++)
30482368   {
3049      ((flac_encoder_data*)client_data)->flac_outputbuffer = (UINT8*)realloc(((flac_encoder_data*)client_data)->flac_outputbuffer, ((flac_encoder_data*)client_data)->flac_outputbuffer_size+INITIAL_GROW_SIZE);
3050      ((flac_encoder_data*)client_data)->flac_outputbuffer_size = ((flac_encoder_data*)client_data)->flac_outputbuffer_size+INITIAL_GROW_SIZE;
2369      work_item &item = m_work_item[itemnum];
2370      item.m_compressor = this;
2371      item.m_data = m_work_buffer + hunk_bytes() * itemnum;
2372      item.m_compressed = m_compressed_buffer + hunk_bytes() * itemnum;
2373      item.m_hash.resize(hunk_bytes() / unit_bytes());
30512374   }
3052
3053   memcpy(((flac_encoder_data*)client_data)->flac_outputbuffer+((flac_encoder_data*)client_data)->flac_output_buffer_curpos, buffer, bytes);
3054   if (((flac_encoder_data*)client_data)->flac_output_buffer_curpos+bytes > ((flac_encoder_data*)client_data)->flac_output_buffer_total)
3055      ((flac_encoder_data*)client_data)->flac_output_buffer_total=((flac_encoder_data*)client_data)->flac_output_buffer_curpos+bytes;
3056
3057   ((flac_encoder_data*)client_data)->flac_output_buffer_curpos+=bytes;
3058
3059   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
2375   
2376   // initialize codec instances
2377   for (int instance = 0; instance < ARRAY_LENGTH(m_codecs); instance++)
2378   {
2379      delete m_codecs[instance];
2380      m_codecs[instance] = new chd_compressor_group(*this, m_compression);
2381   }
2382   
2383   // reset write state
2384   m_write_hunk = 0;
30602385}
30612386
3062#define FLAC_HEADER_SIZE (86)
30632387
3064static chd_error flac_codec_compress(chd_file *chd, const void *src, UINT32 *length, int swap)
3065{
3066   int FLAC_ENCODER_READSIZE = (CD_MAX_SECTOR_DATA/4);
3067   int FLAC_ENCODER_FULLSIZE = ((CD_MAX_SECTOR_DATA+CD_MAX_SUBCODE_DATA)/4);
2388//-------------------------------------------------
2389//  compress_continue - continue compression
2390//-------------------------------------------------
30682391
3069   flac_encoder_data flac_encoder_client;
3070   flac_encoder_data* flac_encoder_client_ptr = &flac_encoder_client;
3071   flac_encoder_client_ptr->flac_outputbuffer = (UINT8*)malloc(INITIAL_BUFFER_SIZE);
3072   flac_encoder_client_ptr->flac_outputbuffer_size = INITIAL_BUFFER_SIZE;
3073   flac_encoder_client_ptr->flac_output_buffer_curpos = 0;
3074   flac_encoder_client_ptr->flac_output_buffer_total = 0;
3075   flac_encoder_client_ptr->pcm=(FLAC__int32*)malloc(FLAC_ENCODER_READSIZE * 2 * 4);
3076   flac_encoder_client_ptr->tempbuffer=(FLAC__byte*)malloc(FLAC_ENCODER_READSIZE * 2 * 2);
3077
3078
3079
3080   FLAC__StreamEncoder *encoder = 0;
3081   FLAC__bool ok = true;
3082
3083   if((encoder = FLAC__stream_encoder_new()) == NULL)
2392chd_error chd_file_compressor::compress_continue(double &progress, double &ratio)
2393{
2394   // if done reading, queue some more
2395   while (m_read_queue_offset < m_logicalbytes && osd_work_queue_items(m_read_queue) < 2)
30842396   {
3085      printf("ERROR: allocating encoder\n");
3086      return CHDERR_COMPRESSION_ERROR;
3087   }
2397      // if we got an error, return an error
2398      if (m_read_error)
2399         return CHDERR_READ_ERROR;
30882400
3089   ok &= FLAC__stream_encoder_set_verify(encoder, false); // we trust libFLAC ;-)
3090   ok &= FLAC__stream_encoder_set_compression_level(encoder, 8);
3091   ok &= FLAC__stream_encoder_set_channels(encoder, 2);
3092   ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, 16);
3093   ok &= FLAC__stream_encoder_set_sample_rate(encoder, 44100);
3094   ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, 0);
3095   ok &= FLAC__stream_encoder_set_streamable_subset(encoder, false);
3096   ok &= FLAC__stream_encoder_set_blocksize(encoder, ((CD_MAX_SECTOR_DATA)*CD_FRAMES_PER_HUNK)/4 ); // /4 because this is in SAMPLES, not bytes
2401      // see if we have enough free work items to read the next half of a buffer
2402      UINT32 startitem = m_read_queue_offset / hunk_bytes();
2403      UINT32 enditem = startitem + WORK_BUFFER_HUNKS / 2;
2404      UINT32 curitem;
2405      for (curitem = startitem; curitem < enditem; curitem++)
2406         if (m_work_item[curitem % WORK_BUFFER_HUNKS].m_status != WS_READY)
2407            break;
30972408
3098   if (!ok)
3099   {
3100      printf("error setting up stream encoder\n");
3101      return CHDERR_COMPRESSION_ERROR;
3102   }
2409      // if it's not all clear, defer     
2410      if (curitem != enditem)
2411         break;
2412     
2413      // if we're walking the parent, we want one more item to have cleared so we
2414      // can read an extra hunk there
2415      if (m_walking_parent && m_work_item[curitem % WORK_BUFFER_HUNKS].m_status != WS_READY)
2416         break;
31032417
3104   if  (FLAC__stream_encoder_init_stream(encoder, flac_encoder_write_callback, NULL, NULL, NULL, flac_encoder_client_ptr)  != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
3105   {
3106      printf("error initializing encoder\n");
3107      return CHDERR_COMPRESSION_ERROR;
2418      // queue the next read
2419      for (curitem = startitem; curitem < enditem; curitem++)
2420         m_work_item[curitem % WORK_BUFFER_HUNKS].m_status = WS_READING;
2421      osd_work_item_queue(m_read_queue, async_read_static, this, WORK_ITEM_FLAG_AUTO_RELEASE);
2422      m_read_queue_offset += WORK_BUFFER_HUNKS * hunk_bytes() / 2;
31082423   }
3109
3110   size_t left = (size_t)chd->header.hunkbytes;
3111   UINT8* srcdata = (UINT8*)src;
3112
3113   while(ok && left)
2424   
2425   // flush out any finished items
2426   while (m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status == WS_COMPLETE)
31142427   {
3115      memcpy(flac_encoder_client_ptr->tempbuffer, srcdata, FLAC_ENCODER_READSIZE*4);
3116      srcdata += FLAC_ENCODER_FULLSIZE*4;
2428      work_item &item = m_work_item[m_write_hunk % WORK_BUFFER_HUNKS];
2429     
2430      // free any OSD work item
2431      if (item.m_osd != NULL)
2432         osd_work_item_release(item.m_osd);
2433      item.m_osd = NULL;
2434
2435      // for parent walking, just add to the hashmap
2436      if (m_walking_parent)
31172437      {
3118         size_t i;
3119         for(i = 0; i < FLAC_ENCODER_READSIZE*2; i++)
2438         UINT32 uph = hunk_bytes() / unit_bytes();
2439         UINT32 units = uph;
2440         if (item.m_hunknum == hunk_count() - 1 || !compressed())
2441            units = 1;
2442         for (UINT32 unit = 0; unit < units; unit++)
2443            if (m_parent_map.find(item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1) == hashmap::NOT_FOUND)
2444               m_parent_map.add(item.m_hunknum * uph + unit, item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1);
2445      }
2446     
2447      // if we're uncompressed, use regular writes
2448      else if (!compressed())
2449      {
2450         bool skip = true;
2451         
2452         // see if it's all 0
2453         for (UINT32 offs = 0; offs < m_hunkbytes && skip; offs++)
2454            if (item.m_data[offs] != 0)
2455               skip = false;
2456         
2457         // see if it's in the parent map
2458         if (!skip && m_parent != NULL && m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) != hashmap::NOT_FOUND)
2459            skip = true;
2460         
2461         // write the block
2462         if (!skip)
31202463         {
3121            if (!swap) flac_encoder_client_ptr->pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)flac_encoder_client_ptr->tempbuffer[2*i] << 8) | (FLAC__int16)flac_encoder_client_ptr->tempbuffer[2*i+1]);
3122            else       flac_encoder_client_ptr->pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)flac_encoder_client_ptr->tempbuffer[2*i+1] << 8) | (FLAC__int16)flac_encoder_client_ptr->tempbuffer[2*i]);
2464            chd_error err = write_hunk(item.m_hunknum, item.m_data);
2465            if (err != CHDERR_NONE)
2466               return err;
2467            m_total_out += m_hunkbytes;
31232468         }
3124
3125         ok = FLAC__stream_encoder_process_interleaved(encoder, flac_encoder_client_ptr->pcm, FLAC_ENCODER_READSIZE);
31262469      }
3127
3128
3129      left -= (FLAC_ENCODER_FULLSIZE*4);
2470     
2471      // for compressing, process the result
2472      else do
2473      {
2474         // first see if the hunk is in the parent or self maps
2475         UINT64 selfhunk = m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1);
2476         if (selfhunk != hashmap::NOT_FOUND)
2477         {
2478            hunk_copy_from_self(item.m_hunknum, selfhunk);
2479            break;
2480         }
2481         
2482         // if not, see if it's in the parent map
2483         if (m_parent != NULL)
2484         {
2485            UINT64 parentunit = m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1);
2486            if (parentunit != hashmap::NOT_FOUND)
2487            {
2488               hunk_copy_from_parent(item.m_hunknum, parentunit);
2489               break;
2490            }
2491         }
2492         
2493         // otherwise, append it compressed and add to the self map
2494         hunk_write_compressed(item.m_hunknum, item.m_compression, item.m_compressed, item.m_complen, item.m_hash[0].m_crc16);
2495         m_total_out += item.m_complen;
2496         m_current_map.add(item.m_hunknum, item.m_hash[0].m_crc16, item.m_hash[0].m_sha1);
2497      } while (0);
2498     
2499      // reset the item and advance
2500      item.m_status = WS_READY;
2501      m_write_hunk++;
2502     
2503      // if we hit the end, finalize
2504      if (m_write_hunk == m_hunkcount)
2505      {
2506         // if this is just walking the parent, reset and get ready for compression
2507         if (m_walking_parent)
2508         {
2509            m_walking_parent = false;
2510            m_read_queue_offset = m_read_done_offset = 0;
2511            m_write_hunk = 0;
2512            for (int itemnum = 0; itemnum < WORK_BUFFER_HUNKS; itemnum++)
2513               m_work_item[itemnum].m_status = WS_READY;
2514         }
2515         
2516         // wait for all reads to finish and if we're compressed, write the final SHA1 and map
2517         else
2518         {
2519            osd_work_queue_wait(m_read_queue, 30 * osd_ticks_per_second());
2520            if (!compressed())
2521               return CHDERR_NONE;
2522            set_raw_sha1(m_compsha1.finish());
2523            return compress_v5_map();
2524         }
2525      }
31302526   }
2527   
2528   // update progress and ratio
2529   if (m_walking_parent)
2530      progress = double(m_read_done_offset) / double(logical_bytes());
2531   else
2532      progress = double(m_write_hunk) / double(m_hunkcount);
2533   ratio = (m_total_in == 0) ? 1.0 : double(m_total_out) / double(m_total_in);
31312534
3132   if (!ok)
3133   {
3134      printf("error encoding!\n");
3135      return CHDERR_COMPRESSION_ERROR;
3136   }
2535   // if we're waiting for work, wait
2536   while (m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status != WS_COMPLETE && m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd != NULL)
2537      osd_work_item_wait(m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd, osd_ticks_per_second());
31372538
3138   ok &= FLAC__stream_encoder_finish(encoder);
2539   return m_walking_parent ? CHDERR_WALKING_PARENT : CHDERR_COMPRESSING;
2540}
31392541
3140   if (!ok)
3141   {
3142      printf("error finishing!\n");
3143      return CHDERR_COMPRESSION_ERROR;
3144   }
31452542
3146   int totalout = flac_encoder_client_ptr->flac_output_buffer_total-FLAC_HEADER_SIZE;
2543//-------------------------------------------------
2544//  async_walk_parent - handle asynchronous parent
2545//  walking operations
2546//-------------------------------------------------
31472547
2548void *chd_file_compressor::async_walk_parent_static(void *param, int threadid)
2549{
2550   work_item *item = reinterpret_cast<work_item *>(param);
2551   item->m_compressor->async_walk_parent(*item);
2552   return NULL;
2553}
31482554
3149
3150   FLAC__stream_encoder_delete(encoder);
3151
3152   if (totalout >= chd->header.hunkbytes)
2555void chd_file_compressor::async_walk_parent(work_item &item)
2556{
2557   // compute CRC-16 and SHA-1 hashes for each unit, unless we're the last one or we're uncompressed
2558   UINT32 units = hunk_bytes() / unit_bytes();
2559   if (item.m_hunknum == m_hunkcount - 1 || !compressed())
2560      units = 1;
2561   for (UINT32 unit = 0; unit < units; unit++)
31532562   {
3154      free(flac_encoder_client_ptr->flac_outputbuffer);
3155      return CHDERR_COMPRESSION_ERROR;
2563      item.m_hash[unit].m_crc16 = crc16_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes());
2564      item.m_hash[unit].m_sha1 = sha1_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes());
31562565   }
3157
3158   *length = totalout;
3159   memcpy(chd->compressed, flac_encoder_client_ptr->flac_outputbuffer+FLAC_HEADER_SIZE, flac_encoder_client_ptr->flac_output_buffer_total-FLAC_HEADER_SIZE);
3160
3161   free(flac_encoder_client_ptr->flac_outputbuffer);
3162   free(flac_encoder_client_ptr->pcm);
3163   free(flac_encoder_client_ptr->tempbuffer);
3164   return CHDERR_NONE;
2566   item.m_status = WS_COMPLETE;
31652567}
31662568
3167static chd_error flac_codec_compress_normal(chd_file *chd, const void *src, UINT32 *length)
3168{
3169   return flac_codec_compress(chd, src, length, 0);
3170}
31712569
3172// this data is always the same for our blocks, so don't store it in the file.
3173static UINT8 flacHeader[FLAC_HEADER_SIZE] = {
3174   0x66, 0x4C, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x12, 0x60, 0x12, 0x60,
3175   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00,
3176   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3177   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x28, 0x20, 0x00,
3178   0x00, 0x00, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x20,
3179   0x6C, 0x69, 0x62, 0x46, 0x4C, 0x41, 0x43, 0x20, 0x31, 0x2E, 0x32, 0x2E,
3180   0x31, 0x20, 0x32, 0x30, 0x30, 0x37, 0x30, 0x39, 0x31, 0x37, 0x00, 0x00,
3181   0x00, 0x00,
3182};
3183/*-------------------------------------------------
3184    flac_codec_decompress - decomrpess data using
3185    the FLAC codec
3186-------------------------------------------------*/
2570//-------------------------------------------------
2571//  async_compress_hunk - handle asynchronous
2572//  hunk compression
2573//-------------------------------------------------
31872574
3188
3189struct flac_decoder_data
2575void *chd_file_compressor::async_compress_hunk_static(void *param, int threadid)
31902576{
3191   int readoffset;
3192   size_t readbuffersize;
3193   UINT8* readbuffer;
3194
3195   int writeoffset;
3196   INT16 tempbuffer[(CD_MAX_SECTOR_DATA * CD_FRAMES_PER_HUNK)/2];
3197   UINT64 amount_to_decode;
3198};
3199
3200FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
3201{
3202
3203   int blocksize = frame->header.blocksize;
3204   int i = 0;
3205   while (blocksize && ((flac_decoder_data*)client_data)->amount_to_decode)
3206   {
3207      ((flac_decoder_data*)client_data)->tempbuffer[(((flac_decoder_data*)client_data)->writeoffset*2)+0] = buffer[0][i];
3208      ((flac_decoder_data*)client_data)->tempbuffer[(((flac_decoder_data*)client_data)->writeoffset*2)+1] =  buffer[1][i];
3209
3210      blocksize--;
3211      i++;
3212      ((flac_decoder_data*)client_data)->amount_to_decode-=4;
3213      ((flac_decoder_data*)client_data)->writeoffset++;
3214   }
3215
3216   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
2577   work_item *item = reinterpret_cast<work_item *>(param);
2578   item->m_compressor->async_compress_hunk(*item, threadid);
2579   return NULL;
32172580}
32182581
3219FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
2582void chd_file_compressor::async_compress_hunk(work_item &item, int threadid)
32202583{
3221   size_t readsize = *bytes;
3222   size_t readbuffersize = ((flac_decoder_data*)client_data)->readbuffersize;
2584   // use our thread's codec
2585   assert(threadid < ARRAY_LENGTH(m_codecs));
2586   item.m_codecs = m_codecs[threadid];
32232587
3224   if ((((flac_decoder_data*)client_data)->readoffset + readsize) > readbuffersize)
3225   {
3226      readsize = ((flac_decoder_data*)client_data)->readbuffersize-((flac_decoder_data*)client_data)->readoffset;
3227   }
2588   // compute CRC-16 and SHA-1 hashes
2589   item.m_hash[0].m_crc16 = crc16_creator::simple(item.m_data, hunk_bytes());
2590   item.m_hash[0].m_sha1 = sha1_creator::simple(item.m_data, hunk_bytes());
32282591
3229   if (readsize==0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
2592   // find the best compression scheme, unless we already have a self or parent match
2593   // (note we may miss a self match from blocks not yet added, but this just results in extra work)
2594   if (m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND &&
2595      m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND)
2596      item.m_compression = item.m_codecs->find_best_compressor(item.m_data, item.m_compressed, item.m_complen);
32302597
3231   memcpy(buffer, ((flac_decoder_data*)client_data)->readbuffer+((flac_decoder_data*)client_data)->readoffset, readsize);
3232
3233   ((flac_decoder_data*)client_data)->readoffset += readsize;
3234
3235   return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
2598   // mark us complete
2599   item.m_status = WS_COMPLETE;
32362600}
32372601
32382602
2603//-------------------------------------------------
2604//  async_read - handle asynchronous source file
2605//  reading
2606//-------------------------------------------------
32392607
3240void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
2608void *chd_file_compressor::async_read_static(void *param, int threadid)
32412609{
3242
2610   reinterpret_cast<chd_file_compressor *>(param)->async_read();
2611   return NULL;
32432612}
32442613
3245void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
2614void chd_file_compressor::async_read()
32462615{
2616   // if in the error or complete state, stop
2617   if (m_read_error)
2618      return;
32472619
3248}
2620   // determine parameters for the read
2621   UINT32 work_buffer_bytes = WORK_BUFFER_HUNKS * hunk_bytes();
2622   UINT32 numbytes = work_buffer_bytes / 2;
2623   if (m_read_done_offset + numbytes > logical_bytes())
2624      numbytes = logical_bytes() - m_read_done_offset;
32492625
3250static chd_error flac_codec_decompress(chd_file *chd, UINT32 srclength, void *dest)
3251{
3252   FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
3253   flac_decoder_data flac_decoder_client;
3254   flac_decoder_data* flac_decoder_client_ptr = &flac_decoder_client;
3255
3256   flac_decoder_client_ptr->readoffset = 0;
3257
3258   flac_decoder_client_ptr->readbuffersize = srclength+FLAC_HEADER_SIZE;
3259   flac_decoder_client_ptr->readbuffer = (UINT8*)malloc(flac_decoder_client_ptr->readbuffersize);
3260   flac_decoder_client_ptr->amount_to_decode =  (CD_MAX_SECTOR_DATA*CD_FRAMES_PER_HUNK);
3261   int frames_to_decode = flac_decoder_client_ptr->amount_to_decode / CD_MAX_SECTOR_DATA;
3262
3263   flac_decoder_client_ptr->writeoffset = 0;
3264
3265   memcpy(flac_decoder_client_ptr->readbuffer, flacHeader, FLAC_HEADER_SIZE);
3266   memcpy(flac_decoder_client_ptr->readbuffer+FLAC_HEADER_SIZE, chd->compressed, srclength);
3267
3268   if (!decoder)
2626   // catch any exceptions coming out of here
2627   try
32692628   {
3270      printf("unable to create FLAC decoder\n");
3271      return CHDERR_READ_ERROR;
3272   }
2629      // do the read
2630      UINT8 *dest = m_work_buffer + (m_read_done_offset % work_buffer_bytes);
2631      assert(dest == m_work_buffer || dest == m_work_buffer + work_buffer_bytes/2);
2632      UINT64 end_offset = m_read_done_offset + numbytes;
32732633
3274   if(FLAC__stream_decoder_init_stream(
3275      decoder,
3276      flac_decoder_read_callback,
3277      NULL,
3278      NULL,
3279      NULL,
3280      NULL,
3281      flac_decoder_write_callback,
3282      flac_decoder_metadata_callback,
3283      flac_decoder_error_callback,
3284      flac_decoder_client_ptr ) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
3285   {
3286      printf("unable to init FLAC decoder\n");
3287      return CHDERR_READ_ERROR;
3288   }
3289
3290   if (FLAC__stream_decoder_process_until_end_of_metadata(decoder) != FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM)
3291   {
3292      printf("Fail FLAC__stream_decoder_process_until_end_of_metadata\n");
3293      return CHDERR_READ_ERROR;
3294   }
3295
3296   /* only ever a single frame */
3297   if (FLAC__stream_decoder_process_single(decoder) != FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM)
3298   {
3299      printf("Fail FLAC__stream_decoder_process_until_end_of_metadata\n");
3300      return CHDERR_READ_ERROR;
3301   }
3302
3303
3304   int srcoffset = 0;
3305   UINT8* dest2 = (UINT8*)dest;
3306   for (int frame = 0; frame<frames_to_decode;frame++)
3307   {
3308      int destoffset = frame * (CD_FRAME_SIZE);
3309
3310
3311      int index;
3312
3313      for (index = 0; index < 2352; index += 2 )
2634      // if walking the parent, read in hunks from the parent CHD
2635      if (m_walking_parent)
33142636      {
3315         dest2[ destoffset + index +1 ] = flac_decoder_client_ptr->tempbuffer[srcoffset] & 0xff;
3316         dest2[ destoffset + index ] = flac_decoder_client_ptr->tempbuffer[srcoffset] >> 8;
2637         UINT8 *curdest = dest;
2638         for (UINT64 curoffs = m_read_done_offset; curoffs < end_offset + 1; curoffs += hunk_bytes())
2639         {
2640            m_parent->read_hunk(curoffs / hunk_bytes(), curdest);
2641            curdest += hunk_bytes();
2642         }
2643      }
2644     
2645      // otherwise, call the virtual function
2646      else
2647         read_data(dest, m_read_done_offset, numbytes);
2648     
2649      // spawn off work for each hunk
2650      for (UINT64 curoffs = m_read_done_offset; curoffs < end_offset; curoffs += hunk_bytes())
2651      {
2652         UINT32 hunknum = curoffs / hunk_bytes();
2653         work_item &item = m_work_item[hunknum % WORK_BUFFER_HUNKS];
2654         assert(item.m_status == WS_READING);
2655         item.m_status = WS_QUEUED;
2656         item.m_hunknum = hunknum;
2657         item.m_osd = osd_work_item_queue(m_work_queue, m_walking_parent ? async_walk_parent_static : async_compress_hunk_static, &item, 0);
2658      }
33172659
3318         srcoffset++;
2660      // continue the running SHA-1
2661      if (!m_walking_parent)
2662      {
2663         if (compressed())
2664            m_compsha1.append(dest, numbytes);
2665         m_total_in += numbytes;
33192666      }
2667     
2668      // advance the read pointer
2669      m_read_done_offset += numbytes;
33202670   }
3321
3322
3323   if (FLAC__stream_decoder_finish (decoder) != true)
2671   catch (...)
33242672   {
3325      printf("unable to finish FLAC decoder\n");
3326      return CHDERR_READ_ERROR;
2673      m_read_error = true;
33272674   }
3328
3329   FLAC__stream_decoder_delete(decoder);
3330   free(flac_decoder_client_ptr->readbuffer);
3331
3332   return CHDERR_NONE;
33332675}
33342676
33352677
33362678
2679//**************************************************************************
2680//  CHD COMPRESSOR HASHMAP
2681//**************************************************************************
33372682
3338/***************************************************************************
3339    AV COMPRESSION CODEC
3340***************************************************************************/
2683//-------------------------------------------------
2684//  hashmap - constructor
2685//-------------------------------------------------
33412686
3342/*-------------------------------------------------
3343    av_raw_data_size - compute the raw data size
3344-------------------------------------------------*/
3345
3346INLINE UINT32 av_raw_data_size(const UINT8 *data)
2687chd_file_compressor::hashmap::hashmap()
2688   : m_block_list(new entry_block(NULL))
33472689{
3348   int size = 0;
3349
3350   /* make sure we have a correct header */
3351   if (data[0] == 'c' && data[1] == 'h' && data[2] == 'a' && data[3] == 'v')
3352   {
3353      /* add in header size plus metadata length */
3354      size = 12 + data[4];
3355
3356      /* add in channels * samples */
3357      size += 2 * data[5] * ((data[6] << 8) + data[7]);
3358
3359      /* add in 2 * width * height */
3360      size += 2 * ((data[8] << 8) + data[9]) * (((data[10] << 8) + data[11]) & 0x7fff);
3361   }
3362   return size;
2690   // initialize the map to empty
2691   memset(m_map, 0, sizeof(m_map));
33632692}
33642693
33652694
3366/*-------------------------------------------------
3367    av_codec_init - initialize the A/V codec
3368-------------------------------------------------*/
2695//-------------------------------------------------
2696//  ~hashmap - destructor
2697//-------------------------------------------------
33692698
3370static chd_error av_codec_init(chd_file *chd)
2699chd_file_compressor::hashmap::~hashmap()
33712700{
3372   av_codec_data *data;
3373
3374   /* allocate memory for the 2 stream buffers */
3375   data = new(std::nothrow) av_codec_data;
3376   if (data == NULL)
3377      return CHDERR_OUT_OF_MEMORY;
3378
3379   /* clear the buffers */
3380   chd->codecdata = data;
3381
3382   /* attempt to do a post-init now; if we're creating a new CHD, this won't work */
3383   /* but that's ok */
3384   av_codec_postinit(chd);
3385   return CHDERR_NONE;
2701   reset();
33862702}
33872703
33882704
3389/*-------------------------------------------------
3390    av_codec_free - free data for the A/V
3391    codec
3392-------------------------------------------------*/
2705//-------------------------------------------------
2706//  reset - reset the state of the map
2707//-------------------------------------------------
33932708
3394static void av_codec_free(chd_file *chd)
2709void chd_file_compressor::hashmap::reset()
33952710{
3396   av_codec_data *data = (av_codec_data *)chd->codecdata;
3397
3398   /* deinit avcomp */
3399   if (data != NULL)
2711   // delete all the blocks
2712   while (m_block_list->m_next != NULL)
34002713   {
3401      if (data->compstate != NULL)
3402         avcomp_free(data->compstate);
3403      delete data;
2714      entry_block *block = m_block_list;
2715      m_block_list = block->m_next;
2716      delete block;
34042717   }
2718   m_block_list->m_nextalloc = 0;
2719   
2720   // reset the hash
2721   memset(m_map, 0, sizeof(m_map));
34052722}
34062723
34072724
3408/*-------------------------------------------------
3409    av_codec_compress - compress data using the
3410    A/V codec
3411-------------------------------------------------*/
2725//-------------------------------------------------
2726//  find - find an item in the CRC map
2727//-------------------------------------------------
34122728
3413static chd_error av_codec_compress(chd_file *chd, const void *src, UINT32 *length)
2729UINT64 chd_file_compressor::hashmap::find(crc16_t crc16, sha1_t sha1)
34142730{
3415   av_codec_data *data = (av_codec_data *)chd->codecdata;
3416   int averr;
3417   int size;
3418
3419   /* if we haven't yet set up the avcomp code, do it now */
3420   if (data->compstate == NULL)
3421   {
3422      chd_error chderr = av_codec_postinit(chd);
3423      if (chderr != CHDERR_NONE)
3424         return chderr;
3425   }
3426
3427   /* make sure short frames are padded with 0 */
3428   if (src != NULL)
3429   {
3430      size = av_raw_data_size((const UINT8 *)src);
3431      while (size < chd->header.hunkbytes)
3432         if (((const UINT8 *)src)[size++] != 0)
3433            return CHDERR_INVALID_DATA;
3434   }
3435
3436   /* encode the audio and video */
3437   averr = avcomp_encode_data(data->compstate, (const UINT8 *)src, chd->compressed, length);
3438   if (averr != AVCERR_NONE || *length > chd->header.hunkbytes)
3439      return CHDERR_COMPRESSION_ERROR;
3440
3441   return CHDERR_NONE;
2731   // look up the entry in the map
2732   for (entry_t *entry = m_map[crc16]; entry != NULL; entry = entry->m_next)
2733      if (entry->m_sha1 == sha1)
2734         return entry->m_itemnum;
2735   return NOT_FOUND;
34422736}
34432737
34442738
3445/*-------------------------------------------------
3446    av_codec_decompress - decomrpess data using
3447    the A/V codec
3448-------------------------------------------------*/
2739//-------------------------------------------------
2740//  add - add an item to the CRC map
2741//-------------------------------------------------
34492742
3450static chd_error av_codec_decompress(chd_file *chd, UINT32 srclength, void *dest)
2743void chd_file_compressor::hashmap::add(UINT64 itemnum, crc16_t crc16, sha1_t sha1)
34512744{
3452   av_codec_data *data = (av_codec_data *)chd->codecdata;
3453   const UINT8 *source;
3454   avcomp_error averr;
3455   int size;
3456
3457   /* if we haven't yet set up the avcomp code, do it now */
3458   if (data->compstate == NULL)
3459   {
3460      chd_error chderr = av_codec_postinit(chd);
3461      if (chderr != CHDERR_NONE)
3462         return chderr;
3463   }
3464
3465   /* decode the audio and video */
3466   source = chd->compressed;
3467   averr = avcomp_decode_data(data->compstate, source, srclength, (UINT8 *)dest);
3468   if (averr != AVCERR_NONE)
3469      return CHDERR_DECOMPRESSION_ERROR;
3470
3471   /* pad short frames with 0 */
3472   if (dest != NULL)
3473   {
3474      size = av_raw_data_size((const UINT8 *)dest);
3475      while (size < chd->header.hunkbytes)
3476         ((UINT8 *)dest)[size++] = 0;
3477   }
3478
3479   return CHDERR_NONE;
2745   // add to the appropriate map
2746   if (m_block_list->m_nextalloc == ARRAY_LENGTH(m_block_list->m_array))
2747      m_block_list = new entry_block(m_block_list);
2748   entry_t *entry = &m_block_list->m_array[m_block_list->m_nextalloc++];
2749   entry->m_itemnum = itemnum;
2750   entry->m_sha1 = sha1;
2751   entry->m_next = m_map[crc16];
2752   m_map[crc16] = entry;
34802753}
3481
3482
3483/*-------------------------------------------------
3484    av_codec_config - codec-specific configuration
3485    for the A/V codec
3486-------------------------------------------------*/
3487
3488static chd_error av_codec_config(chd_file *chd, int param, void *config)
3489{
3490   av_codec_data *data = (av_codec_data *)chd->codecdata;
3491
3492   /* if we're getting the compression configuration, apply it now */
3493   if (param == AV_CODEC_COMPRESS_CONFIG)
3494   {
3495      av_codec_compress_config *configsrc = reinterpret_cast<av_codec_compress_config *>(config);
3496      data->compress.video.wrap(configsrc->video, configsrc->video.cliprect());
3497      data->compress.channels = configsrc->channels;
3498      data->compress.samples = configsrc->samples;
3499      memcpy(data->compress.audio, configsrc->audio, sizeof(data->compress.audio));
3500      data->compress.metalength = configsrc->metalength;
3501      data->compress.metadata = configsrc->metadata;
3502      if (data->compstate != NULL)
3503         avcomp_config_compress(data->compstate, &data->compress);
3504      return CHDERR_NONE;
3505   }
3506
3507   /* if we're getting the decompression configuration, apply it now */
3508   else if (param == AV_CODEC_DECOMPRESS_CONFIG)
3509   {
3510      av_codec_decompress_config *configsrc = reinterpret_cast<av_codec_decompress_config *>(config);
3511      data->decompress.video.wrap(configsrc->video, configsrc->video.cliprect());
3512      data->decompress.maxsamples = configsrc->maxsamples;
3513      data->decompress.actsamples = configsrc->actsamples;
3514      memcpy(data->decompress.audio, configsrc->audio, sizeof(data->decompress.audio));
3515      data->decompress.maxmetalength = configsrc->maxmetalength;
3516      data->decompress.actmetalength = configsrc->actmetalength;
3517      data->decompress.metadata = configsrc->metadata;
3518      if (data->compstate != NULL)
3519         avcomp_config_decompress(data->compstate, &data->decompress);
3520      return CHDERR_NONE;
3521   }
3522
3523   /* anything else is invalid */
3524   return CHDERR_INVALID_PARAMETER;
3525}
3526
3527
3528/*-------------------------------------------------
3529    av_codec_postinit - actual initialization of
3530    avcomp happens here, on the first attempt
3531    to compress or decompress data
3532-------------------------------------------------*/
3533
3534static chd_error av_codec_postinit(chd_file *chd)
3535{
3536   int fps, fpsfrac, width, height, interlaced, channels, rate;
3537   UINT32 fps_times_1million, max_samples_per_frame, bytes_per_frame;
3538   av_codec_data *data = (av_codec_data *)chd->codecdata;
3539   char metadata[256];
3540   chd_error err;
3541
3542   /* the code below won't work asynchronously */
3543   if (chd->workitem != NULL)
3544      return CHDERR_OPERATION_PENDING;
3545
3546   /* get the metadata */
3547   err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
3548   if (err != CHDERR_NONE)
3549      return err;
3550
3551   /* extract the info */
3552   if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
3553      return CHDERR_INVALID_METADATA;
3554
3555   /* compute the bytes per frame */
3556   fps_times_1million = fps * 1000000 + fpsfrac;
3557   max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
3558   bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2;
3559   if (bytes_per_frame > chd->header.hunkbytes)
3560      return CHDERR_INVALID_METADATA;
3561
3562   /* create the avcomp state */
3563   data->compstate = avcomp_init(width, height, channels);
3564
3565   /* configure the codec */
3566   avcomp_config_compress(data->compstate, &data->compress);
3567   avcomp_config_decompress(data->compstate, &data->decompress);
3568   return CHDERR_NONE;
3569}
src/lib/util/bitstream.h
r0r14482
1/***************************************************************************
2
3    bitstream.h
4
5    Helper classes for reading/writing at the bit level.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __BITSTREAM_H__
43#define __BITSTREAM_H__
44
45#include "osdcore.h"
46
47
48//**************************************************************************
49//  TYPE DEFINITIONS
50//**************************************************************************
51
52// helper class for reading from a bit buffer
53class bitstream_in
54{
55public:
56   // construction/destruction
57   bitstream_in(const void *src, UINT32 srclength);
58   
59   // getters
60   bool overflow() const { return ((m_doffset - m_bits / 8) > m_dlength); }
61   UINT32 read_offset() const;
62   
63   // operations
64   UINT32 read(int numbits);
65   UINT32 peek(int numbits);
66   void remove(int numbits);
67   UINT32 flush();
68
69private:
70   // internal state
71   UINT32         m_buffer;      // current bit accumulator
72   int            m_bits;         // number of bits in the accumulator
73   const UINT8 *   m_read;         // read pointer
74   UINT32         m_doffset;      // byte offset within the data
75   UINT32         m_dlength;      // length of the data
76};
77
78
79// helper class for writing to a bit buffer
80class bitstream_out
81{
82public:
83   // construction/destruction
84   bitstream_out(void *dest, UINT32 destlength);
85   
86   // getters
87   bool overflow() const { return (m_doffset > m_dlength); }
88   
89   // operations
90   void write(UINT32 newbits, int numbits);
91   UINT32 flush();
92
93private:
94   // internal state
95   UINT32         m_buffer;         // current bit accumulator
96   int            m_bits;            // number of bits in the accumulator
97   UINT8 *         m_write;         // write pointer
98   UINT32         m_doffset;         // byte offset within the data
99   UINT32         m_dlength;         // length of the data
100};
101
102
103
104//**************************************************************************
105//  INLINE FUNCTIONS
106//**************************************************************************
107
108//-------------------------------------------------
109//  bitstream_in - constructor
110//-------------------------------------------------
111
112inline bitstream_in::bitstream_in(const void *src, UINT32 srclength)
113   : m_buffer(0),
114     m_bits(0),
115     m_read(reinterpret_cast<const UINT8 *>(src)),
116     m_doffset(0),
117     m_dlength(srclength)
118{
119}
120
121
122//-------------------------------------------------
123//  peek - fetch the requested number of bits
124//  but don't advance the input pointer
125//-------------------------------------------------
126
127inline UINT32 bitstream_in::peek(int numbits)
128{
129   // fetch data if we need more
130   if (numbits > m_bits)
131   {
132      while (m_bits <= 24)
133      {
134         if (m_doffset < m_dlength)
135            m_buffer |= m_read[m_doffset] << (24 - m_bits);
136         m_doffset++;
137         m_bits += 8;
138      }
139   }
140
141   // return the data
142   return m_buffer >> (32 - numbits);
143}
144
145
146//-------------------------------------------------
147//  remove - advance the input pointer by the
148//  specified number of bits
149//-------------------------------------------------
150
151inline void bitstream_in::remove(int numbits)
152{
153   m_buffer <<= numbits;
154   m_bits -= numbits;
155}
156
157
158//-------------------------------------------------
159//  read - fetch the requested number of bits
160//-------------------------------------------------
161
162inline UINT32 bitstream_in::read(int numbits)
163{
164   UINT32 result = peek(numbits);
165   remove(numbits);
166   return result;
167}
168
169
170//-------------------------------------------------
171//  read_offset - return the current read offset
172//-------------------------------------------------
173
174inline UINT32 bitstream_in::read_offset() const
175{
176   UINT32 result = m_doffset;
177   int bits = m_bits;
178   while (bits >= 8)
179   {
180      result--;
181      bits -= 8;
182   }
183   return result;
184}
185
186
187//-------------------------------------------------
188//  flush - flush to the nearest byte
189//-------------------------------------------------
190
191inline UINT32 bitstream_in::flush()
192{
193   while (m_bits >= 8)
194   {
195      m_doffset--;
196      m_bits -= 8;
197   }
198   m_bits = m_buffer = 0;
199   return m_doffset;
200}
201
202
203//-------------------------------------------------
204//  bitstream_out - constructor
205//-------------------------------------------------
206
207inline bitstream_out::bitstream_out(void *dest, UINT32 destlength)
208   : m_buffer(0),
209     m_bits(0),
210     m_write(reinterpret_cast<UINT8 *>(dest)),
211     m_doffset(0),
212     m_dlength(destlength)
213{
214}
215
216
217
218//-------------------------------------------------
219//  write - write the given number of bits to the
220//  data stream
221//-------------------------------------------------
222
223inline void bitstream_out::write(UINT32 newbits, int numbits)
224{
225   // flush the buffer if we're going to overflow it
226   if (m_bits + numbits > 32)
227      while (m_bits >= 8)
228      {
229         if (m_doffset < m_dlength)
230            m_write[m_doffset] = m_buffer >> 24;
231         m_doffset++;
232         m_buffer <<= 8;
233         m_bits -= 8;
234      }
235
236   // shift the bits to the top
237   newbits <<= 32 - numbits;
238
239   // now shift it down to account for the number of bits we already have and OR them in
240   m_buffer |= newbits >> m_bits;
241   m_bits += numbits;
242}
243
244
245//-------------------------------------------------
246//  flush - output remaining bits and return the
247//  final output size in bytes
248//-------------------------------------------------
249
250inline UINT32 bitstream_out::flush()
251{
252   while (m_bits > 0)
253   {
254      if (m_doffset < m_dlength)
255         m_write[m_doffset] = m_buffer >> 24;
256      m_doffset++;
257      m_buffer <<= 8;
258      m_bits -= 8;
259   }
260   m_bits = m_buffer = 0;
261   return m_doffset;
262}
263
264
265#endif
src/lib/util/chd.h
r14481r14482
4343#define __CHD_H__
4444
4545#include "osdcore.h"
46#include "coretmpl.h"
47#include "astring.h"
4648#include "bitmap.h"
4749#include "corefile.h"
48#include "avcomp.h"
50#include "hashing.h"
51#include "chdcodec.h"
4952
5053
5154/***************************************************************************
5255
5356    Compressed Hunks of Data header format. All numbers are stored in
54    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
55    bytes long.
57    Motorola (big-endian) byte ordering.
58   
59    =========================================================================
5660
5761    V1 header:
5862
r14481r14482
7074    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
7175    [ 76] (V1 header length)
7276
77    Flags:
78        0x00000001 - set if this drive has a parent
79        0x00000002 - set if this drive allows writes
80
81   Compression types:
82      CHDCOMPRESSION_NONE = 0
83      CHDCOMPRESSION_ZLIB = 1
84   
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   
90    =========================================================================
91
7392    V2 header:
7493
7594    [  0] char   tag[8];        // 'MComprHD'
r14481r14482
86105    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
87106    [ 76] UINT32 seclen;        // number of bytes per sector
88107    [ 80] (V2 header length)
108   
109    Flags and map format are same as V1
110   
111    =========================================================================
89112
90113    V3 header:
91114
r14481r14482
103126    [ 80] UINT8  sha1[20];      // SHA1 checksum of raw data
104127    [100] UINT8  parentsha1[20];// SHA1 checksum of parent file
105128    [120] (V3 header length)
129   
130    Flags are the same as V1
106131
132   Compression types:
133      CHDCOMPRESSION_NONE = 0
134      CHDCOMPRESSION_ZLIB = 1
135      CHDCOMPRESSION_ZLIB_PLUS = 2
136   
137    V3 map format:
138
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
144
145    =========================================================================
146
107147    V4 header:
108148
109149    [  0] char   tag[8];        // 'MComprHD'
r14481r14482
119159    [ 68] UINT8  parentsha1[20];// combined raw+meta SHA1 of parent
120160    [ 88] UINT8  rawsha1[20];   // raw data SHA1
121161    [108] (V4 header length)
162   
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   
171    Map format is the same as V3
172   
173    =========================================================================
122174
123    Flags:
124        0x00000001 - set if this drive has a parent
125        0x00000002 - set if this drive allows writes
175    V5 header:
176   
177    [  0] char   tag[8];        // 'MComprHD'
178    [  8] UINT32 length;        // length of header (including tag and length fields)
179    [ 12] UINT32 version;       // drive format version
180    [ 16] UINT32 compressors[4];// which custom compressors are used?
181    [ 32] UINT64 logicalbytes;  // logical size of the data (in bytes)
182    [ 40] UINT64 mapoffset;     // offset to the map
183    [ 48] UINT64 metaoffset;    // offset to the first blob of metadata
184    [ 56] UINT32 hunkbytes;     // number of bytes per hunk (512k maximum)
185    [ 60] UINT32 unitbytes;     // number of bytes per unit within each hunk
186    [ 64] UINT8  rawsha1[20];   // raw data SHA1
187    [ 84] UINT8  sha1[20];      // combined raw+meta SHA1
188    [104] UINT8  parentsha1[20];// combined raw+meta SHA1 of parent
189    [124] (V5 header length)
126190
127***************************************************************************/
191   If parentsha1 != 0, we have a parent (no need for flags)
192   If compressors[0] == 0, we are uncompressed (including maps)
193   
194    V5 uncompressed map format:
195   
196    [  0] UINT32 offset;         // starting offset / hunk size
197   
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
207    [ 16] (compressed header length)
208   
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
128215
129
130/***************************************************************************
131    CONSTANTS
132216***************************************************************************/
133217
134/* header information */
135#define CHD_HEADER_VERSION         4
136#define CHD_V1_HEADER_SIZE         76
137#define CHD_V2_HEADER_SIZE         80
138#define CHD_V3_HEADER_SIZE         120
139#define CHD_V4_HEADER_SIZE         108
140#define CHD_MAX_HEADER_SIZE         CHD_V4_HEADER_SIZE
141218
142/* checksumming information */
143#define CHD_MD5_BYTES            16
144#define CHD_SHA1_BYTES            20
219//**************************************************************************
220//  CONSTANTS
221//**************************************************************************
145222
146/* CHD global flags */
147#define CHDFLAGS_HAS_PARENT         0x00000001
148#define CHDFLAGS_IS_WRITEABLE      0x00000002
149#define CHDFLAGS_UNDEFINED         0xfffffffc
223// pseudo-codecs returned by hunk_info
224const chd_codec_type CHD_CODEC_SELF       = 1;   // copy of another hunk
225const chd_codec_type CHD_CODEC_PARENT       = 2;   // copy of a parent's hunk
226const chd_codec_type CHD_CODEC_MINI       = 3;   // legacy "mini" 8-byte repeat
150227
151/* compression types */
152#define CHDCOMPRESSION_NONE                 0
153#define CHDCOMPRESSION_ZLIB                 1
154#define CHDCOMPRESSION_ZLIB_PLUS           2
155#define CHDCOMPRESSION_AV                 3
156#define CHDCOMPRESSION_ZLIB_PLUS_WITH_FLAC  4
228// core types
229typedef UINT32 chd_metadata_tag;
157230
158/* A/V codec configuration parameters */
159#define AV_CODEC_COMPRESS_CONFIG   1
160#define AV_CODEC_DECOMPRESS_CONFIG   2
231// metadata parameters
232const chd_metadata_tag CHDMETATAG_WILDCARD = 0;
233const UINT32 CHDMETAINDEX_APPEND = ~0;
161234
162/* metadata parameters */
163#define CHDMETATAG_WILDCARD         0
164#define CHD_METAINDEX_APPEND      ((UINT32)-1)
235// metadata flags
236const UINT8 CHD_MDFLAGS_CHECKSUM = 0x01;      // indicates data is checksummed
165237
166/* metadata flags */
167#define CHD_MDFLAGS_CHECKSUM      0x01      /* indicates data is checksummed */
238// standard hard disk metadata
239const chd_metadata_tag HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D');
240extern const char *HARD_DISK_METADATA_FORMAT;
168241
169/* standard hard disk metadata */
170#define HARD_DISK_METADATA_TAG      0x47444444   /* 'GDDD' */
171#define HARD_DISK_METADATA_FORMAT   "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"
242// hard disk identify information
243const chd_metadata_tag HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T');
172244
173/* hard disk identify information */
174#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */
245// hard disk key information
246const chd_metadata_tag HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' ');
175247
176/* hard disk key information */
177#define HARD_DISK_KEY_METADATA_TAG   0x4b455920  /* 'KEY '  */
248// pcmcia CIS information
249const chd_metadata_tag PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' ');
178250
179/* pcmcia CIS information */
180#define PCMCIA_CIS_METADATA_TAG      0x43495320  /* 'CIS '  */
251// standard CD-ROM metadata
252const chd_metadata_tag CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D');
253const chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R');
254extern const char *CDROM_TRACK_METADATA_FORMAT;
255const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2');
256extern const char *CDROM_TRACK_METADATA2_FORMAT;
181257
182/* standard CD-ROM metadata */
183#define CDROM_OLD_METADATA_TAG      0x43484344   /* 'CHCD' */
184#define CDROM_TRACK_METADATA_TAG   0x43485452   /* 'CHTR' */
185#define CDROM_TRACK_METADATA_FORMAT   "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
186#define CDROM_TRACK_METADATA2_TAG   0x43485432   /* 'CHT2' */
187#define CDROM_TRACK_METADATA2_FORMAT   "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
258// standard A/V metadata
259const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V');
260extern const char *AV_METADATA_FORMAT;
188261
189/* standard A/V metadata */
190#define AV_METADATA_TAG            0x41564156   /* 'AVAV' */
191#define AV_METADATA_FORMAT         "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
262// A/V laserdisc frame metadata
263const chd_metadata_tag AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D');
192264
193/* A/V laserdisc frame metadata */
194#define AV_LD_METADATA_TAG         0x41564C44   /* 'AVLD' */
195
196/* CHD open values */
197#define CHD_OPEN_READ            1
198#define CHD_OPEN_READWRITE         2
199
200/* error types */
201enum _chd_error
265// error types
266enum chd_error
202267{
203268   CHDERR_NONE,
204269   CHDERR_NO_INTERFACE,
205270   CHDERR_OUT_OF_MEMORY,
271   CHDERR_NOT_OPEN,
272   CHDERR_ALREADY_OPEN,
206273   CHDERR_INVALID_FILE,
207274   CHDERR_INVALID_PARAMETER,
208275   CHDERR_INVALID_DATA,
r14481r14482
226293   CHDERR_INVALID_METADATA,
227294   CHDERR_INVALID_STATE,
228295   CHDERR_OPERATION_PENDING,
229   CHDERR_NO_ASYNC_OPERATION,
230   CHDERR_UNSUPPORTED_FORMAT
296   CHDERR_UNSUPPORTED_FORMAT,
297   CHDERR_UNKNOWN_COMPRESSION,
298   CHDERR_WALKING_PARENT,
299   CHDERR_COMPRESSING
231300};
232typedef enum _chd_error chd_error;
233301
234302
235303
236/***************************************************************************
237    TYPE DEFINITIONS
238***************************************************************************/
304//**************************************************************************
305//  TYPE DEFINITIONS
306//**************************************************************************
239307
240/* opaque types */
241typedef struct _chd_file chd_file;
308class chd_codec;
242309
243310
244/* extract header structure (NOT the on-disk header structure) */
245typedef struct _chd_header chd_header;
246struct _chd_header
247{
248   UINT32      length;                  /* length of header data */
249   UINT32      version;               /* drive format version */
250   UINT32      flags;                  /* flags field */
251   UINT32      compression;            /* compression type */
252   UINT32      hunkbytes;               /* number of bytes per hunk */
253   UINT32      totalhunks;               /* total # of hunks represented */
254   UINT64      logicalbytes;            /* logical size of the data */
255   UINT64      metaoffset;               /* offset in file of first metadata */
256   UINT8      md5[CHD_MD5_BYTES];         /* overall MD5 checksum */
257   UINT8      parentmd5[CHD_MD5_BYTES];   /* overall MD5 checksum of parent */
258   UINT8      sha1[CHD_SHA1_BYTES];      /* overall SHA1 checksum */
259   UINT8      rawsha1[CHD_SHA1_BYTES];   /* SHA1 checksum of raw data */
260   UINT8      parentsha1[CHD_SHA1_BYTES];   /* overall SHA1 checksum of parent */
311// ======================> chd_file
261312
262   UINT32      obsolete_cylinders;         /* obsolete field -- do not use! */
263   UINT32      obsolete_sectors;         /* obsolete field -- do not use! */
264   UINT32      obsolete_heads;            /* obsolete field -- do not use! */
265   UINT32      obsolete_hunksize;         /* obsolete field -- do not use! */
266};
267
268
269/* structure for returning information about a verification pass */
270typedef struct _chd_verify_result chd_verify_result;
271struct _chd_verify_result
313// core file class
314class chd_file
272315{
273   UINT8      md5[CHD_MD5_BYTES];         /* overall MD5 checksum */
274   UINT8      sha1[CHD_SHA1_BYTES];      /* overall SHA1 checksum */
275   UINT8      rawsha1[CHD_SHA1_BYTES];   /* SHA1 checksum of raw data */
276   UINT8      metasha1[CHD_SHA1_BYTES];   /* SHA1 checksum of metadata */
277};
316   friend class chd_file_compressor;
317   friend class chd_verifier;
278318
319   // constants
320   static const UINT32 HEADER_VERSION = 5;
321   static const UINT32 V3_HEADER_SIZE = 120;
322   static const UINT32 V4_HEADER_SIZE = 108;
323   static const UINT32 V5_HEADER_SIZE = 124;
324   static const UINT32 MAX_HEADER_SIZE = V5_HEADER_SIZE;
325   
326public:
327   // construction/destruction
328   chd_file();
329   virtual ~chd_file();
279330
331   // operators
332   operator core_file *() { return m_file; }
280333
281/***************************************************************************
282    FUNCTION PROTOTYPES
283***************************************************************************/
334   // getters
335   bool opened() const { return (m_file != NULL); }
336   UINT32 version() const { return m_version; }
337   UINT64 logical_bytes() const { return m_logicalbytes; }
338   UINT32 hunk_bytes() const { return m_hunkbytes; }
339   UINT32 hunk_count() const { return m_hunkcount; }
340   UINT32 unit_bytes() const { return m_unitbytes; }
341   UINT64 unit_count() const { return m_unitcount; }
342   bool compressed() const { return (m_compression[0] != CHD_CODEC_NONE); }
343   chd_codec_type compression(int index) const { return m_compression[index]; }
344   chd_file *parent() const { return m_parent; }
345   sha1_t sha1();
346   sha1_t raw_sha1();
347   sha1_t parent_sha1();
348   chd_error hunk_info(UINT32 hunknum, chd_codec_type &compressor, UINT32 &compbytes);
284349
350   // setters
351   void set_raw_sha1(sha1_t rawdata);
352   void set_parent_sha1(sha1_t parent);
285353
286/* ----- CHD file management ----- */
354   // file create
355   chd_error create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]);
356   chd_error create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]);
357   chd_error create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent);
358   chd_error create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent);
287359
288/* create a new CHD file fitting the given description */
289chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
360   // file open
361   chd_error open(const char *filename, bool writeable = false, chd_file *parent = NULL);
362   chd_error open(core_file &file, bool writeable = false, chd_file *parent = NULL);
363   
364   // file close
365   void close();
290366
291/* same as chd_create(), but accepts an already-opened core_file object */
292chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
367   // read/write
368   chd_error read_hunk(UINT32 hunknum, void *buffer);
369   chd_error write_hunk(UINT32 hunknum, const void *buffer);
370   chd_error read_units(UINT64 unitnum, void *buffer, UINT32 count = 1);
371   chd_error write_units(UINT64 unitnum, const void *buffer, UINT32 count = 1);
372   chd_error read_bytes(UINT64 offset, void *buffer, UINT32 bytes);
373   chd_error write_bytes(UINT64 offset, const void *buffer, UINT32 bytes);
293374
294/* open an existing CHD file */
295chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
375   // metadata management
376   chd_error read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, astring &output);
377   chd_error read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output);
378   chd_error read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 &resultlen);
379   chd_error read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output, chd_metadata_tag &resulttag, UINT8 &resultflags);
380   chd_error write_metadata(chd_metadata_tag metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen, UINT8 flags = CHD_MDFLAGS_CHECKSUM);
381   chd_error write_metadata(chd_metadata_tag metatag, UINT32 metaindex, const astring &input, UINT8 flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input.cstr(), input.len() + 1, flags = CHD_MDFLAGS_CHECKSUM); }
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   chd_error delete_metadata(chd_metadata_tag metatag, UINT32 metaindex);
384   chd_error clone_all_metadata(chd_file &source);
385   
386   // hashing helper
387   sha1_t compute_overall_sha1(sha1_t rawsha1);
296388
297/* same as chd_open(), but accepts an already-opened core_file object */
298chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
389   // codec interfaces
390   chd_error codec_configure(chd_codec_type codec, int param, void *config);
391   
392   // static helpers
393   static const char *error_string(chd_error err);
299394
300/* close a CHD file */
301void chd_close(chd_file *chd);
395private:
396   struct metadata_entry;
397   struct metadata_hash;
398   
399   // inline helpers
400   UINT64 be_read(const UINT8 *base, int numbytes);
401   void be_write(UINT8 *base, UINT64 value, int numbytes);
402   sha1_t be_read_sha1(const UINT8 *base);
403   void be_write_sha1(UINT8 *base, sha1_t value);
404   void file_read(UINT64 offset, void *dest, UINT32 length);
405   void file_write(UINT64 offset, const void *source, UINT32 length);
406   UINT64 file_append(const void *source, UINT32 length, UINT32 alignment = 0);
407   UINT8 bits_for_value(UINT64 value);
302408
303/* return the associated core_file */
304core_file *chd_core_file(chd_file *chd);
409   // internal helpers
410   UINT32 guess_unitbytes();
411   void parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1);
412   void parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1);
413   void parse_v5_header(UINT8 *rawheader, sha1_t &parentsha1);
414   chd_error compress_v5_map();
415   void decompress_v5_map();
416   chd_error create_common();
417   chd_error open_common(bool writeable);
418   void create_open_common();
419   void verify_proper_compression_append(UINT32 hunknum);
420   void hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, crc16_t crc16);
421   void hunk_copy_from_self(UINT32 hunknum, UINT32 otherhunk);
422   void hunk_copy_from_parent(UINT32 hunknum, UINT64 parentunit);
423   bool metadata_find(chd_metadata_tag metatag, INT32 metaindex, metadata_entry &metaentry, bool resume = false);
424   void metadata_set_previous_next(UINT64 prevoffset, UINT64 nextoffset);
425   void metadata_update_hash();
426   static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2);
305427
306/* return an error string for the given CHD error */
307const char *chd_error_string(chd_error err);
428   // file characteristics
429   core_file *            m_file;            // handle to the open core file
430   bool               m_owns_file;      // flag indicating if this file should be closed on chd_close()
431   bool               m_allow_reads;      // permit reads from this CHD?
432   bool               m_allow_writes;      // permit writes to this CHD?
433   
434   // core parameters from the header
435   UINT32               m_version;         // version of the header
436   UINT64               m_logicalbytes;      // logical size of the raw CHD data in bytes
437   UINT64               m_mapoffset;      // offset of map
438   UINT64               m_metaoffset;      // offset to first metadata bit
439   UINT32               m_hunkbytes;      // size of each raw hunk in bytes
440   UINT32               m_hunkcount;      // number of hunks represented
441   UINT32               m_unitbytes;      // size of each unit in bytes
442   UINT64               m_unitcount;      // number of units represented
443   chd_codec_type         m_compression[4];   // array of compression types used
444   chd_file *            m_parent;         // pointer to parent file, or NULL if none
445   bool               m_parent_missing;   // are we missing our parent?
446   
447   // key offsets within the header
448   UINT64               m_mapoffset_offset;   // offset of map offset field
449   UINT64               m_metaoffset_offset;// offset of metaoffset field
450   UINT64               m_sha1_offset;      // offset of SHA1 field
451   UINT64               m_rawsha1_offset;   // offset of raw SHA1 field
452   UINT64               m_parentsha1_offset;// offset of paren SHA1 field
453   
454   // map information
455   UINT32               m_mapentrybytes;   // length of each entry in a map
456   dynamic_buffer         m_rawmap;         // raw map data
308457
458   // compression management
459   chd_decompressor *      m_decompressor[4];   // array of decompression codecs
460   dynamic_buffer         m_compressed;      // temporary buffer for compressed data
461   
462   // caching
463   dynamic_buffer         m_cache;         // single-hunk cache for partial reads/writes
464   UINT32               m_cachehunk;      // which hunk is in the cache?
465};
309466
310467
311/* ----- CHD header management ----- */
468// ======================> chd_file_compressor
312469
313/* return a pointer to the extracted CHD header data */
314const chd_header *chd_get_header(chd_file *chd);
470// class for creating a new compressed CHD
471class chd_file_compressor : public chd_file
472{
473public:
474   // construction/destruction
475   chd_file_compressor();
476   virtual ~chd_file_compressor();
477   
478   // compression management
479   void compress_begin();
480   chd_error compress_continue(double &progress, double &ratio);
315481
316/* set a modified header */
317chd_error chd_set_header(const char *filename, const chd_header *header);
482protected:
483   // required override: read more data
484   virtual UINT32 read_data(void *dest, UINT64 offset, UINT32 length) = 0;
485   
486private:
487   // hash map for looking up values
488   class hashmap
489   {
490   public:
491      // construction/destruction
492      hashmap();
493      ~hashmap();
494     
495      // operations
496      void reset();
497      UINT64 find(crc16_t crc16, sha1_t sha1);
498      void add(UINT64 itemnum, crc16_t crc16, sha1_t sha1);
499   
500      // constants
501      static const UINT64 NOT_FOUND = ~UINT64(0);
502   private:
503      // internal entry
504      struct entry_t
505      {
506         entry_t *         m_next;            // next entry in list
507         UINT64            m_itemnum;         // item number
508         sha1_t            m_sha1;            // SHA-1 of the block
509      };
510     
511      // block of entries
512      struct entry_block
513      {
514         entry_block(entry_block *prev)
515            : m_next(prev), m_nextalloc(0) { }
516     
517         entry_block *      m_next;            // next block in list
518         UINT32            m_nextalloc;      // next to be allocated
519         entry_t            m_array[16384];      // array of entries
520      };
318521
319/* same as chd_set_header(), but accepts an already-opened core_file object */
320chd_error chd_set_header_file(core_file *file, const chd_header *header);
522      // internal state
523      entry_t *         m_map[65536];         // map, hashed by CRC-16
524      entry_block *      m_block_list;         // list of allocated blocks
525   };
321526
527   // status of a given work item
528   enum work_status
529   {
530      WS_READY = 0,
531      WS_READING,
532      WS_QUEUED,
533      WS_COMPLETE
534   };
535   
536   // a CRC-16/SHA-1 pair
537   struct hash_pair
538   {
539      crc16_t            m_crc16;         // calculated CRC-16
540      sha1_t            m_sha1;            // calculated SHA-1
541   };
322542
543   // a single work item   
544   struct work_item
545   {
546      osd_work_item *      m_osd;            // OSD work item running on this block
547      chd_file_compressor *m_compressor;      // pointer back to the compressor
548      volatile work_status m_status;         // current status of this item
549      UINT32            m_hunknum;         // number of the hunk we're working on
550      UINT8 *            m_data;            // pointer to the data we are working on
551      UINT8 *            m_compressed;      // pointer to the compressed data
552      UINT32            m_complen;         // compressed data length
553      INT8            m_compression;      // type of compression used
554      chd_compressor_group *m_codecs;         // codec instance
555      dynamic_array<hash_pair> m_hash;      // array of hashes
556   };
557   
558   // internal helpers
559   static void *async_walk_parent_static(void *param, int threadid);
560   void async_walk_parent(work_item &item);
561   static void *async_compress_hunk_static(void *param, int threadid);
562   void async_compress_hunk(work_item &item, int threadid);
563   static void *async_read_static(void *param, int threadid);
564   void async_read();
323565
324/* ----- core data read/write ----- */
566   // current compression status   
567   bool               m_walking_parent;   // are we building the parent map?   
568   UINT64               m_total_in;         // total bytes in
569   UINT64               m_total_out;      // total bytes out
570   sha1_creator         m_compsha1;         // running SHA-1 on raw data
325571
326/* read one hunk from the CHD file */
327chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer);
572   // hash lookup maps
573   hashmap                m_parent_map;      // hash map for parent
574   hashmap                m_current_map;      // hash map for current
328575
329/* read one hunk from the CHD file asynchronously */
330chd_error chd_read_async(chd_file *chd, UINT32 hunknum, void *buffer);
576   // read I/O thread
577   osd_work_queue *      m_read_queue;      // work queue for reading
578   UINT64               m_read_queue_offset;// next offset to enqueue
579   UINT64               m_read_done_offset;   // next offset that will complete
580   bool               m_read_error;      // error during reading?
331581
332/* write one hunk to a CHD file */
333chd_error chd_write(chd_file *chd, UINT32 hunknum, const void *buffer);
582   // work item thread
583   static const int WORK_BUFFER_HUNKS = 256;
584   osd_work_queue *      m_work_queue;      // queue for doing work on other threads
585   dynamic_buffer         m_work_buffer;      // buffer containing hunk data to work on
586   dynamic_buffer         m_compressed_buffer;// buffer containing compressed data
587   work_item            m_work_item[WORK_BUFFER_HUNKS]; // status of each hunk
588   chd_compressor_group *   m_codecs[WORK_MAX_THREADS]; // codecs to use
334589
335/* write one hunk to a CHD file asynchronously */
336chd_error chd_write_async(chd_file *chd, UINT32 hunknum, const void *buffer);
590   // output state
591   UINT32               m_write_hunk;      // next hunk to write
592};
337593
338/* wait for a previously issued async read/write to complete and return the error */
339chd_error chd_async_complete(chd_file *chd);
340594
341
342
343/* ----- metadata management ----- */
344
345/* get indexed metadata of a particular sort */
346chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags);
347
348/* set indexed metadata of a particular sort */
349chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen, UINT8 flags);
350
351/* clone all of the metadata from one CHD to another */
352chd_error chd_clone_metadata(chd_file *source, chd_file *dest);
353
354
355
356/* ----- compression management ----- */
357
358/* begin compressing data to a CHD */
359chd_error chd_compress_begin(chd_file *chd);
360
361/* compress the next hunk of data */
362chd_error chd_compress_hunk(chd_file *chd, const void *data, double *curratio, int is_half_hunk = 0);
363
364/* finish compressing data to a CHD */
365chd_error chd_compress_finish(chd_file *chd, int write_protect);
366
367
368
369/* ----- verification management ----- */
370
371/* begin verifying a CHD */
372chd_error chd_verify_begin(chd_file *chd);
373
374/* verify a single hunk of data */
375chd_error chd_verify_hunk(chd_file *chd);
376
377/* finish verifying a CHD, returning the computed MD5 and SHA1 */
378chd_error chd_verify_finish(chd_file *chd, chd_verify_result *result);
379
380
381
382/* ----- codec interfaces ----- */
383
384/* set internal codec parameters */
385chd_error chd_codec_config(chd_file *chd, int param, void *config);
386
387/* return a string description of a codec */
388const char *chd_get_codec_name(UINT32 codec);
389
390
391#endif /* __CHD_H__ */
595#endif // __CHD_H__
src/lib/util/cdrom.c
r14481r14482
4040    IMPORTANT:
4141    "physical" block addresses are the actual addresses on the emulated CD.
4242    "chd" block addresses are the block addresses in the CHD file.
43    Because we pad each track to a hunk boundry, these addressing
43    Because we pad each track to a 4-frame boundry, these addressing
4444    schemes will differ after track 1!
4545
4646***************************************************************************/
r14481r14482
7575   chd_file *         chd;            /* CHD file */
7676   cdrom_toc         cdtoc;            /* TOC for the CD */
7777   chdcd_track_input_info track_info;      /* track info */
78   UINT32            hunksectors;      /* sectors per hunk */
79   UINT32            cachehunk;         /* which hunk is cached */
80   UINT8 *            cache;            /* cache of the current hunk */
8178   core_file *         fhandle[CD_MAX_TRACKS];/* file handle */
8279};
8380
8481
8582
8683/***************************************************************************
87    FUNCTION PROTOTYPES
88***************************************************************************/
89
90static chd_error read_sector_into_cache(cdrom_file *file, UINT32 lbasector, UINT32 *sectoroffs, UINT32 *tracknum);
91
92
93
94/***************************************************************************
9584    INLINE FUNCTIONS
9685***************************************************************************/
9786
r14481r14482
10089    and the track number
10190-------------------------------------------------*/
10291
103INLINE UINT32 physical_to_chd_lba(cdrom_file *file, UINT32 physlba, UINT32 *tracknum)
92INLINE UINT32 physical_to_chd_lba(cdrom_file *file, UINT32 physlba, UINT32 &tracknum)
10493{
10594   UINT32 chdlba;
10695   int track;
r14481r14482
11099      if (physlba < file->cdtoc.tracks[track + 1].physframeofs)
111100      {
112101         chdlba = physlba - file->cdtoc.tracks[track].physframeofs + file->cdtoc.tracks[track].chdframeofs;
113         if (tracknum != NULL)
114            *tracknum = track;
102         tracknum = track;
115103         return chdlba;
116104      }
117105
r14481r14482
136124      return NULL;
137125
138126   /* setup the CDROM module and get the disc info */
139   chd_error err = chdcd_parse_toc(inputfile, &file->cdtoc, &file->track_info);
127   chd_error err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info);
140128   if (err != CHDERR_NONE)
141129   {
142      fprintf(stderr, "Error reading input file: %s\n", chd_error_string(err));
130      fprintf(stderr, "Error reading input file: %s\n", chd_file::error_string(err));
143131      return NULL;
144132   }
145133
146134   /* fill in the data */
147135   file->chd = NULL;
148   file->hunksectors = 1;
149   file->cachehunk = -1;
150136
151137   LOG(("CD has %d tracks\n", file->cdtoc.numtrks));
152138
153139   for (i = 0; i < file->cdtoc.numtrks; i++)
154140   {
155      file_error filerr = core_fopen(file->track_info.fname[i], OPEN_FLAG_READ, &file->fhandle[i]);
141      file_error filerr = core_fopen(file->track_info.track[i].fname, OPEN_FLAG_READ, &file->fhandle[i]);
156142      if (filerr != FILERR_NONE)
157143      {
158         fprintf(stderr, "Unable to open file: %s\n", file->track_info.fname[i]);
144         fprintf(stderr, "Unable to open file: %s\n", file->track_info.track[i].fname.cstr());
159145         return NULL;
160146      }
161147   }
162148   /* calculate the starting frame for each track, keeping in mind that CHDMAN
163       pads tracks out with extra frames to fit hunk size boundries
149       pads tracks out with extra frames to fit 4-frame size boundries
164150    */
165151   physofs = 0;
166152   for (i = 0; i < file->cdtoc.numtrks; i++)
r14481r14482
185171   file->cdtoc.tracks[i].physframeofs = physofs;
186172   file->cdtoc.tracks[i].chdframeofs = 0;
187173
188   /* allocate a cache */
189   file->cache = (UINT8 *)malloc(CD_FRAME_SIZE);
190   if (file->cache == NULL)
191   {
192      free(file);
193      return NULL;
194   }
195
196174   return file;
197175}
198176
r14481r14482
203181
204182cdrom_file *cdrom_open(chd_file *chd)
205183{
206   const chd_header *header = chd_get_header(chd);
207184   int i;
208185   cdrom_file *file;
209186   UINT32 physofs, chdofs;
r14481r14482
214191      return NULL;
215192
216193   /* validate the CHD information */
217   if (header->hunkbytes % CD_FRAME_SIZE != 0)
194   if (chd->hunk_bytes() % CD_FRAME_SIZE != 0)
218195      return NULL;
196   if (chd->unit_bytes() != CD_FRAME_SIZE)
197      return NULL;
219198
220199   /* allocate memory for the CD-ROM file */
221200   file = (cdrom_file *)malloc(sizeof(cdrom_file));
r14481r14482
224203
225204   /* fill in the data */
226205   file->chd = chd;
227   file->hunksectors = header->hunkbytes / CD_FRAME_SIZE;
228   file->cachehunk = -1;
229206
230207   /* read the CD-ROM metadata */
231208   err = cdrom_parse_metadata(chd, &file->cdtoc);
r14481r14482
238215   LOG(("CD has %d tracks\n", file->cdtoc.numtrks));
239216
240217   /* calculate the starting frame for each track, keeping in mind that CHDMAN
241       pads tracks out with extra frames to fit hunk size boundries
218       pads tracks out with extra frames to fit 4-frame size boundries
242219    */
243220   physofs = chdofs = 0;
244221   for (i = 0; i < file->cdtoc.numtrks; i++)
r14481r14482
265242   file->cdtoc.tracks[i].physframeofs = physofs;
266243   file->cdtoc.tracks[i].chdframeofs = chdofs;
267244
268   /* allocate a cache */
269   file->cache = (UINT8 *)malloc(chd_get_header(chd)->hunkbytes);
270   if (file->cache == NULL)
271   {
272      free(file);
273      return NULL;
274   }
275
276245   return file;
277246}
278247
r14481r14482
286255   if (file == NULL)
287256      return;
288257
289   /* free the cache */
290   if (file->cache)
291      free(file->cache);
292
293258   if (file->chd == NULL)
294259   {
295260      for (int i = 0; i < file->cdtoc.numtrks; i++)
r14481r14482
307272    CORE READ ACCESS
308273***************************************************************************/
309274
275chd_error read_partial_sector(cdrom_file *file, void *dest, UINT32 chdsector, UINT32 tracknum, UINT32 startoffs, UINT32 length)
276{
277   // if a CHD, just read
278   if (file->chd != NULL)
279      return file->chd->read_bytes(UINT64(chdsector) * UINT64(CD_FRAME_SIZE) + startoffs, dest, length);
280
281   // else read from the appropriate file
282   core_file *srcfile = file->fhandle[tracknum];
283
284   UINT64 sourcefileoffset = file->track_info.track[tracknum].offset;
285   int bytespersector = file->cdtoc.tracks[tracknum].datasize + file->cdtoc.tracks[tracknum].subsize;
286
287   sourcefileoffset += chdsector * bytespersector + startoffs;
288
289   core_fseek(srcfile, sourcefileoffset, SEEK_SET);
290   core_fread(srcfile, dest, length);
291
292   if (file->track_info.track[tracknum].swap)
293   {
294      UINT8 *buffer = (UINT8 *)dest - startoffs;
295      for (int swapindex = startoffs; swapindex < 2352; swapindex += 2 )
296      {
297         int swaptemp = buffer[ swapindex ];
298         buffer[ swapindex ] = buffer[ swapindex + 1 ];
299         buffer[ swapindex + 1 ] = swaptemp;
300      }
301   }
302   return CHDERR_NONE;
303}
304
305
310306/*-------------------------------------------------
311307    cdrom_read_data - read one or more sectors
312308    from a CD-ROM
r14481r14482
314310
315311UINT32 cdrom_read_data(cdrom_file *file, UINT32 lbasector, void *buffer, UINT32 datatype)
316312{
317   UINT32 tracktype, tracknum, sectoroffs;
318   chd_error err;
319   static const UINT8 syncbytes[12] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
320
321313   if (file == NULL)
322314      return 0;
323315
324   /* cache in the sector */
325   err = read_sector_into_cache(file, lbasector, &sectoroffs, &tracknum);
326   if (err != CHDERR_NONE)
327      return 0;
316   // compute CHD sector and tracknumber
317   UINT32 tracknum = 0;
318   UINT32 chdsector = physical_to_chd_lba(file, lbasector, tracknum);
328319
329320   /* copy out the requested sector */
330   tracktype = file->cdtoc.tracks[tracknum].trktype;
321   UINT32 tracktype = file->cdtoc.tracks[tracknum].trktype;
331322   if ((datatype == tracktype) || (datatype == CD_TRACK_RAW_DONTCARE))
332323   {
333      memcpy(buffer, &file->cache[sectoroffs * CD_FRAME_SIZE], file->cdtoc.tracks[tracknum].datasize);
324      return (read_partial_sector(file, buffer, chdsector, tracknum, 0, file->cdtoc.tracks[tracknum].datasize) == CHDERR_NONE);
334325   }
335326   else
336327   {
337328      /* return 2048 bytes of mode 1 data from a 2352 byte mode 1 raw sector */
338329      if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE1_RAW))
339330      {
340         memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 16], 2048);
341         return 1;
331         return (read_partial_sector(file, buffer, chdsector, tracknum, 16, 2048) == CHDERR_NONE);
342332      }
343333
344334      /* return 2352 byte mode 1 raw sector from 2048 bytes of mode 1 data */
r14481r14482
347337         UINT8 *bufptr = (UINT8 *)buffer;
348338         UINT32 msf = lba_to_msf(lbasector);
349339
340         static const UINT8 syncbytes[12] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
350341         memcpy(bufptr, syncbytes, 12);
351342         bufptr[12] = msf>>16;
352343         bufptr[13] = msf>>8;
353344         bufptr[14] = msf&0xff;
354345         bufptr[15] = 1;   // mode 1
355         memcpy(bufptr+16, &file->cache[(sectoroffs * CD_FRAME_SIZE)], 2048);
356346         LOG(("CDROM: promotion of mode1/form1 sector to mode1 raw is not complete!\n"));
357         return 1;
347         return (read_partial_sector(file, bufptr+16, chdsector, tracknum, 0, 2048) == CHDERR_NONE);
358348      }
359349
360350      /* return 2048 bytes of mode 1 data from a mode2 form1 or raw sector */
361351      if ((datatype == CD_TRACK_MODE1) && ((tracktype == CD_TRACK_MODE2_FORM1)||(tracktype == CD_TRACK_MODE2_RAW)))
362352      {
363         memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 24], 2048);
364         return 1;
353         return (read_partial_sector(file, buffer, chdsector, tracknum, 24, 2048) == CHDERR_NONE);
365354      }
366355
367356      /* return mode 2 2336 byte data from a 2352 byte mode 1 or 2 raw sector (skip the header) */
368357      if ((datatype == CD_TRACK_MODE2) && ((tracktype == CD_TRACK_MODE1_RAW) || (tracktype == CD_TRACK_MODE2_RAW)))
369358      {
370         memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 16], 2336);
371         return 1;
359         return (read_partial_sector(file, buffer, chdsector, tracknum, 16, 2336) == CHDERR_NONE);
372360      }
373361
374362      LOG(("CDROM: Conversion from type %d to type %d not supported!\n", tracktype, datatype));
375363      return 0;
376364   }
377   return 1;
378365}
379366
380367
r14481r14482
385372
386373UINT32 cdrom_read_subcode(cdrom_file *file, UINT32 lbasector, void *buffer)
387374{
388   UINT32 sectoroffs, tracknum;
389   chd_error err;
390
391375   if (file == NULL)
392376      return ~0;
393377
394   /* cache in the sector */
395   err = read_sector_into_cache(file, lbasector, &sectoroffs, &tracknum);
396   if (err != CHDERR_NONE)
397      return 0;
398
399   /* copy out the requested data */
400   memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + file->cdtoc.tracks[tracknum].datasize], file->cdtoc.tracks[tracknum].subsize);
401   return 1;
378   // compute CHD sector and tracknumber
379   UINT32 tracknum = 0;
380   UINT32 chdsector = physical_to_chd_lba(file, lbasector, tracknum);
381   if (file->cdtoc.tracks[tracknum].subsize == 0)
382      return 1;
383   
384   // read the data
385   chd_error err = read_partial_sector(file, buffer, chdsector, tracknum, file->cdtoc.tracks[tracknum].datasize, file->cdtoc.tracks[tracknum].subsize);
386   return (err == CHDERR_NONE);
402387}
403388
404389
r14481r14482
420405      return ~0;
421406
422407   /* convert to a CHD sector offset and get track information */
423   physical_to_chd_lba(file, frame, &track);
408   physical_to_chd_lba(file, frame, track);
424409   return track;
425410}
426411
r14481r14482
704689***************************************************************************/
705690
706691/*-------------------------------------------------
707    read_sector_into_cache - cache a sector at
708    the given physical LBA
709-------------------------------------------------*/
710
711static chd_error read_sector_into_cache(cdrom_file *file, UINT32 lbasector, UINT32 *sectoroffs, UINT32 *tracknum)
712{
713   UINT32 chdsector, hunknum;
714   chd_error err;
715
716   /* convert to a CHD sector offset and get track information */
717   *tracknum = 0;
718   chdsector = physical_to_chd_lba(file, lbasector, tracknum);
719   hunknum = chdsector / file->hunksectors;
720   *sectoroffs = chdsector % file->hunksectors;
721
722   /* if we haven't cached this hunk, read it now */
723   if (file->cachehunk != hunknum)
724   {
725      if (file->chd) {
726         err = chd_read(file->chd, hunknum, file->cache);
727         if (err != CHDERR_NONE)
728            return err;
729      } else {
730         core_file *srcfile = file->fhandle[*tracknum];
731
732         UINT64 sourcefileoffset = file->track_info.offset[*tracknum];
733         int bytespersector = file->cdtoc.tracks[*tracknum].datasize + file->cdtoc.tracks[*tracknum].subsize;
734
735         sourcefileoffset += chdsector * bytespersector;
736
737         core_fseek(srcfile, sourcefileoffset, SEEK_SET);
738         core_fread(srcfile, file->cache, bytespersector);
739
740         if (file->track_info.swap[*tracknum])
741         {
742            for (int swapindex = 0; swapindex < 2352; swapindex += 2 )
743            {
744               int swaptemp = file->cache[ swapindex ];
745               file->cache[ swapindex ] = file->cache[ swapindex + 1 ];
746               file->cache[ swapindex + 1 ] = swaptemp;
747            }
748         }
749      }
750
751      file->cachehunk = hunknum;
752   }
753   return CHDERR_NONE;
754}
755
756
757/*-------------------------------------------------
758692    cdrom_parse_metadata - parse metadata into the
759693    TOC structure
760694-------------------------------------------------*/
761695
762696chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
763697{
764   static UINT32 oldmetadata[CD_METADATA_WORDS], *mrp;
765   const chd_header *header = chd_get_header(chd);
766   UINT32 hunksectors = header->hunkbytes / CD_FRAME_SIZE;
767   char metadata[512];
698   astring metadata;
768699   chd_error err;
769700   int i;
770701
771702   /* start with no tracks */
772703   for (toc->numtrks = 0; toc->numtrks < CD_MAX_TRACKS; toc->numtrks++)
773704   {
774      int tracknum = -1, frames = 0, hunks, pregap, postgap;
705      int tracknum = -1, frames = 0, pregap, postgap;
775706      char type[16], subtype[16], pgtype[16], pgsub[16];
776707      cdrom_track_info *track;
777708
778709      pregap = postgap = 0;
779710
780711      /* fetch the metadata for this track */
781      err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata, sizeof(metadata), NULL, NULL, NULL);
712      err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata);
782713      if (err == CHDERR_NONE)
783714      {
784715         /* parse the metadata */
r14481r14482
791722      }
792723      else
793724      {
794         err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata, sizeof(metadata), NULL, NULL, NULL);
725         err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata);
795726         if (err != CHDERR_NONE)
796727            break;
797728         /* parse the metadata */
r14481r14482
818749
819750      /* set the frames and extra frames data */
820751      track->frames = frames;
821      hunks = (frames + hunksectors - 1) / hunksectors;
822      track->extraframes = hunks * hunksectors - frames;
752      int padded = (frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING;
753      track->extraframes = padded * CD_TRACK_PADDING - frames;
823754
824755      /* set the pregap info */
825756      track->pregap = pregap;
r14481r14482
839770      return CHDERR_NONE;
840771
841772   /* look for old-style metadata */
842   err = chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, oldmetadata, sizeof(oldmetadata), NULL, NULL, NULL);
773   dynamic_buffer oldmetadata;
774   err = chd->read_metadata(CDROM_OLD_METADATA_TAG, 0, oldmetadata);
843775   if (err != CHDERR_NONE)
844776      return err;
845777
846778   /* reconstruct the TOC from it */
847   mrp = &oldmetadata[0];
779   UINT32 *mrp = reinterpret_cast<UINT32 *>(&oldmetadata[0]);
848780   toc->numtrks = *mrp++;
849781
850782   for (i = 0; i < CD_MAX_TRACKS; i++)
r14481r14482
855787      toc->tracks[i].subsize = *mrp++;
856788      toc->tracks[i].frames = *mrp++;
857789      toc->tracks[i].extraframes = *mrp++;
790      toc->tracks[i].pregap = 0;
791      toc->tracks[i].postgap = 0;
792      toc->tracks[i].pgtype = 0;
793      toc->tracks[i].pgsub = 0;
794      toc->tracks[i].pgdatasize = 0;
795      toc->tracks[i].pgsubsize = 0;
858796   }
859797
860798   /* TODO: I don't know why sometimes the data is one endian and sometimes another */
r14481r14482
888826   /* write the metadata */
889827   for (i = 0; i < toc->numtrks; i++)
890828   {
891      char metadata[512];
892      sprintf(metadata, CDROM_TRACK_METADATA2_FORMAT, i + 1, cdrom_get_type_string(toc->tracks[i].trktype),
829      astring metadata;
830      metadata.format(CDROM_TRACK_METADATA2_FORMAT, i + 1, cdrom_get_type_string(toc->tracks[i].trktype),
893831            cdrom_get_subtype_string(toc->tracks[i].subtype), toc->tracks[i].frames, toc->tracks[i].pregap,
894832            cdrom_get_type_string(toc->tracks[i].pgtype), cdrom_get_subtype_string(toc->tracks[i].pgsub),
895833            toc->tracks[i].postgap);
896834
897      err = chd_set_metadata(chd, CDROM_TRACK_METADATA2_TAG, i, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
835      err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata);
898836      if (err != CHDERR_NONE)
899837         return err;
900838   }
src/lib/util/flac.c
r0r14482
1/***************************************************************************
2
3    flac.c
4
5    FLAC compression wrappers
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#include "flac.h"
41#include <assert.h>
42#include <new>
43
44
45//**************************************************************************
46//  FLAC ENCODER
47//**************************************************************************
48
49//-------------------------------------------------
50//  flac_encoder - constructors
51//-------------------------------------------------
52
53flac_encoder::flac_encoder()
54{
55   init_common();
56}
57
58
59flac_encoder::flac_encoder(void *buffer, UINT32 buflength)
60{
61   init_common();
62   reset(buffer, buflength);
63}
64
65
66flac_encoder::flac_encoder(core_file &file)
67{
68   init_common();
69   reset(file);
70}
71
72
73//-------------------------------------------------
74//  ~flac_encoder - destructor
75//-------------------------------------------------
76
77flac_encoder::~flac_encoder()
78{
79   // delete the encoder
80   FLAC__stream_encoder_delete(m_encoder);
81}
82
83
84//-------------------------------------------------
85//  reset - reset state with the original
86//  parameters
87//-------------------------------------------------
88
89bool flac_encoder::reset()
90{
91   // configure the output
92   m_compressed_offset = 0;
93   m_ignore_bytes = m_strip_metadata ? 4 : 0;
94   m_found_audio = !m_strip_metadata;
95
96   // configure the encoder in a standard way
97   // note we do this on each reset; if we don't, results are NOT consistent!
98   FLAC__stream_encoder_set_verify(m_encoder, false);
99//   FLAC__stream_encoder_set_do_md5(m_encoder, false);
100   FLAC__stream_encoder_set_compression_level(m_encoder, 8);
101   FLAC__stream_encoder_set_channels(m_encoder, m_channels);
102   FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16);
103   FLAC__stream_encoder_set_sample_rate(m_encoder, m_sample_rate);
104   FLAC__stream_encoder_set_total_samples_estimate(m_encoder, 0);
105   FLAC__stream_encoder_set_streamable_subset(m_encoder, false);
106   FLAC__stream_encoder_set_blocksize(m_encoder, m_block_size);
107
108   // re-start processing
109   return (FLAC__stream_encoder_init_stream(m_encoder, write_callback_static, NULL, NULL, NULL, this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK);
110}
111
112
113//-------------------------------------------------
114//  reset - reset state with new memory parameters
115//-------------------------------------------------
116
117bool flac_encoder::reset(void *buffer, UINT32 buflength)
118{
119   // configure the output
120   m_compressed_start = reinterpret_cast<FLAC__byte *>(buffer);
121   m_compressed_length = buflength;
122   m_file = NULL;
123   return reset();
124}
125
126
127//-------------------------------------------------
128//  reset - reset state with new file parameters
129//-------------------------------------------------
130
131bool flac_encoder::reset(core_file &file)
132{
133   // configure the output
134   m_compressed_start = NULL;
135   m_compressed_length = 0;
136   m_file = &file;
137   return reset();
138}
139
140
141//-------------------------------------------------
142//  encode_interleaved - encode a buffer with
143//  interleaved samples
144//-------------------------------------------------
145
146bool flac_encoder::encode_interleaved(const INT16 *samples, UINT32 samples_per_channel, bool swap_endian)
147{
148   int shift = swap_endian ? 8 : 0;
149
150   // loop over source samples
151   int num_channels = FLAC__stream_encoder_get_channels(m_encoder);
152   UINT32 srcindex = 0;
153   while (samples_per_channel != 0)
154   {
155      // process in batches of 2k samples
156      FLAC__int32 converted_buffer[2048];
157      FLAC__int32 *dest = converted_buffer;
158      UINT32 cur_samples = MIN(ARRAY_LENGTH(converted_buffer) / num_channels, samples_per_channel);
159
160      // convert a buffers' worth
161      for (UINT32 sampnum = 0; sampnum < cur_samples; sampnum++)
162         for (int channel = 0; channel < num_channels; channel++, srcindex++)
163            *dest++ = INT16((UINT16(samples[srcindex]) << shift) | (UINT16(samples[srcindex]) >> shift));
164     
165      // process this batch
166      if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples))
167         return false;
168      samples_per_channel -= cur_samples;
169   }
170   return true;
171}
172
173
174//-------------------------------------------------
175//  encode - encode a buffer with individual
176//  sample streams
177//-------------------------------------------------
178
179bool flac_encoder::encode(INT16 *const *samples, UINT32 samples_per_channel, bool swap_endian)
180{
181   int shift = swap_endian ? 8 : 0;
182
183   // loop over source samples
184   int num_channels = FLAC__stream_encoder_get_channels(m_encoder);
185   UINT32 srcindex = 0;
186   while (samples_per_channel != 0)
187   {
188      // process in batches of 2k samples
189      FLAC__int32 converted_buffer[2048];
190      FLAC__int32 *dest = converted_buffer;
191      UINT32 cur_samples = MIN(ARRAY_LENGTH(converted_buffer) / num_channels, samples_per_channel);
192
193      // convert a buffers' worth
194      for (UINT32 sampnum = 0; sampnum < cur_samples; sampnum++, srcindex++)
195         for (int channel = 0; channel < num_channels; channel++)
196            *dest++ = INT16((UINT16(samples[channel][srcindex]) << shift) | (UINT16(samples[channel][srcindex]) >> shift));
197     
198      // process this batch
199      if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples))
200         return false;
201      samples_per_channel -= cur_samples;
202   }
203   return true;
204}
205
206
207//-------------------------------------------------
208//  finish - complete encoding and flush the
209//  stream
210//-------------------------------------------------
211
212UINT32 flac_encoder::finish()
213{
214   // process the data and return the amount written
215   FLAC__stream_encoder_finish(m_encoder);
216   return (m_file != NULL) ? core_ftell(m_file) : m_compressed_offset;
217}
218
219
220//-------------------------------------------------
221//  init_common - common initialization
222//-------------------------------------------------
223
224void flac_encoder::init_common()
225{
226   // allocate the encoder
227   m_encoder = FLAC__stream_encoder_new();
228   if (m_encoder == NULL)
229      throw std::bad_alloc();
230   
231   // initialize default state
232   m_file = NULL;
233   m_compressed_offset = 0;
234   m_compressed_start = NULL;
235   m_compressed_length = 0;
236   m_sample_rate = 44100;
237   m_channels = 2;
238   m_block_size = 0;
239   m_strip_metadata = false;
240   m_ignore_bytes = 0;
241   m_found_audio = false;
242}
243
244
245//-------------------------------------------------
246//  write_callback - handle writes to the
247//  output stream
248//-------------------------------------------------
249
250FLAC__StreamEncoderWriteStatus flac_encoder::write_callback_static(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
251{
252   return reinterpret_cast<flac_encoder *>(client_data)->write_callback(buffer, bytes, samples, current_frame);
253}
254
255FLAC__StreamEncoderWriteStatus flac_encoder::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
256{
257   // loop over output data
258   size_t offset = 0;
259   while (offset < bytes)
260   {
261      // if we're ignoring, continue to do so
262      if (m_ignore_bytes != 0)
263      {
264         int ignore = MIN(bytes - offset, m_ignore_bytes);
265         offset += ignore;
266         m_ignore_bytes -= ignore;
267      }
268     
269      // if we haven't hit the end of metadata, process a new piece
270      else if (!m_found_audio)
271      {
272         assert(bytes - offset >= 4);
273         m_found_audio = ((buffer[offset] & 0x80) != 0);
274         m_ignore_bytes = (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
275         offset += 4;
276      }
277
278      // otherwise process as audio data and copy to the output     
279      else
280      {
281         int count = bytes - offset;
282         if (m_file != NULL)
283            core_fwrite(m_file, buffer, count);
284         else
285         {
286            if (m_compressed_offset + count <= m_compressed_length)
287               memcpy(m_compressed_start + m_compressed_offset, buffer, count);
288            m_compressed_offset += count;
289         }
290         offset += count;
291      }
292   }
293   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
294}
295
296
297
298//**************************************************************************
299//  FLAC DECODER
300//**************************************************************************
301
302//-------------------------------------------------
303//  flac_decoder - constructor
304//-------------------------------------------------
305
306flac_decoder::flac_decoder()
307   : m_decoder(FLAC__stream_decoder_new()),
308     m_file(NULL),
309     m_compressed_offset(0),
310     m_compressed_start(NULL),
311     m_compressed_length(0),
312     m_compressed2_start(NULL),
313     m_compressed2_length(0)
314{
315}
316
317
318//-------------------------------------------------
319//  flac_decoder - constructor
320//-------------------------------------------------
321
322flac_decoder::flac_decoder(const void *buffer, UINT32 length, const void *buffer2, UINT32 length2)
323   : m_decoder(FLAC__stream_decoder_new()),
324     m_file(NULL),
325     m_compressed_offset(0),
326     m_compressed_start(reinterpret_cast<const FLAC__byte *>(buffer)),
327     m_compressed_length(length),
328     m_compressed2_start(reinterpret_cast<const FLAC__byte *>(buffer2)),
329     m_compressed2_length(length2)
330{
331   reset();
332}
333
334
335//-------------------------------------------------
336//  flac_decoder - constructor
337//-------------------------------------------------
338
339flac_decoder::flac_decoder(core_file &file)
340   : m_decoder(FLAC__stream_decoder_new()),
341     m_file(&file),
342     m_compressed_offset(0),
343     m_compressed_start(NULL),
344     m_compressed_length(0),
345     m_compressed2_start(NULL),
346     m_compressed2_length(0)
347{
348   reset();
349}
350
351
352//-------------------------------------------------
353//  flac_decoder - destructor
354//-------------------------------------------------
355
356flac_decoder::~flac_decoder()
357{
358   FLAC__stream_decoder_delete(m_decoder);
359}
360
361
362//-------------------------------------------------
363//  reset - reset state with the original
364//  parameters
365//-------------------------------------------------
366
367bool flac_decoder::reset()
368{
369   m_compressed_offset = 0;
370   if (FLAC__stream_decoder_init_stream(m_decoder, &flac_decoder::read_callback_static, NULL, NULL, NULL, NULL, &flac_decoder::write_callback_static, NULL, &flac_decoder::error_callback_static, this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
371      return false;
372   return FLAC__stream_decoder_process_until_end_of_metadata(m_decoder);
373}
374
375
376//-------------------------------------------------
377//  reset - reset state with new memory parameters
378//-------------------------------------------------
379
380bool flac_decoder::reset(const void *buffer, UINT32 length, const void *buffer2, UINT32 length2)
381{
382   m_file = NULL;
383   m_compressed_start = reinterpret_cast<const FLAC__byte *>(buffer);
384   m_compressed_length = length;
385   m_compressed2_start = reinterpret_cast<const FLAC__byte *>(buffer2);
386   m_compressed2_length = length2;
387   return reset();
388}
389
390
391//-------------------------------------------------
392//  reset - reset state with new memory parameters
393//  and a custom-generated header
394//-------------------------------------------------
395
396bool flac_decoder::reset(UINT32 sample_rate, UINT8 num_channels, UINT32 block_size, const void *buffer, UINT32 length)
397{
398   // modify the template header with our parameters
399   static const UINT8 s_header_template[0x2a] =
400   {
401      0x66, 0x4C, 0x61, 0x43,                   // +00: 'fLaC' stream header
402      0x80,                                  // +04: metadata block type 0 (STREAMINFO),
403                                          //      flagged as last block
404      0x00, 0x00, 0x22,                         // +05: metadata block length = 0x22
405      0x00, 0x00,                            // +08: minimum block size
406      0x00, 0x00,                              // +0A: maximum block size
407      0x00, 0x00, 0x00,                         // +0C: minimum frame size (0 == unknown)
408      0x00, 0x00, 0x00,                         // +0F: maximum frame size (0 == unknown)
409      0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100),
410                                          //      numchannels (2), sample bits (16),
411                                          //      samples in stream (0 == unknown)
412      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none)
413      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   //
414                                          // +2A: start of stream data
415   };
416   memcpy(m_custom_header, s_header_template, sizeof(s_header_template));
417   m_custom_header[0x08] = m_custom_header[0x0a] = block_size >> 8;
418   m_custom_header[0x09] = m_custom_header[0x0b] = block_size & 0xff;
419   m_custom_header[0x12] = sample_rate >> 12;
420   m_custom_header[0x13] = sample_rate >> 4;
421   m_custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
422
423   // configure the header ahead of the provided buffer
424   m_file = NULL;
425   m_compressed_start = reinterpret_cast<const FLAC__byte *>(m_custom_header);
426   m_compressed_length = sizeof(m_custom_header);
427   m_compressed2_start = reinterpret_cast<const FLAC__byte *>(buffer);
428   m_compressed2_length = length;
429   return reset();
430}
431
432
433//-------------------------------------------------
434//  reset - reset state with new file parameter
435//-------------------------------------------------
436
437bool flac_decoder::reset(core_file &file)
438{
439   m_file = &file;
440   m_compressed_start = NULL;
441   m_compressed_length = 0;
442   m_compressed2_start = NULL;
443   m_compressed2_length = 0;
444   return reset();
445}
446
447
448//-------------------------------------------------
449//  decode_interleaved - decode to an interleaved
450//  sound stream
451//-------------------------------------------------
452
453bool flac_decoder::decode_interleaved(INT16 *samples, UINT32 num_samples, bool swap_endian)
454{
455   // configure the uncompressed buffer
456   memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
457   m_uncompressed_start[0] = samples;
458   m_uncompressed_offset = 0;
459   m_uncompressed_length = num_samples;
460   m_uncompressed_swap = swap_endian;
461   
462   // loop until we get everything we want
463   while (m_uncompressed_offset < m_uncompressed_length)
464      if (!FLAC__stream_decoder_process_single(m_decoder))
465         return false;
466   return true;
467}
468
469
470//-------------------------------------------------
471//  decode - decode to an multiple independent
472//  data streams
473//-------------------------------------------------
474
475bool flac_decoder::decode(INT16 **samples, UINT32 num_samples, bool swap_endian)
476{
477   // make sure we don't have too many channels
478   int chans = channels();
479   if (chans > ARRAY_LENGTH(m_uncompressed_start))
480      return false;
481
482   // configure the uncompressed buffer
483   memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
484   for (int curchan = 0; curchan < chans; curchan++)
485      m_uncompressed_start[curchan] = samples[curchan];
486   m_uncompressed_offset = 0;
487   m_uncompressed_length = num_samples;
488   m_uncompressed_swap = swap_endian;
489   
490   // loop until we get everything we want
491   while (m_uncompressed_offset < m_uncompressed_length)
492      if (!FLAC__stream_decoder_process_single(m_decoder))
493         return false;
494   return true;
495}
496
497
498//-------------------------------------------------
499//  finish - finish up the decode
500//-------------------------------------------------
501
502void flac_decoder::finish()
503{
504   FLAC__stream_decoder_finish(m_decoder);
505}
506
507
508//-------------------------------------------------
509//  read_callback - handle reads from the input
510//  stream
511//-------------------------------------------------
512
513FLAC__StreamDecoderReadStatus flac_decoder::read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
514{
515   return reinterpret_cast<flac_decoder *>(client_data)->read_callback(buffer, bytes);
516}
517
518FLAC__StreamDecoderReadStatus flac_decoder::read_callback(FLAC__byte buffer[], size_t *bytes)
519{
520   UINT32 expected = *bytes;
521   
522   // if a file, just read
523   if (m_file != NULL)
524      *bytes = core_fread(m_file, buffer, expected);
525   
526   // otherwise, copy from memory
527   else
528   {
529      // copy from primary buffer first
530      UINT32 outputpos = 0;
531      if (outputpos < *bytes && m_compressed_offset < m_compressed_length)
532      {
533         UINT32 bytes_to_copy = MIN(*bytes - outputpos, m_compressed_length - m_compressed_offset);
534         memcpy(&buffer[outputpos], m_compressed_start + m_compressed_offset, bytes_to_copy);
535         outputpos += bytes_to_copy;
536         m_compressed_offset += bytes_to_copy;
537      }
538     
539      // once we're out of that, copy from the secondary buffer
540      if (outputpos < *bytes && m_compressed_offset < m_compressed_length + m_compressed2_length)
541      {
542         UINT32 bytes_to_copy = MIN(*bytes - outputpos, m_compressed2_length - (m_compressed_offset - m_compressed_length));
543         memcpy(&buffer[outputpos], m_compressed2_start + m_compressed_offset - m_compressed_length, bytes_to_copy);
544         outputpos += bytes_to_copy;
545         m_compressed_offset += bytes_to_copy;
546      }
547      *bytes = outputpos;
548   }
549
550   // return based on whether we ran out of data
551   return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
552}
553
554
555//-------------------------------------------------
556//  write_callback - handle writes to the output
557//  stream
558//-------------------------------------------------
559
560FLAC__StreamDecoderWriteStatus flac_decoder::write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
561{
562   return reinterpret_cast<flac_decoder *>(client_data)->write_callback(frame, buffer);
563}
564
565FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
566{
567   assert(frame->header.channels == channels());
568   
569   // interleaved case
570   int shift = m_uncompressed_swap ? 8 : 0;
571   int blocksize = frame->header.blocksize;
572   if (m_uncompressed_start[1] == NULL)
573   {
574      INT16 *dest = m_uncompressed_start[0] + m_uncompressed_offset * frame->header.channels;
575      for (int sampnum = 0; sampnum < blocksize && m_uncompressed_offset < m_uncompressed_length; sampnum++, m_uncompressed_offset++)
576         for (int chan = 0; chan < frame->header.channels; chan++)
577            *dest++ = INT16((UINT16(buffer[chan][sampnum]) << shift) | (UINT16(buffer[chan][sampnum]) >> shift));
578   }
579   
580   // non-interleaved case
581   else
582   {
583      for (int sampnum = 0; sampnum < blocksize && m_uncompressed_offset < m_uncompressed_length; sampnum++, m_uncompressed_offset++)
584         for (int chan = 0; chan < frame->header.channels; chan++)
585            if (m_uncompressed_start[chan] != NULL)
586               m_uncompressed_start[chan][m_uncompressed_offset] = INT16((UINT16(buffer[chan][sampnum]) << shift) | (UINT16(buffer[chan][sampnum]) >> shift));
587   }
588   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
589}
590
591
592//-------------------------------------------------
593//  error_callback - handle errors (ignore them)
594//-------------------------------------------------
595
596void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
597{
598}
src/lib/util/aviio.c
r14481r14482
15731573      {
15741574         const UINT8 *base = &chunkdata[24 + entry * 4 * longs_per_entry];
15751575         UINT32 offset = fetch_32bits(&base[0]);
1576         UINT32 size = fetch_32bits(&base[4]);
1576         UINT32 size = fetch_32bits(&base[4]) & 0x7fffffff;   // bit 31 == NOT a keyframe
15771577
15781578         /* set the info for this chunk and advance */
15791579         avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset - 8, size + 8);
src/lib/util/cdrom.h
r14481r14482
5151    CONSTANTS
5252***************************************************************************/
5353
54// tracks are padded to a multiple of this many frames
55const UINT32 CD_TRACK_PADDING = 4;
56
5457#define CD_MAX_TRACKS         (99)   /* AFAIK the theoretical limit */
5558#define CD_MAX_SECTOR_DATA      (2352)
5659#define CD_MAX_SUBCODE_DATA      (96)
r14481r14482
9093typedef struct _cdrom_file cdrom_file;
9194
9295
93typedef struct _cdrom_track_info cdrom_track_info;
94struct _cdrom_track_info
96struct cdrom_track_info
9597{
9698   /* fields used by CHDMAN and in MAME */
9799   UINT32 trktype;      /* track type */
r14481r14482
113115};
114116
115117
116typedef struct _cdrom_toc cdrom_toc;
117struct _cdrom_toc
118struct cdrom_toc
118119{
119120   UINT32 numtrks;      /* number of tracks */
120121   cdrom_track_info tracks[CD_MAX_TRACKS];
src/lib/util/flac.h
r0r14482
1/***************************************************************************
2
3    flac.h
4
5    FLAC compression wrappers
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __FLAC_H__
43#define __FLAC_H__
44
45#include "osdcore.h"
46#include "corefile.h"
47#include "../../lib/libflac/include/flac/all.h"
48
49
50//**************************************************************************
51//  TYPE DEFINITIONS
52//**************************************************************************
53
54// ======================> flac_encoder
55
56class flac_encoder
57{
58public:
59   // construction/destruction
60   flac_encoder();
61   flac_encoder(void *buffer, UINT32 buflength);
62   flac_encoder(core_file &file);
63   ~flac_encoder();
64
65   // configuration
66   void set_sample_rate(UINT32 sample_rate) { m_sample_rate = sample_rate; }
67   void set_num_channels(UINT8 num_channels) { m_channels = num_channels; }
68   void set_block_size(UINT32 block_size) { m_block_size = block_size; }
69   void set_strip_metadata(bool strip) { m_strip_metadata = strip; }
70   
71   // getters (valid after reset)
72   FLAC__StreamEncoderState state() const { return FLAC__stream_encoder_get_state(m_encoder); }
73   const char *state_string() const { return FLAC__stream_encoder_get_resolved_state_string(m_encoder); }
74   
75   // reset
76   bool reset();
77   bool reset(void *buffer, UINT32 buflength);
78   bool reset(core_file &file);
79   
80   // encode a buffer
81   bool encode_interleaved(const INT16 *samples, UINT32 samples_per_channel, bool swap_endian = false);
82   bool encode(INT16 *const *samples, UINT32 samples_per_channel, bool swap_endian = false);
83
84   // finish up
85   UINT32 finish();
86
87private:
88   // internal helpers
89   void init_common();
90   static FLAC__StreamEncoderWriteStatus write_callback_static(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
91   FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame);
92
93   // internal state
94   FLAC__StreamEncoder *   m_encoder;            // actual encoder
95   core_file *            m_file;               // output file
96   UINT32               m_compressed_offset;   // current offset with the compressed stream
97   FLAC__byte *         m_compressed_start;      // start of compressed data
98   UINT32               m_compressed_length;   // length of the compressed stream
99   
100   // parameters
101   UINT32               m_sample_rate;         // sample rate
102   UINT8               m_channels;            // number of channels
103   UINT32               m_block_size;         // block size
104
105   // header stripping
106   bool               m_strip_metadata;      // strip the the metadata?   
107   UINT32               m_ignore_bytes;         // how many bytes to ignore when writing
108   bool               m_found_audio;         // have we hit the audio yet?
109};
110
111
112// ======================> flac_decoder
113
114class flac_decoder
115{
116public:
117   // construction/destruction
118   flac_decoder();
119   flac_decoder(const void *buffer, UINT32 length, const void *buffer2 = NULL, UINT32 length2 = 0);
120   flac_decoder(core_file &file);
121   ~flac_decoder();
122   
123   // getters (valid after reset)
124   UINT32 sample_rate() const { return FLAC__stream_decoder_get_sample_rate(m_decoder); }
125   UINT8 channels() const { return FLAC__stream_decoder_get_channels(m_decoder); }
126   UINT32 block_size() const { return FLAC__stream_decoder_get_blocksize(m_decoder); }
127   FLAC__StreamDecoderState state() const { return FLAC__stream_decoder_get_state(m_decoder); }
128   const char *state_string() const { return FLAC__stream_decoder_get_resolved_state_string(m_decoder); }
129   
130   // reset
131   bool reset();
132   bool reset(const void *buffer, UINT32 length, const void *buffer2 = NULL, UINT32 length2 = 0);
133   bool reset(UINT32 sample_rate, UINT8 num_channels, UINT32 block_size, const void *buffer, UINT32 length);
134   bool reset(core_file &file);
135   
136   // decode to a buffer; num_samples must be a multiple of the block size
137   bool decode_interleaved(INT16 *samples, UINT32 num_samples, bool swap_endian = false);
138   bool decode(INT16 **samples, UINT32 num_samples, bool swap_endian = false);
139
140   // finish up
141   void finish();
142
143private:
144   // internal helpers
145   static FLAC__StreamDecoderReadStatus read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
146   FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
147   static FLAC__StreamDecoderWriteStatus write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
148   FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
149   static void error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
150
151   // output state
152   FLAC__StreamDecoder *   m_decoder;            // actual encoder
153   core_file *            m_file;               // output file
154   UINT32               m_compressed_offset;   // current offset in compressed data
155   const FLAC__byte *      m_compressed_start;      // start of compressed data
156   UINT32               m_compressed_length;   // length of compressed data
157   const FLAC__byte *      m_compressed2_start;   // start of compressed data
158   UINT32               m_compressed2_length;   // length of compressed data
159   INT16 *               m_uncompressed_start[8];// pointer to start of uncompressed data (up to 8 streams)
160   UINT32               m_uncompressed_offset;   // current position in uncompressed data
161   UINT32               m_uncompressed_length;   // length of uncompressed data
162   bool               m_uncompressed_swap;   // swap uncompressed sample data
163   UINT8               m_custom_header[0x2a];   // custom header
164};
165
166
167#endif // __FLAC_H__
src/lib/util/tagmap.h
r14481r14482
158158      for (entry_t *entry = m_table[fullhash % ARRAY_LENGTH(m_table)]; entry != NULL; entry = entry->next())
159159         if (entry->fullhash() == fullhash && entry->tag() == tag)
160160            return entry->object();
161      return (_ElementType)NULL;
161      return _ElementType(NULL);
162162   }
163163
164164   // find by tag without checking anything but the hash
src/lib/util/hashing.c
r0r14482
1/***************************************************************************
2
3   hashing.c
4
5   Hashing helper classes.
6
7****************************************************************************
8
9   Copyright Aaron Giles
10   All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#include "hashing.h"
41
42
43//**************************************************************************
44//  CONSTANTS
45//**************************************************************************
46
47const crc16_t crc16_t::null = { 0 };
48const crc32_t crc32_t::null = { 0 };
49const md5_t md5_t::null = { { 0 } };
50const sha1_t sha1_t::null = { { 0 } };
51
52
53
54//**************************************************************************
55//  INLINE FUNCTIONS
56//**************************************************************************
57
58//-------------------------------------------------
59//  char_to_hex - return the hex value of a
60//  character
61//-------------------------------------------------
62
63inline int char_to_hex(char c)
64{
65   if (c >= '0' && c <= '9')
66      return c - '0';
67   if (c >= 'a' && c <= 'f')
68      return 10 + c - 'a';
69   if (c >= 'A' && c <= 'F')
70      return 10 + c - 'a';
71   return -1;
72}
73
74
75
76//**************************************************************************
77//  SHA-1 HELPERS
78//**************************************************************************
79
80//-------------------------------------------------
81//  from_string - convert from a string
82//-------------------------------------------------
83
84bool sha1_t::from_string(const char *string)
85{
86   // must be at least long enough to hold everything
87   if (strlen(string) < 2 * sizeof(m_raw))
88      return false;
89   
90   // iterate through our raw buffer
91   for (int bytenum = 0; bytenum < sizeof(m_raw); bytenum++)
92   {
93      int upper = char_to_hex(*string++);
94      int lower = char_to_hex(*string++);
95      if (upper == -1 || lower == -1)
96         return false;
97      m_raw[bytenum] = (upper << 4) | lower;
98   }
99   return true;
100}
101
102
103//-------------------------------------------------
104//  as_string - convert to a string
105//-------------------------------------------------
106
107const char *sha1_t::as_string(astring &buffer)
108{
109   buffer.reset();
110   for (int i = 0; i < ARRAY_LENGTH(m_raw); i++)
111      buffer.catformat("%02x", m_raw[i]);
112   return buffer;
113}
114
115
116//**************************************************************************
117//  MD-5 HELPERS
118//**************************************************************************
119
120//-------------------------------------------------
121//  from_string - convert from a string
122//-------------------------------------------------
123
124bool md5_t::from_string(const char *string)
125{
126   // must be at least long enough to hold everything
127   if (strlen(string) < 2 * sizeof(m_raw))
128      return false;
129   
130   // iterate through our raw buffer
131   for (int bytenum = 0; bytenum < sizeof(m_raw); bytenum++)
132   {
133      int upper = char_to_hex(*string++);
134      int lower = char_to_hex(*string++);
135      if (upper == -1 || lower == -1)
136         return false;
137      m_raw[bytenum] = (upper << 4) | lower;
138   }
139   return true;
140}
141
142
143//-------------------------------------------------
144//  as_string - convert to a string
145//-------------------------------------------------
146
147const char *md5_t::as_string(astring &buffer)
148{
149   buffer.reset();
150   for (int i = 0; i < ARRAY_LENGTH(m_raw); i++)
151      buffer.catformat("%02x", m_raw[i]);
152   return buffer;
153}
154
155
156
157//**************************************************************************
158//  CRC-32 HELPERS
159//**************************************************************************
160
161//-------------------------------------------------
162//  from_string - convert from a string
163//-------------------------------------------------
164
165bool crc32_t::from_string(const char *string)
166{
167   // must be at least long enough to hold everything
168   if (strlen(string) < 2 * sizeof(m_raw))
169      return false;
170   
171   // iterate through our raw buffer
172   m_raw = 0;
173   for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++)
174   {
175      int nibble = char_to_hex(*string++);
176      if (nibble == -1)
177         return false;
178      m_raw = (m_raw << 4) | nibble;
179   }
180   return true;
181}
182
183
184//-------------------------------------------------
185//  as_string - convert to a string
186//-------------------------------------------------
187
188const char *crc32_t::as_string(astring &buffer)
189{
190   return buffer.format("%08x", m_raw);
191}
192
193
194
195//**************************************************************************
196//  CRC-16 HELPERS
197//**************************************************************************
198
199//-------------------------------------------------
200//  from_string - convert from a string
201//-------------------------------------------------
202
203bool crc16_t::from_string(const char *string)
204{
205   // must be at least long enough to hold everything
206   if (strlen(string) < 2 * sizeof(m_raw))
207      return false;
208   
209   // iterate through our raw buffer
210   m_raw = 0;
211   for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++)
212   {
213      int nibble = char_to_hex(*string++);
214      if (nibble == -1)
215         return false;
216      m_raw = (m_raw << 4) | nibble;
217   }
218   return true;
219}
220
221
222//-------------------------------------------------
223//  as_string - convert to a string
224//-------------------------------------------------
225
226const char *crc16_t::as_string(astring &buffer)
227{
228   return buffer.format("%04x", m_raw);
229}
230
231
232//-------------------------------------------------
233//  append - hash a block of data, appending to
234//  the currently-accumulated value
235//-------------------------------------------------
236
237void crc16_creator::append(const void *data, UINT32 length)
238{
239   static const UINT16 s_table[256] =
240   {
241       0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
242       0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
243       0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
244       0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
245       0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
246       0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
247       0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
248       0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
249       0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
250       0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
251       0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
252       0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
253       0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
254       0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
255       0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
256       0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
257       0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
258       0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
259       0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
260       0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
261       0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
262       0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
263       0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
264       0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
265       0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
266       0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
267       0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
268       0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
269       0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
270       0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
271       0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
272       0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
273    };
274
275   const UINT8 *src = reinterpret_cast<const UINT8 *>(data);
276   
277   // fetch the current value into a local and rip through the source data
278   UINT16 crc = m_accum.m_raw;
279   while (length-- != 0)
280      crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
281   m_accum.m_raw = crc;
282}
src/lib/util/hashing.h
r0r14482
1/***************************************************************************
2
3   hashing.h
4
5   Hashing helper classes.
6
7****************************************************************************
8
9   Copyright Aaron Giles
10   All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __HASHING_H__
43#define __HASHING_H__
44
45#include "osdcore.h"
46#include "astring.h"
47#include "zlib.h"
48#include "md5.h"
49#include "sha1.h"
50
51
52//**************************************************************************
53//  TYPE DEFINITIONS
54//**************************************************************************
55
56
57// ======================> SHA-1
58
59// final digest
60struct sha1_t
61{
62   bool operator==(const sha1_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) == 0; }
63   bool operator!=(const sha1_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) != 0; }
64   operator UINT8 *() { return m_raw; }
65   const char *as_string(astring &buffer);
66   bool from_string(const char *string);
67   UINT8 m_raw[20];
68   static const sha1_t null;
69};
70
71// creation helper
72class sha1_creator
73{
74public:
75   // construction/destruction
76   sha1_creator() { reset(); }
77   
78   // reset
79   void reset() { sha1_init(&m_context); }
80   
81   // append data
82   void append(const void *data, UINT32 length) { sha1_update(&m_context, length, reinterpret_cast<const UINT8 *>(data)); }
83   
84   // finalize and compute the final digest
85   sha1_t finish()
86   {
87      sha1_t result;
88      sha1_final(&m_context);
89      sha1_digest(&m_context, sizeof(result.m_raw), result.m_raw);
90      return result;
91   }
92
93   // static wrapper to just get the digest from a block
94   static sha1_t simple(const void *data, UINT32 length)
95   {
96      sha1_creator creator;
97      creator.append(data, length);
98      return creator.finish();
99   }
100
101protected:
102   // internal state
103   struct sha1_ctx    m_context;      // internal context
104};
105
106
107
108// ======================> MD5
109
110// final digest
111struct md5_t
112{
113   bool operator==(const md5_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) == 0; }
114   bool operator!=(const md5_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) != 0; }
115   operator UINT8 *() { return m_raw; }
116   const char *as_string(astring &buffer);
117   bool from_string(const char *string);
118   UINT8 m_raw[16];
119   static const md5_t null;
120};
121
122// creation helper
123class md5_creator
124{
125public:
126   // construction/destruction
127   md5_creator() { reset(); }
128   
129   // reset
130   void reset() { MD5Init(&m_context); }
131   
132   // append data
133   void append(const void *data, UINT32 length) { MD5Update(&m_context, reinterpret_cast<const unsigned char *>(data), length); }
134   
135   // finalize and compute the final digest
136   md5_t finish()
137   {
138      md5_t result;
139      MD5Final(result.m_raw, &m_context);
140      return result;
141   }
142
143   // static wrapper to just get the digest from a block
144   static md5_t simple(const void *data, UINT32 length)
145   {
146      md5_creator creator;
147      creator.append(data, length);
148      return creator.finish();
149   }
150
151protected:
152   // internal state
153   struct MD5Context    m_context;      // internal context
154};
155
156
157
158// ======================> CRC-32
159
160// final digest
161struct crc32_t
162{
163   bool operator==(const crc32_t &rhs) const { return m_raw == rhs.m_raw; }
164   operator UINT32() const { return m_raw; }
165   const char *as_string(astring &buffer);
166   bool from_string(const char *string);
167   UINT32 m_raw;
168   static const crc32_t null;
169};
170
171// creation helper
172class crc32_creator
173{
174public:
175   // construction/destruction
176   crc32_creator() { reset(); }
177   
178   // reset
179   void reset() { m_accum.m_raw = 0; }
180   
181   // append data
182   void append(const void *data, UINT32 length) { m_accum.m_raw = crc32(m_accum, reinterpret_cast<const Bytef *>(data), length); }
183   
184   // finalize and compute the final digest
185   crc32_t finish() { return m_accum; }
186
187   // static wrapper to just get the digest from a block
188   static crc32_t simple(const void *data, UINT32 length)
189   {
190      crc32_creator creator;
191      creator.append(data, length);
192      return creator.finish();
193   }
194
195protected:
196   // internal state
197   crc32_t          m_accum;      // internal accumulator
198};
199
200
201
202// ======================> CRC-16
203
204// final digest
205struct crc16_t
206{
207   bool operator==(const crc16_t &rhs) const { return m_raw == rhs.m_raw; }
208   operator UINT16() const { return m_raw; }
209   const char *as_string(astring &buffer);
210   bool from_string(const char *string);
211   UINT16 m_raw;
212   static const crc16_t null;
213};
214
215// creation helper
216class crc16_creator
217{
218public:
219   // construction/destruction
220   crc16_creator() { reset(); }
221   
222   // reset
223   void reset() { m_accum.m_raw = 0xffff; }
224   
225   // append data
226   void append(const void *data, UINT32 length);
227   
228   // finalize and compute the final digest
229   crc16_t finish() { return m_accum; }
230
231   // static wrapper to just get the digest from a block
232   static crc16_t simple(const void *data, UINT32 length)
233   {
234      crc16_creator creator;
235      creator.append(data, length);
236      return creator.finish();
237   }
238
239protected:
240   // internal state
241   crc16_t          m_accum;      // internal accumulator
242};
243
244
245#endif // __HASHING_H__
src/lib/util/coretmpl.h
r0r14482
1/***************************************************************************
2
3    coretmpl.h
4
5    Core templates for basic non-string types.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __CORETMPL_H__
43#define __CORETMPL_H__
44
45#include <assert.h>
46#include "osdcore.h"
47
48
49// ======================> dynamic_array
50
51// an array that is dynamically sized and can optionally auto-expand
52template<class _ElementType>
53class dynamic_array
54{
55private:
56   // we don't support deep copying
57   dynamic_array(const dynamic_array &);
58   dynamic_array &operator=(const dynamic_array &);
59
60public:
61   // construction/destruction
62   dynamic_array(int initial = 0)
63      : m_array(NULL),
64        m_count(0),
65        m_allocated(0) { if (initial != 0) expand_internal(initial); m_count = initial; }
66   virtual ~dynamic_array() { reset(); }
67
68   // operators
69   operator _ElementType *() { return &m_array[0]; }
70   operator const _ElementType *() const { return &m_array[0]; }
71   _ElementType operator[](int index) const { assert(index < m_count); return m_array[index]; }
72   _ElementType &operator[](int index) { assert(index < m_count); return m_array[index]; }
73
74   // simple getters
75   int count() const { return m_count; }
76   
77   // helpers
78   void append(const _ElementType &element) { if (m_count == m_allocated) expand_internal((m_allocated == 0) ? 16 : (m_allocated << 1), true); m_array[m_count++] = element; }
79   void reset() { delete[] m_array; m_array = NULL; m_count = m_allocated = 0; }
80   void resize(int count, bool keepdata = false) { if (count > m_allocated) expand_internal(count, keepdata); m_count = count; }
81
82private:
83   // internal helpers
84   void expand_internal(int count, bool keepdata = true)
85   {
86      // allocate a new array, copy the old one, and proceed
87      m_allocated = count;
88      _ElementType *newarray = new _ElementType[m_allocated];
89      if (keepdata)
90         for (int index = 0; index < m_count; index++)
91            newarray[index] = m_array[index];
92      delete[] m_array;
93      m_array = newarray;
94   }
95
96   // internal state
97   _ElementType *   m_array;      // allocated array
98   int          m_count;      // number of objects accessed in the list
99   int            m_allocated;   // amount of space allocated for the array
100};
101
102
103// ======================> dynamic_buffer
104
105typedef dynamic_array<UINT8> dynamic_buffer;
106
107
108
109#endif
src/lib/util/chdcodec.c
r0r14482
1/***************************************************************************
2
3    chdcodec.c
4
5    Codecs used by the CHD format
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#include "chd.h"
41#include "hashing.h"
42#include "avhuff.h"
43#include "flac.h"
44#include <zlib.h>
45#include "lib7z/lzmaenc.h"
46#include "lib7z/lzmadec.h"
47#include <new>
48
49// function that should exist but doesn't in the official release
50extern "C" SRes LzmaDec_Allocate_MAME(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc);
51
52
53//**************************************************************************
54//  TYPE DEFINITIONS
55//**************************************************************************
56
57// ======================> chd_zlib_allocator
58
59// allocation helper clas for zlib
60class chd_zlib_allocator
61{
62public:
63   // construction/destruction
64   chd_zlib_allocator();
65   ~chd_zlib_allocator();
66   
67   // installation
68   void install(z_stream &stream);
69
70private:
71   // internal helpers
72   static voidpf fast_alloc(voidpf opaque, uInt items, uInt size);
73   static void fast_free(voidpf opaque, voidpf address);
74
75   static const int MAX_ZLIB_ALLOCS = 64;
76   UINT32 *            m_allocptr[MAX_ZLIB_ALLOCS];
77};
78
79
80// ======================> chd_zlib_compressor
81
82// ZLIB compressor
83class chd_zlib_compressor : public chd_compressor
84{
85public:
86   // construction/destruction
87   chd_zlib_compressor(chd_file &chd, bool lossy);
88   ~chd_zlib_compressor();
89
90   // core functionality
91   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest);
92
93private:
94   // internal state
95   z_stream            m_deflater;
96   chd_zlib_allocator      m_allocator;
97};
98
99
100// ======================> chd_zlib_decompressor
101
102// ZLIB decompressor
103class chd_zlib_decompressor : public chd_decompressor
104{
105public:
106   // construction/destruction
107   chd_zlib_decompressor(chd_file &chd, bool lossy);
108   ~chd_zlib_decompressor();
109
110   // core functionality
111   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen);
112
113private:
114   // internal state
115   z_stream            m_inflater;
116   chd_zlib_allocator      m_allocator;
117};
118
119
120// ======================> chd_lzma_allocator
121
122// allocation helper clas for zlib
123class chd_lzma_allocator : public ISzAlloc
124{
125public:
126   // construction/destruction
127   chd_lzma_allocator();
128   ~chd_lzma_allocator();
129
130private:
131   // internal helpers
132   static void *fast_alloc(void *p, size_t size);
133   static void fast_free(void *p, void *address);
134
135   static const int MAX_LZMA_ALLOCS = 64;
136   UINT32 *            m_allocptr[MAX_LZMA_ALLOCS];
137};
138
139
140// ======================> chd_lzma_compressor
141
142// LZMA compressor
143class chd_lzma_compressor : public chd_compressor
144{
145public:
146   // construction/destruction
147   chd_lzma_compressor(chd_file &chd, bool lossy);
148   ~chd_lzma_compressor();
149
150   // core functionality
151   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest);
152   
153   // helpers
154   static void configure_properties(CLzmaEncProps &props, chd_file &chd);
155
156private:
157   // internal state
158   CLzmaEncProps         m_props;
159   chd_lzma_allocator      m_allocator;
160};
161
162
163// ======================> chd_lzma_decompressor
164
165// LZMA decompressor
166class chd_lzma_decompressor : public chd_decompressor
167{
168public:
169   // construction/destruction
170   chd_lzma_decompressor(chd_file &chd, bool lossy);
171   ~chd_lzma_decompressor();
172
173   // core functionality
174   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen);
175
176private:
177   // internal state
178   CLzmaProps            m_props;
179   CLzmaDec            m_decoder;
180   chd_lzma_allocator      m_allocator;
181};
182
183
184// ======================> chd_huffman_compressor
185
186// Huffman compressor
187class chd_huffman_compressor : public chd_compressor
188{
189public:
190   // construction/destruction
191   chd_huffman_compressor(chd_file &chd, bool lossy);
192
193   // core functionality
194   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest);
195
196private:
197   // internal state
198   huffman_8bit_encoder   m_encoder;
199};
200
201
202// ======================> chd_huffman_decompressor
203
204// Huffman decompressor
205class chd_huffman_decompressor : public chd_decompressor
206{
207public:
208   // construction/destruction
209   chd_huffman_decompressor(chd_file &chd, bool lossy);
210
211   // core functionality
212   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen);
213
214private:
215   // internal state
216   huffman_8bit_decoder   m_decoder;
217};
218
219
220// ======================> chd_flac_compressor
221
222// FLAC compressor
223class chd_flac_compressor : public chd_compressor
224{
225public:
226   // construction/destruction
227   chd_flac_compressor(chd_file &chd, bool lossy, bool bigendian);
228
229   // core functionality
230   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest);
231
232private:
233   // internal state
234   bool         m_swap_endian;
235   flac_encoder   m_encoder;
236};
237
238// big-endian variant
239class chd_flac_compressor_be : public chd_flac_compressor
240{
241public:
242   // construction/destruction
243   chd_flac_compressor_be(chd_file &chd, bool lossy)
244      : chd_flac_compressor(chd, lossy, true) { }
245};
246
247// little-endian variant
248class chd_flac_compressor_le : public chd_flac_compressor
249{
250public:
251   // construction/destruction
252   chd_flac_compressor_le(chd_file &chd, bool lossy)
253      : chd_flac_compressor(chd, lossy, false) { }
254};
255
256
257// ======================> chd_flac_decompressor
258
259// FLAC decompressor
260class chd_flac_decompressor : public chd_decompressor
261{
262public:
263   // construction/destruction
264   chd_flac_decompressor(chd_file &chd, bool lossy, bool bigendian);
265
266   // core functionality
267   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen);
268
269private:
270   // internal state
271   bool         m_swap_endian;
272   flac_decoder   m_decoder;
273};
274
275// big-endian variant
276class chd_flac_decompressor_be : public chd_flac_decompressor
277{
278public:
279   // construction/destruction
280   chd_flac_decompressor_be(chd_file &chd, bool lossy)
281      : chd_flac_decompressor(chd, lossy, true) { }
282};
283
284// little-endian variant
285class chd_flac_decompressor_le : public chd_flac_decompressor
286{
287public:
288   // construction/destruction
289   chd_flac_decompressor_le(chd_file &chd, bool lossy)
290      : chd_flac_decompressor(chd, lossy, false) { }
291};
292
293
294// ======================> chd_avhuff_compressor
295
296// A/V compressor
297class chd_avhuff_compressor : public chd_compressor
298{
299public:
300   // construction/destruction
301   chd_avhuff_compressor(chd_file &chd, bool lossy);
302   
303   // core functionality
304   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest);
305
306private:
307   // internal helpers
308   void postinit();
309
310   // internal state
311   avhuff_encoder            m_encoder;
312   bool                  m_postinit;
313};
314
315
316// ======================> chd_avhuff_decompressor
317
318// A/V decompressor
319class chd_avhuff_decompressor : public chd_decompressor
320{
321public:
322   // construction/destruction
323   chd_avhuff_decompressor(chd_file &chd, bool lossy);
324   
325   // core functionality
326   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen);
327   virtual void configure(int param, void *config);
328
329private:
330   // internal state
331   avhuff_decoder            m_decoder;
332};
333
334
335
336//**************************************************************************
337//  CODEC LIST
338//**************************************************************************
339
340// static list of available known codecs
341const chd_codec_list::codec_entry chd_codec_list::s_codec_list[] =
342{
343   { CHD_CODEC_ZLIB,      false,   "Deflate",            &chd_codec_list::construct_compressor<chd_zlib_compressor>,      &chd_codec_list::construct_decompressor<chd_zlib_decompressor> },
344   { CHD_CODEC_LZMA,      false,   "LZMA",               &chd_codec_list::construct_compressor<chd_lzma_compressor>,      &chd_codec_list::construct_decompressor<chd_lzma_decompressor> },
345   { CHD_CODEC_HUFFMAN,   false,   "Huffman",            &chd_codec_list::construct_compressor<chd_huffman_compressor>,   &chd_codec_list::construct_decompressor<chd_huffman_decompressor> },
346   { CHD_CODEC_FLAC_BE,   false,   "FLAC, big-endian",      &chd_codec_list::construct_compressor<chd_flac_compressor_be>,   &chd_codec_list::construct_decompressor<chd_flac_decompressor_be> },
347   { CHD_CODEC_FLAC_LE,   false,   "FLAC, little-endian",   &chd_codec_list::construct_compressor<chd_flac_compressor_le>,   &chd_codec_list::construct_decompressor<chd_flac_decompressor_le> },
348   { CHD_CODEC_AVHUFF,      false,   "A/V Huffman",         &chd_codec_list::construct_compressor<chd_avhuff_compressor>,   &chd_codec_list::construct_decompressor<chd_avhuff_decompressor> },
349};
350
351
352
353//**************************************************************************
354//  CHD CODEC
355//**************************************************************************
356
357//-------------------------------------------------
358//  chd_codec - constructor
359//-------------------------------------------------
360
361chd_codec::chd_codec(chd_file &file, bool lossy)
362   : m_chd(file),
363     m_lossy(lossy)
364{
365}
366
367
368//-------------------------------------------------
369//  ~chd_codec - destructor
370//-------------------------------------------------
371
372chd_codec::~chd_codec()
373{
374}
375   
376
377//-------------------------------------------------
378//  configure - configuration
379//-------------------------------------------------
380
381void chd_codec::configure(int param, void *config)
382{
383   // if not overridden, it is always a failure
384   throw CHDERR_INVALID_PARAMETER;
385}
386
387
388
389//**************************************************************************
390//  CHD COMPRESSOR
391//**************************************************************************
392
393//-------------------------------------------------
394//  chd_compressor - constructor
395//-------------------------------------------------
396
397chd_compressor::chd_compressor(chd_file &file, bool lossy)
398   : chd_codec(file, lossy)
399{
400}
401
402
403
404//**************************************************************************
405//  CHD DECOMPRESSOR
406//**************************************************************************
407
408//-------------------------------------------------
409//  chd_decompressor - constructor
410//-------------------------------------------------
411
412chd_decompressor::chd_decompressor(chd_file &file, bool lossy)
413   : chd_codec(file, lossy)
414{
415}
416
417
418
419//**************************************************************************
420//  CHD CODEC LIST
421//**************************************************************************
422
423//-------------------------------------------------
424//  new_compressor - create a new compressor
425//  instance of the given type
426//-------------------------------------------------
427
428chd_compressor *chd_codec_list::new_compressor(chd_codec_type type, chd_file &file)
429{
430   // find in the list and construct the class
431   const codec_entry *entry = find_in_list(type);
432   return (entry == NULL) ? NULL : (*entry->m_construct_compressor)(file, entry->m_lossy);
433}
434
435
436//-------------------------------------------------
437//  new_compressor - create a new decompressor
438//  instance of the given type
439//-------------------------------------------------
440
441chd_decompressor *chd_codec_list::new_decompressor(chd_codec_type type, chd_file &file)
442{
443   // find in the list and construct the class
444   const codec_entry *entry = find_in_list(type);
445   return (entry == NULL) ? NULL : (*entry->m_construct_decompressor)(file, entry->m_lossy);
446}
447
448
449//-------------------------------------------------
450//  codec_name - return the name of the given
451//  codec
452//-------------------------------------------------
453
454const char *chd_codec_list::codec_name(chd_codec_type type)
455{
456   // find in the list and construct the class
457   const codec_entry *entry = find_in_list(type);
458   return (entry == NULL) ? NULL : entry->m_name;
459}
460
461
462//-------------------------------------------------
463//  find_in_list - create a new compressor
464//  instance of the given type
465//-------------------------------------------------
466
467const chd_codec_list::codec_entry *chd_codec_list::find_in_list(chd_codec_type type)
468{
469   // find in the list and construct the class
470   for (int listnum = 0; listnum < ARRAY_LENGTH(s_codec_list); listnum++)
471      if (s_codec_list[listnum].m_type == type)
472         return &s_codec_list[listnum];
473   return NULL;
474}
475
476
477
478//**************************************************************************
479//  CODEC INSTANCE
480//**************************************************************************
481
482//-------------------------------------------------
483//  chd_compressor_group - constructor
484//-------------------------------------------------
485
486chd_compressor_group::chd_compressor_group(chd_file &file, UINT32 compressor_list[4])
487   : m_hunkbytes(file.hunk_bytes()),
488     m_compress_test(m_hunkbytes)
489#if CHDCODEC_VERIFY_COMPRESSION
490     ,m_decompressed(m_hunkbytes)
491#endif
492{
493   // verify the compression types and initialize the codecs
494   for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compressor); codecnum++)
495   {
496      m_compressor[codecnum] = NULL;
497      if (compressor_list[codecnum] != CHD_CODEC_NONE)
498      {
499         m_compressor[codecnum] = chd_codec_list::new_compressor(compressor_list[codecnum], file);
500         if (m_compressor[codecnum] == NULL)
501            throw CHDERR_UNKNOWN_COMPRESSION;
502#if CHDCODEC_VERIFY_COMPRESSION
503         m_decompressor[codecnum] = chd_codec_list::new_decompressor(compressor_list[codecnum], file);
504         if (m_decompressor[codecnum] == NULL)
505            throw CHDERR_UNKNOWN_COMPRESSION;
506#endif
507      }
508   }
509}
510
511
512//-------------------------------------------------
513//  ~chd_compressor_group - destructor
514//-------------------------------------------------
515
516chd_compressor_group::~chd_compressor_group()
517{
518   // delete the codecs and the test buffer
519   for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compressor); codecnum++)
520      delete m_compressor[codecnum];
521}
522
523
524//-------------------------------------------------
525//  find_best_compressor - iterate over all codecs
526//  to determine which one produces the best
527//  compression for this hunk
528//-------------------------------------------------
529
530INT8 chd_compressor_group::find_best_compressor(const UINT8 *src, UINT8 *compressed, UINT32 &complen)
531{
532   // determine best compression technique
533   complen = m_hunkbytes;
534   INT8 compression = -1;
535   for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compressor); codecnum++)
536      if (m_compressor[codecnum] != NULL)
537      {
538         // attempt to compress, swallowing errors
539         try
540         {
541            // if this is the best one, copy the data into the permanent buffer
542            UINT32 compbytes = m_compressor[codecnum]->compress(src, m_hunkbytes, m_compress_test);
543#if CHDCODEC_VERIFY_COMPRESSION
544            try
545            {
546               memset(m_decompressed, 0, m_hunkbytes);
547               m_decompressor[codecnum]->decompress(m_compress_test, compbytes, m_decompressed, m_hunkbytes);
548            }
549            catch (...)
550            {
551            }
552           
553            if (memcmp(src, m_decompressed, m_hunkbytes) != 0)
554            {
555               compbytes = m_compressor[codecnum]->compress(src, m_hunkbytes, m_compress_test);
556               try
557               {
558                  m_decompressor[codecnum]->decompress(m_compress_test, compbytes, m_decompressed, m_hunkbytes);
559               }
560               catch (...)
561               {
562                  memset(m_decompressed, 0, m_hunkbytes);
563               }
564            }
565printf("   codec%d=%d bytes            \n", codecnum, compbytes);
566#endif
567            if (compbytes < complen)
568            {
569               compression = codecnum;
570               complen = compbytes;
571               memcpy(compressed, m_compress_test, compbytes);
572            }
573         }
574         catch (...) { }
575      }
576   
577   // if the best is none, copy it over
578   if (compression == -1)
579      memcpy(compressed, src, m_hunkbytes);
580   return compression;
581}
582   
583
584
585//**************************************************************************
586//  ZLIB ALLOCATOR HELPER
587//**************************************************************************
588
589//-------------------------------------------------
590//  chd_zlib_allocator - constructor
591//-------------------------------------------------
592
593chd_zlib_allocator::chd_zlib_allocator()
594{
595   // reset pointer list
596   memset(m_allocptr, 0, sizeof(m_allocptr));
597}
598
599
600//-------------------------------------------------
601//  ~chd_zlib_allocator - constructor
602//-------------------------------------------------
603
604chd_zlib_allocator::~chd_zlib_allocator()
605{
606   // free our memory
607   for (int memindex = 0; memindex < ARRAY_LENGTH(m_allocptr); memindex++)
608      delete[] m_allocptr[memindex];
609}
610
611
612//-------------------------------------------------
613//  install - configure the allocators for a
614//  stream
615//-------------------------------------------------
616
617void chd_zlib_allocator::install(z_stream &stream)
618{
619   stream.zalloc = &chd_zlib_allocator::fast_alloc;
620   stream.zfree = &chd_zlib_allocator::fast_free;
621   stream.opaque = this;
622}
623
624
625//-------------------------------------------------
626//  zlib_fast_alloc - fast malloc for ZLIB, which
627//  allocates and frees memory frequently
628//-------------------------------------------------
629
630voidpf chd_zlib_allocator::fast_alloc(voidpf opaque, uInt items, uInt size)
631{
632   chd_zlib_allocator *codec = reinterpret_cast<chd_zlib_allocator *>(opaque);
633
634   // compute the size, rounding to the nearest 1k
635   size = (size * items + 0x3ff) & ~0x3ff;
636
637   // reuse a hunk if we can
638   for (int scan = 0; scan < MAX_ZLIB_ALLOCS; scan++)
639   {
640      UINT32 *ptr = codec->m_allocptr[scan];
641      if (ptr != NULL && size == *ptr)
642      {
643         // set the low bit of the size so we don't match next time
644         *ptr |= 1;
645         return ptr + 1;
646      }
647   }
648
649   // alloc a new one and put it into the list
650   UINT32 *ptr = reinterpret_cast<UINT32 *>(new UINT8[size + sizeof(UINT32)]);
651   for (int scan = 0; scan < MAX_ZLIB_ALLOCS; scan++)
652      if (codec->m_allocptr[scan] == NULL)
653      {
654         codec->m_allocptr[scan] = ptr;
655         break;
656      }
657
658   // set the low bit of the size so we don't match next time
659   *ptr = size | 1;
660   return ptr + 1;
661}
662
663
664//-------------------------------------------------
665//  zlib_fast_free - fast free for ZLIB, which
666//  allocates and frees memory frequently
667//-------------------------------------------------
668
669void chd_zlib_allocator::fast_free(voidpf opaque, voidpf address)
670{
671   chd_zlib_allocator *codec = reinterpret_cast<chd_zlib_allocator *>(opaque);
672
673   // find the hunk
674   UINT32 *ptr = reinterpret_cast<UINT32 *>(address) - 1;
675   for (int scan = 0; scan < MAX_ZLIB_ALLOCS; scan++)
676      if (ptr == codec->m_allocptr[scan])
677      {
678         // clear the low bit of the size to allow matches
679         *ptr &= ~1;
680         return;
681      }
682}
683
684
685
686//**************************************************************************
687//  ZLIB COMPRESSOR
688//**************************************************************************
689
690//-------------------------------------------------
691//  chd_zlib_compressor - constructor
692//-------------------------------------------------
693
694chd_zlib_compressor::chd_zlib_compressor(chd_file &chd, bool lossy)
695   : chd_compressor(chd, lossy)
696{
697   // initialize the deflater
698   m_deflater.next_in = (Bytef *)this;   // bogus, but that's ok
699   m_deflater.avail_in = 0;
700   m_allocator.install(m_deflater);
701   int zerr = deflateInit2(&m_deflater, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
702
703   // convert errors
704   if (zerr == Z_MEM_ERROR)
705      throw std::bad_alloc();
706   else if (zerr != Z_OK)
707      throw CHDERR_CODEC_ERROR;
708}
709
710
711//-------------------------------------------------
712//  ~chd_zlib_compressor - destructor
713//-------------------------------------------------
714
715chd_zlib_compressor::~chd_zlib_compressor()
716{
717   deflateEnd(&m_deflater);
718}
719
720
721//-------------------------------------------------
722//  compress - compress data using the ZLIB codec
723//-------------------------------------------------
724
725UINT32 chd_zlib_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest)
726{
727   // reset the decompressor
728   m_deflater.next_in = const_cast<Bytef *>(src);
729   m_deflater.avail_in = srclen;
730   m_deflater.total_in = 0;
731   m_deflater.next_out = dest;
732   m_deflater.avail_out = srclen;
733   m_deflater.total_out = 0;
734   int zerr = deflateReset(&m_deflater);
735   if (zerr != Z_OK)
736      throw CHDERR_COMPRESSION_ERROR;
737
738   // do it
739   zerr = deflate(&m_deflater, Z_FINISH);
740
741   // if we ended up with more data than we started with, return an error
742   if (zerr != Z_STREAM_END || m_deflater.total_out >= srclen)
743      throw CHDERR_COMPRESSION_ERROR;
744
745   // otherwise, return the length
746   return m_deflater.total_out;
747}
748
749
750
751//**************************************************************************
752//  ZLIB DECOMPRESSOR
753//**************************************************************************
754
755//-------------------------------------------------
756//  chd_zlib_decompressor - constructor
757//-------------------------------------------------
758
759chd_zlib_decompressor::chd_zlib_decompressor(chd_file &chd, bool lossy)
760   : chd_decompressor(chd, lossy)
761{
762   // init the inflater first
763   m_inflater.next_in = (Bytef *)this;   // bogus, but that's ok
764   m_inflater.avail_in = 0;
765   m_allocator.install(m_inflater);
766   int zerr = inflateInit2(&m_inflater, -MAX_WBITS);
767
768   // convert errors
769   if (zerr == Z_MEM_ERROR)
770      throw std::bad_alloc();
771   else if (zerr != Z_OK)
772      throw CHDERR_CODEC_ERROR;
773}
774
775
776//-------------------------------------------------
777//  ~chd_zlib_decompressor - destructor
778//-------------------------------------------------
779
780chd_zlib_decompressor::~chd_zlib_decompressor()
781{
782   inflateEnd(&m_inflater);
783}
784
785
786//-------------------------------------------------
787//  decompress - decompress data using the ZLIB
788//  codec
789//-------------------------------------------------
790
791void chd_zlib_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen)
792{
793   // reset the decompressor
794   m_inflater.next_in = const_cast<Bytef *>(src);
795   m_inflater.avail_in = complen;
796   m_inflater.total_in = 0;
797   m_inflater.next_out = dest;
798   m_inflater.avail_out = destlen;
799   m_inflater.total_out = 0;
800   int zerr = inflateReset(&m_inflater);
801   if (zerr != Z_OK)
802      throw CHDERR_DECOMPRESSION_ERROR;
803
804   // do it
805   zerr = inflate(&m_inflater, Z_FINISH);
806   if (m_inflater.total_out != destlen)
807      throw CHDERR_DECOMPRESSION_ERROR;
808}
809
810
811
812//**************************************************************************
813//  LZMA ALLOCATOR HELPER
814//**************************************************************************
815
816//-------------------------------------------------
817//  chd_lzma_allocator - constructor
818//-------------------------------------------------
819
820chd_lzma_allocator::chd_lzma_allocator()
821{
822   // reset pointer list
823   memset(m_allocptr, 0, sizeof(m_allocptr));
824   
825   // set our pointers
826   Alloc = &chd_lzma_allocator::fast_alloc;
827   Free = &chd_lzma_allocator::fast_free;
828}
829
830
831//-------------------------------------------------
832//  ~chd_lzma_allocator - constructor
833//-------------------------------------------------
834
835chd_lzma_allocator::~chd_lzma_allocator()
836{
837   // free our memory
838   for (int memindex = 0; memindex < ARRAY_LENGTH(m_allocptr); memindex++)
839      delete[] m_allocptr[memindex];
840}
841
842
843//-------------------------------------------------
844//  lzma_fast_alloc - fast malloc for lzma, which
845//  allocates and frees memory frequently
846//-------------------------------------------------
847
848void *chd_lzma_allocator::fast_alloc(void *p, size_t size)
849{
850   chd_lzma_allocator *codec = reinterpret_cast<chd_lzma_allocator *>(p);
851
852   // compute the size, rounding to the nearest 1k
853   size = (size + 0x3ff) & ~0x3ff;
854
855   // reuse a hunk if we can
856   for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
857   {
858      UINT32 *ptr = codec->m_allocptr[scan];
859      if (ptr != NULL && size == *ptr)
860      {
861         // set the low bit of the size so we don't match next time
862         *ptr |= 1;
863         return ptr + 1;
864      }
865   }
866
867   // alloc a new one and put it into the list
868   UINT32 *ptr = reinterpret_cast<UINT32 *>(new UINT8[size + sizeof(UINT32)]);
869   for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
870      if (codec->m_allocptr[scan] == NULL)
871      {
872         codec->m_allocptr[scan] = ptr;
873         break;
874      }
875
876   // set the low bit of the size so we don't match next time
877   *ptr = size | 1;
878   return ptr + 1;
879}
880
881
882//-------------------------------------------------
883//  lzma_fast_free - fast free for lzma, which
884//  allocates and frees memory frequently
885//-------------------------------------------------
886
887void chd_lzma_allocator::fast_free(void *p, void *address)
888{
889   if (address == NULL)
890      return;
891     
892   chd_lzma_allocator *codec = reinterpret_cast<chd_lzma_allocator *>(p);
893
894   // find the hunk
895   UINT32 *ptr = reinterpret_cast<UINT32 *>(address) - 1;
896   for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
897      if (ptr == codec->m_allocptr[scan])
898      {
899         // clear the low bit of the size to allow matches
900         *ptr &= ~1;
901         return;
902      }
903}
904
905
906
907//**************************************************************************
908//  LZMA COMPRESSOR
909//**************************************************************************
910
911//-------------------------------------------------
912//  chd_lzma_compressor - constructor
913//-------------------------------------------------
914
915chd_lzma_compressor::chd_lzma_compressor(chd_file &chd, bool lossy)
916   : chd_compressor(chd, lossy)
917{
918   // initialize the properties
919   configure_properties(m_props, chd);
920}
921
922
923//-------------------------------------------------
924//  ~chd_lzma_compressor - destructor
925//-------------------------------------------------
926
927chd_lzma_compressor::~chd_lzma_compressor()
928{
929}
930
931
932//-------------------------------------------------
933//  compress - compress data using the LZMA codec
934//-------------------------------------------------
935
936UINT32 chd_lzma_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest)
937{
938   // allocate the encoder
939   CLzmaEncHandle encoder = LzmaEnc_Create(&m_allocator);
940   if (encoder == NULL)
941      throw CHDERR_COMPRESSION_ERROR;
942
943   try
944   {
945      // configure the encoder
946      SRes res = LzmaEnc_SetProps(encoder, &m_props);
947      if (res != SZ_OK)
948         throw CHDERR_COMPRESSION_ERROR;
949     
950      // run it
951      SizeT complen = srclen;
952      res = LzmaEnc_MemEncode(encoder, dest, &complen, src, srclen, 0, NULL, &m_allocator, &m_allocator);
953      if (res != SZ_OK)
954         throw CHDERR_COMPRESSION_ERROR;
955
956      // clean up
957      LzmaEnc_Destroy(encoder, &m_allocator, &m_allocator);
958      return complen;
959   }
960   catch (...)
961   {
962      // destroy before re-throwing
963      LzmaEnc_Destroy(encoder, &m_allocator, &m_allocator);
964      throw;
965   }
966}
967
968
969//-------------------------------------------------
970//  configure_properties - configure the LZMA
971//  codec
972//-------------------------------------------------
973
974void chd_lzma_compressor::configure_properties(CLzmaEncProps &props, chd_file &chd)
975{
976   LzmaEncProps_Init(&props);
977   props.level = 9;
978   props.reduceSize = chd.hunk_bytes();
979   LzmaEncProps_Normalize(&props);
980}
981
982
983
984//**************************************************************************
985//  LZMA DECOMPRESSOR
986//**************************************************************************
987
988//-------------------------------------------------
989//  chd_lzma_decompressor - constructor
990//-------------------------------------------------
991
992chd_lzma_decompressor::chd_lzma_decompressor(chd_file &chd, bool lossy)
993   : chd_decompressor(chd, lossy)
994{
995   // construct the decoder
996   LzmaDec_Construct(&m_decoder);
997
998   // configure the properties like the compressor did
999   CLzmaEncProps encoder_props;
1000   chd_lzma_compressor::configure_properties(encoder_props, chd);
1001   
1002   // convert to decoder properties
1003   CLzmaProps decoder_props;
1004   decoder_props.lc = encoder_props.lc;
1005   decoder_props.lp = encoder_props.lp;
1006   decoder_props.pb = encoder_props.pb;
1007   decoder_props.dicSize = encoder_props.dictSize;
1008   
1009   // do memory allocations
1010   SRes res = LzmaDec_Allocate_MAME(&m_decoder, &decoder_props, &m_allocator);
1011   if (res != SZ_OK)
1012      throw CHDERR_DECOMPRESSION_ERROR;
1013}
1014
1015
1016//-------------------------------------------------
1017//  ~chd_lzma_decompressor - destructor
1018//-------------------------------------------------
1019
1020chd_lzma_decompressor::~chd_lzma_decompressor()
1021{
1022   // free memory
1023   LzmaDec_Free(&m_decoder, &m_allocator);
1024}
1025
1026
1027//-------------------------------------------------
1028//  decompress - decompress data using the LZMA
1029//  codec
1030//-------------------------------------------------
1031
1032void chd_lzma_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen)
1033{
1034   // initialize
1035   LzmaDec_Init(&m_decoder);
1036   
1037   // decode
1038   SizeT consumedlen = complen;
1039   SizeT decodedlen = destlen;
1040   ELzmaStatus status;
1041   SRes res = LzmaDec_DecodeToBuf(&m_decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
1042   if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
1043      throw CHDERR_DECOMPRESSION_ERROR;
1044}
1045
1046
1047
1048//**************************************************************************
1049//  HUFFMAN COMPRESSOR
1050//**************************************************************************
1051
1052//-------------------------------------------------
1053//  chd_huffman_compressor - constructor
1054//-------------------------------------------------
1055
1056chd_huffman_compressor::chd_huffman_compressor(chd_file &chd, bool lossy)
1057   : chd_compressor(chd, lossy)
1058{
1059}
1060
1061
1062//-------------------------------------------------
1063//  compress - compress data using the Huffman
1064//  codec
1065//-------------------------------------------------
1066
1067UINT32 chd_huffman_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest)
1068{
1069   UINT32 complen;
1070   if (m_encoder.encode(src, srclen, dest, srclen, complen) != HUFFERR_NONE)
1071      throw CHDERR_COMPRESSION_ERROR;
1072   return complen;
1073}
1074
1075
1076
1077//**************************************************************************
1078//  HUFFMAN DECOMPRESSOR
1079//**************************************************************************
1080
1081//-------------------------------------------------
1082//  chd_huffman_decompressor - constructor
1083//-------------------------------------------------
1084
1085chd_huffman_decompressor::chd_huffman_decompressor(chd_file &chd, bool lossy)
1086   : chd_decompressor(chd, lossy)
1087{
1088}
1089
1090
1091//-------------------------------------------------
1092//  decompress - decompress data using the Huffman
1093//  codec
1094//-------------------------------------------------
1095
1096void chd_huffman_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen)
1097{
1098   if (m_decoder.decode(src, complen, dest, destlen) != HUFFERR_NONE)
1099      throw CHDERR_COMPRESSION_ERROR;
1100}
1101
1102
1103
1104//**************************************************************************
1105//  FLAC COMPRESSOR
1106//**************************************************************************
1107
1108//-------------------------------------------------
1109//  chd_flac_compressor - constructor
1110//-------------------------------------------------
1111
1112chd_flac_compressor::chd_flac_compressor(chd_file &chd, bool lossy, bool bigendian)
1113   : chd_compressor(chd, lossy)
1114{
1115   // determine whether we want native or swapped samples
1116   UINT16 native_endian = 0;
1117   *reinterpret_cast<UINT8 *>(&native_endian) = 1;
1118   if (native_endian == 1)
1119      m_swap_endian = bigendian;
1120   else
1121      m_swap_endian = !bigendian;
1122   
1123   // configure the encoder
1124   m_encoder.set_sample_rate(44100);
1125   m_encoder.set_num_channels(2);
1126   m_encoder.set_block_size(chd.hunk_bytes());
1127   m_encoder.set_strip_metadata(true);
1128}
1129
1130
1131//-------------------------------------------------
1132//  compress - compress data using the FLAC codec
1133//-------------------------------------------------
1134
1135UINT32 chd_flac_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest)
1136{
1137   // reset and encode
1138   m_encoder.reset(dest, chd().hunk_bytes());
1139   if (!m_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(src), srclen / 4, m_swap_endian))
1140      throw CHDERR_COMPRESSION_ERROR;
1141
1142   // finish up
1143   UINT32 complen = m_encoder.finish();
1144   if (complen >= chd().hunk_bytes())
1145      throw CHDERR_COMPRESSION_ERROR;
1146   return complen;
1147}
1148
1149
1150
1151//**************************************************************************
1152//  FLAC COMPRESSOR
1153//**************************************************************************
1154
1155//-------------------------------------------------
1156//  chd_flac_decompressor - constructor
1157//-------------------------------------------------
1158
1159chd_flac_decompressor::chd_flac_decompressor(chd_file &chd, bool lossy, bool bigendian)
1160   : chd_decompressor(chd, lossy)
1161{
1162   // determine whether we want native or swapped samples
1163   UINT16 native_endian = 0;
1164   *reinterpret_cast<UINT8 *>(&native_endian) = 1;
1165   if (native_endian == 1)
1166      m_swap_endian = bigendian;
1167   else
1168      m_swap_endian = !bigendian;
1169}
1170
1171
1172//-------------------------------------------------
1173//  decompress - decompress data using the FLAC
1174//  codec
1175//-------------------------------------------------
1176
1177void chd_flac_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen)
1178{
1179   // reset and decode
1180   if (!m_decoder.reset(44100, 2, chd().hunk_bytes() / 4, src, complen))
1181      throw CHDERR_DECOMPRESSION_ERROR;
1182   if (!m_decoder.decode_interleaved(reinterpret_cast<INT16 *>(dest), destlen / 4, m_swap_endian))
1183      throw CHDERR_DECOMPRESSION_ERROR;
1184
1185   // finish up
1186   m_decoder.finish();
1187}
1188
1189
1190
1191//**************************************************************************
1192//  AVHUFF COMPRESSOR
1193//**************************************************************************
1194
1195//-------------------------------------------------
1196//  chd_avhuff_compressor - constructor
1197//-------------------------------------------------
1198
1199chd_avhuff_compressor::chd_avhuff_compressor(chd_file &chd, bool lossy)
1200   : chd_compressor(chd, lossy),
1201     m_postinit(false)
1202{
1203   try
1204   {
1205      // attempt to do a post-init now
1206      postinit();
1207   }
1208   catch (chd_error &)
1209   {
1210      // if we're creating a new CHD, it won't work but that's ok
1211   }
1212}
1213
1214
1215//-------------------------------------------------
1216//  compress - compress data using the A/V codec
1217//-------------------------------------------------
1218
1219UINT32 chd_avhuff_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest)
1220{
1221   // if we haven't yet set up the avhuff code, do it now
1222   if (!m_postinit)
1223      postinit();
1224
1225   // make sure short frames are padded with 0
1226   if (src != NULL)
1227   {
1228      int size = avhuff_encoder::raw_data_size(src);
1229      while (size < srclen)
1230         if (src[size++] != 0)
1231            throw CHDERR_INVALID_DATA;
1232   }
1233
1234   // encode the audio and video
1235   UINT32 complen;
1236   avhuff_error averr = m_encoder.encode_data(src, dest, complen);
1237   if (averr != AVHERR_NONE || complen > srclen)
1238      throw CHDERR_COMPRESSION_ERROR;
1239   return complen;
1240}
1241
1242
1243//-------------------------------------------------
1244//  postinit - actual initialization of avhuff
1245//  happens here, on the first attempt to compress
1246//  or decompress data
1247//-------------------------------------------------
1248
1249void chd_avhuff_compressor::postinit()
1250{
1251   // get the metadata
1252   astring metadata;
1253   chd_error err = chd().read_metadata(AV_METADATA_TAG, 0, metadata);
1254   if (err != CHDERR_NONE)
1255      throw err;
1256
1257   // extract the info
1258   int fps, fpsfrac, width, height, interlaced, channels, rate;
1259   if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
1260      throw CHDERR_INVALID_METADATA;
1261
1262   // compute the bytes per frame
1263   UINT32 fps_times_1million = fps * 1000000 + fpsfrac;
1264   UINT32 max_samples_per_frame = (UINT64(rate) * 1000000 + fps_times_1million - 1) / fps_times_1million;
1265   UINT32 bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2;
1266   if (bytes_per_frame > chd().hunk_bytes())
1267      throw CHDERR_INVALID_METADATA;
1268
1269   // done with post-init
1270   m_postinit = true;
1271}
1272
1273
1274
1275//**************************************************************************
1276//  AVHUFF DECOMPRESSOR
1277//**************************************************************************
1278
1279//-------------------------------------------------
1280//  chd_avhuff_decompressor - constructor
1281//-------------------------------------------------
1282
1283chd_avhuff_decompressor::chd_avhuff_decompressor(chd_file &chd, bool lossy)
1284   : chd_decompressor(chd, lossy)
1285{
1286}
1287
1288
1289//-------------------------------------------------
1290//  decompress - decompress data using the A/V
1291//  codec
1292//-------------------------------------------------
1293
1294void chd_avhuff_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen)
1295{
1296   // decode the audio and video
1297   avhuff_error averr = m_decoder.decode_data(src, complen, dest);
1298   if (averr != AVHERR_NONE)
1299      throw CHDERR_DECOMPRESSION_ERROR;
1300
1301   // pad short frames with 0
1302   if (dest != NULL)
1303   {
1304      int size = avhuff_encoder::raw_data_size(dest);
1305      if (size < destlen)
1306         memset(dest + size, 0, destlen - size);
1307   }
1308}
1309
1310
1311//-------------------------------------------------
1312//  config - codec-specific configuration for the
1313//  A/V codec
1314//-------------------------------------------------
1315
1316void chd_avhuff_decompressor::configure(int param, void *config)
1317{
1318   // if we're getting the decompression configuration, apply it now
1319   if (param == AVHUFF_CODEC_DECOMPRESS_CONFIG)
1320      m_decoder.configure(*reinterpret_cast<avhuff_decompress_config *>(config));
1321   
1322   // anything else is invalid
1323   else
1324      throw CHDERR_INVALID_PARAMETER;
1325}
src/lib/util/chdcodec.h
r0r14482
1/***************************************************************************
2
3    chdcodec.h
4
5    Codecs used by the CHD format
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __CHDCODEC_H__
43#define __CHDCODEC_H__
44
45#include "osdcore.h"
46
47
48#define CHDCODEC_VERIFY_COMPRESSION 0
49
50
51//**************************************************************************
52//  MACROS
53//**************************************************************************
54
55#define CHD_MAKE_TAG(a,b,c,d)      (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
56
57
58
59//**************************************************************************
60//  TYPE DEFINITIONS
61//**************************************************************************
62
63// forward references
64class chd_file;
65
66// base types
67typedef UINT32 chd_codec_type;
68
69
70// ======================> chd_codec
71
72// common base class for all compressors and decompressors
73class chd_codec
74{
75protected:
76   // can't create these directly
77   chd_codec(chd_file &file, bool lossy);
78   
79public:
80   // allow public deletion
81   virtual ~chd_codec();
82
83   // accessors
84   chd_file &chd() const { return m_chd; }
85   bool lossy() const { return m_lossy; }
86
87   // implementation
88   virtual void configure(int param, void *config);
89
90private:
91   // internal state
92   chd_file &         m_chd;
93   bool            m_lossy;
94};
95
96
97// ======================> chd_compressor
98
99// base class for all compressors
100class chd_compressor : public chd_codec
101{
102protected:
103   // can't create these directly
104   chd_compressor(chd_file &file, bool lossy);
105
106public:
107   // implementation
108   virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest) = 0;
109};
110
111
112// ======================> chd_decompressor
113
114// base class for all decompressors
115class chd_decompressor : public chd_codec
116{
117protected:
118   // can't create these directly
119   chd_decompressor(chd_file &file, bool lossy);
120
121public:
122   // implementation
123   virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen) = 0;
124};
125
126
127// ======================> chd_codec_list
128
129// wrapper to get at the list of codecs
130class chd_codec_list
131{
132public:
133   // create compressors or decompressors
134   static chd_compressor *new_compressor(chd_codec_type type, chd_file &file);
135   static chd_decompressor *new_decompressor(chd_codec_type type, chd_file &file);
136   
137   // utilities
138   static bool codec_exists(chd_codec_type type) { return (find_in_list(type) != NULL); }
139   static const char *codec_name(chd_codec_type type);
140
141private:
142   // an entry in the list
143   struct codec_entry
144   {
145      chd_codec_type      m_type;
146      bool            m_lossy;
147      const char *      m_name;
148      chd_compressor *   (*m_construct_compressor)(chd_file &, bool);
149      chd_decompressor *   (*m_construct_decompressor)(chd_file &, bool);
150   };
151
152   // internal helper functions
153   static const codec_entry *find_in_list(chd_codec_type type);
154   
155   template<class _CompressorClass>
156   static chd_compressor *construct_compressor(chd_file &chd, bool lossy) { return new _CompressorClass(chd, lossy); }
157
158   template<class _DecompressorClass>
159   static chd_decompressor *construct_decompressor(chd_file &chd, bool lossy) { return new _DecompressorClass(chd, lossy); }
160
161   // the static list
162   static const codec_entry s_codec_list[];
163};
164
165
166// ======================> chd_compressor_group
167
168// helper class that wraps several compressors
169class chd_compressor_group
170{
171public:
172   // construction/destruction
173   chd_compressor_group(chd_file &file, chd_codec_type compressor_list[4]);
174   ~chd_compressor_group();
175   
176   // find the best compressor
177   INT8 find_best_compressor(const UINT8 *src, UINT8 *compressed, UINT32 &complen);
178   
179private:
180   // internal state
181   UINT32               m_hunkbytes;      // number of bytes in a hunk
182   chd_compressor *      m_compressor[4];   // array of active codecs
183   dynamic_buffer         m_compress_test;   // test buffer for compression
184#if CHDCODEC_VERIFY_COMPRESSION
185   chd_decompressor *      m_decompressor[4];   // array of active codecs
186   dynamic_buffer         m_decompressed;      // verification buffer
187#endif
188};
189
190
191
192//**************************************************************************
193//  CONSTANTS
194//**************************************************************************
195
196// currently-defined codecs
197const chd_codec_type CHD_CODEC_NONE    = 0;
198const chd_codec_type CHD_CODEC_ZLIB    = CHD_MAKE_TAG('z','l','i','b');
199const chd_codec_type CHD_CODEC_LZMA    = CHD_MAKE_TAG('l','z','m','a');
200const chd_codec_type CHD_CODEC_HUFFMAN    = CHD_MAKE_TAG('h','u','f','f');
201const chd_codec_type CHD_CODEC_FLAC_BE    = CHD_MAKE_TAG('f','l','c','b');
202const chd_codec_type CHD_CODEC_FLAC_LE    = CHD_MAKE_TAG('f','l','c','l');
203const chd_codec_type CHD_CODEC_AVHUFF   = CHD_MAKE_TAG('a','v','h','u');
204
205// A/V codec configuration parameters
206enum
207{
208   AVHUFF_CODEC_DECOMPRESS_CONFIG = 1
209};
210
211
212#endif // __CHDCODEC_H__
src/lib/util/chdcd.c
r14481r14482
304304    chdcd_parse_toc - parse a CDRWin format CUE file
305305-------------------------------------------------*/
306306
307chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo)
307chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
308308{
309309   FILE *infile;
310310   unsigned char buffer[12];
r14481r14482
322322   }
323323
324324   /* clear structures */
325   memset(outtoc, 0, sizeof(cdrom_toc));
326   memset(outinfo, 0, sizeof(chdcd_track_input_info));
325   memset(&outtoc, 0, sizeof(outtoc));
326   outinfo.reset();
327327
328328   // seek to 12 bytes before the end
329329   fseek(infile, -12, SEEK_END);
r14481r14482
372372
373373//          printf("TOC type: %08x.  Start track %d  End track: %d\n", toc_type, start, end);
374374
375         outtoc->numtrks = (end-start) + 1;
375         outtoc.numtrks = (end-start) + 1;
376376
377377         offset = 0;
378378         for (track = start; track <= end; track++)
r14481r14482
388388            index2 = read_uint64(infile);
389389
390390//              printf("Track %d: sector size %d mode %x index0 %llx index1 %llx index2 %llx (pregap %d sectors, length %d sectors)\n", track, size, mode, index0, index1, index2, (UINT32)(index1-index0)/size, (UINT32)(index2-index1)/size);
391            strncpy(outinfo->fname[track-1], path.cstr(), 256);
392            strncat(outinfo->fname[track-1], tocfname, 256);
393            outinfo->offset[track-1] = offset + (UINT32)(index1-index0);
394            outinfo->idx0offs[track-1] = 0;
395            outinfo->idx1offs[track-1] = 0;
391            outinfo.track[track-1].fname.cpy(path.cstr()).cat(tocfname);
392            outinfo.track[track-1].offset = offset + (UINT32)(index1-index0);
393            outinfo.track[track-1].idx0offs = 0;
394            outinfo.track[track-1].idx1offs = 0;
396395
397396            switch (mode>>24)
398397            {
399398               case 0x00:   // 2048 byte data
400                  outtoc->tracks[track-1].trktype = CD_TRACK_MODE1;
401                  outinfo->swap[track-1] = 0;
399                  outtoc.tracks[track-1].trktype = CD_TRACK_MODE1;
400                  outinfo.track[track-1].swap = false;
402401                  break;
403402
404403               case 0x06:   // 2352 byte mode 2 raw
405                  outtoc->tracks[track-1].trktype = CD_TRACK_MODE2_RAW;
406                  outinfo->swap[track-1] = 0;
404                  outtoc.tracks[track-1].trktype = CD_TRACK_MODE2_RAW;
405                  outinfo.track[track-1].swap = false;
407406                  break;
408407
409408               case 0x07:   // 2352 byte audio
410                  outtoc->tracks[track-1].trktype = CD_TRACK_AUDIO;
411                  outinfo->swap[track-1] = 1;
409                  outtoc.tracks[track-1].trktype = CD_TRACK_AUDIO;
410                  outinfo.track[track-1].swap = true;
412411                  break;
413412
414413               default:
r14481r14482
416415                  break;
417416            }
418417
419            outtoc->tracks[track-1].datasize = size;
418            outtoc.tracks[track-1].datasize = size;
420419
421            outtoc->tracks[track-1].subtype = CD_SUB_NONE;
422            outtoc->tracks[track-1].subsize = 0;
420            outtoc.tracks[track-1].subtype = CD_SUB_NONE;
421            outtoc.tracks[track-1].subsize = 0;
423422
424            outtoc->tracks[track-1].pregap = (UINT32)(index1-index0)/size;
425            outtoc->tracks[track-1].frames = (UINT32)(index2-index1)/size;
426            outtoc->tracks[track-1].postgap = 0;
427            outtoc->tracks[track-1].pgtype = 0;
428            outtoc->tracks[track-1].pgsub = CD_SUB_NONE;
429            outtoc->tracks[track-1].pgdatasize = 0;
430            outtoc->tracks[track-1].pgsubsize = 0;
423            outtoc.tracks[track-1].pregap = (UINT32)(index1-index0)/size;
424            outtoc.tracks[track-1].frames = (UINT32)(index2-index1)/size;
425            outtoc.tracks[track-1].postgap = 0;
426            outtoc.tracks[track-1].pgtype = 0;
427            outtoc.tracks[track-1].pgsub = CD_SUB_NONE;
428            outtoc.tracks[track-1].pgdatasize = 0;
429            outtoc.tracks[track-1].pgsubsize = 0;
431430
432431            offset += (UINT32)index2-index1;
433432         }
r14481r14482
452451    chdcd_parse_gdi - parse a Sega GD-ROM rip
453452-------------------------------------------------*/
454453
455static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo)
454static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
456455{
457456   FILE *infile;
458457   int i, numtracks;
r14481r14482
469468   }
470469
471470   /* clear structures */
472   memset(outtoc, 0, sizeof(cdrom_toc));
473   memset(outinfo, 0, sizeof(chdcd_track_input_info));
471   memset(&outtoc, 0, sizeof(outtoc));
472   outinfo.reset();
474473
475474
476475   fgets(linebuffer,511,infile);
r14481r14482
491490
492491      trknum=atoi(tok)-1;
493492
494      outinfo->swap[trknum]=0;
495      outinfo->offset[trknum]=0;
493      outinfo.track[trknum].swap=false;
494      outinfo.track[trknum].offset=0;
496495
497      //outtoc->tracks[trknum].trktype = CD_TRACK_MODE1;
498      outtoc->tracks[trknum].datasize = 0;
499      outtoc->tracks[trknum].subtype = CD_SUB_NONE;
500      outtoc->tracks[trknum].subsize = 0;
496      //outtoc.tracks[trknum].trktype = CD_TRACK_MODE1;
497      outtoc.tracks[trknum].datasize = 0;
498      outtoc.tracks[trknum].subtype = CD_SUB_NONE;
499      outtoc.tracks[trknum].subsize = 0;
501500
502501      tok=strtok(NULL," ");
503      outtoc->tracks[trknum].physframeofs=atoi(tok);
502      outtoc.tracks[trknum].physframeofs=atoi(tok);
504503
505504      tok=strtok(NULL," ");
506505      trktype=atoi(tok);
r14481r14482
510509
511510      if(trktype==4 && trksize==2352)
512511      {
513         outtoc->tracks[trknum].trktype=CD_TRACK_MODE1_RAW;
514         outtoc->tracks[trknum].datasize=2352;
512         outtoc.tracks[trknum].trktype=CD_TRACK_MODE1_RAW;
513         outtoc.tracks[trknum].datasize=2352;
515514      }
516515      if(trktype==4 && trksize==2048)
517516      {
518         outtoc->tracks[trknum].trktype=CD_TRACK_MODE1;
519         outtoc->tracks[trknum].datasize=2048;
517         outtoc.tracks[trknum].trktype=CD_TRACK_MODE1;
518         outtoc.tracks[trknum].datasize=2048;
520519      }
521520      if(trktype==0)
522521      {
523522         //assert(trksize==2352);
524         outtoc->tracks[trknum].trktype=CD_TRACK_AUDIO;
525         outtoc->tracks[trknum].datasize=2352;
523         outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO;
524         outtoc.tracks[trknum].datasize=2352;
526525      }
527526
528527      astring name;
r14481r14482
539538         } while(tok!=NULL && (strrchr(tok,'"')-tok !=(strlen(tok)-1)));
540539         name = name.delchr('"');
541540      }
542      strncpy(outinfo->fname[trknum], path.cstr(), 256);
543      strncat(outinfo->fname[trknum], name, 256);
541      outinfo.track[trknum].fname.cpy(path.cstr()).cat(name);
544542
545      sz=get_file_size(outinfo->fname[trknum]);
543      sz=get_file_size(outinfo.track[trknum].fname);
546544
547      outtoc->tracks[trknum].frames=sz/trksize;
548      outtoc->tracks[trknum].extraframes=0;
545      outtoc.tracks[trknum].frames=sz/trksize;
546      outtoc.tracks[trknum].extraframes=0;
549547
550548      if(trknum!=0)
551549      {
552         int dif=outtoc->tracks[trknum].physframeofs-(outtoc->tracks[trknum-1].frames+outtoc->tracks[trknum-1].physframeofs);
553         outtoc->tracks[trknum-1].frames+=dif;
550         int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs);
551         outtoc.tracks[trknum-1].frames+=dif;
554552      }
555553
556554/*
557555        if(trknum!=0)
558556        {
559            outtoc->tracks[trknum-1].extraframes=outtoc->tracks[trknum].physframeofs-(outtoc->tracks[trknum-1].frames+outtoc->tracks[trknum-1].physframeofs);
557            outtoc.tracks[trknum-1].extraframes=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs);
560558        }
561559*/
562      hunks = (outtoc->tracks[trknum].frames+CD_FRAMES_PER_HUNK - 1) / CD_FRAMES_PER_HUNK;
563      outtoc->tracks[trknum].extraframes = hunks * CD_FRAMES_PER_HUNK - outtoc->tracks[trknum].frames;
560      hunks = (outtoc.tracks[trknum].frames+CD_FRAMES_PER_HUNK - 1) / CD_FRAMES_PER_HUNK;
561      outtoc.tracks[trknum].extraframes = hunks * CD_FRAMES_PER_HUNK - outtoc.tracks[trknum].frames;
564562
565      //chdpos+=outtoc->tracks[trknum].frames+outtoc->tracks[trknum].extraframes;
563      //chdpos+=outtoc.tracks[trknum].frames+outtoc.tracks[trknum].extraframes;
566564
567565   }
568566   /*
569567    for(i=0;i<numtracks;++i)
570568    {
571        printf("%s %d %d %d\n",outinfo->fname[i],outtoc->tracks[i].frames,outtoc->tracks[i].extraframes,outtoc->tracks[i].physframeofs);
569        printf("%s %d %d %d\n",outinfo.track[i].fname,outtoc.tracks[i].frames,outtoc.tracks[i].extraframes,outtoc.tracks[i].physframeofs);
572570    }
573571    */
574572   /* close the input TOC */
575573   fclose(infile);
576574
577575   /* store the number of tracks found */
578   outtoc->numtrks = numtracks;
576   outtoc.numtrks = numtracks;
579577
580578   return CHDERR_NONE;
581579}
r14481r14482
584582    chdcd_parse_toc - parse a CDRWin format CUE file
585583-------------------------------------------------*/
586584
587chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo)
585chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
588586{
589587   FILE *infile;
590588   int i, trknum;
r14481r14482
601599   }
602600
603601   /* clear structures */
604   memset(outtoc, 0, sizeof(cdrom_toc));
605   memset(outinfo, 0, sizeof(chdcd_track_input_info));
602   memset(&outtoc, 0, sizeof(outtoc));
603   outinfo.reset();
606604
607605   trknum = -1;
608606   wavoffs = wavlen = 0;
r14481r14482
633631
634632            if (!strcmp(token, "BINARY"))
635633            {
636               outinfo->swap[trknum] = 0;
634               outinfo.track[trknum].swap = false;
637635            }
638636            else if (!strcmp(token, "MOTOROLA"))
639637            {
640               outinfo->swap[trknum] = 1;
638               outinfo.track[trknum].swap = true;
641639            }
642640            else if (!strcmp(token, "WAVE"))
643641            {
r14481r14482
672670
673671            if (wavlen != 0)
674672            {
675               outtoc->tracks[trknum].trktype = CD_TRACK_AUDIO;
676               outtoc->tracks[trknum].frames = wavlen/2352;
677               outinfo->offset[trknum] = wavoffs;
673               outtoc.tracks[trknum].trktype = CD_TRACK_AUDIO;
674               outtoc.tracks[trknum].frames = wavlen/2352;
675               outinfo.track[trknum].offset = wavoffs;
678676               wavoffs = wavlen = 0;
679677            }
680678            else
681679            {
682               outtoc->tracks[trknum].trktype = CD_TRACK_MODE1;
683               outtoc->tracks[trknum].datasize = 0;
684               outinfo->offset[trknum] = 0;
680               outtoc.tracks[trknum].trktype = CD_TRACK_MODE1;
681               outtoc.tracks[trknum].datasize = 0;
682               outinfo.track[trknum].offset = 0;
685683            }
686            outtoc->tracks[trknum].subtype = CD_SUB_NONE;
687            outtoc->tracks[trknum].subsize = 0;
688            outtoc->tracks[trknum].pregap = 0;
689            outinfo->idx0offs[trknum] = -1;
690            outinfo->idx1offs[trknum] = 0;
684            outtoc.tracks[trknum].subtype = CD_SUB_NONE;
685            outtoc.tracks[trknum].subsize = 0;
686            outtoc.tracks[trknum].pregap = 0;
687            outinfo.track[trknum].idx0offs = -1;
688            outinfo.track[trknum].idx1offs = 0;
691689
692            strncpy(outinfo->fname[trknum], lastfname, 256); // default filename to the last one
693//              printf("trk %d: fname %s offset %d\n", trknum, &outinfo->fname[trknum][0], outinfo->offset[trknum]);
690            outinfo.track[trknum].fname.cpy(lastfname); // default filename to the last one
691//              printf("trk %d: fname %s offset %d\n", trknum, outinfo.track[trknum].fname.cstr(), outinfo.track[trknum].offset);
694692
695            cdrom_convert_type_string_to_track_info(token, &outtoc->tracks[trknum]);
696            if (outtoc->tracks[trknum].datasize == 0)
693            cdrom_convert_type_string_to_track_info(token, &outtoc.tracks[trknum]);
694            if (outtoc.tracks[trknum].datasize == 0)
697695            {
698696               printf("ERROR: Unknown track type [%s].  Contact MAMEDEV.\n", token);
699697               return CHDERR_FILE_NOT_FOUND;
r14481r14482
702700            /* next (optional) token on the line is the subcode type */
703701            TOKENIZE
704702
705            cdrom_convert_subtype_string_to_track_info(token, &outtoc->tracks[trknum]);
703            cdrom_convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]);
706704         }
707705         else if (!strcmp(token, "INDEX"))   /* only in bin/cue files */
708706         {
r14481r14482
718716
719717            if (idx == 0)
720718            {
721               outinfo->idx0offs[trknum] = frames;
719               outinfo.track[trknum].idx0offs = frames;
722720            }
723721            else if (idx == 1)
724722            {
725               outinfo->idx1offs[trknum] = frames;
726               if ((outtoc->tracks[trknum].pregap == 0) && (outinfo->idx0offs[trknum] != -1))
723               outinfo.track[trknum].idx1offs = frames;
724               if ((outtoc.tracks[trknum].pregap == 0) && (outinfo.track[trknum].idx0offs != -1))
727725               {
728                  outtoc->tracks[trknum].pregap = frames - outinfo->idx0offs[trknum];
726                  outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx0offs;
729727               }
730728            }
731729         }
r14481r14482
737735            TOKENIZE
738736            frames = msf_to_frames( token );
739737
740            outtoc->tracks[trknum].pregap = frames;
738            outtoc.tracks[trknum].pregap = frames;
741739         }
742740         else if (!strcmp(token, "POSTGAP"))
743741         {
r14481r14482
747745            TOKENIZE
748746            frames = msf_to_frames( token );
749747
750            outtoc->tracks[trknum].postgap = frames;
748            outtoc.tracks[trknum].postgap = frames;
751749         }
752750      }
753751   }
r14481r14482
756754   fclose(infile);
757755
758756   /* store the number of tracks found */
759   outtoc->numtrks = trknum + 1;
757   outtoc.numtrks = trknum + 1;
760758
761759   /* now go over the files again and set the lengths */
762   for (trknum = 0; trknum < outtoc->numtrks; trknum++)
760   for (trknum = 0; trknum < outtoc.numtrks; trknum++)
763761   {
764762      UINT64 tlen = 0;
765763
766764      // this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian
767      if (outtoc->tracks[trknum].trktype == CD_TRACK_AUDIO)
765      if (outtoc.tracks[trknum].trktype == CD_TRACK_AUDIO)
768766      {
769         outinfo->swap[trknum] = 1;
767         outinfo.track[trknum].swap = true;
770768      }
771769
772770      // don't do this for .WAV tracks, we already have their length and offset filled out
773      if (outinfo->offset[trknum] == 0)
771      if (outinfo.track[trknum].offset == 0)
774772      {
775773         // is this the last track?
776         if (trknum == (outtoc->numtrks-1))
774         if (trknum == (outtoc.numtrks-1))
777775         {
778776            /* if we have the same filename as the last track, do it that way */
779            if (!strcmp(&outinfo->fname[trknum][0], &outinfo->fname[trknum-1][0]))
777            if (outinfo.track[trknum].fname == outinfo.track[trknum-1].fname)
780778            {
781               tlen = get_file_size(outinfo->fname[trknum]);
779               tlen = get_file_size(outinfo.track[trknum].fname);
782780               if (tlen == 0)
783781               {
784                  printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum-1]);
782                  printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.cstr());
785783                  return CHDERR_FILE_NOT_FOUND;
786784               }
787               outinfo->offset[trknum] = outinfo->offset[trknum-1] + outtoc->tracks[trknum-1].frames * (outtoc->tracks[trknum-1].datasize + outtoc->tracks[trknum-1].subsize);
788               outtoc->tracks[trknum].frames = (tlen - outinfo->offset[trknum]) / (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
785               outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
786               outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
789787            }
790788            else   /* data files are different */
791789            {
792               tlen = get_file_size(outinfo->fname[trknum]);
790               tlen = get_file_size(outinfo.track[trknum].fname);
793791               if (tlen == 0)
794792               {
795                  printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum-1]);
793                  printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.cstr());
796794                  return CHDERR_FILE_NOT_FOUND;
797795               }
798               tlen /= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
799               outtoc->tracks[trknum].frames = tlen;
800               outinfo->offset[trknum] = 0;
796               tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
797               outtoc.tracks[trknum].frames = tlen;
798               outinfo.track[trknum].offset = 0;
801799            }
802800         }
803801         else
804802         {
805803            /* if we have the same filename as the next track, do it that way */
806            if (!strcmp(&outinfo->fname[trknum][0], &outinfo->fname[trknum+1][0]))
804            if (outinfo.track[trknum].fname == outinfo.track[trknum+1].fname)
807805            {
808               outtoc->tracks[trknum].frames = outinfo->idx1offs[trknum+1] - outinfo->idx1offs[trknum];
806               outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx1offs - outinfo.track[trknum].idx1offs;
809807
810808               if (trknum == 0)   // track 0 offset is 0
811809               {
812                  outinfo->offset[trknum] = 0;
810                  outinfo.track[trknum].offset = 0;
813811               }
814812               else
815813               {
816                  outinfo->offset[trknum] = outinfo->offset[trknum-1] + outtoc->tracks[trknum-1].frames * (outtoc->tracks[trknum-1].datasize + outtoc->tracks[trknum-1].subsize);
814                  outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
817815               }
818816
819               if (!outtoc->tracks[trknum].frames)
817               if (!outtoc.tracks[trknum].frames)
820818               {
821819                  printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1);
822820                  return CHDERR_FILE_NOT_FOUND;
r14481r14482
824822            }
825823            else   /* data files are different */
826824            {
827               tlen = get_file_size(outinfo->fname[trknum]);
825               tlen = get_file_size(outinfo.track[trknum].fname);
828826               if (tlen == 0)
829827               {
830                  printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum]);
828                  printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.cstr());
831829                  return CHDERR_FILE_NOT_FOUND;
832830               }
833               tlen /= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
834               outtoc->tracks[trknum].frames = tlen;
835               outinfo->offset[trknum] = 0;
831               tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
832               outtoc.tracks[trknum].frames = tlen;
833               outinfo.track[trknum].offset = 0;
836834            }
837835         }
838836      }
839      printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc->tracks[trknum].frames, outinfo->offset[trknum]);
837      printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc.tracks[trknum].frames, outinfo.track[trknum].offset);
840838   }
841839
842840   return CHDERR_NONE;
r14481r14482
846844    chdcd_parse_toc - parse a CDRDAO format TOC file
847845-------------------------------------------------*/
848846
849chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo)
847chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
850848{
851849   FILE *infile;
852850   int i, trknum;
r14481r14482
885883   }
886884
887885   /* clear structures */
888   memset(outtoc, 0, sizeof(cdrom_toc));
889   memset(outinfo, 0, sizeof(chdcd_track_input_info));
886   memset(&outtoc, 0, sizeof(outtoc));
887   outinfo.reset();
890888
891889   trknum = -1;
892890
r14481r14482
910908            TOKENIZE
911909
912910            /* keep the filename */
913            strncpy(outinfo->fname[trknum], path.cstr(), 256);
914            strncat(outinfo->fname[trknum], token, 256);
911            outinfo.track[trknum].fname.cpy(path.cstr()).cat(token);
915912
916913            /* get either the offset or the length */
917914            TOKENIZE
r14481r14482
920917            {
921918               TOKENIZE
922919
923               outinfo->swap[trknum] = 1;
920               outinfo.track[trknum].swap = true;
924921            }
925922            else
926923            {
927               outinfo->swap[trknum] = 0;
924               outinfo.track[trknum].swap = false;
928925            }
929926
930927            if (token[0] == '#')
r14481r14482
937934               /* convert the time to an offset */
938935               f = msf_to_frames( token );
939936
940               f *= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
937               f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
941938            }
942939            else
943940            {
944941               f = 0;
945942            }
946943
947            outinfo->offset[trknum] = f;
944            outinfo.track[trknum].offset = f;
948945
949946            TOKENIZE
950947
r14481r14482
958955               if (isdigit((UINT8)token[0]))
959956               {
960957                  // it was an offset.
961                  f *= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
958                  f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
962959
963                  outinfo->offset[trknum] += f;
960                  outinfo.track[trknum].offset += f;
964961
965962                  // this is the length.
966963                  f = msf_to_frames( token );
967964               }
968965            }
969            else if( trknum == 0 && outinfo->offset[trknum] != 0 )
966            else if( trknum == 0 && outinfo.track[trknum].offset != 0 )
970967            {
971968               /* the 1st track might have a length with no offset */
972               f = outinfo->offset[trknum] / (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize);
973               outinfo->offset[trknum] = 0;
969               f = outinfo.track[trknum].offset / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
970               outinfo.track[trknum].offset = 0;
974971            }
975972            else
976973            {
r14481r14482
978975               f = 0;
979976            }
980977
981            outtoc->tracks[trknum].frames = f;
978            outtoc.tracks[trknum].frames = f;
982979         }
983980         else if (!strcmp(token, "TRACK"))
984981         {
r14481r14482
987984            /* next token on the line is the track type */
988985            TOKENIZE
989986
990            outtoc->tracks[trknum].trktype = CD_TRACK_MODE1;
991            outtoc->tracks[trknum].datasize = 0;
992            outtoc->tracks[trknum].subtype = CD_SUB_NONE;
993            outtoc->tracks[trknum].subsize = 0;
987            outtoc.tracks[trknum].trktype = CD_TRACK_MODE1;
988            outtoc.tracks[trknum].datasize = 0;
989            outtoc.tracks[trknum].subtype = CD_SUB_NONE;
990            outtoc.tracks[trknum].subsize = 0;
994991
995            cdrom_convert_type_string_to_track_info(token, &outtoc->tracks[trknum]);
996            if (outtoc->tracks[trknum].datasize == 0)
992            cdrom_convert_type_string_to_track_info(token, &outtoc.tracks[trknum]);
993            if (outtoc.tracks[trknum].datasize == 0)
997994            {
998995               printf("ERROR: Unknown track type [%s].  Contact MAMEDEV.\n", token);
999996               return CHDERR_FILE_NOT_FOUND;
r14481r14482
1002999            /* next (optional) token on the line is the subcode type */
10031000            TOKENIZE
10041001
1005            cdrom_convert_subtype_string_to_track_info(token, &outtoc->tracks[trknum]);
1002            cdrom_convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]);
10061003         }
10071004         else if (!strcmp(token, "START"))
10081005         {
r14481r14482
10121009            TOKENIZE
10131010            frames = msf_to_frames( token );
10141011
1015            outtoc->tracks[trknum].pregap = frames;
1012            outtoc.tracks[trknum].pregap = frames;
10161013         }
10171014      }
10181015   }
r14481r14482
10211018   fclose(infile);
10221019
10231020   /* store the number of tracks found */
1024   outtoc->numtrks = trknum + 1;
1021   outtoc.numtrks = trknum + 1;
10251022
10261023   return CHDERR_NONE;
10271024}
src/lib/util/chdcd.h
r14481r14482
1414
1515#include "cdrom.h"
1616
17typedef struct _chdcd_track_input_info chdcd_track_input_info;
18struct _chdcd_track_input_info   /* used only at compression time */
17struct chdcd_track_input_entry
1918{
20   char fname[CD_MAX_TRACKS][256];   /* filename for each track */
21   UINT32 offset[CD_MAX_TRACKS];   /* offset in the data file for each track */
22   int swap[CD_MAX_TRACKS];   /* data needs to be byte swapped */
23   UINT32 idx0offs[CD_MAX_TRACKS];
24   UINT32 idx1offs[CD_MAX_TRACKS];
19   chdcd_track_input_entry() { reset(); }
20   void reset() { fname.reset(); offset = idx0offs = idx1offs = 0; swap = false; }
21
22   astring fname;      // filename for each track
23   UINT32 offset;      // offset in the data file for each track
24   bool swap;         // data needs to be byte swapped
25   UINT32 idx0offs;
26   UINT32 idx1offs;
2527};
2628
29struct chdcd_track_input_info
30{
31   void reset() { for (int i = 0; i < CD_MAX_TRACKS; i++) track[i].reset(); }
2732
28chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo);
33   chdcd_track_input_entry track[CD_MAX_TRACKS];
34};
2935
36
37chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo);
38
3039#endif   /* __CHDCD_H__ */
src/lib/util/astring.h
r14481r14482
5252//  TYPE DEFINITIONS
5353//**************************************************************************
5454
55// derived class for C++
55// basic allocated string class
5656class astring
5757{
5858public:
src/lib/util/bitmap.c
r14481r14482
271271//  bitmap does not own the memory
272272//-------------------------------------------------
273273
274void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect)
274void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect)
275275{
276276   assert(m_format == source.m_format);
277277   assert(m_bpp == source.m_bpp);
src/lib/util/avhuff.c
r0r14482
1/***************************************************************************
2
3    avhuff.c
4
5    Audio/video compression and decompression helpers.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38****************************************************************************
39
40    Each frame is compressed as a unit. The raw data is of the form:
41    (all multibyte values are stored in big-endian format)
42
43        +00 = 'chav' (4 bytes) - fixed header data to identify the format
44        +04 = metasize (1 byte) - size of metadata in bytes (max=255 bytes)
45        +05 = channels (1 byte) - number of audio channels
46        +06 = samples (2 bytes) - number of samples per audio stream
47        +08 = width (2 bytes) - width of video data
48        +0A = height (2 bytes) - height of video data
49        +0C = <metadata> - as raw bytes
50              <audio stream 0> - as signed 16-bit samples
51              <audio stream 1> - as signed 16-bit samples
52              ...
53              <video data> - as a raw array of 8-bit YUY data in (Cb,Y,Cr,Y) order
54
55    When compressed, the data is stored as follows:
56    (all multibyte values are stored in big-endian format)
57
58        +00 = metasize (1 byte) - size of metadata in bytes
59        +01 = channels (1 byte) - number of audio channels
60        +02 = samples (2 bytes) - number of samples per audio stream
61        +04 = width (2 bytes) - width of video data
62        +06 = height (2 bytes) - height of video data
63        +08 = audio huffman size (2 bytes) - size of audio huffman tables
64              (0x0000 => uncompressed deltas are used)
65        +0A = str0size (2 bytes) - compressed size of stream 0
66        +0C = str1size (2 bytes) - compressed size of stream 1
67              ...
68              <metadata> - as raw data
69              <audio huffman table> - Huffman table for audio decoding
70              <audio stream 0 data> - Huffman-compressed deltas
71              <audio stream 1 data> - Huffman-compressed deltas
72              <...>
73              <video huffman tables> - Huffman tables for video decoding
74              <video data> - compressed data
75
76****************************************************************************
77
78    Attempted techniques that have not been worthwhile:
79
80    * Attempted to use integer DCTs from the IJG code; even the "slow"
81      variants produce a lot of error and thus kill our compression ratio,
82      since our compression is based on error not bitrate.
83
84    * Tried various other predictors for the lossless video encoding, but
85      none tended to give any significant gain over predicting the
86      previous pixel.
87
88***************************************************************************/
89
90#include "avhuff.h"
91#include "huffman.h"
92#include "chd.h"
93
94#include <math.h>
95#include <stdlib.h>
96#include <new>
97
98
99
100//**************************************************************************
101//  INLINE FUNCTIONS
102//**************************************************************************
103
104//-------------------------------------------------
105//  code_to_rlecount - number of RLE repetitions
106//  encoded in a given byte
107//-------------------------------------------------
108
109inline int code_to_rlecount(int code)
110{
111   if (code == 0x00)
112      return 1;
113   if (code <= 0x107)
114      return 8 + (code - 0x100);
115   return 16 << (code - 0x108);
116}
117
118
119//-------------------------------------------------
120//  rlecount_to_byte - return a byte encoding
121//  the maximum RLE count less than or equal to
122//  the provided amount
123//-------------------------------------------------
124
125inline int rlecount_to_code(int rlecount)
126{
127   if (rlecount >= 2048)
128      return 0x10f;
129   if (rlecount >= 1024)
130      return 0x10e;
131   if (rlecount >= 512)
132      return 0x10d;
133   if (rlecount >= 256)
134      return 0x10c;
135   if (rlecount >= 128)
136      return 0x10b;
137   if (rlecount >= 64)
138      return 0x10a;
139   if (rlecount >= 32)
140      return 0x109;
141   if (rlecount >= 16)
142      return 0x108;
143   if (rlecount >= 8)
144      return 0x100 + (rlecount - 8);
145   return 0x00;
146}
147
148
149//-------------------------------------------------
150//  encode_one - encode data
151//-------------------------------------------------
152
153inline void avhuff_encoder::deltarle_encoder::encode_one(bitstream_out &bitbuf, UINT16 *&rleptr)
154{
155   // return RLE data if we still have some
156   if (m_rlecount != 0)
157   {
158      m_rlecount--;
159      return;
160   }
161
162   // fetch the data and process
163   UINT16 data = *rleptr++;
164   m_encoder.encode_one(bitbuf, data);
165   if (data >= 0x100)
166      m_rlecount = code_to_rlecount(data) - 1;
167}
168
169
170//-------------------------------------------------
171//  decode_one - decode data
172//-------------------------------------------------
173
174inline UINT32 avhuff_decoder::deltarle_decoder::decode_one(bitstream_in &bitbuf)
175{
176   // return RLE data if we still have some
177   if (m_rlecount != 0)
178   {
179      m_rlecount--;
180      return m_prevdata;
181   }
182
183   // fetch the data and process
184   int data = m_decoder.decode_one(bitbuf);
185   if (data < 0x100)
186   {
187      m_prevdata += UINT8(data);
188      return m_prevdata;
189   }
190   else
191   {
192      m_rlecount = code_to_rlecount(data);
193      m_rlecount--;
194      return m_prevdata;
195   }
196}
197
198
199
200//**************************************************************************
201//  AVHUFF ENCODER
202//**************************************************************************
203
204//-------------------------------------------------
205//  avhuff_encoder - constructor
206//-------------------------------------------------
207
208avhuff_encoder::avhuff_encoder()
209{
210m_flac_encoder.set_sample_rate(48000);
211m_flac_encoder.set_num_channels(1);
212m_flac_encoder.set_strip_metadata(true);
213}
214
215
216//-------------------------------------------------
217//  encode_data - encode a block of data into a
218//  compressed data stream
219//-------------------------------------------------
220
221avhuff_error avhuff_encoder::encode_data(const UINT8 *source, UINT8 *dest, UINT32 &complength)
222{
223   // validate the header
224   if (source[0] != 'c' || source[1] != 'h' || source[2] != 'a' || source[3] != 'v')
225      return AVHERR_INVALID_DATA;
226
227   // extract info from the header
228   UINT32 metasize = source[4];
229   UINT32 channels = source[5];
230   UINT32 samples = (source[6] << 8) + source[7];
231   UINT32 width = (source[8] << 8) + source[9];
232   UINT32 height = (source[10] << 8) + source[11];
233   source += 12;
234
235   // write the basics to the new header
236   dest[0] = metasize;
237   dest[1] = channels;
238   dest[2] = samples >> 8;
239   dest[3] = samples;
240   dest[4] = width >> 8;
241   dest[5] = width;
242   dest[6] = height >> 8;
243   dest[7] = height;
244
245   // starting offsets
246   UINT32 dstoffs = 10 + 2 * channels;
247
248   // copy the metadata first
249   if (metasize > 0)
250   {
251      memcpy(dest + dstoffs, source, metasize);
252      source += metasize;
253      dstoffs += metasize;
254   }
255
256   // encode the audio channels
257   if (channels > 0)
258   {
259      // encode the audio
260      avhuff_error err = encode_audio(source, channels, samples, dest + dstoffs, &dest[8]);
261      source += channels * samples * 2;
262      if (err != AVHERR_NONE)
263         return err;
264
265      // advance the pointers past the data
266      UINT16 treesize = (dest[8] << 8) + dest[9];
267      if (treesize != 0xffff)
268         dstoffs += treesize;
269      for (int chnum = 0; chnum < channels; chnum++)
270         dstoffs += (dest[10 + 2 * chnum] << 8) + dest[11 + 2 * chnum];
271   }
272
273   // encode the video data
274   if (width > 0 && height > 0)
275   {
276      // encode the video
277      UINT32 vidlength = 0;
278      avhuff_error err = encode_video(source, width, height, dest + dstoffs, vidlength);
279      if (err != AVHERR_NONE)
280         return err;
281
282      // advance the pointers past the data
283      dstoffs += vidlength;
284   }
285
286   // set the total compression
287   complength = dstoffs;
288   return AVHERR_NONE;
289}
290
291
292//-------------------------------------------------
293//  raw_data_size - return the raw data size of
294//  a raw stream based on the header
295//-------------------------------------------------
296
297UINT32 avhuff_encoder::raw_data_size(const UINT8 *data)
298{
299   // make sure we have a correct header
300   int size = 0;
301   if (data[0] == 'c' && data[1] == 'h' && data[2] == 'a' && data[3] == 'v')
302   {
303      // add in header size plus metadata length
304      size = 12 + data[4];
305
306      // add in channels * samples
307      size += 2 * data[5] * ((data[6] << 8) + data[7]);
308
309      // add in 2 * width * height
310      size += 2 * ((data[8] << 8) + data[9]) * (((data[10] << 8) + data[11]) & 0x7fff);
311   }
312   return size;
313}
314
315
316//-------------------------------------------------
317//  assemble_data - assemble a datastream from raw
318//  bits
319//-------------------------------------------------
320
321avhuff_error avhuff_encoder::assemble_data(UINT8 *dest, UINT32 dlength, bitmap_yuy16 &bitmap, UINT8 channels, UINT32 numsamples, INT16 **samples, UINT8 *metadata, UINT32 metadatasize)
322{
323   // sanity check the inputs
324   if (metadatasize > 255)
325      return AVHERR_METADATA_TOO_LARGE;
326   if (numsamples > 65535)
327      return AVHERR_AUDIO_TOO_LARGE;
328   if (bitmap.width() > 65535 || bitmap.height() > 65535)
329      return AVHERR_VIDEO_TOO_LARGE;
330   if (dlength < 12 + metadatasize + numsamples * channels * 2 + bitmap.width() * bitmap.height() * 2)
331      return AVHERR_BUFFER_TOO_SMALL;
332
333   // fill in the header
334   *dest++ = 'c';
335   *dest++ = 'h';
336   *dest++ = 'a';
337   *dest++ = 'v';
338   *dest++ = metadatasize;
339   *dest++ = channels;
340   *dest++ = numsamples >> 8;
341   *dest++ = numsamples & 0xff;
342   *dest++ = bitmap.width() >> 8;
343   *dest++ = bitmap.width() & 0xff;
344   *dest++ = bitmap.height() >> 8;
345   *dest++ = bitmap.height() & 0xff;
346   
347   // copy the metadata
348   if (metadatasize > 0)
349      memcpy(dest, metadata, metadatasize);
350   dest += metadatasize;
351   
352   // copy the audio streams
353   for (UINT8 curchan = 0; curchan < channels; curchan++)
354      for (UINT32 cursamp = 0; cursamp < numsamples; cursamp++)
355      {
356         *dest++ = samples[curchan][cursamp] >> 8;
357         *dest++ = samples[curchan][cursamp] & 0xff;
358      }
359   
360   // copy the video data
361   for (INT32 y = 0; y < bitmap.height(); y++)
362   {
363      UINT16 *src = &bitmap.pix(y);
364      for (INT32 x = 0; x < bitmap.width(); x++)
365      {
366         *dest++ = src[x] >> 8;
367         *dest++ = src[x] & 0xff;
368      }
369   }
370   return AVHERR_NONE;
371}
372
373
374//-------------------------------------------------
375//  encode_audio - encode raw audio data to the
376//  destination
377//-------------------------------------------------
378
379avhuff_error avhuff_encoder::encode_audio(const UINT8 *source, int channels, int samples, UINT8 *dest, UINT8 *sizes)
380{
381#if AVHUFF_USE_FLAC
382
383   // input data is big-endian; determine our platform endianness
384   UINT16 be_test = 0;
385   *(UINT8 *)&be_test = 1;
386   bool swap_endian = (be_test == 1);
387   
388   // set huffman tree size to 0xffff to indicate FLAC
389   sizes[0] = 0xff;
390   sizes[1] = 0xff;
391   
392   // set the block size for this round and iterate over channels
393   m_flac_encoder.set_block_size(samples);
394   for (int chnum = 0; chnum < channels; chnum++)
395   {
396      // encode the data
397      m_flac_encoder.reset(dest, samples * 2);
398      if (!m_flac_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(source) + chnum * samples, samples, swap_endian))
399         return AVHERR_COMPRESSION_ERROR;
400     
401      // set the size for this channel
402      UINT32 cursize = m_flac_encoder.finish();
403      sizes[chnum * 2 + 2] = cursize >> 8;
404      sizes[chnum * 2 + 3] = cursize;
405      dest += cursize;
406   }
407
408#else
409
410   // expand the delta buffer if needed
411   m_audiobuffer.resize(channels * samples * 2);
412   UINT8 *deltabuf = m_audiobuffer;
413
414   // iterate over channels to compute deltas
415   m_audiohi_encoder.histo_reset();
416   m_audiolo_encoder.histo_reset();
417   for (int chnum = 0; chnum < channels; chnum++)
418   {
419      // extract audio data into hi and lo deltas stored in big-endian order
420      INT16 prevsample = 0;
421      for (int sampnum = 0; sampnum < samples; sampnum++)
422      {
423         INT16 newsample = (source[0] << 8) | source[1];
424         source += 2;
425
426         INT16 delta = newsample - prevsample;
427         prevsample = newsample;
428         m_audiohi_encoder.histo_one(*deltabuf++ = delta >> 8);
429         m_audiolo_encoder.histo_one(*deltabuf++ = delta);
430      }
431   }
432
433   // compute the trees
434   huffman_error hufferr = m_audiohi_encoder.compute_tree_from_histo();
435   if (hufferr != HUFFERR_NONE)
436      return AVHERR_COMPRESSION_ERROR;
437   hufferr = m_audiolo_encoder.compute_tree_from_histo();
438   if (hufferr != HUFFERR_NONE)
439      return AVHERR_COMPRESSION_ERROR;
440
441   // export the trees to the output
442   bitstream_out bitbuf(dest, 2 * channels * samples);
443   hufferr = m_audiohi_encoder.export_tree_rle(bitbuf);
444   if (hufferr != HUFFERR_NONE)
445      return AVHERR_COMPRESSION_ERROR;
446   bitbuf.flush();
447   hufferr = m_audiolo_encoder.export_tree_rle(bitbuf);
448   if (hufferr != HUFFERR_NONE)
449      return AVHERR_COMPRESSION_ERROR;
450
451   // note the size of the two trees
452   UINT32 huffsize = bitbuf.flush();
453   sizes[0] = huffsize >> 8;
454   sizes[1] = huffsize;
455
456   // iterate over channels
457   UINT32 totalsize = huffsize;
458   int chnum;
459   for (chnum = 0; chnum < channels; chnum++)
460   {
461      // encode the data
462      const UINT8 *input = m_audiobuffer + chnum * samples * 2;
463      for (int sampnum = 0; sampnum < samples; sampnum++)
464      {
465         m_audiohi_encoder.encode_one(bitbuf, *input++);
466         m_audiolo_encoder.encode_one(bitbuf, *input++);
467      }
468
469      // store the size of this stream
470      UINT32 cursize = bitbuf.flush() - totalsize;
471      totalsize += cursize;
472      if (totalsize >= channels * samples * 2)
473         break;
474      sizes[chnum * 2 + 2] = cursize >> 8;
475      sizes[chnum * 2 + 3] = cursize;
476   }
477
478   // if we ran out of room, throw it all away and just store raw
479   if (chnum < channels)
480   {
481      memcpy(dest, m_audiobuffer, channels * samples * 2);
482      UINT32 size = samples * 2;
483      sizes[0] = sizes[1] = 0;
484      for (chnum = 0; chnum < channels; chnum++)
485      {
486         sizes[chnum * 2 + 2] = size >> 8;
487         sizes[chnum * 2 + 3] = size;
488      }
489   }
490
491#endif
492
493   return AVHERR_NONE;
494}
495
496
497//-------------------------------------------------
498//  encode_video - encode raw video data to the
499//  destination
500//-------------------------------------------------
501
502avhuff_error avhuff_encoder::encode_video(const UINT8 *source, int width, int height, UINT8 *dest, UINT32 &complength)
503{
504   // only lossless supported at this time
505   return encode_video_lossless(source, width, height, dest, complength);
506}
507
508
509//-------------------------------------------------
510//  encode_video_lossless - do a lossless video
511//  encoding using deltas and huffman encoding
512//-------------------------------------------------
513
514avhuff_error avhuff_encoder::encode_video_lossless(const UINT8 *source, int width, int height, UINT8 *dest, UINT32 &complength)
515{
516   // set up the output; first byte is 0x80 to indicate lossless encoding
517   bitstream_out bitbuf(dest, width * height * 2);
518   bitbuf.write(0x80, 8);
519   
520   // compute the histograms for the data
521   UINT16 *yrle = m_ycontext.rle_and_histo_bitmap(source + 0, width, 2, height);
522   UINT16 *cbrle = m_cbcontext.rle_and_histo_bitmap(source + 1, width / 2, 4, height);
523   UINT16 *crrle = m_crcontext.rle_and_histo_bitmap(source + 3, width / 2, 4, height);
524
525   // export the trees to the data stream
526   huffman_error hufferr = m_ycontext.export_tree_rle(bitbuf);
527   if (hufferr != HUFFERR_NONE)
528      return AVHERR_COMPRESSION_ERROR;
529   bitbuf.flush();
530   hufferr = m_cbcontext.export_tree_rle(bitbuf);
531   if (hufferr != HUFFERR_NONE)
532      return AVHERR_COMPRESSION_ERROR;
533   bitbuf.flush();
534   hufferr = m_crcontext.export_tree_rle(bitbuf);
535   if (hufferr != HUFFERR_NONE)
536      return AVHERR_COMPRESSION_ERROR;
537   bitbuf.flush();
538
539   // encode the data using the trees
540   for (UINT32 sy = 0; sy < height; sy++)
541   {
542      m_ycontext.flush_rle();
543      m_cbcontext.flush_rle();
544      m_crcontext.flush_rle();
545      for (UINT32 sx = 0; sx < width / 2; sx++)
546      {
547         m_ycontext.encode_one(bitbuf, yrle);
548         m_cbcontext.encode_one(bitbuf, cbrle);
549         m_ycontext.encode_one(bitbuf, yrle);
550         m_crcontext.encode_one(bitbuf, crrle);
551      }
552   }
553
554   // set the final length
555   complength = bitbuf.flush();
556   return AVHERR_NONE;
557}
558
559
560
561//**************************************************************************
562//  DELTA-RLE ENCODER
563//**************************************************************************
564
565//-------------------------------------------------
566//  rle_and_histo_bitmap - RLE compress and
567//  histogram a bitmap's worth of data
568//-------------------------------------------------
569
570UINT16 *avhuff_encoder::deltarle_encoder::rle_and_histo_bitmap(const UINT8 *source, UINT32 items_per_row, UINT32 item_advance, UINT32 row_count)
571{
572   // resize our RLE buffer
573   m_rlebuffer.resize(items_per_row * row_count);
574   UINT16 *dest = m_rlebuffer;
575
576   // iterate over rows
577   m_encoder.histo_reset();
578   UINT8 prevdata = 0;
579   for (UINT32 row = 0; row < row_count; row++)
580   {
581      const UINT8 *end = source + items_per_row * item_advance;
582      for ( ; source < end; source += item_advance)
583      {
584         // fetch current data
585         UINT8 curdelta = *source - prevdata;
586         prevdata = *source;
587         
588         // 0 deltas scan forward for a count
589         if (curdelta == 0)
590         {
591            int zerocount = 1;
592           
593            // count the number of consecutive values
594            const UINT8 *scandata;
595            for (scandata = source + item_advance; scandata < end; scandata += item_advance)
596               if (*scandata == prevdata)
597                  zerocount++;
598               else
599                  break;
600           
601            // if we hit the end of a row, maximize the count
602            if (scandata >= end && zerocount >= 8)
603               zerocount = 100000;
604
605            // encode the maximal count we can
606            int rlecode = rlecount_to_code(zerocount);
607            m_encoder.histo_one(*dest++ = rlecode);
608
609            // advance past the run
610            source += (code_to_rlecount(rlecode) - 1) * item_advance;
611         }
612         
613         // otherwise, encode the actual data
614         else
615            m_encoder.histo_one(*dest++ = curdelta);
616      }
617     
618      // advance to the next row
619      source = end;
620   }
621   
622   // compute the tree for our histogram
623   m_encoder.compute_tree_from_histo();
624   return m_rlebuffer;
625}
626
627
628
629//**************************************************************************
630//  AVHUFF DECODER
631//**************************************************************************
632
633//-------------------------------------------------
634//  avhuff_decoder - constructor
635//-------------------------------------------------
636
637avhuff_decoder::avhuff_decoder()
638{
639}
640
641
642//-------------------------------------------------
643//  configure - configure decompression parameters
644//-------------------------------------------------
645
646void avhuff_decoder::configure(const avhuff_decompress_config &config)
647{
648   m_config.video.wrap(config.video, config.video.cliprect());
649   m_config.maxsamples = config.maxsamples;
650   m_config.actsamples = config.actsamples;
651   memcpy(m_config.audio, config.audio, sizeof(m_config.audio));
652   m_config.maxmetalength = config.maxmetalength;
653   m_config.actmetalength = config.actmetalength;
654   m_config.metadata = config.metadata;
655}
656
657
658//-------------------------------------------------
659//  decode_data - decode both audio and video from
660//  a raw data stream
661//-------------------------------------------------
662
663avhuff_error avhuff_decoder::decode_data(const UINT8 *source, UINT32 complength, UINT8 *dest)
664{
665   // extract info from the header
666   if (complength < 8)
667      return AVHERR_INVALID_DATA;
668   UINT32 metasize = source[0];
669   UINT32 channels = source[1];
670   UINT32 samples = (source[2] << 8) + source[3];
671   UINT32 width = (source[4] << 8) + source[5];
672   UINT32 height = (source[6] << 8) + source[7];
673
674   // validate that the sizes make sense
675   if (complength < 10 + 2 * channels)
676      return AVHERR_INVALID_DATA;
677   UINT32 totalsize = 10 + 2 * channels;
678   totalsize += (source[8] << 8) | source[9];
679   for (int chnum = 0; chnum < channels; chnum++)
680      totalsize += (source[10 + 2 * chnum] << 8) | source[11 + 2 * chnum];
681   if (totalsize >= complength)
682      return AVHERR_INVALID_DATA;
683
684   // starting offsets
685   UINT32 srcoffs = 10 + 2 * channels;
686
687   // if we are decoding raw, set up the output parameters
688   UINT8 *metastart, *videostart, *audiostart[16];
689   UINT32 audioxor, videoxor, videostride;
690   if (dest != NULL)
691   {
692      // create a header
693      dest[0] = 'c';
694      dest[1] = 'h';
695      dest[2] = 'a';
696      dest[3] = 'v';
697      dest[4] = metasize;
698      dest[5] = channels;
699      dest[6] = samples >> 8;
700      dest[7] = samples;
701      dest[8] = width >> 8;
702      dest[9] = width;
703      dest[10] = height >> 8;
704      dest[11] = height;
705      dest += 12;
706
707      // determine the start of each piece of data
708      metastart = dest;
709      dest += metasize;
710      for (int chnum = 0; chnum < channels; chnum++)
711      {
712         audiostart[chnum] = dest;
713         dest += 2 * samples;
714      }
715      videostart = dest;
716
717      // data is assumed to be big-endian already
718      audioxor = videoxor = 0;
719      videostride = 2 * width;
720   }
721
722   // otherwise, extract from the state
723   else
724   {
725      // determine the start of each piece of data
726      metastart = m_config.metadata;
727      for (int chnum = 0; chnum < channels; chnum++)
728         audiostart[chnum] = (UINT8 *)m_config.audio[chnum];
729      videostart = (m_config.video.valid()) ? reinterpret_cast<UINT8 *>(&m_config.video.pix(0)) : NULL;
730      videostride = (m_config.video.valid()) ? m_config.video.rowpixels() * 2 : 0;
731
732      // data is assumed to be native-endian
733      UINT16 betest = 0;
734      *(UINT8 *)&betest = 1;
735      audioxor = videoxor = (betest == 1) ? 1 : 0;
736
737      // verify against sizes
738      if (m_config.video.valid() && (m_config.video.width() < width || m_config.video.height() < height))
739         return AVHERR_VIDEO_TOO_LARGE;
740      for (int chnum = 0; chnum < channels; chnum++)
741         if (m_config.audio[chnum] != NULL && m_config.maxsamples < samples)
742            return AVHERR_AUDIO_TOO_LARGE;
743      if (m_config.metadata != NULL && m_config.maxmetalength < metasize)
744         return AVHERR_METADATA_TOO_LARGE;
745
746      // set the output values
747      if (m_config.actsamples != NULL)
748         *m_config.actsamples = samples;
749      if (m_config.actmetalength != NULL)
750         *m_config.actmetalength = metasize;
751   }
752
753   // copy the metadata first
754   if (metasize > 0)
755   {
756      if (metastart != NULL)
757         memcpy(metastart, source + srcoffs, metasize);
758      srcoffs += metasize;
759   }
760
761   // decode the audio channels
762   if (channels > 0)
763   {
764      // decode the audio
765      avhuff_error err = decode_audio(channels, samples, source + srcoffs, audiostart, audioxor, &source[8]);
766      if (err != AVHERR_NONE)
767         return err;
768
769      // advance the pointers past the data
770      UINT32 treesize = (source[8] << 8) + source[9];
771      if (treesize != 0xffff)
772         srcoffs += treesize;
773      for (int chnum = 0; chnum < channels; chnum++)
774         srcoffs += (source[10 + 2 * chnum] << 8) + source[11 + 2 * chnum];
775   }
776
777   // decode the video data
778   if (width > 0 && height > 0 && videostart != NULL)
779   {
780      // decode the video
781      avhuff_error err = decode_video(width, height, source + srcoffs, complength - srcoffs, videostart, videostride, videoxor);
782      if (err != AVHERR_NONE)
783         return err;
784   }
785   return AVHERR_NONE;
786}
787
788
789//-------------------------------------------------
790//  decode_audio - decode audio from a compressed
791//  data stream
792//-------------------------------------------------
793
794avhuff_error avhuff_decoder::decode_audio(int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes)
795{
796   // extract the huffman trees
797   UINT16 treesize = (sizes[0] << 8) | sizes[1];
798
799#if AVHUFF_USE_FLAC
800
801   // if the tree size is 0xffff, the streams are FLAC-encoded
802   if (treesize == 0xffff)
803   {
804      // output data is big-endian; determine our platform endianness
805      UINT16 be_test = 0;
806      *(UINT8 *)&be_test = 1;
807      bool swap_endian = (be_test == 1);
808      if (dxor != 0)
809         swap_endian = !swap_endian;
810
811      // loop over channels
812      for (int chnum = 0; chnum < channels; chnum++)
813      {
814         // extract the size of this channel
815         UINT16 size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
816
817         // only process if the data is requested
818         UINT8 *curdest = dest[chnum];
819         if (curdest != NULL)
820         {
821            // reset and decode
822            if (!m_flac_decoder.reset(48000, 1, samples, source, size))
823               throw CHDERR_DECOMPRESSION_ERROR;
824            if (!m_flac_decoder.decode_interleaved(reinterpret_cast<INT16 *>(curdest), samples, swap_endian))
825               throw CHDERR_DECOMPRESSION_ERROR;
826
827            // finish up
828            m_flac_decoder.finish();
829         }
830     
831         // advance to the next channel's data
832         source += size;
833      }
834      return AVHERR_NONE;
835   }
836
837#endif
838
839   // if we have a non-zero tree size, extract the trees
840   if (treesize != 0)
841   {
842      bitstream_in bitbuf(source, treesize);
843      huffman_error hufferr = m_audiohi_decoder.import_tree_rle(bitbuf);
844      if (hufferr != HUFFERR_NONE)
845         return AVHERR_INVALID_DATA;
846      bitbuf.flush();
847      hufferr = m_audiolo_decoder.import_tree_rle(bitbuf);
848      if (hufferr != HUFFERR_NONE)
849         return AVHERR_INVALID_DATA;
850      if (bitbuf.flush() != treesize)
851         return AVHERR_INVALID_DATA;
852      source += treesize;
853   }
854
855   // loop over channels
856   for (int chnum = 0; chnum < channels; chnum++)
857   {
858      // extract the size of this channel
859      UINT16 size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
860
861      // only process if the data is requested
862      UINT8 *curdest = dest[chnum];
863      if (curdest != NULL)
864      {
865         INT16 prevsample = 0;
866
867         // if no huffman length, just copy the data
868         if (treesize == 0)
869         {
870            const UINT8 *cursource = source;
871            for (int sampnum = 0; sampnum < samples; sampnum++)
872            {
873               INT16 delta = (cursource[0] << 8) | cursource[1];
874               cursource += 2;
875
876               INT16 newsample = prevsample + delta;
877               prevsample = newsample;
878
879               curdest[0 ^ dxor] = newsample >> 8;
880               curdest[1 ^ dxor] = newsample;
881               curdest += 2;
882            }
883         }
884         
885         // otherwise, Huffman-decode the data
886         else
887         {
888            bitstream_in bitbuf(source, size);
889            for (int sampnum = 0; sampnum < samples; sampnum++)
890            {
891               INT16 delta = m_audiohi_decoder.decode_one(bitbuf) << 8;
892               delta |= m_audiolo_decoder.decode_one(bitbuf);
893
894               INT16 newsample = prevsample + delta;
895               prevsample = newsample;
896
897               curdest[0 ^ dxor] = newsample >> 8;
898               curdest[1 ^ dxor] = newsample;
899               curdest += 2;
900            }
901            if (bitbuf.overflow())
902               return AVHERR_INVALID_DATA;
903         }
904      }
905     
906      // advance to the next channel's data
907      source += size;
908   }
909   return AVHERR_NONE;
910}
911
912
913//-------------------------------------------------
914//  decode_video - decode video from a compressed
915//  data stream
916//-------------------------------------------------
917
918avhuff_error avhuff_decoder::decode_video(int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor)
919{
920   // if the high bit of the first byte is set, we decode losslessly
921   if (source[0] & 0x80)
922      return decode_video_lossless(width, height, source, complength, dest, dstride, dxor);
923   else
924      return AVHERR_INVALID_DATA;
925}
926
927
928//-------------------------------------------------
929//  decode_video_lossless - do a lossless video
930//  decoding using deltas and huffman encoding
931//-------------------------------------------------
932
933avhuff_error avhuff_decoder::decode_video_lossless(int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor)
934{
935   // skip the first byte
936   bitstream_in bitbuf(source, complength);
937   bitbuf.read(8);
938
939   // import the tables
940   huffman_error hufferr = m_ycontext.import_tree_rle(bitbuf);
941   if (hufferr != HUFFERR_NONE)
942      return AVHERR_INVALID_DATA;
943   bitbuf.flush();
944   hufferr = m_cbcontext.import_tree_rle(bitbuf);
945   if (hufferr != HUFFERR_NONE)
946      return AVHERR_INVALID_DATA;
947   bitbuf.flush();
948   hufferr = m_crcontext.import_tree_rle(bitbuf);
949   if (hufferr != HUFFERR_NONE)
950      return AVHERR_INVALID_DATA;
951   bitbuf.flush();
952
953   // decode to the destination
954   m_ycontext.reset();
955   m_cbcontext.reset();
956   m_crcontext.reset();
957   for (UINT32 dy = 0; dy < height; dy++)
958   {
959      UINT8 *row = dest + dy * dstride;
960      for (UINT32 dx = 0; dx < width / 2; dx++)
961      {
962         row[0 ^ dxor] = m_ycontext.decode_one(bitbuf);
963         row[1 ^ dxor] = m_cbcontext.decode_one(bitbuf);
964         row[2 ^ dxor] = m_ycontext.decode_one(bitbuf);
965         row[3 ^ dxor] = m_crcontext.decode_one(bitbuf);
966         row += 4;
967      }
968      m_ycontext.flush_rle();
969      m_cbcontext.flush_rle();
970      m_crcontext.flush_rle();
971   }
972   
973   // check for errors if we overflowed or decoded too little data
974   if (bitbuf.overflow() || bitbuf.flush() != complength)
975      return AVHERR_INVALID_DATA;
976   return AVHERR_NONE;
977}
src/lib/util/bitmap.h
r14481r14482
177177protected:
178178   // for use by subclasses only to ensure type correctness
179179   void wrap(void *base, int width, int height, int rowpixels);
180   void wrap(bitmap_t &source, const rectangle &subrect);
180   void wrap(const bitmap_t &source, const rectangle &subrect);
181181
182182private:
183183   // internal helpers
r14481r14482
306306   bitmap_ind8(UINT8 *base, int width, int height, int rowpixels) : bitmap8_t(k_bitmap_format, base, width, height, rowpixels) { }
307307   bitmap_ind8(bitmap_ind8 &source, const rectangle &subrect) : bitmap8_t(k_bitmap_format, source, subrect) { }
308308   void wrap(UINT8 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
309   void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
309   void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
310310
311311   // getters
312312   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
323323   bitmap_ind16(UINT16 *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
324324   bitmap_ind16(bitmap_ind16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
325325   void wrap(UINT16 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
326   void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
326   void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
327327
328328   // getters
329329   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
340340   bitmap_ind32(UINT32 *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
341341   bitmap_ind32(bitmap_ind32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
342342   void wrap(UINT32 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
343   void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
343   void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
344344
345345   // getters
346346   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
357357   bitmap_ind64(UINT64 *base, int width, int height, int rowpixels) : bitmap64_t(k_bitmap_format, base, width, height, rowpixels) { }
358358   bitmap_ind64(bitmap_ind64 &source, const rectangle &subrect) : bitmap64_t(k_bitmap_format, source, subrect) { }
359359   void wrap(UINT64 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
360   void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
360   void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
361361
362362   // getters
363363   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
377377   bitmap_yuy16(UINT16 *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
378378   bitmap_yuy16(bitmap_yuy16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
379379   void wrap(UINT16 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
380   void wrap(bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
380   void wrap(const bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
381381
382382   // getters
383383   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
394394   bitmap_rgb32(UINT32 *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
395395   bitmap_rgb32(bitmap_rgb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
396396   void wrap(UINT32 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
397   void wrap(bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
397   void wrap(const bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
398398
399399   // getters
400400   bitmap_format format() const { return k_bitmap_format; }
r14481r14482
411411   bitmap_argb32(UINT32 *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
412412   bitmap_argb32(bitmap_argb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
413413   void wrap(UINT32 *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
414   void wrap(bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
414   void wrap(const bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
415415
416416   // getters
417417   bitmap_format format() const { return k_bitmap_format; }
src/lib/util/huffman.c
r14481r14482
22
33    huffman.c
44
5    Video compression and decompression helpers.
5    Static Huffman compression and decompression helpers.
66
77****************************************************************************
88
r14481r14482
127127
128128#include <stdlib.h>
129129
130#include "coretmpl.h"
130131#include "huffman.h"
131132
132133
133134
134/***************************************************************************
135    CONSTANTS
136***************************************************************************/
135//**************************************************************************
136//  MACROS
137//**************************************************************************
137138
138#define HUFFMAN_CODES         256
139#define HUFFMAN_DELTARLE_CODES   (HUFFMAN_CODES + 16)
139#define MAKE_LOOKUP(code,bits)   (((code) << 5) | ((bits) & 0x1f))
140140
141#define MAX_HUFFMAN_CODES      (HUFFMAN_DELTARLE_CODES)
142#define MAX_HUFFMAN_NODES      (MAX_HUFFMAN_CODES + MAX_HUFFMAN_CODES)
143141
144142
143//**************************************************************************
144//  IMPLEMENTATION
145//**************************************************************************
145146
146/***************************************************************************
147    MACROS
148***************************************************************************/
147//-------------------------------------------------
148//  huffman_context_base - create an encoding/
149//  decoding context
150//-------------------------------------------------
149151
150#define MAKE_LOOKUP(code,bits)   (((code) << 6) | ((bits) & 0x1f))
151#define LOOKUP_CODE(val)      ((val) >> 6)
152#define LOOKUP_BITS(val)      ((val) & 0x1f)
153
154
155
156/***************************************************************************
157    TYPE DEFINITIONS
158***************************************************************************/
159
160typedef struct _bit_buffer bit_buffer;
161struct _bit_buffer
152huffman_context_base::huffman_context_base(int numcodes, int maxbits, lookup_value *lookup, UINT32 *histo, node_t *nodes)
153   : m_numcodes(numcodes),
154     m_maxbits(maxbits),
155     m_prevdata(0),
156     m_rleremaining(0),
157     m_lookup(lookup),
158     m_datahisto(histo),
159     m_huffnode(nodes)
162160{
163   UINT32               buffer;                     /* current bit accumulator */
164   int                  bits;                     /* number of bits in the accumulator */
165   union
166   {
167      const UINT8 *      read;                     /* read pointer */
168      UINT8 *            write;                     /* write pointer */
169   } data;
170   UINT32               doffset;                  /* byte offset within the data */
171   UINT32               dlength;                  /* length of the data */
172   int                  overflow;                  /* flag: true if we read/wrote past the end */
173};
174
175
176typedef struct _huffman_node huffman_node;
177struct _huffman_node
178{
179   huffman_node *         parent;                     /* pointer to parent node */
180   UINT32               count;                     /* number of hits on this node */
181   UINT32               weight;                     /* assigned weight of this node */
182   UINT32               bits;                     /* bits used to encode the node */
183   UINT8               numbits;                  /* number of bits needed for this node */
184};
185
186
187struct _huffman_context
188{
189   UINT8               maxbits;                  /* maximum bits per code */
190   UINT8               lookupdirty;               /* TRUE if the lookup table is dirty */
191   UINT8               prevdata;                  /* value of the previous data (for delta-RLE encoding) */
192   UINT32               datahisto[MAX_HUFFMAN_CODES];   /* histogram of data values */
193   int                  rleremaining;               /* number of RLE bytes remaining (for delta-RLE encoding) */
194   huffman_node         huffnode[MAX_HUFFMAN_NODES];   /* array of nodes */
195   huffman_lookup_value *   lookup;                     /* pointer to the lookup table */
196};
197
198
199
200/***************************************************************************
201    PROTOTYPES
202***************************************************************************/
203
204static huffman_error huffman_deltarle_decode_data_interleaved_0102(huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
205
206static huffman_error import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength, UINT32 numcodes);
207static huffman_error export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength, UINT32 numcodes);
208static void write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits);
209static int CLIB_DECL tree_node_compare(const void *item1, const void *item2);
210static huffman_error compute_optimal_tree(huffman_context *context, const UINT32 *datahisto, UINT32 numcodes);
211static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight, UINT32 numcodes);
212static huffman_error assign_canonical_codes(huffman_context *context, UINT32 numcodes);
213static huffman_error build_lookup_table(huffman_context *context, UINT32 numcodes);
214
215
216
217/***************************************************************************
218    INLINE FUNCTIONS
219***************************************************************************/
220
221/*-------------------------------------------------
222    bit_buffer_write_init - initialize a bit
223    buffer for writing
224-------------------------------------------------*/
225
226INLINE void bit_buffer_write_init(bit_buffer *bitbuf, UINT8 *data, UINT32 dlength)
227{
228   /* fill in the basic data structure */
229   bitbuf->buffer = 0;
230   bitbuf->bits = 0;
231   bitbuf->data.write = data;
232   bitbuf->doffset = 0;
233   bitbuf->dlength = dlength;
234   bitbuf->overflow = FALSE;
235}
236
237
238/*-------------------------------------------------
239    bit_buffer_write - write 'numbits' to the
240    bit buffer, assuming that 'newbits' is right-
241    justified
242-------------------------------------------------*/
243
244INLINE void bit_buffer_write(bit_buffer *bitbuf, UINT32 newbits, int numbits)
245{
246   /* flush the buffer if we're going to overflow it */
247   if (bitbuf->bits + numbits > 32)
248      while (bitbuf->bits >= 8)
249      {
250         if (bitbuf->doffset < bitbuf->dlength)
251            bitbuf->data.write[bitbuf->doffset] = bitbuf->buffer >> 24;
252         else
253            bitbuf->overflow = TRUE;
254         bitbuf->doffset++;
255         bitbuf->buffer <<= 8;
256         bitbuf->bits -= 8;
257      }
258
259   /* shift the bits to the top */
260   newbits <<= 32 - numbits;
261
262   /* now shift it down to account for the number of bits we already have and OR them in */
263   bitbuf->buffer |= newbits >> bitbuf->bits;
264   bitbuf->bits += numbits;
265}
266
267
268/*-------------------------------------------------
269    bit_buffer_flush - flush any bits in the write
270    buffer and return the final data offset
271-------------------------------------------------*/
272
273INLINE UINT32 bit_buffer_flush(bit_buffer *bitbuf)
274{
275   while (bitbuf->bits > 0)
276   {
277      if (bitbuf->doffset < bitbuf->dlength)
278         bitbuf->data.write[bitbuf->doffset] = bitbuf->buffer >> 24;
279      else
280         bitbuf->overflow = TRUE;
281      bitbuf->doffset++;
282      bitbuf->buffer <<= 8;
283      bitbuf->bits -= 8;
284   }
285   return bitbuf->doffset;
286}
287
288
289/*-------------------------------------------------
290    bit_buffer_read_init - initialize a bit
291    buffer for reading
292-------------------------------------------------*/
293
294INLINE void bit_buffer_read_init(bit_buffer *bitbuf, const UINT8 *data, UINT32 dlength)
295{
296   /* fill in the basic data structure */
297   bitbuf->buffer = 0;
298   bitbuf->bits = 0;
299   bitbuf->data.read = data;
300   bitbuf->doffset = 0;
301   bitbuf->dlength = dlength;
302   bitbuf->overflow = FALSE;
303}
304
305
306/*-------------------------------------------------
307    bit_buffer_read - read 'numbits' bits from
308    the buffer, returning them right-justified
309-------------------------------------------------*/
310
311INLINE UINT32 bit_buffer_read(bit_buffer *bitbuf, int numbits)
312{
313   UINT32 result;
314
315   /* fetch data if we need more */
316   if (numbits > bitbuf->bits)
317   {
318      while (bitbuf->bits <= 24)
319      {
320         if (bitbuf->doffset < bitbuf->dlength)
321            bitbuf->buffer |= bitbuf->data.read[bitbuf->doffset] << (24 - bitbuf->bits);
322         bitbuf->doffset++;
323         bitbuf->bits += 8;
324      }
325      if (numbits > bitbuf->bits)
326         bitbuf->overflow = TRUE;
327   }
328
329   /* return the data */
330   result = bitbuf->buffer >> (32 - numbits);
331   bitbuf->buffer <<= numbits;
332   bitbuf->bits -= numbits;
333   return result;
334}
335
336
337/*-------------------------------------------------
338    bit_buffer_peek - peek ahead and return
339    'numbits' bits from the buffer, returning
340    them right-justified
341-------------------------------------------------*/
342
343INLINE UINT32 bit_buffer_peek(bit_buffer *bitbuf, int numbits)
344{
345   /* fetch data if we need more */
346   if (numbits > bitbuf->bits)
347   {
348      while (bitbuf->bits <= 24)
349      {
350         if (bitbuf->doffset < bitbuf->dlength)
351            bitbuf->buffer |= bitbuf->data.read[bitbuf->doffset] << (24 - bitbuf->bits);
352         bitbuf->doffset++;
353         bitbuf->bits += 8;
354      }
355      if (numbits > bitbuf->bits)
356         bitbuf->overflow = TRUE;
357   }
358
359   /* return the data */
360   return bitbuf->buffer >> (32 - numbits);
361}
362
363
364/*-------------------------------------------------
365    bit_buffer_remove - remove 'numbits' bits
366    from the bit buffer; this presupposes that
367    at least 'numbits' are present
368-------------------------------------------------*/
369
370INLINE void bit_buffer_remove(bit_buffer *bitbuf, int numbits)
371{
372   bitbuf->buffer <<= numbits;
373   bitbuf->bits -= numbits;
374}
375
376
377/*-------------------------------------------------
378    bit_buffer_read_offset - return the current
379    rounded byte reading offset
380-------------------------------------------------*/
381
382INLINE UINT32 bit_buffer_read_offset(bit_buffer *bitbuf)
383{
384   UINT32 result = bitbuf->doffset;
385   int bits = bitbuf->bits;
386   while (bits >= 8)
387   {
388      result--;
389      bits -= 8;
390   }
391   return result;
392}
393
394
395/*-------------------------------------------------
396    code_to_rlecount - number of RLE repetitions
397    encoded in a given byte
398-------------------------------------------------*/
399
400INLINE int code_to_rlecount(int code)
401{
402   if (code == 0x00)
403      return 1;
404   if (code <= 0x107)
405      return 8 + (code - 0x100);
406   return 16 << (code - 0x108);
407}
408
409
410/*-------------------------------------------------
411    rlecount_to_byte - return a byte encoding
412    the maximum RLE count less than or equal to
413    the provided amount
414-------------------------------------------------*/
415
416INLINE int rlecount_to_code(int rlecount)
417{
418   if (rlecount >= 2048)
419      return 0x10f;
420   if (rlecount >= 1024)
421      return 0x10e;
422   if (rlecount >= 512)
423      return 0x10d;
424   if (rlecount >= 256)
425      return 0x10c;
426   if (rlecount >= 128)
427      return 0x10b;
428   if (rlecount >= 64)
429      return 0x10a;
430   if (rlecount >= 32)
431      return 0x109;
432   if (rlecount >= 16)
433      return 0x108;
434   if (rlecount >= 8)
435      return 0x100 + (rlecount - 8);
436   return 0x00;
437}
438
439
440
441/***************************************************************************
442    IMPLEMENTATION
443***************************************************************************/
444
445/*-------------------------------------------------
446    huffman_create_context - create an encoding/
447    decoding context
448-------------------------------------------------*/
449
450huffman_error huffman_create_context(huffman_context **context, int maxbits)
451{
452   /* limit to 24 bits */
161   // limit to 24 bits
453162   if (maxbits > 24)
454      return HUFFERR_TOO_MANY_BITS;
455
456   /* allocate a context */
457   *context = (huffman_context *)malloc(sizeof(**context));
458   if (*context == NULL)
459      return HUFFERR_OUT_OF_MEMORY;
460
461   /* set the info */
462   memset(*context, 0, sizeof(**context));
463   (*context)->maxbits = maxbits;
464   (*context)->lookupdirty = TRUE;
465
466   return HUFFERR_NONE;
163      throw HUFFERR_TOO_MANY_BITS;
467164}
468165
469166
470/*-------------------------------------------------
471    huffman_free_context - free an encoding/
472    decoding context
473-------------------------------------------------*/
167//-------------------------------------------------
168//  import_tree_rle - import an RLE-encoded
169//  huffman tree from a source data stream
170//-------------------------------------------------
474171
475void huffman_free_context(huffman_context *context)
172huffman_error huffman_context_base::import_tree_rle(bitstream_in &bitbuf)
476173{
477   if (context->lookup != NULL)
478      free(context->lookup);
479   free(context);
480}
174   // bits per entry depends on the maxbits
175   int numbits;
176   if (m_maxbits >= 16)
177      numbits = 5;
178   else if (m_maxbits >= 8)
179      numbits = 4;
180   else
181      numbits = 3;
481182
482
483/*-------------------------------------------------
484    huffman_import_tree - import a huffman tree
485    from a source data stream
486-------------------------------------------------*/
487
488huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
489{
490   return import_tree(context, source, slength, actlength, HUFFMAN_CODES);
491}
492
493
494/*-------------------------------------------------
495    huffman_export_tree - export a huffman tree
496    to a target data stream
497-------------------------------------------------*/
498
499huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
500{
501   return export_tree(context, dest, dlength, actlength, HUFFMAN_CODES);
502}
503
504
505/*-------------------------------------------------
506    huffman_deltarle_import_tree - import a
507    huffman tree from a source data stream for
508    delta-RLE encoded data
509-------------------------------------------------*/
510
511huffman_error huffman_deltarle_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
512{
513   return import_tree(context, source, slength, actlength, HUFFMAN_DELTARLE_CODES);
514}
515
516
517/*-------------------------------------------------
518    huffman__deltarle_export_tree - export a
519    huffman tree to a target data stream for
520    delta-RLE encoded data
521-------------------------------------------------*/
522
523huffman_error huffman_deltarle_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
524{
525   return export_tree(context, dest, dlength, actlength, HUFFMAN_DELTARLE_CODES);
526}
527
528
529/*-------------------------------------------------
530    huffman_compute_tree - compute an optimal
531    huffman tree for the given source data
532-------------------------------------------------*/
533
534huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
535{
536   return huffman_compute_tree_interleaved(1, &context, source, swidth, sheight, sstride, sxor);
537}
538
539huffman_error huffman_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
540{
541   UINT32 sx, sy, ctxnum;
542   huffman_error error;
543
544   /* initialize all nodes */
545   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
183   // loop until we read all the nodes
184   int curnode;
185   for (curnode = 0; curnode < m_numcodes; )
546186   {
547      huffman_context *context = contexts[ctxnum];
548      memset(context->datahisto, 0, sizeof(context->datahisto));
549   }
187      // a non-one value is just raw
188      int nodebits = bitbuf.read(numbits);
189      if (nodebits != 1)
190         m_huffnode[curnode++].m_numbits = nodebits;
550191
551   /* iterate over "height" */
552   for (sy = 0; sy < sheight; sy++)
553   {
554      /* iterate over "width" */
555      for (sx = 0; sx < swidth; )
192      // a one value is an escape code
193      else
556194      {
557         /* iterate over contexts */
558         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
559         {
560            huffman_context *context = contexts[ctxnum];
561            context->datahisto[source[sx ^ sxor]]++;
562         }
563      }
195         // a double 1 is just a single 1
196         nodebits = bitbuf.read(numbits);
197         if (nodebits == 1)
198            m_huffnode[curnode++].m_numbits = nodebits;
564199
565      /* advance to the next row */
566      source += sstride;
567   }
568
569   /* compute optimal trees for each */
570   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
571   {
572      huffman_context *context = contexts[ctxnum];
573      error = compute_optimal_tree(context, context->datahisto, HUFFMAN_CODES);
574      if (error != HUFFERR_NONE)
575         return error;
576   }
577   return HUFFERR_NONE;
578}
579
580
581/*-------------------------------------------------
582    huffman_deltarle_compute_tree - compute an
583    optimal huffman tree for the given source
584    data, with pre-encoding as delta-RLE
585-------------------------------------------------*/
586
587huffman_error huffman_deltarle_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
588{
589   return huffman_deltarle_compute_tree_interleaved(1, &context, source, swidth, sheight, sstride, sxor);
590}
591
592huffman_error huffman_deltarle_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
593{
594   UINT32 sx, sy, ctxnum;
595   huffman_error error;
596
597   /* initialize all nodes */
598   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
599   {
600      huffman_context *context = contexts[ctxnum];
601      memset(context->datahisto, 0, sizeof(context->datahisto));
602      context->prevdata = 0;
603   }
604
605   /* iterate over "height" */
606   for (sy = 0; sy < sheight; sy++)
607   {
608      /* reset RLE counts */
609      for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
610      {
611         huffman_context *context = contexts[ctxnum];
612         context->rleremaining = 0;
613      }
614
615      /* iterate over "width" */
616      for (sx = 0; sx < swidth; )
617      {
618         /* iterate over contexts */
619         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
200         // otherwise, we need one for value for the repeat count
201         else
620202         {
621            huffman_context *context = contexts[ctxnum];
622            UINT8 newdata, delta;
623
624            /* if still counting RLE, do nothing */
625            if (context->rleremaining != 0)
626            {
627               context->rleremaining--;
628               continue;
629            }
630
631            /* fetch new data and compute the delta */
632            newdata = source[sx ^ sxor];
633            delta = newdata - context->prevdata;
634            context->prevdata = newdata;
635
636            /* 0 deltas scan forward for a count */
637            if (delta == 0)
638            {
639               int zerocount = 1;
640               int rlecode;
641               UINT32 scan;
642
643               /* count the number of consecutive values */
644               for (scan = sx + 1; scan < swidth; scan++)
645                  if (contexts[scan % numcontexts] == context)
646                  {
647                     if (newdata == source[scan ^ sxor])
648                        zerocount++;
649                     else
650                        break;
651                  }
652
653               /* if we hit the end of row, maximize the count */
654               if (scan >= swidth && zerocount >= 8)
655                  zerocount = 100000;
656
657               /* encode the maximal count we can */
658               rlecode = rlecount_to_code(zerocount);
659               context->datahisto[rlecode]++;
660
661               /* set up the remaining count */
662               context->rleremaining = code_to_rlecount(rlecode) - 1;
663            }
664            else
665            {
666               /* encode the actual delta */
667               context->datahisto[delta]++;
668            }
203            int repcount = bitbuf.read(numbits) + 3;
204            while (repcount--)
205               m_huffnode[curnode++].m_numbits = nodebits;
669206         }
670207      }
671
672      /* advance to the next row */
673      source += sstride;
674208   }
675209
676   /* compute optimal trees for each */
677   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
678   {
679      huffman_context *context = contexts[ctxnum];
680      error = compute_optimal_tree(context, context->datahisto, HUFFMAN_DELTARLE_CODES);
681      if (error != HUFFERR_NONE)
682         return error;
683   }
684   return HUFFERR_NONE;
685}
210   // make sure we ended up with the right number
211   if (curnode != m_numcodes)
212      return HUFFERR_INVALID_DATA;
686213
214   // assign canonical codes for all nodes based on their code lengths
215   huffman_error error = assign_canonical_codes();
216   if (error != HUFFERR_NONE)
217      return error;
218   
219   // build the lookup table
220   build_lookup_table();
687221
688/*-------------------------------------------------
689    huffman_encode_data - encode data using the
690    given tree
691-------------------------------------------------*/
692
693huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
694{
695   return huffman_encode_data_interleaved(1, &context, source, swidth, sheight, sstride, sxor, dest, dlength, actlength);
222   // determine final input length and report errors
223   return bitbuf.overflow() ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
696224}
697225
698huffman_error huffman_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
699{
700   UINT32 sx, sy, ctxnum;
701   bit_buffer bitbuf;
702226
703   /* initialize the output buffer */
704   bit_buffer_write_init(&bitbuf, dest, dlength);
227//-------------------------------------------------
228//  export_tree_rle - export a huffman tree to an
229//  RLE target data stream
230//-------------------------------------------------
705231
706   /* iterate over "height" */
707   for (sy = 0; sy < sheight; sy++)
708   {
709      /* iterate over "width" */
710      for (sx = 0; sx < swidth; )
711      {
712         /* iterate over contexts */
713         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
714         {
715            huffman_context *context = contexts[ctxnum];
716            huffman_node *node = &context->huffnode[source[sx ^ sxor]];
717            bit_buffer_write(&bitbuf, node->bits, node->numbits);
718         }
719      }
720
721      /* advance to the next row */
722      source += sstride;
723   }
724
725   /* flush and return a status */
726   *actlength = bit_buffer_flush(&bitbuf);
727   return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
728}
729
730
731/*-------------------------------------------------
732    huffman_deltarle_encode_data - encode data
733    using the given tree with delta-RLE
734    pre-encoding
735-------------------------------------------------*/
736
737huffman_error huffman_deltarle_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
232huffman_error huffman_context_base::export_tree_rle(bitstream_out &bitbuf)
738233{
739   return huffman_deltarle_encode_data_interleaved(1, &context, source, swidth, sheight, sstride, sxor, dest, dlength, actlength);
740}
234   // bits per entry depends on the maxbits
235   int numbits;
236   if (m_maxbits >= 16)
237      numbits = 5;
238   else if (m_maxbits >= 8)
239      numbits = 4;
240   else
241      numbits = 3;
741242
742huffman_error huffman_deltarle_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
743{
744   UINT32 sx, sy, ctxnum;
745   bit_buffer bitbuf;
746
747   /* initialize the output buffer */
748   bit_buffer_write_init(&bitbuf, dest, dlength);
749
750   /* initialize the contexts */
751   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
243   // RLE encode the lengths
244   int lastval = ~0;
245   int repcount = 0;
246   for (int curcode = 0; curcode < m_numcodes; curcode++)
752247   {
753      huffman_context *context = contexts[ctxnum];
754      context->prevdata = 0;
755   }
248      // if we match the previous value, just bump the repcount
249      int newval = m_huffnode[curcode].m_numbits;
250      if (newval == lastval)
251         repcount++;
756252
757   /* iterate over "height" */
758   for (sy = 0; sy < sheight; sy++)
759   {
760      /* reset RLE counts */
761      for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
253      // otherwise, we need to flush the previous repeats
254      else
762255      {
763         huffman_context *context = contexts[ctxnum];
764         context->rleremaining = 0;
256         if (repcount != 0)
257            write_rle_tree_bits(bitbuf, lastval, repcount, numbits);
258         lastval = newval;
259         repcount = 1;
765260      }
766
767      /* iterate over "width" */
768      for (sx = 0; sx < swidth; )
769      {
770         /* iterate over contexts */
771         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
772         {
773            huffman_context *context = contexts[ctxnum];
774            UINT8 newdata, delta;
775            huffman_node *node;
776
777            /* if still counting RLE, do nothing */
778            if (context->rleremaining != 0)
779            {
780               context->rleremaining--;
781               continue;
782            }
783
784            /* fetch new data and compute the delta */
785            newdata = source[sx ^ sxor];
786            delta = newdata - context->prevdata;
787            context->prevdata = newdata;
788
789            /* 0 deltas scan forward for a count */
790            if (delta == 0)
791            {
792               int zerocount = 1;
793               int rlecode;
794               UINT32 scan;
795
796               /* count the number of consecutive values */
797               for (scan = sx + 1; scan < swidth; scan++)
798                  if (contexts[scan % numcontexts] == context)
799                  {
800                     if (newdata == source[scan ^ sxor])
801                        zerocount++;
802                     else
803                        break;
804                  }
805
806               /* if we hit the end of row, maximize the count */
807               if (scan >= swidth && zerocount >= 8)
808                  zerocount = 100000;
809
810               /* encode the maximal count we can */
811               rlecode = rlecount_to_code(zerocount);
812               node = &context->huffnode[rlecode];
813               bit_buffer_write(&bitbuf, node->bits, node->numbits);
814
815               /* set up the remaining count */
816               context->rleremaining = code_to_rlecount(rlecode) - 1;
817            }
818            else
819            {
820               /* encode the actual delta */
821               node = &context->huffnode[delta];
822               bit_buffer_write(&bitbuf, node->bits, node->numbits);
823            }
824         }
825      }
826
827      /* advance to the next row */
828      source += sstride;
829261   }
830262
831   /* flush and return a status */
832   *actlength = bit_buffer_flush(&bitbuf);
833   return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
263   // flush the last value
264   write_rle_tree_bits(bitbuf, lastval, repcount, numbits);
265   return bitbuf.overflow() ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
834266}
835267
836268
837/*-------------------------------------------------
838    huffman_decode_data - decode data using the
839    given tree
840-------------------------------------------------*/
269//-------------------------------------------------
270//  import_tree_huffman - import a huffman-encoded
271//  huffman tree from a source data stream
272//-------------------------------------------------
841273
842huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
274huffman_error huffman_context_base::import_tree_huffman(bitstream_in &bitbuf)
843275{
844   const huffman_lookup_value *table;
845   int maxbits = context->maxbits;
846   huffman_error error;
847   bit_buffer bitbuf;
848   UINT32 dx, dy;
849
850   /* regenerate the lookup table if necessary */
851   if (context->lookupdirty)
276   // start by parsing the lengths for the small tree
277   huffman_decoder<24, 6> smallhuff;
278   smallhuff.m_huffnode[0].m_numbits = bitbuf.read(3);
279   int start = bitbuf.read(3) + 1;
280   int count = 0;
281   for (int index = 1; index < 24; index++)
852282   {
853      error = build_lookup_table(context, HUFFMAN_CODES);
854      if (error != HUFFERR_NONE)
855         return error;
856   }
857   table = context->lookup;
858
859   /* initialize our bit buffer */
860   bit_buffer_read_init(&bitbuf, source, slength);
861
862   /* iterate over "height" */
863   for (dy = 0; dy < dheight; dy++)
864   {
865      /* iterate over "width" */
866      for (dx = 0; dx < dwidth; dx++)
283      if (index < start || count == 7)
284         smallhuff.m_huffnode[index].m_numbits = 0;
285      else
867286      {
868         huffman_lookup_value lookup;
869         UINT32 bits;
870
871         /* peek ahead to get maxbits worth of data */
872         bits = bit_buffer_peek(&bitbuf, maxbits);
873
874         /* look it up, then remove the actual number of bits for this code */
875         lookup = table[bits];
876         bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
877
878         /* store the upper byte */
879         dest[dx ^ dxor] = LOOKUP_CODE(lookup);
287         count = bitbuf.read(3);
288         smallhuff.m_huffnode[index].m_numbits = (count == 7) ? 0 : count;
880289      }
881
882      /* advance to the next row */
883      dest += dstride;
884290   }
291   
292   // then regenerate the tree
293   huffman_error error = smallhuff.assign_canonical_codes();
294   if (error != HUFFERR_NONE)
295      return error;
296   smallhuff.build_lookup_table();
297   
298   // determine the maximum length of an RLE count
299   UINT32 temp = m_numcodes - 9;
300   UINT8 rlefullbits = 0;
301   while (temp != 0)
302      temp >>= 1, rlefullbits++;
885303
886   /* determine the actual length and indicate overflow */
887   *actlength = bit_buffer_read_offset(&bitbuf);
888   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
889}
890
891
892/*-------------------------------------------------
893    huffman_decode_data_interleaved - decode
894    interleaved data using multiple contexts
895-------------------------------------------------*/
896
897huffman_error huffman_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
898{
899   UINT32 dx, dy, ctxnum;
900   huffman_error error;
901   bit_buffer bitbuf;
902
903   /* regenerate the lookup tables if necessary */
904   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
304   // now process the rest of the data
305   int last = 0;
306   int curcode;
307   for (curcode = 0; curcode < m_numcodes; )
905308   {
906      huffman_context *context = contexts[ctxnum];
907      if (context->lookupdirty)
309      int value = smallhuff.decode_one(bitbuf);
310      if (value != 0)
311         m_huffnode[curcode++].m_numbits = last = value - 1;
312      else
908313      {
909         error = build_lookup_table(context, HUFFMAN_CODES);
910         if (error != HUFFERR_NONE)
911            return error;
314         int count = bitbuf.read(3) + 2;
315         if (count == 7+2)
316            count += bitbuf.read(rlefullbits);
317         for ( ; count != 0 && curcode < m_numcodes; count--)
318            m_huffnode[curcode++].m_numbits = last;
912319      }
913320   }
914321
915   /* initialize our bit buffer */
916   bit_buffer_read_init(&bitbuf, source, slength);
322   // make sure we ended up with the right number
323   if (curcode != m_numcodes)
324      return HUFFERR_INVALID_DATA;
917325
918   /* iterate over "height" */
919   for (dy = 0; dy < dheight; dy++)
920   {
921      /* iterate over "width" */
922      for (dx = 0; dx < dwidth; )
923      {
924         /* iterate over contexts */
925         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, dx++)
926         {
927            huffman_context *context = contexts[ctxnum];
928            huffman_lookup_value lookup;
929            UINT32 bits;
326   // assign canonical codes for all nodes based on their code lengths
327   error = assign_canonical_codes();
328   if (error != HUFFERR_NONE)
329      return error;
930330
931            /* peek ahead to get maxbits worth of data */
932            bits = bit_buffer_peek(&bitbuf, context->maxbits);
331   // build the lookup table
332   build_lookup_table();
933333
934            /* look it up, then remove the actual number of bits for this code */
935            lookup = context->lookup[bits];
936            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
937
938            /* store the upper byte */
939            dest[dx ^ dxor] = LOOKUP_CODE(lookup);
940         }
941      }
942
943      /* advance to the next row */
944      dest += dstride;
945   }
946
947   /* determine the actual length and indicate overflow */
948   *actlength = bit_buffer_read_offset(&bitbuf);
949   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
334   // determine final input length and report errors
335   return bitbuf.overflow() ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
950336}
951337
952338
953/*-------------------------------------------------
954    huffman_deltarle_decode_data - decode data
955    using the given tree with delta-RLE
956    post-decoding
957-------------------------------------------------*/
339//-------------------------------------------------
340//  export_tree_huffman - export a huffman tree to
341//  a huffman target data stream
342//-------------------------------------------------
958343
959huffman_error huffman_deltarle_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
344huffman_error huffman_context_base::export_tree_huffman(bitstream_out &bitbuf)
960345{
961   const huffman_lookup_value *table;
962   int maxbits = context->maxbits;
963   UINT32 rleremaining = 0;
964   huffman_error error;
965   UINT8 prevdata = 0;
966   bit_buffer bitbuf;
967   UINT32 dx, dy;
346   // first RLE compress the lengths of all the nodes
347   dynamic_array<UINT8> rle_data(m_numcodes);
348   UINT8 *dest = rle_data;
349   dynamic_array<UINT16> rle_lengths(m_numcodes/3);
350   UINT16 *lengths = rle_lengths;
351   int last = ~0;
352   int repcount = 0;
353   
354   // use a small huffman context to create a tree (ignoring RLE lengths)
355   huffman_encoder<24, 6> smallhuff;
968356
969   /* regenerate the lookup table if necessary */
970   if (context->lookupdirty)
357   // RLE-compress the lengths
358   for (int curcode = 0; curcode < m_numcodes; curcode++)
971359   {
972      error = build_lookup_table(context, HUFFMAN_DELTARLE_CODES);
973      if (error != HUFFERR_NONE)
974         return error;
975   }
976   table = context->lookup;
977
978   /* initialize our bit buffer */
979   bit_buffer_read_init(&bitbuf, source, slength);
980
981   /* iterate over "height" */
982   for (dy = 0; dy < dheight; dy++)
983   {
984      /* reset RLE counts */
985      rleremaining = 0;
986
987      /* iterate over "width" */
988      for (dx = 0; dx < dwidth; dx++)
360      // if this is the end of a repeat, flush any accumulation
361      int newval = m_huffnode[curcode].m_numbits;
362      if (newval != last && repcount > 0)
989363      {
990         huffman_lookup_value lookup;
991         UINT32 bits;
992         int data;
993
994         /* if we have RLE remaining, just store that */
995         if (rleremaining != 0)
996         {
997            rleremaining--;
998            dest[dx ^ dxor] = prevdata;
999            continue;
1000         }
1001
1002         /* peek ahead to get maxbits worth of data */
1003         bits = bit_buffer_peek(&bitbuf, maxbits);
1004
1005         /* look it up, then remove the actual number of bits for this code */
1006         lookup = table[bits];
1007         bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1008
1009         /* compute the data and handle RLE decoding */
1010         data = LOOKUP_CODE(lookup);
1011
1012         /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1013         if (data < 0x100)
1014            prevdata += (UINT8)data;
1015         else
1016            rleremaining = code_to_rlecount(data) - 1;
1017
1018         /* store the updated data value */
1019         dest[dx ^ dxor] = prevdata;
364         if (repcount == 1)
365            smallhuff.histo_one(*dest++ = last + 1);
366         else
367            smallhuff.histo_one(*dest++ = 0), *lengths++ = repcount - 2;
1020368      }
1021
1022      /* advance to the next row */
1023      dest += dstride;
369     
370      // if same as last, just track repeats
371      if (newval == last)
372         repcount++;
373     
374      // otherwise, write it and start a new run
375      else
376      {
377         smallhuff.histo_one(*dest++ = newval + 1);
378         last = newval;
379         repcount = 0;
380      }
1024381   }
1025382
1026   /* determine the actual length and indicate overflow */
1027   *actlength = bit_buffer_read_offset(&bitbuf);
1028   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
1029}
1030
1031
1032/*-------------------------------------------------
1033    huffman_deltarle_decode_data_interleaved -
1034    decode data using multiple contexts and
1035    delta-RLE post-decoding
1036-------------------------------------------------*/
1037
1038huffman_error huffman_deltarle_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
1039{
1040   UINT32 dx, dy, ctxnum;
1041   huffman_error error;
1042   bit_buffer bitbuf;
1043
1044   /* fast case the A/V Y/Cb/Y/Cr case */
1045   if (numcontexts == 4 && contexts[0] == contexts[2] && contexts[0] != contexts[1] && contexts[1] != contexts[3] &&
1046      contexts[0]->maxbits == contexts[1]->maxbits && contexts[0]->maxbits == contexts[3]->maxbits)
1047      return huffman_deltarle_decode_data_interleaved_0102(contexts, source, slength, dest, dwidth, dheight, dstride, dxor, actlength);
1048
1049   /* regenerate the lookup tables if necessary */
1050   for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
383   // flush any final RLE counts
384   if (repcount > 0)
1051385   {
1052      huffman_context *context = contexts[ctxnum];
1053      if (context->lookupdirty)
1054      {
1055         error = build_lookup_table(context, HUFFMAN_DELTARLE_CODES);
1056         if (error != HUFFERR_NONE)
1057            return error;
1058      }
1059      context->prevdata = 0;
386      if (repcount == 1)
387         smallhuff.histo_one(*dest++ = last + 1);
388      else
389         smallhuff.histo_one(*dest++ = 0), *lengths++ = repcount - 2;
1060390   }
1061391
1062   /* initialize our bit buffer */
1063   bit_buffer_read_init(&bitbuf, source, slength);
392   // compute an optimal tree
393   smallhuff.compute_tree_from_histo();
1064394
1065   /* iterate over "height" */
1066   for (dy = 0; dy < dheight; dy++)
1067   {
1068      /* reset RLE counts */
1069      for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
395   // determine the first and last non-zero nodes
396   int first_non_zero = 31, last_non_zero = 0;
397   for (int index = 1; index < smallhuff.m_numcodes; index++)
398      if (smallhuff.m_huffnode[index].m_numbits != 0)
1070399      {
1071         huffman_context *context = contexts[ctxnum];
1072         context->rleremaining = 0;
400         if (first_non_zero == 31)
401            first_non_zero = index;
402         last_non_zero = index;
1073403      }
1074404
1075      /* iterate over "width" */
1076      for (dx = 0; dx < dwidth; )
1077      {
1078         /* iterate over contexts */
1079         for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, dx++)
1080         {
1081            huffman_context *context = contexts[ctxnum];
1082            huffman_lookup_value lookup;
1083            UINT32 bits;
1084            int data;
405   // clamp first non-zero to be 8 at a maximum
406   first_non_zero = MIN(first_non_zero, 8);
1085407
1086            /* if we have RLE remaining, just store that */
1087            if (context->rleremaining != 0)
1088            {
1089               context->rleremaining--;
1090               dest[dx ^ dxor] = context->prevdata;
1091               continue;
1092            }
408   // output the lengths of the each small tree node, starting with the RLE
409   // token (0), followed by the first_non_zero value, followed by the data
410   // terminated by a 7
411   bitbuf.write(smallhuff.m_huffnode[0].m_numbits, 3);
412   bitbuf.write(first_non_zero - 1, 3);
413   for (int index = first_non_zero; index <= last_non_zero; index++)
414      bitbuf.write(smallhuff.m_huffnode[index].m_numbits, 3);
415   bitbuf.write(7, 3);
416   
417   // determine the maximum length of an RLE count
418   UINT32 temp = m_numcodes - 9;
419   UINT8 rlefullbits = 0;
420   while (temp != 0)
421      temp >>= 1, rlefullbits++;
1093422
1094            /* peek ahead to get maxbits worth of data */
1095            bits = bit_buffer_peek(&bitbuf, context->maxbits);
1096
1097            /* look it up, then remove the actual number of bits for this code */
1098            lookup = context->lookup[bits];
1099            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1100
1101            /* compute the data and handle RLE decoding */
1102            data = LOOKUP_CODE(lookup);
1103
1104            /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1105            if (data < 0x100)
1106               context->prevdata += (UINT8)data;
1107            else
1108               context->rleremaining = code_to_rlecount(data) - 1;
1109
1110            /* store the updated data value */
1111            dest[dx ^ dxor] = context->prevdata;
1112         }
1113      }
1114
1115      /* advance to the next row */
1116      dest += dstride;
1117   }
1118
1119   /* determine the actual length and indicate overflow */
1120   *actlength = bit_buffer_read_offset(&bitbuf);
1121   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
1122}
1123
1124
1125/*-------------------------------------------------
1126    huffman_deltarle_decode_data_interleaved_0102 -
1127    decode data using 3 unique contexts in
1128    0/1/0/2 order (used for Y/Cb/Y/Cr encoding)
1129-------------------------------------------------*/
1130
1131static huffman_error huffman_deltarle_decode_data_interleaved_0102(huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
1132{
1133   const huffman_lookup_value *table02, *table1, *table3;
1134   int rleremaining02, rleremaining1, rleremaining3;
1135   UINT8 prevdata02 = 0, prevdata1 = 0, prevdata3 = 0;
1136   int maxbits = contexts[0]->maxbits;
1137   huffman_error error;
1138   bit_buffer bitbuf;
1139   UINT32 dx, dy;
1140
1141   /* regenerate the lookup tables if necessary */
1142   if (contexts[0]->lookupdirty)
423   // now encode the RLE data
424   lengths = rle_lengths;
425   for (UINT8 *src = rle_data; src < dest; src++)
1143426   {
1144      error = build_lookup_table(contexts[0], HUFFMAN_DELTARLE_CODES);
1145      if (error != HUFFERR_NONE)
1146         return error;
1147   }
1148   if (contexts[1]->lookupdirty)
1149   {
1150      error = build_lookup_table(contexts[1], HUFFMAN_DELTARLE_CODES);
1151      if (error != HUFFERR_NONE)
1152         return error;
1153   }
1154   if (contexts[3]->lookupdirty)
1155   {
1156      error = build_lookup_table(contexts[3], HUFFMAN_DELTARLE_CODES);
1157      if (error != HUFFERR_NONE)
1158         return error;
1159   }
1160
1161   /* cache the tables locally */
1162   table02 = contexts[0]->lookup;
1163   table1 = contexts[1]->lookup;
1164   table3 = contexts[3]->lookup;
1165
1166   /* initialize our bit buffer */
1167   bit_buffer_read_init(&bitbuf, source, slength);
1168
1169   /* iterate over "height" */
1170   for (dy = 0; dy < dheight; dy++)
1171   {
1172      /* reset RLE counts */
1173      rleremaining02 = rleremaining1 = rleremaining3 = 0;
1174
1175      /* iterate over "width" */
1176      for (dx = 0; dx < dwidth; dx += 4)
427      // encode the data
428      UINT8 data = *src;
429      smallhuff.encode_one(bitbuf, data);
430     
431      // if this is an RLE token, encode the length following
432      if (data == 0)
1177433      {
1178         huffman_lookup_value lookup;
1179         UINT32 bits;
1180         int data;
1181
1182         /* ----- offset 0 ----- */
1183
1184         /* if we have RLE remaining, just store that */
1185         if (rleremaining02 != 0)
1186            rleremaining02--;
434         int count = *lengths++;
435         if (count < 7)
436            bitbuf.write(count, 3);
1187437         else
1188         {
1189            /* peek ahead to get maxbits worth of data */
1190            bits = bit_buffer_peek(&bitbuf, maxbits);
1191
1192            /* look it up, then remove the actual number of bits for this code */
1193            lookup = table02[bits];
1194            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1195
1196            /* compute the data and handle RLE decoding */
1197            data = LOOKUP_CODE(lookup);
1198
1199            /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1200            if (data < 0x100)
1201               prevdata02 += (UINT8)data;
1202            else
1203               rleremaining02 = code_to_rlecount(data) - 1;
1204         }
1205
1206         /* store the updated data value */
1207         dest[(dx + 0) ^ dxor] = prevdata02;
1208
1209         /* ----- offset 1 ----- */
1210
1211         /* if we have RLE remaining, just store that */
1212         if (rleremaining1 != 0)
1213            rleremaining1--;
1214         else
1215         {
1216            /* peek ahead to get maxbits worth of data */
1217            bits = bit_buffer_peek(&bitbuf, maxbits);
1218
1219            /* look it up, then remove the actual number of bits for this code */
1220            lookup = table1[bits];
1221            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1222
1223            /* compute the data and handle RLE decoding */
1224            data = LOOKUP_CODE(lookup);
1225
1226            /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1227            if (data < 0x100)
1228               prevdata1 += (UINT8)data;
1229            else
1230               rleremaining1 = code_to_rlecount(data) - 1;
1231         }
1232
1233         /* store the updated data value */
1234         dest[(dx + 1) ^ dxor] = prevdata1;
1235
1236         /* ----- offset 2 (same as 0) ----- */
1237
1238         /* if we have RLE remaining, just store that */
1239         if (rleremaining02 != 0)
1240            rleremaining02--;
1241         else
1242         {
1243            /* peek ahead to get maxbits worth of data */
1244            bits = bit_buffer_peek(&bitbuf, maxbits);
1245
1246            /* look it up, then remove the actual number of bits for this code */
1247            lookup = table02[bits];
1248            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1249
1250            /* compute the data and handle RLE decoding */
1251            data = LOOKUP_CODE(lookup);
1252
1253            /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1254            if (data < 0x100)
1255               prevdata02 += (UINT8)data;
1256            else
1257               rleremaining02 = code_to_rlecount(data) - 1;
1258         }
1259
1260         /* store the updated data value */
1261         dest[(dx + 2) ^ dxor] = prevdata02;
1262
1263         /* ----- offset 3 ----- */
1264
1265         /* if we have RLE remaining, just store that */
1266         if (rleremaining3 != 0)
1267            rleremaining3--;
1268         else
1269         {
1270            /* peek ahead to get maxbits worth of data */
1271            bits = bit_buffer_peek(&bitbuf, maxbits);
1272
1273            /* look it up, then remove the actual number of bits for this code */
1274            lookup = table3[bits];
1275            bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
1276
1277            /* compute the data and handle RLE decoding */
1278            data = LOOKUP_CODE(lookup);
1279
1280            /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
1281            if (data < 0x100)
1282               prevdata3 += (UINT8)data;
1283            else
1284               rleremaining3 = code_to_rlecount(data) - 1;
1285         }
1286
1287         /* store the updated data value */
1288         dest[(dx + 3) ^ dxor] = prevdata3;
438            bitbuf.write(7, 3), bitbuf.write(count - 7, rlefullbits);
1289439      }
1290
1291      /* advance to the next row */
1292      dest += dstride;
1293440   }
1294
1295   /* determine the actual length and indicate overflow */
1296   *actlength = bit_buffer_read_offset(&bitbuf);
1297   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
441   
442   // flush the final buffer
443   return bitbuf.overflow() ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
1298444}
1299445
1300446
447//-------------------------------------------------
448//  compute_tree_from_histo - common backend for
449//  computing a tree based on the data histogram
450//-------------------------------------------------
1301451
1302/***************************************************************************
1303    INTERNAL FUNCTIONS
1304***************************************************************************/
1305
1306/*-------------------------------------------------
1307    import_tree - import a huffman tree from a
1308    source data stream
1309-------------------------------------------------*/
1310
1311static huffman_error import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength, UINT32 numcodes)
452huffman_error huffman_context_base::compute_tree_from_histo()
1312453{
1313   huffman_error error;
1314   bit_buffer bitbuf;
1315   int curnode;
1316   int numbits;
454   // compute the number of data items in the histogram
455   UINT32 sdatacount = 0;
456   for (int i = 0; i < m_numcodes; i++)
457      sdatacount += m_datahisto[i];
1317458
1318   /* initialize the input buffer */
1319   bit_buffer_read_init(&bitbuf, source, slength);
1320
1321   /* bits per entry depends on the maxbits */
1322   if (context->maxbits >= 16)
1323      numbits = 5;
1324   else if (context->maxbits >= 8)
1325      numbits = 4;
1326   else
1327      numbits = 3;
1328
1329   /* loop until we read all the nodes */
1330   for (curnode = 0; curnode < numcodes; )
459   // binary search to achieve the optimum encoding
460   UINT32 lowerweight = 0;
461   UINT32 upperweight = sdatacount * 2;
462   while (1)
1331463   {
1332      int nodebits = bit_buffer_read(&bitbuf, numbits);
464      // build a tree using the current weight
465      UINT32 curweight = (upperweight + lowerweight) / 2;
466      int curmaxbits = build_tree(sdatacount, curweight);
1333467
1334      /* a non-one value is just raw */
1335      if (nodebits != 1)
1336         context->huffnode[curnode++].numbits = nodebits;
1337
1338      /* a one value is an escape code */
1339      else
468      // apply binary search here
469      if (curmaxbits <= m_maxbits)
1340470      {
1341         nodebits = bit_buffer_read(&bitbuf, numbits);
471         lowerweight = curweight;
1342472
1343         /* a double 1 is just a single 1 */
1344         if (nodebits == 1)
1345            context->huffnode[curnode++].numbits = nodebits;
1346
1347         /* otherwise, we need one for value for the repeat count */
1348         else
1349         {
1350            int repcount = bit_buffer_read(&bitbuf, numbits) + 3;
1351            while (repcount--)
1352               context->huffnode[curnode++].numbits = nodebits;
1353         }
473         // early out if it worked with the raw weights, or if we're done searching
474         if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
475            break;
1354476      }
477      else
478         upperweight = curweight;
1355479   }
1356480
1357   /* assign canonical codes for all nodes based on their code lengths */
1358   error = assign_canonical_codes(context, numcodes);
1359   if (error != HUFFERR_NONE)
1360      return error;
1361
1362   /* make sure we ended up with the right number */
1363   if (curnode != numcodes)
1364      return HUFFERR_INVALID_DATA;
1365
1366   *actlength = bit_buffer_read_offset(&bitbuf);
1367   return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
481   // assign canonical codes for all nodes based on their code lengths
482   return assign_canonical_codes();
1368483}
1369484
1370485
1371/*-------------------------------------------------
1372    export_tree - export a huffman tree to a
1373    target data stream
1374-------------------------------------------------*/
1375486
1376static huffman_error export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength, UINT32 numcodes)
1377{
1378   bit_buffer bitbuf;
1379   int repcount;
1380   int lastval;
1381   int numbits;
1382   int i;
487//**************************************************************************
488//  INTERNAL FUNCTIONS
489//**************************************************************************
1383490
1384   /* initialize the output buffer */
1385   bit_buffer_write_init(&bitbuf, dest, dlength);
491//-------------------------------------------------
492//  write_rle_tree_bits - write an RLE encoded
493//  set of data to a target stream
494//-------------------------------------------------
1386495
1387   /* bits per entry depends on the maxbits */
1388   if (context->maxbits >= 16)
1389      numbits = 5;
1390   else if (context->maxbits >= 8)
1391      numbits = 4;
1392   else
1393      numbits = 3;
1394
1395   /* RLE encode the lengths */
1396   lastval = ~0;
1397   repcount = 0;
1398   for (i = 0; i < numcodes; i++)
1399   {
1400      int newval = context->huffnode[i].numbits;
1401
1402      /* if we match the previous value, just bump the repcount */
1403      if (newval == lastval)
1404         repcount++;
1405
1406      /* otherwise, we need to flush the previous repeats */
1407      else
1408      {
1409         if (repcount != 0)
1410            write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
1411         lastval = newval;
1412         repcount = 1;
1413      }
1414   }
1415
1416   /* flush the last value */
1417   write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
1418   *actlength = bit_buffer_flush(&bitbuf);
1419   return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
1420}
1421
1422
1423/*-------------------------------------------------
1424    write_rle_tree_bits - write an RLE encoded
1425    set of data to a target stream
1426-------------------------------------------------*/
1427
1428static void write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits)
496void huffman_context_base::write_rle_tree_bits(bitstream_out &bitbuf, int value, int repcount, int numbits)
1429497{
1430   /* loop until we have output all of the repeats */
498   // loop until we have output all of the repeats
1431499   while (repcount > 0)
1432500   {
1433      /* if we have a 1, write it twice as it is an escape code */
501      // if we have a 1, write it twice as it is an escape code
1434502      if (value == 1)
1435503      {
1436         bit_buffer_write(bitbuf, 1, numbits);
1437         bit_buffer_write(bitbuf, 1, numbits);
504         bitbuf.write(1, numbits);
505         bitbuf.write(1, numbits);
1438506         repcount--;
1439507      }
1440508
1441      /* if we have two or fewer in a row, write them raw */
509      // if we have two or fewer in a row, write them raw
1442510      else if (repcount <= 2)
1443511      {
1444         bit_buffer_write(bitbuf, value, numbits);
512         bitbuf.write(value, numbits);
1445513         repcount--;
1446514      }
1447515
1448      /* otherwise, write a triple using 1 as the escape code */
516      // otherwise, write a triple using 1 as the escape code
1449517      else
1450518      {
1451519         int cur_reps = MIN(repcount - 3, (1 << numbits) - 1);
1452         bit_buffer_write(bitbuf, 1, numbits);
1453         bit_buffer_write(bitbuf, value, numbits);
1454         bit_buffer_write(bitbuf, cur_reps, numbits);
520         bitbuf.write(1, numbits);
521         bitbuf.write(value, numbits);
522         bitbuf.write(cur_reps, numbits);
1455523         repcount -= cur_reps + 3;
1456524      }
1457525   }
1458526}
1459527
1460528
1461/*-------------------------------------------------
1462    tree_node_compare - compare two tree nodes
1463    by weight
1464-------------------------------------------------*/
529//-------------------------------------------------
530//  tree_node_compare - compare two tree nodes
531//  by weight
532//-------------------------------------------------
1465533
1466static int CLIB_DECL tree_node_compare(const void *item1, const void *item2)
534int CLIB_DECL huffman_context_base::tree_node_compare(const void *item1, const void *item2)
1467535{
1468   const huffman_node *node1 = *(const huffman_node **)item1;
1469   const huffman_node *node2 = *(const huffman_node **)item2;
1470   return node2->weight - node1->weight;
536   const node_t *node1 = *(const node_t **)item1;
537   const node_t *node2 = *(const node_t **)item2;
538   return node2->m_weight - node1->m_weight;
1471539}
1472540
1473541
1474/*-------------------------------------------------
1475    compute_optimal_tree - common backend for
1476    computing a tree based on the data histogram
1477-------------------------------------------------*/
542//-------------------------------------------------
543//  build_tree - build a huffman tree based on the
544//  data distribution
545//-------------------------------------------------
1478546
1479static huffman_error compute_optimal_tree(huffman_context *context, const UINT32 *datahisto, UINT32 numcodes)
547int huffman_context_base::build_tree(UINT32 totaldata, UINT32 totalweight)
1480548{
1481   UINT32 lowerweight, upperweight;
1482   UINT32 sdatacount;
1483   int i;
1484
1485   /* compute the number of data items in the histogram */
1486   sdatacount = 0;
1487   for (i = 0; i < numcodes; i++)
1488      sdatacount += datahisto[i];
1489
1490   /* binary search to achieve the optimum encoding */
1491   lowerweight = 0;
1492   upperweight = sdatacount * 2;
1493   while (TRUE)
1494   {
1495      UINT32 curweight = (upperweight + lowerweight) / 2;
1496      int curmaxbits;
1497
1498      /* build a tree using the current weight */
1499      curmaxbits = huffman_build_tree(context, datahisto, sdatacount, curweight, numcodes);
1500
1501      /* apply binary search here */
1502      if (curmaxbits <= context->maxbits)
549   // make a list of all non-zero nodes
550   dynamic_array<node_t *> list(m_numcodes * 2);
551   int listitems = 0;
552   memset(m_huffnode, 0, m_numcodes * sizeof(m_huffnode[0]));
553   for (int curcode = 0; curcode < m_numcodes; curcode++)
554      if (m_datahisto[curcode] != 0)
1503555      {
1504         lowerweight = curweight;
556         list[listitems++] = &m_huffnode[curcode];
557         m_huffnode[curcode].m_count = m_datahisto[curcode];
1505558
1506         /* early out if it worked with the raw weights, or if we're done searching */
1507         if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
1508            break;
559         // scale the weight by the current effective length, ensuring we don't go to 0
560         m_huffnode[curcode].m_weight = UINT64(m_datahisto[curcode]) * UINT64(totalweight) / UINT64(totaldata);
561         if (m_huffnode[curcode].m_weight == 0)
562            m_huffnode[curcode].m_weight = 1;
1509563      }
1510      else
1511         upperweight = curweight;
1512   }
1513564
1514   /* assign canonical codes for all nodes based on their code lengths */
1515   return assign_canonical_codes(context, numcodes);
1516}
1517
1518
1519/*-------------------------------------------------
1520    huffman_build_tree - build a huffman tree
1521    based on the data distribution
1522-------------------------------------------------*/
1523
1524static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight, UINT32 numcodes)
1525{
1526   huffman_node *list[MAX_HUFFMAN_CODES];
1527   int listitems;
1528   int nextalloc;
1529   int maxbits;
1530   int i;
1531
1532   /* make a list of all non-zero nodes */
1533   listitems = 0;
1534   memset(context->huffnode, 0, numcodes * sizeof(context->huffnode[0]));
1535   for (i = 0; i < numcodes; i++)
1536      if (datahisto[i] != 0)
1537      {
1538         list[listitems++] = &context->huffnode[i];
1539         context->huffnode[i].count = datahisto[i];
1540
1541         /* scale the weight by the current effective length, ensuring we don't go to 0 */
1542         context->huffnode[i].weight = (UINT64)datahisto[i] * (UINT64)totalweight / (UINT64)totaldata;
1543         if (context->huffnode[i].weight == 0)
1544            context->huffnode[i].weight = 1;
1545      }
1546
1547   /* sort the list by weight, largest weight first */
565   // sort the list by weight, largest weight first
1548566   qsort(list, listitems, sizeof(list[0]), tree_node_compare);
1549567
1550   /* now build the tree */
1551   nextalloc = MAX_HUFFMAN_CODES;
568   // now build the tree
569   int nextalloc = m_numcodes;
1552570   while (listitems > 1)
1553571   {
1554      huffman_node *node0, *node1, *newnode;
572      // remove lowest two items
573      node_t &node1 = *list[--listitems];
574      node_t &node0 = *list[--listitems];
1555575
1556      /* remove lowest two items */
1557      node1 = list[--listitems];
1558      node0 = list[--listitems];
576      // create new node
577      node_t &newnode = m_huffnode[nextalloc++];
578      newnode.m_parent = NULL;
579      node0.m_parent = node1.m_parent = &newnode;
580      newnode.m_weight = node0.m_weight + node1.m_weight;
1559581
1560      /* create new node */
1561      newnode = &context->huffnode[nextalloc++];
1562      newnode->parent = NULL;
1563      node0->parent = node1->parent = newnode;
1564      newnode->weight = node0->weight + node1->weight;
1565
1566      /* insert into list at appropriate location */
1567      for (i = 0; i < listitems; i++)
1568         if (newnode->weight > list[i]->weight)
582      // insert into list at appropriate location
583      int curitem;
584      for (curitem = 0; curitem < listitems; curitem++)
585         if (newnode.m_weight > list[curitem]->m_weight)
1569586         {
1570            memmove(&list[i+1], &list[i], (listitems - i) * sizeof(list[0]));
587            memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));
1571588            break;
1572589         }
1573      list[i] = newnode;
590      list[curitem] = &newnode;
1574591      listitems++;
1575592   }
1576593
1577   /* compute the number of bits in each code, and fill in another histogram */
1578   maxbits = 0;
1579   for (i = 0; i < numcodes; i++)
594   // compute the number of bits in each code, and fill in another histogram
595   int maxbits = 0;
596   for (int curcode = 0; curcode < m_numcodes; curcode++)
1580597   {
1581      huffman_node *node = &context->huffnode[i];
1582      node->numbits = 0;
598      node_t &node = m_huffnode[curcode];
599      node.m_numbits = 0;
1583600
1584      /* if we have a non-zero weight, compute the number of bits */
1585      if (node->weight > 0)
601      // if we have a non-zero weight, compute the number of bits
602      if (node.m_weight > 0)
1586603      {
1587         huffman_node *curnode;
604         // determine the number of bits for this node
605         for (node_t *curnode = &node; curnode->m_parent != NULL; curnode = curnode->m_parent)
606            node.m_numbits++;
607         if (node.m_numbits == 0)
608            node.m_numbits = 1;
1588609
1589         /* determine the number of bits for this node */
1590         for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
1591            node->numbits++;
1592         if (node->numbits == 0)
1593            node->numbits = 1;
1594
1595         /* keep track of the max */
1596         maxbits = MAX(maxbits, node->numbits);
610         // keep track of the max
611         maxbits = MAX(maxbits, node.m_numbits);
1597612      }
1598613   }
1599
1600614   return maxbits;
1601615}
1602616
1603617
1604/*-------------------------------------------------
1605    assign_canonical_codes - assign
1606    canonical codes to all the nodes based on the
1607    number of bits in each
1608-------------------------------------------------*/
618//-------------------------------------------------
619//  assign_canonical_codes - assign canonical codes
620//  to all the nodes based on the number of bits
621//  in each
622//-------------------------------------------------
1609623
1610static huffman_error assign_canonical_codes(huffman_context *context, UINT32 numcodes)
624huffman_error huffman_context_base::assign_canonical_codes()
1611625{
1612   UINT32 bithisto[33];
1613   int curstart;
1614   int i;
1615
1616   /* build up a histogram of bit lengths */
1617   memset(bithisto, 0, sizeof(bithisto));
1618   for (i = 0; i < numcodes; i++)
626   // build up a histogram of bit lengths
627   UINT32 bithisto[33] = { 0 };
628   for (int curcode = 0; curcode < m_numcodes; curcode++)
1619629   {
1620      huffman_node *node = &context->huffnode[i];
1621      if (node->numbits > context->maxbits)
630      node_t &node = m_huffnode[curcode];
631      if (node.m_numbits > m_maxbits)
1622632         return HUFFERR_INTERNAL_INCONSISTENCY;
1623      if (node->numbits <= 32)
1624         bithisto[node->numbits]++;
633      if (node.m_numbits <= 32)
634         bithisto[node.m_numbits]++;
1625635   }
1626636
1627   /* for each code length, determine the starting code number */
1628   curstart = 0;
1629   for (i = 32; i > 0; i--)
637   // for each code length, determine the starting code number
638   UINT32 curstart = 0;
639   for (int codelen = 32; codelen > 0; codelen--)
1630640   {
1631      UINT32 nextstart = (curstart + bithisto[i]) >> 1;
1632      if (i != 1 && nextstart * 2 != (curstart + bithisto[i]))
641      UINT32 nextstart = (curstart + bithisto[codelen]) >> 1;
642      if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
1633643         return HUFFERR_INTERNAL_INCONSISTENCY;
1634      bithisto[i] = curstart;
644      bithisto[codelen] = curstart;
1635645      curstart = nextstart;
1636646   }
1637647
1638   /* now assign canonical codes */
1639   for (i = 0; i < numcodes; i++)
648   // now assign canonical codes
649   for (int curcode = 0; curcode < m_numcodes; curcode++)
1640650   {
1641      huffman_node *node = &context->huffnode[i];
1642      if (node->numbits > 0)
1643         node->bits = bithisto[node->numbits]++;
651      node_t &node = m_huffnode[curcode];
652      if (node.m_numbits > 0)
653         node.m_bits = bithisto[node.m_numbits]++;
1644654   }
1645
1646   /* if there was a decoding table, get rid of it now */
1647   context->lookupdirty = TRUE;
1648655   return HUFFERR_NONE;
1649656}
1650657
1651658
1652/*-------------------------------------------------
1653    build_lookup_table - build a lookup
1654    table for fast decoding
1655-------------------------------------------------*/
659//-------------------------------------------------
660//  build_lookup_table - build a lookup table for
661//  fast decoding
662//-------------------------------------------------
1656663
1657static huffman_error build_lookup_table(huffman_context *context, UINT32 numcodes)
664void huffman_context_base::build_lookup_table()
1658665{
1659   int i;
1660
1661   /* allocate a table if needed */
1662   if (context->lookup == NULL)
1663      context->lookup = (huffman_lookup_value *)malloc((UINT32)sizeof(context->lookup[0]) * (UINT32)(1 << context->maxbits));
1664   if (context->lookup == NULL)
1665      return HUFFERR_OUT_OF_MEMORY;
1666
1667   /* now build */
1668   for (i = 0; i < numcodes; i++)
666   // iterate over all codes
667   for (int curcode = 0; curcode < m_numcodes; curcode++)
1669668   {
1670      huffman_node *node = &context->huffnode[i];
1671      if (node->numbits > 0)
669      // process all nodes which have non-zero bits
670      node_t &node = m_huffnode[curcode];
671      if (node.m_numbits > 0)
1672672      {
1673         huffman_lookup_value *dest, *destend;
673         // set up the entry
674         lookup_value value = MAKE_LOOKUP(curcode, node.m_numbits);
1674675
1675         /* left justify this node's bit values to max bits */
1676         int shift = context->maxbits - node->numbits;
1677         UINT32 start = node->bits << shift;
1678         UINT32 end = ((node->bits + 1) << shift) - 1;
1679         huffman_lookup_value value;
1680
1681         /* set up the entry */
1682         value = (i << 6) | node->numbits;
1683
1684         /* fill all matching entries */
1685         dest = &context->lookup[start];
1686         destend = &context->lookup[end];
676         // fill all matching entries
677         int shift = m_maxbits - node.m_numbits;
678         lookup_value *dest = &m_lookup[node.m_bits << shift];
679         lookup_value *destend = &m_lookup[((node.m_bits + 1) << shift) - 1];
1687680         while (dest <= destend)
1688681            *dest++ = value;
1689682      }
1690683   }
684}
1691685
1692   /* no longer dirty */
1693   context->lookupdirty = FALSE;
1694   return HUFFERR_NONE;
686
687
688//**************************************************************************
689//  8-BIT ENCODER
690//**************************************************************************
691
692//-------------------------------------------------
693//  huffman_8bit_encoder - constructor
694//-------------------------------------------------
695
696huffman_8bit_encoder::huffman_8bit_encoder()
697{
1695698}
699   
700
701//-------------------------------------------------
702//  encode - encode a full buffer
703//-------------------------------------------------
704
705huffman_error huffman_8bit_encoder::encode(const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 &complength)
706{
707   // first compute the histogram
708   histo_reset();
709   for (UINT32 cur = 0; cur < slength; cur++)
710      histo_one(source[cur]);
711
712   // then compute the tree
713   huffman_error err = compute_tree_from_histo();
714   if (err != HUFFERR_NONE)
715      return err;
716   
717   // export the tree
718   bitstream_out bitbuf(dest, dlength);
719   err = export_tree_huffman(bitbuf);
720   if (err != HUFFERR_NONE)
721      return err;
722   
723   // then encode the data
724   for (UINT32 cur = 0; cur < slength; cur++)
725      encode_one(bitbuf, source[cur]);
726   complength = bitbuf.flush();
727   return bitbuf.overflow() ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
728}
729
730   
731
732//**************************************************************************
733//  8-BIT DECODER
734//**************************************************************************
735
736//-------------------------------------------------
737//  huffman_8bit_decoder - constructor
738//-------------------------------------------------
739
740huffman_8bit_decoder::huffman_8bit_decoder()
741{
742}
743   
744
745//-------------------------------------------------
746//  decode - decode a full buffer
747//-------------------------------------------------
748
749huffman_error huffman_8bit_decoder::decode(const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength)
750{
751   // first import the tree
752   bitstream_in bitbuf(source, slength);
753   huffman_error err = import_tree_huffman(bitbuf);
754   if (err != HUFFERR_NONE)
755      return err;
756   
757   // then decode the data
758   for (UINT32 cur = 0; cur < dlength; cur++)
759      dest[cur] = decode_one(bitbuf);
760   bitbuf.flush();
761   return bitbuf.overflow() ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
762}
src/lib/util/avhuff.h
r0r14482
1/***************************************************************************
2
3    avhuff.h
4
5    Audio/video compression and decompression helpers.
6
7****************************************************************************
8
9    Copyright Aaron Giles
10    All rights reserved.
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:
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.
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.
37
38***************************************************************************/
39
40#pragma once
41
42#ifndef __AVHUFF_H__
43#define __AVHUFF_H__
44
45#include "osdcore.h"
46#include "coretmpl.h"
47#include "bitmap.h"
48#include "huffman.h"
49#include "flac.h"
50
51
52//**************************************************************************
53//  CONSTANTS
54//**************************************************************************
55
56#define AVHUFF_USE_FLAC      (1)
57
58
59// errors
60enum avhuff_error
61{
62   AVHERR_NONE = 0,
63   AVHERR_INVALID_DATA,
64   AVHERR_VIDEO_TOO_LARGE,
65   AVHERR_AUDIO_TOO_LARGE,
66   AVHERR_METADATA_TOO_LARGE,
67   AVHERR_OUT_OF_MEMORY,
68   AVHERR_COMPRESSION_ERROR,
69   AVHERR_TOO_MANY_CHANNELS,
70   AVHERR_INVALID_CONFIGURATION,
71   AVHERR_INVALID_PARAMETER,
72   AVHERR_BUFFER_TOO_SMALL
73};
74
75
76
77//**************************************************************************
78//  TYPE DEFINITIONS
79//**************************************************************************
80
81// ======================> av_codec_decompress_config
82
83// decompression configuration
84class avhuff_decompress_config
85{
86public:
87   avhuff_decompress_config()
88      : maxsamples(0),
89        actsamples(NULL),
90        maxmetalength(0),
91        actmetalength(NULL),
92        metadata(NULL)
93   {
94      memset(audio, 0, sizeof(audio));
95   }
96
97   bitmap_yuy16 video;                  // pointer to video bitmap
98   UINT32      maxsamples;               // maximum number of samples per channel
99   UINT32 *   actsamples;               // actual number of samples per channel
100   INT16 *      audio[16];               // pointer to individual audio channels
101   UINT32      maxmetalength;            // maximum length of metadata
102   UINT32 *   actmetalength;            // actual length of metadata
103   UINT8 *      metadata;               // pointer to metadata buffer
104};
105
106
107// ======================> avhuff_encoder
108
109// core state for the codec
110class avhuff_encoder
111{
112public:
113   // construction/destruction
114   avhuff_encoder();
115
116   // encode/decode
117   avhuff_error encode_data(const UINT8 *source, UINT8 *dest, UINT32 &complength);
118
119   // static helpers
120   static UINT32 raw_data_size(const UINT8 *data);
121   static UINT32 raw_data_size(UINT32 width, UINT32 height, UINT8 channels, UINT32 numsamples, UINT32 metadatasize = 0) { return 12 + channels * numsamples * 2 + width * height * 2; }
122   static avhuff_error assemble_data(UINT8 *dest, UINT32 dlength, bitmap_yuy16 &bitmap, UINT8 channels, UINT32 numsamples, INT16 **samples, UINT8 *metadata = NULL, UINT32 metadatasize = 0);
123
124private:
125   // delta-RLE Huffman encoder
126   class deltarle_encoder
127   {
128   public:
129      // construction/destruction
130      deltarle_encoder()
131         : m_rlecount(0) { }
132         
133      // histogramming
134      UINT16 *rle_and_histo_bitmap(const UINT8 *source, UINT32 items_per_row, UINT32 item_advance, UINT32 row_count);
135
136      // encoding
137      void flush_rle() { m_rlecount = 0; }
138      void encode_one(bitstream_out &bitbuf, UINT16 *&rleptr);
139      huffman_error export_tree_rle(bitstream_out &bitbuf) { return m_encoder.export_tree_rle(bitbuf); }
140
141   private:
142      // internal state
143      int                     m_rlecount;
144      huffman_encoder<256 + 16>   m_encoder;
145      dynamic_array<UINT16>      m_rlebuffer;
146   };
147
148   // internal helpers
149   avhuff_error encode_audio(const UINT8 *source, int channels, int samples, UINT8 *dest, UINT8 *sizes);
150   avhuff_error encode_video(const UINT8 *source, int width, int height, UINT8 *dest, UINT32 &complength);
151   avhuff_error encode_video_lossless(const UINT8 *source, int width, int height, UINT8 *dest, UINT32 &complength);
152
153   // video encoding contexts   
154   deltarle_encoder          m_ycontext;
155   deltarle_encoder          m_cbcontext;
156   deltarle_encoder          m_crcontext;
157
158   // audio encoding contexts
159   dynamic_buffer            m_audiobuffer;
160#if AVHUFF_USE_FLAC
161   flac_encoder            m_flac_encoder;
162#else
163   huffman_8bit_encoder      m_audiohi_encoder;
164   huffman_8bit_encoder      m_audiolo_encoder;
165#endif
166};
167
168
169// ======================> avhuff_decoder
170
171// core state for the codec
172class avhuff_decoder
173{
174public:
175   // construction/destruction
176   avhuff_decoder();
177
178   // configuration
179   void configure(const avhuff_decompress_config &config);
180
181   // encode/decode
182   avhuff_error decode_data(const UINT8 *source, UINT32 complength, UINT8 *dest);
183
184private:
185   // delta-RLE Huffman decoder
186   class deltarle_decoder
187   {
188   public:
189      // construction/destruction
190      deltarle_decoder()
191         : m_rlecount(0), m_prevdata(0) { }
192         
193      // general
194      void reset() { m_rlecount = m_prevdata = 0; }
195
196      // decoding
197      void flush_rle() { m_rlecount = 0; }
198      UINT32 decode_one(bitstream_in &bitbuf);
199      huffman_error import_tree_rle(bitstream_in &bitbuf) { return m_decoder.import_tree_rle(bitbuf); }
200
201   private:
202      // internal state
203      int                     m_rlecount;
204      UINT8                  m_prevdata;
205      huffman_decoder<256 + 16>   m_decoder;
206   };
207
208
209   // internal helpers
210   avhuff_error decode_audio(int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes);
211   avhuff_error decode_video(int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor);
212   avhuff_error decode_video_lossless(int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor);
213
214   // internal state
215   avhuff_decompress_config    m_config;
216
217   // video decoding contexts
218   deltarle_decoder          m_ycontext;
219   deltarle_decoder          m_cbcontext;
220   deltarle_decoder          m_crcontext;
221
222   // audio decoding contexts
223   huffman_8bit_decoder      m_audiohi_decoder;
224   huffman_8bit_decoder      m_audiolo_decoder;
225#if AVHUFF_USE_FLAC
226   flac_decoder            m_flac_decoder;
227#endif
228};
229
230
231#endif
src/lib/util/corefile.c
r14481r14482
757757   return FILERR_NONE;
758758}
759759
760file_error core_fload(const char *filename, dynamic_buffer &data)
761{
762   core_file *file = NULL;
763   file_error err;
764   UINT64 size;
760765
766   /* attempt to open the file */
767   err = core_fopen(filename, OPEN_FLAG_READ, &file);
768   if (err != FILERR_NONE)
769      return err;
761770
771   /* get the size */
772   size = core_fsize(file);
773   if ((UINT32)size != size)
774   {
775      core_fclose(file);
776      return FILERR_OUT_OF_MEMORY;
777   }
778
779   /* allocate memory */
780   data.resize(size);
781
782   /* read the data */
783   if (core_fread(file, data, size) != size)
784   {
785      core_fclose(file);
786      data.reset();
787      return FILERR_FAILURE;
788   }
789
790   /* close the file and return data */
791   core_fclose(file);
792   return FILERR_NONE;
793}
794
795
796
762797/***************************************************************************
763798    FILE WRITE
764799***************************************************************************/
src/lib/util/huffman.h
r14481r14482
22
33    huffman.h
44
5    Huffman compression routines.
5    Static Huffman compression and decompression helpers.
66
77****************************************************************************
88
r14481r14482
3737
3838***************************************************************************/
3939
40#pragma once
41
4042#ifndef __HUFFMAN_H__
43#define __HUFFMAN_H__
4144
4245#include "osdcore.h"
46#include "bitstream.h"
4347
4448
45/***************************************************************************
46    CONSTANTS
47***************************************************************************/
49//**************************************************************************
50//  CONSTANTS
51//**************************************************************************
4852
49enum _huffman_error
53enum huffman_error
5054{
5155   HUFFERR_NONE = 0,
52   HUFFERR_OUT_OF_MEMORY,
5356   HUFFERR_TOO_MANY_BITS,
5457   HUFFERR_INVALID_DATA,
5558   HUFFERR_INPUT_BUFFER_TOO_SMALL,
r14481r14482
5760   HUFFERR_INTERNAL_INCONSISTENCY,
5861   HUFFERR_TOO_MANY_CONTEXTS
5962};
60typedef enum _huffman_error huffman_error;
6163
6264
6365
64/***************************************************************************
65    TYPE DEFINITIONS
66***************************************************************************/
66//**************************************************************************
67//  TYPE DEFINITIONS
68//**************************************************************************
6769
68typedef UINT16 huffman_lookup_value;
70// ======================> huffman_context_base
6971
70typedef struct _huffman_context huffman_context;
72// base class for encoding and decoding
73class huffman_context_base
74{
75protected:
76   typedef UINT16 lookup_value;
7177
78   // a node in the huffman tree
79   struct node_t
80   {
81      node_t *         m_parent;            // pointer to parent node
82      UINT32            m_count;            // number of hits on this node
83      UINT32            m_weight;            // assigned weight of this node
84      UINT32            m_bits;               // bits used to encode the node
85      UINT8            m_numbits;            // number of bits needed for this node
86   };
87   
88   // construction/destruction
89   huffman_context_base(int numcodes, int maxbits, lookup_value *lookup, UINT32 *histo, node_t *nodes);
7290
91   // tree creation
92   huffman_error compute_tree_from_histo();
7393
74/***************************************************************************
75    FUNCTION PROTOTYPES
76***************************************************************************/
94   // static tree import; huffman is notably more efficient
95   huffman_error import_tree_rle(bitstream_in &bitbuf);
96   huffman_error import_tree_huffman(bitstream_in &bitbuf);
7797
78huffman_error huffman_create_context(huffman_context **context, int maxbits);
79void huffman_free_context(huffman_context *context);
98   // static tree export
99   huffman_error export_tree_rle(bitstream_out &bitbuf);
100   huffman_error export_tree_huffman(bitstream_out &bitbuf);
80101
81huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength);
82huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
83huffman_error huffman_deltarle_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength);
84huffman_error huffman_deltarle_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
102   // internal helpers
103   void write_rle_tree_bits(bitstream_out &bitbuf, int value, int repcount, int numbits);
104   static int CLIB_DECL tree_node_compare(const void *item1, const void *item2);
105   int build_tree(UINT32 totaldata, UINT32 totalweight);
106   huffman_error assign_canonical_codes();
107   void build_lookup_table();
85108
86huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
87huffman_error huffman_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
88huffman_error huffman_deltarle_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
89huffman_error huffman_deltarle_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
109protected:
110   // internal state
111   UINT32               m_numcodes;            // number of total codes being processed
112   UINT8               m_maxbits;            // maximum bits per code
113   UINT8               m_prevdata;            // value of the previous data (for delta-RLE encoding)
114   int                  m_rleremaining;         // number of RLE bytes remaining (for delta-RLE encoding)
115   lookup_value *         m_lookup;            // pointer to the lookup table
116   UINT32 *            m_datahisto;         // histogram of data values
117   node_t *            m_huffnode;            // array of nodes
118};
90119
91huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
92huffman_error huffman_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
93huffman_error huffman_deltarle_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
94huffman_error huffman_deltarle_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
95120
96huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
97huffman_error huffman_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
98huffman_error huffman_deltarle_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
99huffman_error huffman_deltarle_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
121// ======================> huffman_encoder
100122
123// template class for encoding
124template<int _NumCodes = 256, int _MaxBits = 16>
125class huffman_encoder : public huffman_context_base
126{
127public:
128   // pass through to the underlying constructor
129   huffman_encoder()
130      : huffman_context_base(_NumCodes, _MaxBits, NULL, m_datahisto_array, m_huffnode_array) { histo_reset(); }
131
132   // single item operations
133   void histo_reset() { memset(m_datahisto_array, 0, sizeof(m_datahisto_array)); }
134   void histo_one(UINT32 data);
135   void encode_one(bitstream_out &bitbuf, UINT32 data);
136   
137   // expose tree computation and export
138   using huffman_context_base::compute_tree_from_histo;
139   using huffman_context_base::export_tree_rle;
140   using huffman_context_base::export_tree_huffman;
141   
142private:
143   // array versions of the info we need
144   UINT32               m_datahisto_array[_NumCodes];
145   node_t               m_huffnode_array[_NumCodes * 2];
146};
147
148
149// ======================> huffman_decoder
150
151// template class for decoding
152template<int _NumCodes = 256, int _MaxBits = 16>
153class huffman_decoder : public huffman_context_base
154{
155public:
156   // pass through to the underlying constructor
157   huffman_decoder()
158      : huffman_context_base(_NumCodes, _MaxBits, m_lookup_array, NULL, m_huffnode_array) { }
159
160   // single item operations
161   UINT32 decode_one(bitstream_in &bitbuf);
162   
163   // expose tree import
164   using huffman_context_base::import_tree_rle;
165   using huffman_context_base::import_tree_huffman;
166   
167private:
168   // array versions of the info we need
169   node_t               m_huffnode_array[_NumCodes];
170   lookup_value         m_lookup_array[1 << _MaxBits];
171};
172
173
174// ======================> huffman_8bit_encoder
175
176// generic 8-bit encoder/decoder
177class huffman_8bit_encoder : public huffman_encoder<>
178{
179public:
180   // construction/destruction
181   huffman_8bit_encoder();
182   
183   // operations
184   huffman_error encode(const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 destlength, UINT32 &complength);
185};
186
187   
188// ======================> huffman_8bit_decoder
189
190// generic 8-bit encoder/decoder
191class huffman_8bit_decoder : public huffman_decoder<>
192{
193public:
194   // construction/destruction
195   huffman_8bit_decoder();
196   
197   // operations
198   huffman_error decode(const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 destlength);
199};
200
201
202
203//**************************************************************************
204//  INLINE FUNCTIONS
205//**************************************************************************
206
207//-------------------------------------------------
208//  histo_one - update the histogram
209//-------------------------------------------------
210
211template<int _NumCodes, int _MaxBits>
212inline void huffman_encoder<_NumCodes, _MaxBits>::histo_one(UINT32 data)
213{
214   m_datahisto[data]++;
215}
216
217
218//-------------------------------------------------
219//  encode_one - encode a single code to the
220//  huffman stream
221//-------------------------------------------------
222
223template<int _NumCodes, int _MaxBits>
224inline void huffman_encoder<_NumCodes, _MaxBits>::encode_one(bitstream_out &bitbuf, UINT32 data)
225{
226   // write the data
227   node_t &node = m_huffnode[data];
228   bitbuf.write(node.m_bits, node.m_numbits);
229}
230
231
232//-------------------------------------------------
233//  decode_one - decode a single code from the
234//  huffman stream
235//-------------------------------------------------
236
237template<int _NumCodes, int _MaxBits>
238inline UINT32 huffman_decoder<_NumCodes, _MaxBits>::decode_one(bitstream_in &bitbuf)
239{
240   // peek ahead to get maxbits worth of data
241   UINT32 bits = bitbuf.peek(m_maxbits);
242
243   // look it up, then remove the actual number of bits for this code
244   lookup_value lookup = m_lookup[bits];
245   bitbuf.remove(lookup & 0x1f);
246
247   // return the value
248   return lookup >> 5;
249}
250
251
101252#endif
src/lib/util/harddisk.c
r14481r14482
4646    TYPE DEFINITIONS
4747***************************************************************************/
4848
49struct _hard_disk_file
49struct hard_disk_file
5050{
5151   chd_file *         chd;            /* CHD file */
5252   hard_disk_info      info;            /* hard disk info */
53   UINT32            hunksectors;      /* sectors per hunk */
54   UINT32            cachehunk;         /* which hunk is cached */
55   UINT8 *            cache;            /* cache of the current hunk */
5653};
5754
5855
r14481r14482
7067{
7168   int cylinders, heads, sectors, sectorbytes;
7269   hard_disk_file *file;
73   char metadata[256];
70   astring metadata;
7471   chd_error err;
7572
7673   /* punt if no CHD */
r14481r14482
7875      return NULL;
7976
8077   /* read the hard disk metadata */
81   err = chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
78   err = chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
8279   if (err != CHDERR_NONE)
8380      return NULL;
8481
r14481r14482
9794   file->info.heads = heads;
9895   file->info.sectors = sectors;
9996   file->info.sectorbytes = sectorbytes;
100   file->hunksectors = chd_get_header(chd)->hunkbytes / file->info.sectorbytes;
101   file->cachehunk = -1;
102
103   /* allocate a cache */
104   file->cache = (UINT8 *)malloc(chd_get_header(chd)->hunkbytes);
105   if (file->cache == NULL)
106   {
107      free(file);
108      return NULL;
109   }
110
11197   return file;
11298}
11399
r14481r14482
118104
119105void hard_disk_close(hard_disk_file *file)
120106{
121   /* free the cache */
122   if (file->cache != NULL)
123      free(file->cache);
124107   free(file);
125108}
126109
r14481r14482
154137
155138UINT32 hard_disk_read(hard_disk_file *file, UINT32 lbasector, void *buffer)
156139{
157   UINT32 hunknum = lbasector / file->hunksectors;
158   UINT32 sectoroffs = lbasector % file->hunksectors;
159
160   /* if we haven't cached this hunk, read it now */
161   if (file->cachehunk != hunknum)
162   {
163      chd_error err = chd_read(file->chd, hunknum, file->cache);
164      if (err != CHDERR_NONE)
165         return 0;
166      file->cachehunk = hunknum;
167   }
168
169   /* copy out the requested sector */
170   memcpy(buffer, &file->cache[sectoroffs * file->info.sectorbytes], file->info.sectorbytes);
171   return 1;
140   chd_error err = file->chd->read_units(lbasector, buffer);
141   return (err == CHDERR_NONE);
172142}
173143
174144
r14481r14482
179149
180150UINT32 hard_disk_write(hard_disk_file *file, UINT32 lbasector, const void *buffer)
181151{
182   UINT32 hunknum = lbasector / file->hunksectors;
183   UINT32 sectoroffs = lbasector % file->hunksectors;
184   chd_error err;
185
186   /* if we haven't cached this hunk, read it now */
187   if (file->cachehunk != hunknum)
188   {
189      err = chd_read(file->chd, hunknum, file->cache);
190      if (err != CHDERR_NONE)
191         return 0;
192      file->cachehunk = hunknum;
193   }
194
195   /* copy in the requested data */
196   memcpy(&file->cache[sectoroffs * file->info.sectorbytes], buffer, file->info.sectorbytes);
197
198   /* write it back out */
199   err = chd_write(file->chd, hunknum, file->cache);
200   return (err == CHDERR_NONE) ? 1 : 0;
152   chd_error err = file->chd->write_units(lbasector, buffer);
153   return (err == CHDERR_NONE);
201154}
src/lib/util/corefile.h
r14481r14482
4545#include <stdarg.h>
4646#include "osdcore.h"
4747#include "astring.h"
48#include "coretmpl.h"
4849
4950
5051
r14481r14482
129130
130131/* open a file with the specified filename, read it into memory, and return a pointer */
131132file_error core_fload(const char *filename, void **data, UINT32 *length);
133file_error core_fload(const char *filename, dynamic_buffer &data);
132134
133135
134136
src/ldplayer/ldplayer.c
r14481r14482
166166
167167   // iterate while we get new objects
168168   const osd_directory_entry *dir;
169   emu_file *image_file = NULL;
170   chd_file *image_chd = NULL;
171169   while ((dir = path.next()) != NULL)
172170   {
173171      int length = strlen(dir->name);
r14481r14482
180178         tolower(dir->name[length - 1]) == 'd')
181179      {
182180         // open the file itself via our search path
183         image_file = auto_alloc(machine(), emu_file(machine().options().media_path(), OPEN_FLAG_READ));
184         file_error filerr = image_file->open(dir->name);
181         emu_file image_file(machine().options().media_path(), OPEN_FLAG_READ);
182         file_error filerr = image_file.open(dir->name);
185183         if (filerr == FILERR_NONE)
186184         {
185            astring fullpath(image_file->fullpath();
186            image_file.close();
187           
187188            // try to open the CHD
188            chd_error chderr = chd_open_file(*image_file, CHD_OPEN_READ, NULL, &image_chd);
189            if (chderr == CHDERR_NONE)
189           
190            if (set_disk_handle(machine(), "laserdisc", fullpath) == CHDERR_NONE)
190191            {
191               set_disk_handle(machine(), "laserdisc", *image_file, *image_chd);
192192               m_filename.cpy(dir->name);
193193               break;
194194            }

Previous 15994 Revisions Next


© 1998-2018 The MESS Team