home *** CD-ROM | disk | FTP | other *** search
/ PC Shareware 1996 December / PC_Shareware-1996-12.iso / windows / spectrum / sources / sna_save.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-25  |  25.3 KB  |  1,045 lines

  1. /* Sna_Save.c : Snapshot and data transfer disk logic -- saving part.
  2.  *
  3.  * Copyright 1996 Rui Fernando Ferreira Ribeiro.
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /*
  21.  * History:
  22.  *
  23.  *      4th April 96:
  24.  *              . Added .SIT and .BLK handling logic
  25.  */
  26.  
  27.  
  28. #include <windows.h>
  29. #include <commdlg.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <dir.h>
  34. #include "env.h"
  35. #include "snap.h"
  36.  
  37. static char snapname[260]; 
  38.  
  39. /* built-in software cache logic */
  40. static is_eof = 0;
  41.  
  42. #define BUFFER_SIZE 2048
  43.  
  44. /* position of the buffer being read */
  45. static short BufferPos = BUFFER_SIZE;
  46. /* Bytes read from the buffer */
  47. static short BytesRead = BUFFER_SIZE;
  48. static PBYTE pbBuf = NULL;
  49.  
  50. /* local functions prototypes */
  51. static sna_save(HFILE fp);
  52. static snx_save(HFILE fp);
  53. static sp_save(HFILE  fp);
  54. static sit_save(HFILE fp);
  55. static z80_save(HFILE fp);
  56. static zx_save(HFILE  fp);
  57. static prg_save(HFILE fp);
  58. static ach_save(HFILE fp);
  59. static tap_save(HFILE fp);
  60. static rom_save(HFILE fp);
  61. static scr_save(HFILE fp);
  62. static save_options(HFILE fp);
  63.  
  64.  
  65. /* put a byte in file */
  66. void putbyte(UCHAR c, HFILE fp)
  67. {
  68.    if(pbBuf == NULL)
  69.    {
  70.       pbBuf = (PBYTE)LocalAlloc(LMEM_FIXED, BUFFER_SIZE);
  71.       LocalLock((HLOCAL)pbBuf);
  72.       BufferPos = 0;
  73.    }
  74.    *(pbBuf+BufferPos++) = c;
  75.    if(BufferPos == BUFFER_SIZE)
  76.    {
  77.       _lwrite(fp, pbBuf, BUFFER_SIZE);
  78.       BufferPos = 0;
  79.    }
  80. }
  81.  
  82. // seek inside the buffer disp bytes from the current position
  83. static void w_seek(HFILE hfp, long disp)
  84. {
  85.    while(disp--)
  86.       putbyte(0, hfp);
  87. }
  88.  
  89. // close file and buffer
  90. static void w_close(HFILE hfp)
  91. {
  92.    if(BufferPos)
  93.    {
  94.       _lwrite(hfp, pbBuf, BufferPos);
  95.    }
  96.    LocalUnlock((HLOCAL)pbBuf);
  97.    LocalFree((HLOCAL)pbBuf);
  98.    pbBuf = NULL;
  99.    BufferPos = BytesRead;
  100.    _lclose(hfp);
  101. }
  102.  
  103.  
  104. /* type of files */
  105. static snap_type(char * file_name)
  106. {
  107.   char ext[MAXEXT];
  108.    int flags;
  109.    int val = 255;
  110.    struct map
  111.    {
  112.       char * snap_extension;
  113.       short snap_val;
  114.    } map_ext[] =
  115.    {
  116.     { ".PCX", PCX_FMT },
  117.     { ".SNA", SNA_FMT },
  118.     { ".SNX", SNX_FMT },
  119.     { ".Z80", Z80_FMT },
  120.     { ".SIT", SIT_FMT },
  121.     { ".SP",  SP_FMT  },
  122.     { ".RAW", RAW_FMT },
  123.     { ".ZX",  ZX_FMT  },
  124.     { ".PRG", PRG_FMT },
  125.     { ".ACH", ACH_FMT },
  126.     { ".TAP", TAP_FMT },
  127.     { ".ROM", ROM_FMT },
  128.     { ".DAT", DAT_FMT },
  129.     { ".SCR", SCR_FMT },
  130.     { ".INI", INI_FMT }
  131.    };
  132.  
  133.    flags = fnsplit(file_name, NULL, NULL, NULL, ext);
  134.    if(flags & EXTENSION)
  135.    {
  136.       short i;
  137.  
  138.       for(i = 0 ; i < sizeof(map_ext)/sizeof(struct map) ; i++)
  139.     if(!strcmpi(ext,map_ext[i].snap_extension))
  140.     {
  141.        val = map_ext[i].snap_val;
  142.        break;
  143.      }
  144.    }
  145.    return val;
  146. }
  147.  
  148.  
  149. /* open file for saving */
  150. void save_sna(LPSTR file_name)
  151. {
  152.    HFILE  stream = NULL;
  153.    UCHAR tmp;
  154.    int status = 1;
  155.  
  156.    /* strcpy(file_name, snapname); */
  157.    tmp = snap_type((char *)file_name);
  158.    if(tmp == 255)
  159.       status = 2;
  160.    else
  161.    {
  162.    if((tmp == TAP_FMT) || (tmp == BLK_FMT))
  163.    {
  164.       if((stream = _lopen(file_name, READ_WRITE))!= HFILE_ERROR)
  165.      /* move to end of file */
  166.       {
  167.      USHORT size;
  168.          USHORT bytes;
  169.  
  170.      /* hack needed because of dangling 0 at the end of .TAP
  171.        files...
  172.       */
  173.      while((bytes = _lread(stream, &size, 2)) == 2)
  174.      {
  175.             if(size)
  176.            _llseek(stream, (long)size, 1);
  177.         else
  178.            break;
  179.      }
  180.      /* We've already read the 0(s), so we want to go
  181.        back
  182.       */
  183.      if((bytes == 1) || (bytes == 2))
  184.         _llseek(stream, (long)(-bytes), 2);
  185.       }
  186.       else
  187.      stream = NULL;
  188.    }
  189.  
  190.    if(stream == NULL)
  191.       stream = _lcreat(file_name, 0);
  192.    R = (R & ~BIT_7) | R_BIT7;
  193.    build_F();
  194.    if(stream)
  195.    {
  196.       switch(tmp)
  197.       {
  198.      case SNA_FMT:
  199.         status = sna_save(stream);
  200.         break;
  201.      case SNX_FMT:
  202.         status = snx_save(stream);
  203.         break;
  204.      case Z80_FMT:
  205.         status = z80_save(stream);
  206.         break;
  207.      case SIT_FMT:
  208.         status = sit_save(stream);
  209.         break;
  210.      case SP_FMT:
  211.         status = sp_save(stream);
  212.         break;
  213.      case ZX_FMT:
  214.         status = zx_save(stream);
  215.         break;
  216.      case PRG_FMT:
  217.         status = prg_save(stream);
  218.         break;
  219.      case ACH_FMT:
  220.         status = ach_save(stream);
  221.         break;
  222.      case PCX_FMT:
  223.             status = save_pcx(stream);
  224.         break;
  225.      case TAP_FMT:
  226.      case BLK_FMT:
  227.         status = tap_save(stream);
  228.         break;
  229.      case ROM_FMT:
  230.         status = rom_save(stream);
  231.         break;
  232.  
  233.      case SCR_FMT:
  234.         status = scr_save(stream);
  235.         break;
  236.      case INI_FMT:
  237.         status = save_options(stream);
  238.         break;
  239.       }
  240.       w_close(stream);
  241.    }
  242.    }
  243.    if(status)
  244.    {
  245.       if(status == 2)
  246.      Warning("Can't recognize this extension.");
  247.       else
  248.      Warning("Could not save data:\ntry another format"
  249.           " or do it later");
  250.    }
  251. }
  252.  
  253. /* put a word in file -- Intel format */
  254. void unsigned short put2(USHORT w, HFILE fp)
  255. {
  256.    putbyte(w & 0xFF, fp);
  257.    putbyte(w >> 8, fp);
  258. }
  259.  
  260. /* put a word in a file -- Motorola format */
  261. static void unsigned short putword(USHORT w, HFILE fp)
  262. {
  263.    putbyte(w >> 8, fp);
  264.    putbyte(w & 0xFF, fp);
  265. }
  266.  
  267.  
  268. static void save_raw(HFILE fp, USHORT inic, USHORT end)
  269. {
  270.    USHORT i;
  271.  
  272.    for(i=inic ; i < end ; )
  273.       putbyte(readbyte(i++), fp);
  274.    putbyte(readbyte(i), fp);
  275. }
  276.  
  277. /* save .SNA type of file */
  278. static sna_save(HFILE fp)
  279. {
  280.    USHORT tmp_val;
  281.  
  282.    /* PC can't be pushed in ROM */
  283.    if(SP < 0x4002)
  284.       return 1;
  285.  
  286.    /* save word to be corrupted */
  287.    tmp_val = readword(SP-2);
  288.  
  289.    push((USHORT)PC);
  290.    putbyte(I, fp);
  291.    put2(HL2, fp);
  292.    put2(DE2, fp);
  293.    put2(BC2, fp);
  294.    put2(AF2, fp);
  295.    put2(HL, fp);
  296.    put2(DE, fp);
  297.    put2(BC, fp);
  298.    put2(IY, fp);
  299.    put2(IX, fp);
  300.    putbyte(IFF1<<2, fp);
  301.    putbyte(R, fp);
  302.    putbyte(F, fp);
  303.    putbyte(A, fp);
  304.    put2(SP, fp);
  305.    putbyte(_IM, fp);
  306.    putbyte(get_sbrdr(), fp);
  307.    save_raw(fp, (USHORT)0x4000, (USHORT)0xFFFF);
  308.    PutPC(pop());
  309.    /* restore word corrupted */
  310.    writeword(SP-2, tmp_val);
  311.    return 0;
  312. }
  313.  
  314. // save rom file
  315. static rom_save(HFILE fp)
  316. {
  317.    patch_rom(0);
  318.    save_raw(fp, (USHORT)0, (USHORT)0x3FFF);
  319.    patch_rom(1);
  320.    return 0;
  321. }
  322.  
  323. // save screen file
  324. static scr_save(HFILE fp)
  325. {
  326.    save_raw(fp, (USHORT)0x4000, (USHORT)(0x4000+6912-1) );
  327.    return 0;
  328. }
  329.  
  330. /* save .SNX type of file */
  331. static snx_save(HFILE fp)
  332. {
  333.    USHORT tmp_val;
  334.    USHORT addr, addr2, addr3, cnt, cnt2;
  335.    UCHAR oldbyte, byte;
  336.  
  337.    /* PC can't be pushed in ROM */
  338.    if(SP < 0x4002)
  339.       return 1;
  340.  
  341.    /* save word to be corrupted */
  342.    tmp_val = readword(SP-2);
  343.  
  344.    push((USHORT)PC);
  345.    put2('XS', fp);
  346.    put2('NA', fp);
  347.    put2(774, fp); /* header len */
  348.    putbyte(I, fp);
  349.    put2(HL2, fp);
  350.    put2(DE2, fp);
  351.    put2(BC2, fp);
  352.    put2(AF2, fp);
  353.    put2(HL, fp);
  354.    put2(DE, fp);
  355.    put2(BC, fp);
  356.    put2(IY, fp);
  357.    put2(IX, fp);
  358.    putbyte(IFF1<<2, fp);
  359.    putbyte(R, fp);
  360.    putbyte(F, fp);
  361.    putbyte(A, fp);
  362.    put2(SP, fp);
  363.    putbyte(_IM, fp);
  364.    putbyte(get_sbrdr(), fp);
  365.  
  366.    //  if1sw      1       switch Interface 1: 0=not emulated, 1=emulated
  367.    putbyte(0, fp);
  368.    //  flashsw    1       switch FLASH:       0=not emulated, 1=emulated
  369.    putbyte(1, fp);
  370.    //  attrsw     1       switch Attributes:  0=no attributes,1=attributes
  371.    putbyte(1, fp);
  372.    //  zy_sw      1       switch keys Z-Y:    Bit 7=0 QWERTY, 1=QWERZ
  373.    //                           +joystick emulation Bit 0,1 00=Kempston
  374.    //                                                       01=IF1/1
  375.    //                                                       10=IF2/2
  376.    //                                                       11=Cursor
  377.    //                           Bit 6 contains ULA-emulation from Version 2.07 on.
  378.    //                                                      (0=off, 1=on).
  379.    putbyte(0x80, fp);
  380.    //       r_sw       1       switch R-register:0=R not emulated, 1=R emulated
  381.    //                               Bit 7 is used as value for the EAR-bit.
  382.    putbyte(1, fp);
  383.    //       int_sw     1       switch interrupt frequency: 0=50Hz, 1=100Hz
  384.    putbyte(1, fp);
  385.    //       rs232sw    1       switch RS232 redirection:  Bit 0=RS232, Bit 1=CENTR.
  386.    putbyte(0, fp);
  387.    //       sndsw      1       switch sound emulation:
  388.    //                             Lower nibble:  0=OFF,1=direct,2=Interrupt
  389.    //                             Higher nibble: frequency 0..4 for mode 2
  390.    putbyte(2, fp);
  391.    //       bordsw     1       switch border emulation: 0=OFF,1=direkt,2=Interrupt
  392.    putbyte(2, fp);
  393.    //       im2hw      1       switch IM2 hardware vector 0..255
  394.    putbyte(0xFF, fp);
  395.    addr = 0x4000u;
  396.    while(addr)
  397.    {
  398.       cnt = 0;
  399.       addr3 = addr2 = addr;
  400.       oldbyte = readbyte(addr2) + 1;
  401.       while((cnt < 4) && addr2)
  402.       {
  403.      byte = readbyte(addr2);
  404.      if(oldbyte == byte)
  405.         cnt++;
  406.      else
  407.      {
  408.         oldbyte = byte;
  409.         addr3 = addr2;
  410.         cnt=1;
  411.      }
  412.      addr2++;
  413.       }
  414.       if(addr != addr3)
  415.       {
  416.      cnt2 = addr3 - addr + (!addr2);
  417.      if(cnt2 < 17)
  418.         putbyte(0xE0 | (cnt2-1), fp);
  419.      else
  420.      {
  421.         putword(cnt2, fp);
  422.         putbyte(0, fp);
  423.      }
  424.      save_raw(fp, addr, addr3-1 );
  425.       }
  426.  
  427.       if(cnt>=4)
  428.       {
  429.      while((readbyte(addr2) == oldbyte) && addr2)
  430.      {
  431.         cnt++;
  432.         addr2++;
  433.      }
  434.      /*if(addr != addr3)
  435.       { */
  436.      if(cnt < 17)
  437.         putbyte(0xF0 | (cnt-1), fp);
  438.      else
  439.      {
  440.         putword(cnt, fp);
  441.         putbyte(0xFF, fp);
  442.      }
  443.      putbyte(oldbyte, fp);
  444.       }
  445.       addr = addr2;
  446.    }
  447.    PutPC(pop());
  448.  
  449.    /* restore word corrupted */
  450.    writeword(SP-2, tmp_val);
  451.    return 0;
  452. }
  453.  
  454. // save .SIT snapshot
  455. static sit_save(HFILE hfp)
  456. {
  457.    put2(BC, hfp);
  458.    put2(DE, hfp);
  459.    put2(HL, hfp);
  460.    put2(AF, hfp);
  461.    put2(IX, hfp);
  462.    put2(IY, hfp);
  463.    put2(SP, hfp);
  464.    put2(PC, hfp);
  465.    putbyte(R, hfp);
  466.    putbyte(I, hfp);
  467.    put2(BC2, hfp);
  468.    put2(DE2, hfp);
  469.    put2(HL2, hfp);
  470.    put2(AF2, hfp);
  471.    putbyte(_IM, hfp);
  472.    putbyte(get_sbrdr(), hfp);
  473.    save_raw(hfp, (USHORT)0, (USHORT)0xFFFFu);
  474.    return 0;
  475. }
  476.  
  477. /* saves .sp type */
  478. static sp_save(HFILE fp)
  479. {
  480.    /********************************/
  481.    short vgaspec = 0;
  482.    /********************************/
  483.  
  484.    if(!vgaspec)
  485.    {
  486.       putbyte('S', fp);
  487.       putbyte('P', fp);
  488.  
  489.       put2((USHORT)0xC000, fp); /* length of data block */
  490.       put2((USHORT)0x4000, fp); /* begin of block */
  491.    }
  492.  
  493.    put2(BC, fp);
  494.    put2(DE, fp);
  495.    put2(HL, fp);
  496.    put2(AF, fp);
  497.    put2(IX, fp);
  498.    put2(IY, fp);
  499.    put2(BC2, fp);
  500.    put2(DE2, fp);
  501.    put2(HL2, fp);
  502.    put2(AF2, fp);
  503.    putbyte(R, fp);
  504.    putbyte(I, fp);
  505.    put2(SP, fp);
  506.    put2((USHORT)PC, fp);
  507.  
  508.    /* reserved word */
  509.    put2(0, fp);
  510.  
  511.    putbyte(get_sbrdr(), fp);
  512.  
  513.    /* reserved byte */
  514.    putbyte(0, fp);
  515.  
  516.    putbyte(IFF1|((_IM==2)?2:0), fp);
  517.  
  518.    /* reserved byte */
  519.    putbyte(0, fp);
  520.  
  521.    save_raw(fp, (USHORT)0x4000, (USHORT)0xFFFF);
  522.  
  523.    return 0;
  524. }
  525.  
  526. // save .ZX snapshot
  527. static zx_save(HFILE  fp)
  528. {
  529.    /* this format also saves the last ROM 132 bytes */
  530.    save_raw(fp, (USHORT)0x4000u-132u, (USHORT)0xFFFFu);
  531.    w_seek(fp, 0x8EL);
  532.    putbyte(IFF1, fp);
  533.    w_seek(fp, 7L);
  534.    putword(BC,  fp);
  535.    putword(BC2, fp);
  536.    putword(DE,  fp);
  537.    putword(DE2, fp);
  538.    putword(HL,  fp);
  539.    putword(HL2, fp);
  540.    putword(IX,  fp);
  541.    putword(IY,  fp);
  542.    putbyte(I,fp);
  543.    putbyte(R,fp);
  544.    putword(0, fp); putbyte(0, fp);
  545.    putbyte(A2, fp);
  546.    putbyte(0, fp);
  547.    putbyte(A, fp);
  548.    putbyte(0, fp);
  549.    putbyte(F2, fp);
  550.    putbyte(0, fp);
  551.    putbyte(F, fp);
  552.    putword(0, fp);
  553.    putword((USHORT)PC, fp);
  554.    putword(0,  fp);
  555.    putword(SP, fp);
  556.    w_seek(fp, 7L);
  557.    putbyte((_IM == 2)?0xFF:0, fp);
  558.    return 0;
  559. }
  560.  
  561. /* saves .prg type */
  562. static prg_save(HFILE fp)
  563. {
  564.    UCHAR tmp1;
  565.    USHORT tmp2, tmp3;
  566.  
  567.    putbyte(5, fp);
  568.    /* write code to include module name! here! */
  569.  
  570.    w_seek(fp, 0xDBL);
  571.  
  572. /*DC*/  put2(IY,  fp);
  573. /*DE*/  put2(IX,  fp);
  574. /*E0*/  put2(DE2, fp);
  575. /*E2*/  put2(BC2, fp);
  576. /*E4*/  put2(HL2, fp);
  577. /*E6*/  put2(AF2, fp);
  578. /*E8*/  put2(DE, fp);
  579. /*EA*/  put2(BC, fp);
  580. /*EC*/  put2(HL, fp);
  581. /*EE*/  putbyte(IFF1, fp);
  582. /*EF*/  putbyte(I, fp);
  583. /*F0 */ put2(SP-6, fp);
  584.  
  585.    /* save the 5 bytes corrupted */
  586.    tmp1 = readbyte(SP + 1);
  587.    tmp2 = readword(SP + 2);
  588.    tmp3 = readword(SP + 4);
  589.  
  590.    writebyte(SP+1-6, R);
  591.    writeword(SP+2-6, AF);
  592.    writeword(SP+4-6, (USHORT)PC);
  593.  
  594.    w_seek(fp, 0x0EL);
  595.    save_raw(fp, (USHORT)0x4000u, (USHORT)0xFFFFu);
  596.  
  597.    /* restore the 5 bytes corrupted */
  598.    writebyte(SP+1, tmp1);
  599.    writeword(SP+2, tmp2);
  600.    writeword(SP+4, tmp3);
  601.    return 0;
  602. }
  603.  
  604. // save .ACH format
  605. int ach_save(HFILE  fp)
  606. {
  607.    putbyte(A, fp);                 /* 00 */
  608.    put2(0, fp); putbyte(0, fp);
  609.    putbyte(F, fp);                 /* 04 */
  610.    put2(0, fp); putbyte(0, fp);
  611.    putbyte(B, fp);                 /* 08 */
  612.    put2(0, fp); putbyte(0, fp);
  613.    putbyte(C, fp);                 /* 0C */
  614.    put2(0, fp); putbyte(0, fp);
  615.    putbyte(D, fp);                 /* 10 */
  616.    put2(0, fp); putbyte(0, fp);
  617.    putbyte(E, fp);                 /* 14 */
  618.    put2(0, fp); putbyte(0, fp);
  619.    putbyte(H, fp);                 /* 18 */
  620.    put2(0, fp); putbyte(0, fp);
  621.    putbyte(L, fp);                 /* 1C */
  622.    put2(0, fp); putbyte(0, fp);
  623.  
  624.    put2((USHORT)PC, fp);           /* 20 */
  625.    w_seek(fp, 6L);
  626.    put2(SP, fp);                   /* 28 */
  627.    w_seek(fp, 0x94L-0x2AL);
  628.    putbyte(R, fp);                 /* 94 */
  629.    w_seek(fp, 0x9CL-0x95L);
  630.    putbyte(get_sbrdr(), fp);       /* 9C */
  631.    w_seek(fp, 0xA4L-0x9DL);
  632.    putbyte(_IM, fp);               /* A4 */
  633.    w_seek(fp, 0xBEL - 0xA5L);
  634.    putbyte(I, fp);                 /* BE */
  635.    putbyte(IFF1, fp);              /* BF */
  636.    w_seek(fp, 0xECL-0xC0L);
  637.    putword(AF2, fp);               /* EC */
  638.    put2(0, fp);
  639.    putword(BC2, fp);               /* F0 */
  640.    put2(0, fp);
  641.    putword(DE2, fp);               /* F4 */
  642.    putword(HL2, fp);               /* F6 */
  643.    put2(IX, fp);           /* F8 */
  644.    put2(0, fp);
  645.    put2(IY, fp);           /* FC */
  646.    put2(0, fp);
  647.    save_raw(fp, (USHORT)0u, (USHORT)0xFFFFu);
  648.    return 0;
  649. }
  650.  
  651. // save .Z80 format
  652. static z80_save(HFILE fp)
  653. {
  654.    UCHAR byte;
  655.    /*********************************/
  656.    USHORT compressed = 1;
  657.    /*********************************/
  658.  
  659.    putbyte(A, fp);
  660.    putbyte(F, fp);
  661.    put2(BC, fp);
  662.    put2(HL, fp);
  663.    put2((USHORT)PC, fp);
  664.    put2(SP, fp);
  665.    putbyte(I, fp);
  666.    putbyte(R&0x7F, fp);
  667.    byte = get_sbrdr() << 1;
  668.    byte |= ((R&0x80)?1:0) | (compressed << 5);
  669.    putbyte(byte, fp);
  670.    put2(DE, fp);
  671.    put2(BC2, fp);
  672.    put2(DE2, fp);
  673.    put2(HL2, fp);
  674.    putbyte(A2, fp);
  675.    putbyte(F2, fp);
  676.    put2(IY, fp);
  677.    put2(IX, fp);
  678.    putbyte(IFF1, fp);
  679.    putbyte(IFF2, fp);
  680.    putbyte(_IM, fp);
  681.    /* bit 2 == 1 --- issue 2 emulation */
  682.    /* bit 6,7 0-Cursor/Protek/AGF joystick
  683.           1-Sinclair 1 joystick
  684.           2-Sinclair 2 joystick
  685.     */
  686.    if (compressed)
  687.    {
  688.       USHORT address;
  689.       UCHAR oldbyte;
  690.       USHORT cnt;
  691.  
  692.       address = 0x4000u;
  693.       oldbyte = readbyte(address++);
  694.       cnt = 1;
  695.       do
  696.       {
  697.      byte = readbyte(address++);
  698.      if(address == 1)
  699.         byte = oldbyte+1; /* hack for last byte */
  700.  
  701.      if (((byte != oldbyte) && cnt) || (cnt == 255))
  702.      {
  703.         if(((oldbyte == (UCHAR)0xED) && cnt > 1) || (cnt > 4))
  704.         {
  705.            put2(0xEDEDu, fp);
  706.            putbyte(cnt, fp);
  707.            putbyte(oldbyte, fp);
  708.            cnt = 1;
  709.         }
  710.         else
  711.         {
  712.            while(cnt--)
  713.            {
  714.           putbyte(oldbyte, fp);
  715.            }
  716.            if(address!=1)
  717.            {
  718.           if((oldbyte != (UCHAR)0xED))
  719.              cnt = 1;
  720.           else
  721.           {
  722.              putbyte(byte, fp);
  723.              cnt = 0;
  724.           }
  725.            }
  726.            else
  727.           cnt = 0;
  728.         }
  729.      }
  730.      else
  731.         cnt++;
  732.      oldbyte = byte;
  733.       }
  734.       while(address != 1);
  735.      putbyte(0, fp);
  736.       putbyte(0xED, fp);
  737.       putbyte(0xED, fp);
  738.       putbyte(0, fp);
  739.    }
  740.    else
  741.       save_raw(fp, (USHORT)0x4000u, (USHORT)0xFFFFu);
  742.    return 0;
  743. }
  744.  
  745.  
  746. // save WSpecEm options
  747. static save_options(HFILE hfp)
  748. {
  749.    putbyte(Scale   ,     hfp);
  750.    putbyte(bSoundOn,     hfp);
  751.    putbyte(bFlashOn,     hfp);
  752.    putbyte(bModel3 ,     hfp);
  753.    putbyte(ScreenUpdate, hfp);
  754.    put2(DelayEmVal,      hfp);
  755.    return 0;
  756. }
  757.  
  758. /* save current state of a emulator as a TAP blocks instead of a snapshot
  759.   --- inspiration taken from the much longed 'Multiface'
  760.  */
  761. static tap_save(HFILE fp)
  762. {
  763. #define START_AD 0x4E28
  764.    short tmp;
  765.    USHORT i;
  766.    UCHAR save_mem[64];
  767.    /* Basic loader block in .TAP binary format */
  768.    static UCHAR loader[] = { 0x13, 0x00,      /* len   */
  769.                  0x00,            /* A reg */
  770.                  0x00,            /* first byte -- code block */
  771.        /* 0x04 */            ' ',' ',' ',' ', /* name - 10 bytes */
  772.                  ' ',' ',' ',' ',
  773.                  ' ',' ',
  774.       /* 0x0E */         0x4D, 0x00,      /* size of block ? */
  775.       /* 0x10 */         0x14, 0x00,      /* line to execute by basic */
  776.       /* 0x12 */         0x4D, 0x00,      /* size of basic */
  777.       /* 0x14 */         0x00,            /* checksum --altered in prog*/
  778.  
  779.       /* 0x15 */         0x4F, 0x00,      /* len */
  780.       /* 0x17 */         0xFF,            /* A reg */
  781.       /* 0x18 */         0x00, 0x0A,      /* 10 */
  782.       /* 0x1a */         0x2C, 0x00,      /* len of line 10 */
  783.       /* 0x1c */         0xEA,            /* REM */
  784.  
  785.       /* 23760 */        0x31,            /* LD  SP,START_AD */
  786.                  START_AD & 0xFF,
  787.                  START_AD >> 8,
  788.                  0x21, 0xE1, 0x5C,/* LD HL,5CE1 */
  789.                  0x11, 0x00, 0x40,/* LD DE,4000h */
  790.                  0x01, 0x1A, 0x00,/* LD BC, LEN  */
  791.  
  792.                  0xED, 0xB0,      /* LDIR */
  793.                  0xC3, 0x00, 0x40,/* JP 4000h */
  794.       /* 0x20 */         0x3E, 0xFF,      /* LD A,FFh */
  795.       /* 0x22 */         0x37,            /* SCF */
  796.       /* 0x23 */         0xDD, 0x21, 0x00, 0x5B, /* LD IX,5B00h */
  797.       /* 0x27 */         0x11, 0x00, 0xA5,/* LD DE, 0xA500 */
  798.       /* 0x2a */         0xCD, 0x56, 0x05,/* CALL 0556h */
  799.       /* 0x2d */         0x3E, 0xFF,      /* LD A,FFh */
  800.       /* 0x2f */         0x37,            /* SCF */
  801.       /* 0x30 */         0xDD, 0x21, 0x00, 0x40, /* LD IX,4000h */
  802.       /* 0x34 */         0x11, 0x00, 0x1B,/* LD DE, 0x1B00 */
  803.       /* 0x37 */         0xC3, 0x56, 0x05,/* JP 0556h */
  804.       /* 0x3A */         0x00, 0x14,      /* 20 */
  805.       /* 0x3c */         0x19, 0x00,      /* len of line 20 */
  806.                  0xE7, 0xB0, '\"',/* BORDER VAL " */
  807.                  '0', '\"', ':',  /* 0": */
  808.                  0xDA, 0xB0, '\"',/* PAPER VAL " */
  809.                  '0', '\"', ':',  /* 0": */
  810.                  0xFB, ':',
  811.       /* 0x3e */         0xF9, 0xC0, 0xB0,/* RANDOMIZE USR VAL */
  812.       /* 0x41 */         '\"','2','3','7',
  813.       /* 0x45 */         '6','0','\"',
  814.       /* 0x48 */         0x0D,            /* End of Basic */
  815.       /* 0x49 */         0x82             /* checksum */
  816.    };
  817.  
  818.    /* save bytes that will be corrupted */
  819.    for(i = 0 ; i <= 63 ; i++)
  820.       save_mem[i] = readbyte(i+START_AD-2);
  821.  
  822.    /* write machine code to restore the state of machine when called
  823.     */
  824.    writebyte(START_AD+ 0, 0xF3);     /* DI     */
  825.    writebyte(START_AD+ 1, 0x3E);     /* LD A,x */
  826.    writebyte(START_AD+ 2, I);
  827.    writebyte(START_AD+ 3, 0xED);     /* LD I,A */
  828.    writebyte(START_AD+ 4, 0x47);
  829.  
  830.    writebyte(START_AD+ 5, 0xED);     /* IM x */
  831.    switch(_IM)
  832.    {
  833.       case 0:
  834.      tmp = 0x46;
  835.     break;
  836.  
  837.       case 1:
  838.      tmp = 0x56;
  839.     break;
  840.  
  841.       case 2:
  842.      tmp = 0x5E;
  843.     break;
  844.    }
  845.    writebyte(START_AD+ 6, tmp);
  846.  
  847.    writebyte(START_AD+ 7, 0x3E);     /* LD  A,x */
  848.  
  849.    tmp = R;
  850.    /* modify R to compensate to instructions needed to reach
  851.      the last state
  852.     */
  853.    R = R - 0x17;
  854.    if(tmp & (UCHAR)0x80)
  855.       R|= 0x80;
  856.    else
  857.       R&=0x7F;
  858.    writebyte(START_AD+ 8, R);
  859.    R = tmp;
  860.  
  861.    writebyte(START_AD+ 9, 0xED);     /* LD  R,A */
  862.    writebyte(START_AD+10, 0x4F);
  863.  
  864.  
  865.    writebyte(START_AD+11, 0x21);     /* MOV HL,x */
  866.    writeword(START_AD+12, AF2);
  867.    writebyte(START_AD+14, 0xE5);     /* PUSH HL  */
  868.    writebyte(START_AD+15, 0xF1);     /* POP        AF  */
  869.    writebyte(START_AD+16, 0x01);     /* LD BC,x */
  870.    writeword(START_AD+17, BC2);
  871.    writebyte(START_AD+19, 0x21);     /* LD HL,x */
  872.    writeword(START_AD+20, HL2);
  873.    writebyte(START_AD+22, 0x11);     /* LD DE,x */
  874.    writeword(START_AD+23, DE2);
  875.    writebyte(START_AD+25, 0xD9);     /* EXX */
  876.    writebyte(START_AD+26, 0x08);     /* EX AF,AF' */
  877.  
  878.    writebyte(START_AD+27, 0x3E);     /* LD A,x */
  879.    writebyte(START_AD+28, get_sbrdr() );
  880.  
  881.    writebyte(START_AD+29, 0xD3);     /*    OUT (254),A */
  882.    writebyte(START_AD+30, 0xFE);
  883.  
  884.    writebyte(START_AD+31, 0x21);     /* MOV HL,x */
  885.    writeword(START_AD+32, AF);
  886.    writebyte(START_AD+34, 0xE5);     /* PUSH HL  */
  887.    writebyte(START_AD+35, 0xF1);     /* POP        AF  */
  888.  
  889.    writebyte(START_AD+36, 0x21);     /* LD HL,x */
  890.    writeword(START_AD+37, HL);
  891.    writebyte(START_AD+39, 0x01);     /* LD BC,x */
  892.    writeword(START_AD+40, BC);
  893.    writebyte(START_AD+42, 0x11);     /* LD DE,x */
  894.    writeword(START_AD+43, DE);
  895.  
  896.    writebyte(START_AD+45, 0xFD);     /* LD IY,x */
  897.    writebyte(START_AD+46, 0x21);
  898.    writeword(START_AD+47, IY);
  899.    writebyte(START_AD+49, 0xDD);     /* LD IX,x */
  900.    writebyte(START_AD+50, 0x21);
  901.    writeword(START_AD+51, IX);
  902.  
  903.    writebyte(START_AD+53, 0x31);     /* LD SP,x */
  904.    writeword(START_AD+54, SP);
  905.  
  906.    writebyte(START_AD+56,IFF1?0xFB:0xF3);  /* EI / DI */
  907.    writebyte(START_AD+57, 0xC3);           /* JP x    */
  908.    writeword(START_AD+58, (USHORT)PC);
  909.  
  910.    writeword(START_AD-2, START_AD);
  911.  
  912.    /* find name of program */
  913.    for(i = 0 ; snapname[i] ; i++ )
  914.       if((snapname[i] == '.') || (i == 10))
  915.      break;
  916.       else
  917.      loader[i+4] = snapname[i];
  918.  
  919.    /* compute checksum of header of Basic loader */
  920.    tmp = loader[0x04];
  921.    for(i = 0x05 ; i < 0x14 ; i++)
  922.       tmp ^= loader[i];
  923.    loader[0x14] = tmp;
  924.  
  925.    /* write Basic loader */
  926.    for(i=0 ; i<sizeof(loader); i++)
  927.       putbyte(loader[i], fp);
  928.  
  929.    /* save .TAP block */
  930.    put2(0xA500u+2u, fp);/* len of block */
  931.    putbyte(0xFF, fp);      /* type of block */
  932.    /* save in file */
  933.    save_raw(fp, (USHORT)0x5B00u, (USHORT)0xFFFFu);
  934.    tmp = 0xFF;             /* valor inicial */
  935.    i = 0x5B00-1;
  936.    do
  937.    {
  938.       tmp^= readbyte(++i);
  939.    }
  940.    while(i != 0xFFFFu);
  941.       putbyte(tmp, fp);
  942.  
  943.    /* save .TAP block */
  944.    put2(0x1B00u+2u, fp);/* len of block */
  945.    putbyte(0xFF, fp);      /* type of block */
  946.    /* save in file */
  947.    save_raw(fp, (USHORT)0x4000u, (USHORT)0x5AFFu);
  948.    tmp = 0xFF;             /* valor inicial */
  949.    i = 0x4000-1;
  950.    do
  951.    {
  952.       tmp^= readbyte(++i);
  953.    }
  954.    while(i != 0x5AFFu);
  955.    putbyte(tmp, fp);
  956.  
  957.    /* restore corrupted bytes */
  958.    for(i = 0 ; i <= 63 ; i++)
  959.       writebyte(i+START_AD-2, save_mem[i]);
  960.    return 0;
  961. }
  962.  
  963. // Windows menu for saving snapshots
  964. void open_menu_save(HWND hwnd)
  965. {
  966.    OPENFILENAME ofn;
  967.    char szDirName[256];
  968.    char szFile[256], szFileTitle[256];
  969.    UINT  i, cbString;
  970.    char  chReplace;    /* string separator for szFilter */
  971.    char szFilter[500];
  972.    HFILE hf;
  973.  
  974.    /*
  975.     * Retrieve the system directory name, and store it in
  976.     * szDirName.
  977.     */
  978.  
  979.    /*GetSystemDirectory(szDirName, sizeof(szDirName)); */
  980.  
  981.    /*if ((cbString = LoadString(hinst, IDS_FILTERSTRING,
  982.       szFilter, sizeof(szFilter))) == 0) {
  983.     ErrorHandler();
  984.     return 0;
  985.       }
  986.     */
  987.  
  988.       strcpy(szFilter,
  989.     "All spectrum files|*.ach;*.blk;*.prg;*.pcx;*.scr;*.sit;"  
  990.     "*.sp;*.sna;*.snx;*.raw;*.tap;*.z80;*.zx;*.rom|"
  991.     "ACH - !Speccy|*.ach|" 
  992.     "BLK - Sinclair|*.blk|"
  993.     "PRG - SpecEm|*.prg|"
  994.     "PCX - Graphic images|*.pcx|" 
  995.     "SCR - Spectrum screen|*.scr|"
  996.     "SIT - Sinclair|*.sit|"
  997.     "SP  - Spectrum,VgaSpec|*.sp|"  
  998.     "SNA - JPP, xzx|*.sna|"
  999.     "SNX - Specci|*.snx|" 
  1000.     "RAW - raw files|*.raw|" 
  1001.     "TAP - cassete files|*.tap|" 
  1002.     "Z80 - Z80, Waravejo,x128|*.z80|"
  1003.     "ZX  - KGB|*.zx|"
  1004.     "ROM - change ROM|*.rom|"
  1005.     );
  1006.    /*chReplace = szFilter[cbString - 1];*/ /* retrieve wildcard */
  1007.     chReplace = '|';
  1008.  
  1009.    /*chReplace = szFilter[cbString - 1];*/ /* retrieve wildcard */
  1010.  
  1011.       for (i = 0; szFilter[i] != '\0'; i++)
  1012.       {
  1013.      if (szFilter[i] == chReplace)
  1014.         szFilter[i] = '\0';
  1015.       }
  1016.  
  1017.    /* Set all structure members to zero. */
  1018.  
  1019.    memset(&ofn, 0, sizeof(OPENFILENAME));
  1020.  
  1021.    /* Initialize the OPENFILENAME members. */
  1022.  
  1023.    szFile[0] = '\0';
  1024.  
  1025.    ofn.lStructSize = sizeof(OPENFILENAME);
  1026.    ofn.hwndOwner = hwnd;
  1027.    ofn.lpstrFilter = szFilter;
  1028.    ofn.lpstrFile= szFile;
  1029.    ofn.nMaxFile = sizeof(szFile);
  1030.    ofn.lpstrFileTitle = szFileTitle;
  1031.    ofn.nMaxFileTitle = sizeof(szFileTitle);
  1032.    ofn.lpstrTitle = "Save Snapshot";  // Title for dialog
  1033.  
  1034.    ofn.lpstrInitialDir = szDirName;
  1035.    ofn.Flags = /*OFN_SHOWHELP*/ OFN_HIDEREADONLY |
  1036.            OFN_OVERWRITEPROMPT | OFN_LONGNAMES;
  1037.  
  1038.    if (GetSaveFileName(&ofn))
  1039.    {
  1040.       save_sna(ofn.lpstrFile);
  1041.    }
  1042. }
  1043.  
  1044. /* EOF : Sna_save.c */
  1045.