home *** CD-ROM | disk | FTP | other *** search
/ MACD 4 / MACD4.iso / Emulatory / SPConv / Src / SPCONV.C < prev    next >
Encoding:
C/C++ Source or Header  |  1978-03-06  |  47.0 KB  |  2,204 lines

  1. /*
  2.  * SPCONV -    ZX-Spectrum 48K snapshot converter
  3.  *
  4.  *        Public Domain software
  5.  *
  6.  * Author: Henk de Groot
  7.  *         SNX conversion routines added by Damien Burke (v1.09)
  8.  */
  9.  
  10. #if defined(__STDC__) || defined(__TURBOC__)
  11. #include <stdlib.h>
  12. #else
  13. #include <sys/types.h>
  14. #endif
  15.  
  16. #ifdef __TURBOC__
  17. #include <io.h>
  18. #else
  19. #include <unistd.h>
  20. #endif
  21.  
  22. #include <stdio.h>
  23. #include <fcntl.h>
  24. #include <sys/stat.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. #ifdef __TURBOC__
  28. #include <alloc.h>
  29. #endif
  30.  
  31. #ifndef O_BINARY
  32. #define O_BINARY 0
  33. #endif
  34.  
  35. #include "d:\spconv\spconv.h"
  36.  
  37. struct snx_s snx;
  38. struct sna_s sna;
  39. struct vga_s vga;
  40. struct z80_s z80;
  41. struct prg_s prg;
  42. struct ach_s ach;
  43. struct kgb_s kgb;
  44.  
  45. /* extra space just in case the Z80 decompress fails due to a corrupt image */
  46. unsigned char image[IMSIZE+0x100];
  47. unsigned int z80_size;
  48.  
  49. signed int    intype;
  50. signed int    outtype;
  51.  
  52. /* Prototype for main */
  53. extern int main(int argc, char *argv[]);
  54.  
  55. /* Path names are limited to 80 characters under MSDOS so this sould be */
  56. /* enough... If you are using UNIX than you may have to make this array */
  57. /* larger.                                                              */
  58. char    my_directory[120];
  59.  
  60. int main(int argc, char *argv[])
  61. {
  62.     char        *p;
  63.     struct stat    status;
  64.     const  char    *fromstring;
  65.     const  char    *tostring;
  66.     char        *outfile;
  67.     long        file_size;
  68.  
  69. #ifdef __TURBOC__
  70.     /* for Trubo-C: open all files in binary mode */
  71.     extern int _fmode;
  72.     _fmode = O_BINARY;
  73. #endif
  74.  
  75.     if(argc != 3)
  76.         USAG_usage();
  77.  
  78.     if((strchr(argv[1],'*')!=NULL) || (strrchr(argv[1],'?')!=NULL) ||
  79.        (strchr(argv[2],'*')!=NULL) || (strrchr(argv[2],'?')!=NULL))    {
  80.         fprintf(stderr,"This program can't handle wildcards, sorry!\n");
  81.         return EXIT_USAGE;
  82.     }
  83.  
  84.     /*
  85.      * Find the directory path where this program is started from.
  86.      * This will be needed for finding the spectrum-rom. Some formats
  87.      * need the spectrum-rom for proper conversion.
  88.      */
  89.     strcpy(my_directory,argv[0]);
  90.     if(strrchr(my_directory,'\\')!=NULL) {
  91.         *strrchr(my_directory,'\\')='\0';
  92.     }
  93.     else if(strrchr(my_directory,'/')!=NULL) {
  94.         *strrchr(my_directory,'/')='\0';
  95.     }
  96.     else if(strrchr(my_directory,':')!=NULL) {
  97.         *strrchr(my_directory,':')='\0';
  98.     } else {
  99.         my_directory[0]='\\';
  100.         my_directory[1]='\0';
  101.     }
  102.  
  103.     /*
  104.      * Check if the input file exists and fetch the file lenght of
  105.      * the file in the mean time. Two for the prise of one...
  106.      */
  107.     if(stat(argv[1],&status)<0) {
  108.         perror(argv[1]);
  109.         return EXIT_FILE_ERROR;
  110.     }
  111.     file_size = status.st_size;
  112.  
  113.     /*
  114.      * recognize input type on filename:
  115.      *
  116.      *      .SNX    ->    SNX file (used by Atari emulator)
  117.      *    .SNA    ->    SNA file (used in JPP)
  118.      *    .SP    ->    SP file (was VGASPEC)
  119.      *    .Z80    ->    Z80 file
  120.      *    .PRG    ->    PRG file
  121.      *    .ACH    ->    ACH file (from archimedes emulator)
  122.      *    .ZX    ->    KGB file (from KGB emulator)
  123.      *    other    ->    if exact 48+header -> raw file
  124.      *    otherwise     unknown
  125.      */
  126.  
  127.     fromstring = DTYP_determine_type(argv[1],&intype);
  128.  
  129.     if (intype == UNKNOWN) {
  130.         if (file_size == (hdr_size+IMSIZE)) {
  131.             fromstring="RAW";
  132.             intype=RAW;
  133.         } else {
  134.             fprintf(stderr,"Unknown input file format. Must be a valid .SNX, .SNA, .SP, .Z80, .PRG, .ACH or\n");
  135.             fprintf(stderr,".ZX file, or a Raw file\n");
  136.             return EXIT_FILE_ERROR;
  137.         }
  138.     }
  139.  
  140.     /*
  141.      * recognize output type on filename:
  142.      *
  143.      *      .SNX    ->    SNX file
  144.      *    .SNA    ->    SNA file
  145.      *    .SP    ->    SP file (was VGASPEC)
  146.      *    .Z80    ->    Z80 file
  147.      *    .PRG    ->    PRG file
  148.      *    .ACH    ->    ACH file (from archimedes emulator)
  149.      *    .ZX    ->    KGB file (from KGB emulator)
  150.      *    otherwise     unknown
  151.      */
  152.  
  153.     tostring = DTYP_determine_type(argv[2],&outtype);
  154.  
  155.     if(outtype==UNKNOWN) {
  156.         fprintf(stderr,"Unknown output file format. Must be a .SNX, .SNA, .SP, .Z80, .PRG, .ACH or .ZX file\n");
  157.         return EXIT_FILE_ERROR;
  158.     }
  159.  
  160.     /*
  161.      * if argv[2] only contains the suffix then use the prefix of
  162.      * argv[1];
  163.      */
  164.     if(argv[2][0]=='.') {
  165.         outfile=malloc(strlen(argv[1])+strlen(argv[2])+1);
  166.         strcpy(outfile,argv[1]); /* copy prefix    */
  167.  
  168.         p=strrchr(outfile,'.');
  169.         if(p!=NULL) *p='\0'; /* put end of string at position of '.' */
  170.  
  171.         strcat(outfile,argv[2]); /* append suffix  */
  172.     } else {
  173.         outfile=malloc(strlen(argv[2])+1);
  174.  
  175.         strcpy(outfile,argv[2]);
  176.     }
  177.  
  178.     /*
  179.      * Special converion between versions of the same type
  180.      */
  181.     if(intype == outtype)
  182.         return DIRC_direct_convert(intype, argv[1], outfile);
  183.  
  184.     /*
  185.      * General conversion from one type to another
  186.      */
  187.  
  188.     printf("Converting %s from %s to %s\n",argv[1],fromstring,tostring);
  189.  
  190.     /*
  191.      * convert input_file to SNA
  192.      */
  193.  
  194.     switch(intype) {
  195.     case SNX:    RSNX_read_snx(argv[1]);
  196.             SXSN_snx_to_sna();
  197.             break;
  198.     case SNA:    if (file_size == (sna_size+IMSIZE)) {
  199.                 RSNA_read_sna(argv[1]);
  200.             }
  201.             break;
  202.     case SP:    if ((file_size == (vga_size+IMSIZE))) {
  203.                 RVGA_read_vgaspec(argv[1]);
  204.                 VGSN_vgaspec_to_sna();
  205.             } else if ((file_size == (vga_size+IMSIZE-6))) {
  206.                 ROVG_read_old_vgaspec(argv[1]);
  207.                 VGSN_vgaspec_to_sna();
  208.             }
  209.             break;
  210.     case RAW:    RRAW_read_raw(argv[1]);
  211.             RASN_raw_to_sna();
  212.             break;
  213.     case Z80:    RZ80_read_z80(argv[1]);
  214.             Z8SN_z80_to_sna();
  215.             break;
  216.     case PRG:    if(file_size != (prg_size+IMSIZE)) {
  217.                 printf("Warning: the image part of %s is not exactly 48k!\n",argv[1]);
  218.                 printf("         Converting anyway, the converted file may not work\n");
  219.             }
  220.             RPRG_read_prg(argv[1]);
  221.             PRSN_prg_to_sna();
  222.             break;
  223.     case ACH:    if(file_size == (ach_size+16384L+IMSIZE)) {
  224.                 RACH_read_ach(argv[1]);
  225.                 ACSN_ach_to_sna();
  226.             }
  227.             break;
  228.     case KGB:    if(file_size == (132L+IMSIZE+kgb_size)) {
  229.                 RKGB_read_kgb(argv[1]);
  230.                 KGSN_kgb_to_sna();
  231.             }
  232.             break;
  233.     default:    printf("Unrecognized input file type, can't convert\n");
  234.             return EXIT_FILE_ERROR;
  235.     }
  236.  
  237.     /*
  238.      * convert internal SNA format to output file
  239.      */
  240.  
  241.     switch(outtype) {
  242.     case SNX:       SNSX_sna_to_snx();
  243.             WSNX_write_snx(outfile);
  244.             break;
  245.     case SNA:    WSNA_write_sna(outfile);
  246.             break;
  247.     case SP:    SNVG_sna_to_vgaspec();
  248.             WVGA_write_vgaspec(outfile);
  249.             break;
  250.     case Z80:    SNZ8_sna_to_z80();
  251.             WZ80_write_z80(outfile);
  252.             break;
  253.     case PRG:    SNPR_sna_to_prg(outfile);
  254.             WPRG_write_prg(outfile);
  255.             break;
  256.     case ACH:    SNAC_sna_to_ach();
  257.             WACH_write_ach(outfile);
  258.             break;
  259.     case KGB:    SNKG_sna_to_kgb();
  260.             WKGB_write_kgb(outfile);
  261.             break;
  262.     default:    printf("Unrecognized output file type, can't convert\n");
  263.             return EXIT_FILE_ERROR;
  264.     }
  265.  
  266.     /*
  267.      * That's it, simple isn't it?
  268.      */
  269.     return EXIT_OK;
  270. }
  271.  
  272. /* SPECIAL FUNCTIONS */
  273.  
  274. /* Determine file type and return both type and type-name */
  275.  
  276. const char * DTYP_determine_type(char * filename, signed int * type)
  277. {
  278.     const        char *p;
  279.     char        ext[5];
  280.     signed int    i;
  281.  
  282.     /*
  283.      * recognize type on filename:
  284.      *
  285.      *    .SNX    ->    SNX file
  286.      *    .SNA    ->    SNA file
  287.      *    .SP    ->    SP file (was VGASPEC)
  288.      *    .Z80    ->    Z80 file
  289.      *    .PRG    ->    PRG file
  290.      *    .ACH    ->    ACH file (from archimedes emulator)
  291.      *    .ZX    ->    KGB file (from KGB emulator)
  292.      *    otherwise     unknown
  293.      */
  294.  
  295.     *type=UNKNOWN;    /* default if all ifs below fail */
  296.  
  297.     p=strrchr(filename,'.');
  298.     if(p==NULL) p=filename; /* not found, set at begin of string */
  299.  
  300.     /* Take extension and convert to uppercase */
  301.     for(i = 0; i < 4; i++) {
  302.         if(*p != '\0') {
  303.             ext[i] = toupper(*p);
  304.             p++;
  305.         } else {
  306.             ext[i] = '\0';
  307.         }
  308.     }
  309.     ext[4] = '\0'; /* termination at least on the fifth char */
  310.  
  311.     if(strcmp(ext,".SNX")==0) {
  312.         *type=SNX;
  313.         return ".SNX";
  314.     }
  315.     if(strcmp(ext,".SNA")==0) {
  316.         *type=SNA;
  317.         return ".SNA";
  318.     }
  319.     if(strcmp(ext,".Z80")==0) {
  320.         *type=Z80;
  321.         return ".Z80";
  322.     }
  323.     if(strcmp(ext,".SP")==0) {
  324.         *type=SP;
  325.         return ".SP";
  326.     }
  327.     if(strcmp(ext,".PRG")==0) {
  328.         *type=PRG;
  329.         return ".PRG";
  330.     }
  331.     if(strcmp(ext,".ACH")==0) {
  332.         *type=ACH;
  333.         return ".ACH";
  334.     }
  335.     if(strcmp(ext,".ZX")==0) {
  336.         *type=KGB;
  337.         return ".ZX";
  338.     }
  339.  
  340.     /* unknown type, return question-mark */
  341.     return "?";
  342. }
  343.  
  344. /* Special converion between versions of the same type */
  345.  
  346. signed int DIRC_direct_convert(signed int type, char * infile, char * outfile)
  347. {
  348.     struct stat status;
  349.     signed long file_size;
  350.  
  351.     /*
  352.      * Special conversion between versions of the same type.
  353.      * These conversion don't use the intermediate 'sna' format
  354.      * to preserve as much information as possible.
  355.      *
  356.      * This currently only applies to .SP and the .Z80 formats.
  357.      *
  358.      * The .SP formats will convert from the New to the Old format or
  359.      * from the Old to the New format, controled by the current format
  360.      * of the input.
  361.      *
  362.      * The .Z80 formats will convert to the version 1.45 .Z80 format
  363.      * since version 1.45 .Z80 files can be read by both old and new
  364.      * Z80-emulators.
  365.      */
  366.  
  367.     /* check if it is for the SP format */
  368.     if(type == SP) {
  369.         if(stat(infile,&status)<0) {
  370.             perror(infile);
  371.             return EXIT_FILE_ERROR;
  372.         }
  373.         file_size = status.st_size;
  374.  
  375.         if((file_size == (vga_size+IMSIZE))) {
  376.             printf("Converting %s from new .SP format to old .SP format.\n",infile);
  377.             RVGA_read_vgaspec(infile);
  378.  
  379.             WOVG_write_old_vgaspec(outfile);
  380.             return EXIT_OK;
  381.         }
  382.  
  383.         if((file_size == (vga_size+IMSIZE-6))) {
  384.             RVGH_read_vgaspec_header(infile);
  385.  
  386.             if((vga.S=='S')&&(vga.P=='P')) {
  387. fprintf(stderr,"Invalid input file format. This could be a new syle .SP file with\n");
  388. fprintf(stderr,"an image of another length than 48Kb. This kind of .SP files cannot\n");
  389. fprintf(stderr,"be converted. All other file formats (including the old .SP format)\n");
  390. fprintf(stderr,"contain images of 48Kb length.\n");
  391.                 return EXIT_FILE_ERROR;
  392.             }
  393.  
  394.             printf("Converting %s from old .SP format to new .SP format.\n",infile);
  395.             ROVG_read_old_vgaspec(infile);
  396.  
  397.             /* These values are fixed for a full 48K .SP file */
  398.             vga.S='S';
  399.             vga.P='P';
  400.             vga.len_l=0x00;
  401.             vga.len_h=0xC0;
  402.             vga.start_l=0x00;
  403.             vga.start_h=0x40;
  404.  
  405.             WVGA_write_vgaspec(outfile);
  406.  
  407.             return EXIT_OK;
  408.         } else {
  409.             RVGH_read_vgaspec_header(infile);
  410.             if((vga.S=='S')&&(vga.P=='P')) {
  411. fprintf(stderr,"Invalid input file format. This could be a new syle .SP file with\n");
  412. fprintf(stderr,"an image of another length than 48Kb. This kind of .SP files cannot\n");
  413. fprintf(stderr,"be converted. All other file formats (including the old .SP format)\n");
  414. fprintf(stderr,"contain images of 48Kb length.\n");
  415.             } else {
  416. fprintf(stderr,"Unknown input file format. Must be a valid .SNA, .SP, .Z80, .PRG, .ACH, .ZX or RAW file\n");
  417.             }
  418.             return EXIT_FILE_ERROR;
  419.         }
  420.     }
  421.  
  422.     if(type == Z80)
  423.     {
  424.         printf("Converting %s from .Z80 to .Z80 (output in version 1.45 format)\n",infile);
  425.         RZ80_read_z80(infile);
  426.  
  427.         WZ80_write_z80(outfile);
  428.         return EXIT_OK;
  429.     }
  430.  
  431.     /* If we get here than we had no special handling for this type */
  432.     /* return an error in that case...                              */
  433.     fprintf(stderr,"Input and output file format are the same. ");
  434.     fprintf(stderr,"What you try to do\n");
  435.     fprintf(stderr,"is handled much better by the MSDOS \"COPY\" ");
  436.     fprintf(stderr,"command!\n");
  437.  
  438.     return EXIT_USAGE;
  439. }
  440.  
  441. /* ERROR HANDLING FUNCTIONS */
  442.  
  443. /* Print Usage and exit */
  444. void USAG_usage()
  445. {
  446.     fprintf(stderr,"SPCONV version 1.09 - %s\n\n",__DATE__);
  447.     fprintf(stderr,"Usage: spconv <source> <target>\n\n");
  448.     fprintf(stderr,"Source must be a valid .SNA, .SP, .Z80, .PRG, .ACH, .ZX, .SNX or RAW file.\n");
  449.     fprintf(stderr,"Target must be a .SNA, .SP, .Z80, .PRG, .ACH, .ZX or .SNX file.\n\n");
  450.     fprintf(stderr,"If the second parameter contains only a suffix, the prefix\n");
  451.     fprintf(stderr,"of the input file will be used (i.e. 'spconv file.sna .z80')\n\n");
  452.     fprintf(stderr,"Output .SP files are in the new format, .Z80 files are compressed\n");
  453.     fprintf(stderr,"in the version 1.45 .Z80 format\n\n");
  454.     fprintf(stderr,"If <source> and <target> are .SP files, convertion from old\n");
  455.     fprintf(stderr,"to new format or from new to old format will be performed.\n");
  456.     fprintf(stderr,"If <source> and <target> are .Z80 files, convertion to\n");
  457.     fprintf(stderr,"the version 1.45 format will be performed.\n");
  458.     fprintf(stderr,"If <source> and <target> are of the same type an error message\n");
  459.     fprintf(stderr,"will be generated (unless they are both .SP or .Z80 files)\n");
  460.     fprintf(stderr,"\n\nPublic Domain, H. de Groot & D. Burke 1995\n\n");
  461.  
  462.     exit(EXIT_USAGE);
  463. }
  464.  
  465. void RERR_read_error(char * s, FILE * fd)
  466. {
  467.     perror(s);
  468.     if(fd != NULL) fclose(fd);
  469.     exit(EXIT_READ_ERROR);
  470. }
  471.  
  472. void WERR_write_error(char * s, FILE * fd)
  473. {
  474.     perror(s);
  475.     if(fd != NULL) fclose(fd);
  476.     exit(EXIT_WRITE_ERROR);
  477. }
  478.  
  479. /* I/O FUNCTIONS */
  480.  
  481. /* GENERIC I/O - READ/WRITE SNAPSHOT */
  482.  
  483. void RGEN_read_generic(char * s, void * header, size_t h_size)
  484. {
  485.     FILE * fd;
  486.  
  487.     fd=fopen(s,"r");
  488.     if(fd == NULL)
  489.         RERR_read_error(s, fd);
  490.  
  491.     if(fread(header, h_size, 1, fd)!=1)
  492.         RERR_read_error(s, fd);
  493.  
  494.     if(fread(image, (size_t) IMSIZE, 1, fd)!=1)
  495.         RERR_read_error(s, fd);
  496.  
  497.     fclose(fd);
  498. }
  499.  
  500. void WGEN_write_generic(char * s, void * header, size_t h_size)
  501. {
  502.     FILE * fd;
  503.  
  504.     unlink(s);
  505.  
  506.     fd=fopen(s,"w");
  507.     if(fd == NULL)
  508.         WERR_write_error(s, fd);
  509.  
  510.     if(fwrite(header, h_size, 1, fd)!=1)
  511.         WERR_write_error(s, fd);
  512.  
  513.     if(fwrite(image, (size_t) IMSIZE, 1, fd)!=1)
  514.         WERR_write_error(s, fd);
  515.  
  516.     fclose(fd);
  517. }
  518.  
  519. /* SPECIFIC I/O - READ/WRITE .SNA IMAGE */
  520.  
  521. void RSNA_read_sna(char * s)
  522. {
  523.     RGEN_read_generic(s, (void *) &sna, sna_size);
  524. }
  525.  
  526. void WSNA_write_sna(char * s)
  527. {
  528.     WGEN_write_generic(s, (void *) &sna, sna_size);
  529. }
  530.  
  531. /* SPECIFIC I/O - READ NEW .SP HEADER */
  532.  
  533. void RVGH_read_vgaspec_header(char * s)
  534. {
  535.     FILE * fd;
  536.  
  537.     fd=fopen(s,"r");
  538.     if(fd == NULL)
  539.         RERR_read_error(s, fd);
  540.  
  541.     if(fread(&vga,vga_size,1,fd)!=1)
  542.         RERR_read_error(s, fd);
  543.  
  544.     fclose(fd);
  545. }
  546.  
  547. /* SPECIFIC I/O - READ/WRITE NEW .SP IMAGE */
  548.  
  549. void RVGA_read_vgaspec(char * s)
  550. {
  551.     RGEN_read_generic(s, (void *) &vga, vga_size);
  552. }
  553.  
  554. void WVGA_write_vgaspec(char * s)
  555. {
  556.     WGEN_write_generic(s, (void *) &vga, vga_size);
  557. }
  558.  
  559. /* SPECIFIC I/O - READ/WRITE OLD .SP IMAGE */
  560.  
  561. void ROVG_read_old_vgaspec(char * s)
  562. {
  563.     RGEN_read_generic(s, (void *)(((char *)&vga)+6), (unsigned int) (vga_size-6));
  564. }
  565.  
  566. void WOVG_write_old_vgaspec(char * s)
  567. {
  568.     WGEN_write_generic(s, (void *)(((char *)&vga)+6), (unsigned int) (vga_size-6));
  569. }
  570.  
  571. /* SPECIFIC I/O - READ RAW IMAGE */
  572.  
  573. void RRAW_read_raw(char * s)
  574. {
  575.     signed int i;
  576.     FILE       * fd;
  577.  
  578.     fd=fopen(s,"r");
  579.     if(fd == NULL)
  580.         RERR_read_error(s, fd);
  581.  
  582.     if(fread(&h, hdr_size, 1, fd)!=1)
  583.         RERR_read_error(s, fd);
  584.  
  585.     /* check if the image was saved the correct way */
  586.     for(i=0;i<9;i++) {
  587.         if(h.in[i]!=expect[i]) {
  588.             fprintf(stderr,"Header of Spectrum image not ok, ");
  589.             fprintf(stderr,"Spectrum image should be saved with:\n");
  590.             fprintf(stderr,"SAVE *\"b\"CODE 16384,49152");
  591.             fclose(fd);
  592.             exit(EXIT_FILE_ERROR);
  593.         }
  594.     }
  595.  
  596.     if(fread(image, (size_t) IMSIZE, 1, fd)!=1)
  597.         RERR_read_error(s, fd);
  598.  
  599.     fclose(fd);
  600. }
  601.  
  602. /* SPECIFIC I/O - READ/WRITE .Z80 IMAGE */
  603.  
  604. void RZ80_read_z80(char * s)
  605. {
  606.     FILE       * fd;
  607.     signed int ext_size;
  608.  
  609.     fd=fopen(s,"r");
  610.     if(fd == NULL)
  611.         RERR_read_error(s, fd);
  612.  
  613.     /* read old header part */
  614.     if(fread(&z80,z80_145_size,1,fd)!=1)
  615.         RERR_read_error(s, fd);
  616.  
  617.     /* check for 2.01 format */
  618.     if((z80.pch == (unsigned char) 0) &&
  619.        (z80.pcl == (unsigned char) 0)) {
  620.  
  621.         /* 2.01 or better format, check if we can use this */
  622.         unsigned char *p;
  623.         p = (unsigned char *) &z80;
  624.  
  625.         /* read an aditional 2 bytes */
  626.         if(fread(&p[z80_145_size],2,1,fd)!=1)
  627.             RERR_read_error(s, fd);
  628.  
  629.         ext_size = ((signed int) p[z80_145_size]) +
  630.                  256 * ((signed int) p[z80_145_size+1]);
  631.  
  632.         if(ext_size < z80_201_ext_size) {
  633.             fprintf(stderr,"%s seems to be a new type Z80 file!\n",s);
  634.             fprintf(stderr,"This program is only tested for files up to version 3.0 format.\n");
  635.             fprintf(stderr,"The .Z80 file doesn't seem to be upwards compatible, since the\n");
  636.             fprintf(stderr,"extended header seems to be smaller than the version 2.01 extended\n");
  637.             fprintf(stderr,"header. The program can NOT convert this file!\n");
  638.             fclose(fd);
  639.             exit(EXIT_FILE_ERROR);
  640.         }
  641.         if(
  642.              (ext_size != z80_201_ext_size)
  643.              &&
  644.              (ext_size != z80_300_ext_size )
  645.           ) {
  646.             printf("Warning: %s seems to be a new type Z80 file!\n",s);
  647.             printf("         This program is only tested for files up to version 3.0 format.\n");
  648.             printf("         Assuming upwards compatibiliy, the program will attempt to convert\n");
  649.             printf("         the file anyway. The resulting file may not work!.\n");
  650.         }
  651.  
  652.         /* we passed this test, read the first part of the extended header */
  653.         if(fread(&p[z80_145_size+2], z80_201_ext_size, 1, fd) != 1)
  654.             RERR_read_error(s, fd);
  655.  
  656.         /* seek over the remaining extended header part if needed */
  657.         if(ext_size > z80_201_ext_size)
  658.         {
  659.             if (fseek(fd, (long) (ext_size - z80_201_ext_size), SEEK_CUR) != 0)
  660.                 RERR_read_error(s, fd);
  661.         }
  662.  
  663.         /* we got a complete header now. */
  664.         /* check the type of the file... */
  665.         switch (ext_size) {
  666.         case z80_201_ext_size:
  667.             if((unsigned int) z80.hardware >= 3) {
  668.                 fprintf(stderr,"%s is not a 48K Spectrum Z80 file, can't convert!\n",s);
  669.                 fclose(fd);
  670.                 exit(EXIT_FILE_ERROR);
  671.             }
  672.             break;
  673.         case z80_300_ext_size:
  674.             if((unsigned int) z80.hardware >= 4) {
  675.                 fprintf(stderr,"%s is not a 48K Spectrum Z80 file, can't convert!\n",s);
  676.                 fclose(fd);
  677.                 exit(EXIT_FILE_ERROR);
  678.             }
  679.             break;
  680.         default:
  681.             if((unsigned int) z80.hardware >= 4) {
  682.                 printf("Warning: %s might not be a 48K Spectrum Z80 file!\n",s);
  683.                 printf("         (hardware flag in .Z80 file >= 4)\n");
  684.                 printf("         Assuming 48K Spectrum anyway, continuing...\n");
  685.             }
  686.             break;
  687.         }
  688.  
  689.         /* check if the interface-1 rom was paged in */
  690.         if(z80.if1_paged != (unsigned char) 0) {
  691.             fprintf(stderr,"%s has interface-1 rom paged in, can't convert!\n",s);
  692.             fclose(fd);
  693.             exit(EXIT_FILE_ERROR);
  694.         }
  695.         /* all fine up till now, put PC back to the old place and reset the */
  696.         /* compressed memory bit, the z80_read_page function decompresses.  */
  697.         z80.pch = z80.n_pch;
  698.         z80.pcl = z80.n_pcl;
  699.         z80.data = z80.data & ~0x20; /* reset compressed mode bit to be sure */
  700.  
  701.         while(RDPG_z80_read_page(s, fd)!=0);
  702.     } else {
  703.         /* The file is in version 1.45 format.             */
  704.         /* Read and decompress if the image is compressed, */
  705.         /* just read if it is not compressed at all...     */
  706.  
  707.         if((z80.data & 0x20)!=0) {
  708.             Z80D_z80_decompress(fd,0,(unsigned int) IMSIZE);
  709.             z80.data = z80.data & ~0x20; /* reset compressed mode bit to be sure */
  710.         } else {
  711.             if(fread(image, (size_t) IMSIZE, 1, fd)!=1)
  712.                 RERR_read_error(s, fd);
  713.         }
  714.     }
  715.     fclose(fd);
  716. }
  717.  
  718. void WZ80_write_z80(char * s)
  719. {
  720.     FILE * fd;
  721.  
  722.     /* Try to compress the data */
  723.     z80.data=z80.data | Z80C_z80_compress();
  724.  
  725.     unlink(s);
  726.  
  727.     fd=fopen(s,"w");
  728.     if(fd == NULL)
  729.         WERR_write_error(s, fd);
  730.  
  731.     if(fwrite(&z80, z80_145_size, 1, fd)!=1)
  732.         WERR_write_error(s, fd);
  733.  
  734.     if(fwrite(image, (size_t) z80_size, 1, fd)!=1)
  735.         WERR_write_error(s, fd);
  736.  
  737.     fclose(fd);
  738. }
  739.  
  740. /* SPECIFIC I/O - READ/WRITE .PRG IMAGE */
  741.  
  742. void RPRG_read_prg(char * s)
  743. {
  744.     RGEN_read_generic(s, (void *) &prg, prg_size);
  745. }
  746.  
  747. void WPRG_write_prg(char * s)
  748. {
  749.     WGEN_write_generic(s, (void *) &prg, prg_size);
  750. }
  751.  
  752. /* SPECIFIC I/O - READ/WRITE .ACH IMAGE */
  753.  
  754. void RACH_read_ach(char * s)
  755. {
  756.     FILE * fd;
  757.  
  758.     fd=fopen(s,"r");
  759.     if(fd == NULL)
  760.         RERR_read_error(s, fd);
  761.  
  762.     if(fread(&ach,ach_size,1,fd)!=1)
  763.         RERR_read_error(s, fd);
  764.  
  765.     /* fseek over the 16K ram area */
  766.     if(fseek(fd,16384L,SEEK_CUR)!=0)
  767.         RERR_read_error(s, fd);
  768.  
  769.     if(fread(image, (size_t) IMSIZE, 1, fd)!=1)
  770.         RERR_read_error(s, fd);
  771.  
  772.     fclose(fd);
  773. }
  774.  
  775. void WACH_write_ach(char * s)
  776. {
  777.     char          buffer[1024];
  778.     char          * p;
  779.     signed int        i;
  780.     struct stat       status;
  781.     const char      * rom;
  782.     FILE              * fd;
  783.     signed long       file_size;
  784.  
  785.     /* clean buffer first */
  786.     p=(char *) buffer;
  787.     for(i=0; i < 1024; i++) p[i]='\0';
  788.  
  789.     unlink(s);
  790.  
  791.     fd=fopen(s,"w");
  792.     if(fd == NULL)
  793.         WERR_write_error(s, fd);
  794.  
  795.     if(fwrite(&ach,ach_size,1,fd)!=1)
  796.         WERR_write_error(s, fd);
  797.  
  798.     strcat(my_directory,"\\spectrum.rom");
  799.  
  800.     rom=NULL;
  801.  
  802.     if(stat("spectrum.rom",&status)>=0) {
  803.         rom="spectrum.rom";
  804.     }
  805.     else if (stat(my_directory,&status)>=0)    {
  806.         rom=(const char *) my_directory;
  807.     }
  808.     file_size = status.st_size;
  809.  
  810.     if(rom==NULL) {
  811.         printf("Warning: The file \"spectrum.rom\" needed for proper conversion to the .ach\n");
  812.         printf("         format could not be located, Converting anyway. The ROM space\n");
  813.         printf("         will be filled with 0 bytes, the converted file may not work\n");
  814.  
  815.         /* write the 16K ram area as zero's */
  816.         for(i=0; i < 16; i++) {
  817.             if(fwrite(buffer,1024,1,fd)!=1)
  818.                 WERR_write_error(s, fd);
  819.         }
  820.     } else {
  821.         if (file_size != 16384) {
  822.         printf("Warning: The file \"spectrum.rom\" needed for proper conversion to the .ach\n");
  823.         printf("         format has a wrong size (not 16K). Converting anyway. The ROM space\n");
  824.         printf("         will be filled with 0 bytes, the converted file may not work\n");
  825.  
  826.             /* copy the 16K ROM area */
  827.             for(i=0; i < 16; i++) {
  828.                 if(fwrite(buffer,1024,1,fd)!=1)
  829.                     WERR_write_error(s, fd);
  830.             }
  831.         } else {
  832.             FILE * fd_specrom;
  833.  
  834.             printf("Using Spectrum ROM: %s\n",rom);
  835.  
  836.             fd_specrom=fopen(rom,"r");
  837.             if(fd_specrom==NULL) {
  838.                 perror(rom);
  839.                 fclose(fd);
  840.                 exit(EXIT_WRITE_ERROR);
  841.             }
  842.  
  843.             for(i=0; i < 16; i++) {
  844.                 if(fread(buffer,1024,1,fd_specrom)!=1) {
  845.                     perror(rom);
  846.                     fclose(fd_specrom);
  847.                     fclose(fd);
  848.                     exit(EXIT_WRITE_ERROR);
  849.                 }
  850.                 if(fwrite(buffer,1024,1,fd)!=1) {
  851.                     perror(s);
  852.                     fclose(fd_specrom);
  853.                     fclose(fd);
  854.                     exit(EXIT_WRITE_ERROR);
  855.                 }
  856.             }
  857.             fclose(fd_specrom);
  858.         }
  859.     }
  860.  
  861.     if(fwrite(image, (size_t) IMSIZE, 1, fd)!=1)
  862.         WERR_write_error(s, fd);
  863.  
  864.     fclose(fd);
  865. }
  866.  
  867. /* SPECIFIC I/O - READ/WRITE .ZX IMAGE */
  868.  
  869. void RKGB_read_kgb(char * s)
  870. {
  871.     FILE * fd;
  872.  
  873.     fd=fopen(s,"r");
  874.     if(fd == NULL)
  875.         RERR_read_error(s, fd);
  876.  
  877.     /* fseek over the first 132 bytes */
  878.     if(fseek(fd,132L,SEEK_CUR)!=0)
  879.         RERR_read_error(s, fd);
  880.  
  881.     if(fread(image, (size_t) IMSIZE, 1, fd)!=1)
  882.         RERR_read_error(s, fd);
  883.  
  884.     if(fread(&kgb,kgb_size,1,fd)!=1)
  885.         RERR_read_error(s,fd);
  886.  
  887.     fclose(fd);
  888. }
  889.  
  890. void WKGB_write_kgb(char * s)
  891. {
  892.     char          buffer[132];
  893.     char          * p;
  894.     signed int        i;
  895.     struct stat       status;
  896.     const char        * rom;
  897.     FILE              * fd;
  898.     signed long       file_size;
  899.  
  900.     /* clean buffer first */
  901.     p=(char *) buffer;
  902.     for(i=0; i < 132; i++) p[i]='\0';
  903.  
  904.     unlink(s);
  905.  
  906.     fd=fopen(s,"w");
  907.     if(fd == NULL)
  908.         WERR_write_error(s, fd);
  909.  
  910.     strcat(my_directory,"\\spectrum.rom");
  911.  
  912.     rom=NULL;
  913.  
  914.     if(stat("spectrum.rom",&status)>=0) {
  915.         rom="spectrum.rom";
  916.     }
  917.     else if (stat(my_directory,&status)>=0) {
  918.         rom=(const char *) my_directory;
  919.     }
  920.     file_size = status.st_size;
  921.  
  922.     if(rom==NULL) {
  923.         printf("Warning: The file \"spectrum.rom\" needed for proper conversion to the .zx\n");
  924.         printf("         format could not be located, Converting anyway. The 132 bytes needed\n");
  925.         printf("         from the ROM will be filled with 0 bytes, the converted file may not\n");
  926.         printf("         work\n");
  927.  
  928.         /* write the 132 byte area as zero's */
  929.         if(fwrite(buffer,132,1,fd)!=1)
  930.             WERR_write_error(s, fd);
  931.     } else {
  932.         if (file_size != 16384) {
  933.         printf("Warning: The file \"spectrum.rom\" needed for proper conversion to the .zx\n");
  934.         printf("         format has a wrong size (not 16K). Converting anyway. The 132 bytes\n");
  935.         printf("         needed from the ROM will be filled with 0 bytes, the converted file\n");
  936.         printf("         may not work\n");
  937.  
  938.             /* write the 132 byte area as zero's */
  939.             if(fwrite(buffer,132,1,fd)!=1)
  940.                 WERR_write_error(s, fd);
  941.         } else {
  942.             FILE * fd_specrom;
  943.  
  944.             printf("Using Spectrum ROM: %s\n",rom);
  945.  
  946.             fd_specrom=fopen(rom,"r");
  947.  
  948.             if(fd_specrom == NULL) {
  949.                 perror(rom);
  950.                 fclose(fd);
  951.                 exit(EXIT_WRITE_ERROR);
  952.             }
  953.  
  954.             /* fseek over the first 16384-132 bytes */
  955.             if(fseek(fd_specrom,16252L,SEEK_CUR)!=0) {
  956.                 perror(rom);
  957.                 fclose(fd_specrom);
  958.                 fclose(fd);
  959.                 exit(EXIT_WRITE_ERROR);
  960.             }
  961.             if(fread(buffer,132,1,fd_specrom)!=1) {
  962.                 perror(rom);
  963.                 fclose(fd_specrom);
  964.                 fclose(fd);
  965.                 exit(EXIT_WRITE_ERROR);
  966.             }
  967.             if(fwrite(buffer,132,1,fd)!=1) {
  968.                 perror(s);
  969.                 fclose(fd_specrom);
  970.                 fclose(fd);
  971.                 exit(EXIT_WRITE_ERROR);
  972.             }
  973.             fclose(fd_specrom);
  974.         }
  975.     }
  976.  
  977.     if(fwrite(image, (size_t) IMSIZE, 1, fd)!=1)
  978.         WERR_write_error(s, fd);
  979.  
  980.     if(fwrite(&kgb,kgb_size,1,fd)!=1)
  981.         WERR_write_error(s, fd);
  982.  
  983.     fclose(fd);
  984. }
  985.  
  986. /* SPECIFIC I/O - READ/WRITE .SNX IMAGE */
  987.  
  988. void RSNX_read_snx(char * s)
  989. {
  990.     FILE       * fd;
  991.     unsigned char    counthi, countlo, marker, fill;
  992.     unsigned int    count, i, addr;
  993.  
  994.     fd=fopen(s,"r");
  995.     if(fd == NULL)
  996.         RERR_read_error(s, fd);
  997.  
  998.     /* read header part */
  999.     if(fread(&snx,snx_size,1,fd)!=1)
  1000.         RERR_read_error(s, fd);
  1001.  
  1002.     if((snx.signature[0] != 'X') || (snx.signature[1] != 'S') ||
  1003.        (snx.signature[2] != 'N') || (snx.signature[3] != 'A'))
  1004.     {
  1005.         printf("This is not a .SNX file, it should have the 'XSNA' text at the start!\n");
  1006.         RERR_read_error(s,fd);
  1007.     }
  1008.  
  1009.     /* If the header is an unexpected size, seek past it, ignoring any
  1010.        extra information held in it */
  1011.     if (snx.headerlenhi * 256 + snx.headerlenlo != snx_size-6)
  1012.     {
  1013.         printf("Warning: the header part of %s is not the expected %u bytes!\n",s,snx_size);
  1014.         printf("         Converting anyway, the converted file may not work\n");
  1015.         fseek(fd,snx.headerlenhi*256+snx.headerlenlo+6,SEEK_SET);
  1016.     }
  1017.     /* Read and decompress the image. */
  1018.     addr = 0;
  1019.     while (addr < IMSIZE)
  1020.     {
  1021.         if(fread(&counthi,1,1,fd)!=1)
  1022.             RERR_read_error(s,fd);
  1023.         if (counthi >= 0xE0)
  1024.         {
  1025.             count = (counthi & 0x0F) + 1;
  1026.             if ((counthi & 0xF0) == 0xF0)
  1027.                 marker = SNX_COMPRESSED;
  1028.             else
  1029.                 marker = SNX_UNCOMPRESSED;
  1030.         }
  1031.         else
  1032.         {
  1033.             if(fread(&countlo,1,1,fd)!=1)
  1034.                 RERR_read_error(s,fd);
  1035.             count = (counthi << 8) + countlo;
  1036.             if(fread(&marker,1,1,fd)!=1)
  1037.                 RERR_read_error(s,fd);
  1038.         }
  1039.  
  1040.         if (addr + count > IMSIZE)
  1041.             RERR_read_error(s,fd);
  1042.         if (marker == SNX_COMPRESSED)
  1043.         {
  1044.             if(fread(&fill,1,1,fd)!=1)
  1045.                 RERR_read_error(s,fd);
  1046.             for(i = 0; i < count; i++)
  1047.                 image[addr + i] = fill;
  1048.             addr += count;
  1049.         }
  1050.         else
  1051.         {
  1052.             i = 0;
  1053.             while (i < count)
  1054.             {
  1055.                 if(fread(&image[addr + i++],1,1,fd)!=1)
  1056.                     RERR_read_error(s,fd);
  1057.             }
  1058.             addr += count;
  1059.         }
  1060.     }
  1061.     fclose(fd);
  1062. }
  1063.  
  1064. void WSNX_write_snx(char * s)
  1065. {
  1066.     FILE            * fd;
  1067.     unsigned char    marker, countlo, counthi;
  1068.     unsigned int    addr, i, j, count, packable;
  1069.  
  1070.     unlink(s);
  1071.  
  1072.     fd=fopen(s,"w");
  1073.     if(fd == NULL)
  1074.         WERR_write_error(s, fd);
  1075.  
  1076.     /* Write header first */
  1077.     if(fwrite(&snx,snx_size,1,fd)!=1)
  1078.         WERR_write_error(s, fd);
  1079.  
  1080.     /* Now compress and write RAM image */
  1081.  
  1082.     addr = 0;
  1083.     while (addr < IMSIZE)
  1084.     {
  1085.         i = addr;
  1086.         j = i;
  1087.         /* First find a run we can compress; must be at least 6
  1088.            identical bytes in a row. */
  1089.         while ( (j+5 < IMSIZE) && (image[j] == image[j+1]) &&
  1090.                       (image[j] == image[j+2]) &&
  1091.                       (image[j] == image[j+3]) &&
  1092.                       (image[j] == image[j+4]) &&
  1093.                       (image[j] == image[j+5]) )
  1094.         {
  1095.             j++;
  1096.         }
  1097.         if (j > i)
  1098.         {
  1099.             count = (j - i) + 5;
  1100.             if (count <= 16)
  1101.             {
  1102.                 counthi = 0xF0 + (count - 1);
  1103.                 if(fwrite(&counthi,1,1,fd)!=1)
  1104.                     WERR_write_error(s,fd);
  1105.             }
  1106.             else
  1107.             {
  1108.                 counthi = count >> 8;
  1109.                 countlo = count & 0xFF;
  1110.                 if(fwrite(&counthi,1,1,fd)!=1)
  1111.                     WERR_write_error(s,fd);
  1112.                 if(fwrite(&countlo,1,1,fd)!=1)
  1113.                     WERR_write_error(s,fd);
  1114.                 marker = SNX_COMPRESSED;
  1115.                 if(fwrite(&marker,1,1,fd)!=1)
  1116.                     WERR_write_error(s,fd);
  1117.             }
  1118.  
  1119.             if(fwrite(&image[i],1,1,fd)!=1)
  1120.                 WERR_write_error(s,fd);
  1121.  
  1122.             addr += count;
  1123.             i = j + 5;
  1124.         }
  1125.  
  1126.         j = i + 1;
  1127.         packable = count = 0;
  1128.         /* Now find a run of non-identical bytes */
  1129.         do
  1130.         {
  1131.             if (image[j] != image[j-1])
  1132.             {
  1133.                 packable = 0;
  1134.                 count++;
  1135.                 j++;
  1136.             }
  1137.             else /* Found two consecutive identical bytes */
  1138.             {
  1139.                 if ( (j+3 < IMSIZE) &&
  1140.                      (image[j] == image[j+1]) &&
  1141.                      (image[j] == image[j+2]) &&
  1142.                      (image[j] == image[j+3]) &&
  1143.                      (image[j] == image[j+4]) )
  1144.                 { /* Found six consecutive identical bytes */
  1145.                     packable = 6;
  1146.                     j--;
  1147.                 }
  1148.                 else
  1149.                 {
  1150.                     packable = 0;
  1151.                     count++;
  1152.                     j++;
  1153.                 }
  1154.             }
  1155.         } while ( (j < IMSIZE) && (packable < 6) );
  1156.  
  1157.         if (count > 0)
  1158.         {
  1159.             if (IMSIZE - (i + count) < 6)
  1160.                 count = (unsigned int)(IMSIZE - i);
  1161.             if (count <= 16)
  1162.             {
  1163.                 counthi = 0xE0 + (count - 1);
  1164.                 if(fwrite(&counthi,1,1,fd)!=1)
  1165.                     WERR_write_error(s,fd);
  1166.             }
  1167.             else
  1168.             {
  1169.                 counthi = count >> 8;
  1170.                 countlo = count & 0xFF;
  1171.                 if(fwrite(&counthi,1,1,fd)!=1)
  1172.                     WERR_write_error(s,fd);
  1173.                 if(fwrite(&countlo,1,1,fd)!=1)
  1174.                     WERR_write_error(s,fd);
  1175.                 marker = SNX_UNCOMPRESSED;
  1176.                 if(fwrite(&marker,1,1,fd)!=1)
  1177.                     WERR_write_error(s,fd);
  1178.             }
  1179.  
  1180.             while (i < j)
  1181.             {
  1182.                 if(fwrite(&image[i++],1,1,fd)!=1)
  1183.                     WERR_write_error(s,fd);
  1184.             }
  1185.             addr += count;
  1186.         }
  1187.     }
  1188.  
  1189.     fclose(fd);
  1190. }
  1191.  
  1192. /* CONVERSION FUNCTIONS - TO .SNA FORMAT */
  1193.  
  1194. void VGSN_vgaspec_to_sna()
  1195. {
  1196.     unsigned int addr;
  1197.     unsigned int sp;
  1198.  
  1199.     sna.f=vga.f;
  1200.     sna.a=vga.a;
  1201.     sna.b=vga.b;
  1202.     sna.c=vga.c;
  1203.     sna.d=vga.d;
  1204.     sna.e=vga.e;
  1205.     sna.h=vga.h;
  1206.     sna.l=vga.l;
  1207.  
  1208.     sna.fax=vga.fax;
  1209.     sna.aax=vga.aax;
  1210.     sna.bax=vga.bax;
  1211.     sna.cax=vga.cax;
  1212.     sna.dax=vga.dax;
  1213.     sna.eax=vga.eax;
  1214.     sna.hax=vga.hax;
  1215.     sna.lax=vga.lax;
  1216.  
  1217.     sna.ixh=vga.ixh;
  1218.     sna.ixl=vga.ixl;
  1219.     sna.iyh=vga.iyh;
  1220.     sna.iyl=vga.iyl;
  1221.  
  1222.     sna.border=vga.border;
  1223.  
  1224.     sna.i=vga.i;
  1225.     sna.r=vga.r;
  1226.  
  1227.     /* If register I has changed, chances are good that it runs in
  1228.        IM2 mode */
  1229.     if(sna.i==0x3f)
  1230.         sna.im=0x01;
  1231.     else
  1232.         sna.im=0x02;
  1233.  
  1234.     if((vga.im & 0x01) == 0)
  1235.         sna.iff2=0x00;
  1236.     else
  1237.         sna.iff2=0xff;
  1238.  
  1239.     sp=256*vga.sph+vga.spl;
  1240.     sp=sp-2;
  1241.     addr=sp-0x4000;
  1242.     image[addr]=vga.pcl;
  1243.     image[addr+1]=vga.pch;
  1244.  
  1245.     sna.sph=sp/256;
  1246.     sna.spl=sp%256;
  1247. }
  1248.  
  1249. void RASN_raw_to_sna()
  1250. {
  1251.     unsigned int addr;
  1252.     unsigned int sp;
  1253.     unsigned int pc;
  1254.  
  1255.     pc=0x1bf4; /* entry of "next statement" */
  1256.  
  1257.     sna.f=0x99;
  1258.     sna.a=0x5f;
  1259.     sna.b=0x1f;
  1260.     sna.c=0xf0;
  1261.     sna.d=0x5d;
  1262.     sna.e=0x0c;
  1263.     sna.h=0x5d;
  1264.     sna.l=0x0e;
  1265.  
  1266.     sna.fax=0x44;
  1267.     sna.aax=0x00;
  1268.     sna.bax=0x18;
  1269.     sna.cax=0x20;
  1270.     sna.dax=0x00;
  1271.     sna.eax=0x07;
  1272.     sna.hax=0x5c;
  1273.     sna.lax=0xf1;
  1274.  
  1275.     sna.ixh=0x03;
  1276.     sna.ixl=0xd4;
  1277.     sna.iyh=0x5c;
  1278.     sna.iyl=0x3a;
  1279.  
  1280.     sna.i=0x3f;
  1281.     sna.r=0x00;
  1282.     sna.im=0x01;
  1283.     sna.iff2=0xFF;
  1284.  
  1285.     /* set sp by means of RAMTOP in the image */
  1286.     addr=0x5cb2-0x4000;
  1287.     sp=256*image[addr+1]+image[addr]-1;
  1288.  
  1289.     /* Reset ERR NR to no error */
  1290.     image[0x5c3a-0x4000]=0xff;
  1291.     
  1292.     /* Set border by means of BORDCR */
  1293.     sna.border=(image[0x5c48-0x4000] & 0x38)>>3;
  1294.     
  1295.     /* put return address to MAIN-4 (0x1303) on stack */
  1296.     sp=sp-2;
  1297.     addr=sp-0x4000;    
  1298.     image[addr]=0x03; 
  1299.     image[addr+1]=0x13;
  1300.     
  1301.     sp=sp-2;
  1302.     addr=sp-0x4000;
  1303.     image[addr]=pc%256;
  1304.     image[addr+1]=pc/256;
  1305.  
  1306.     sna.sph=sp/256;
  1307.     sna.spl=sp%256;
  1308. }
  1309.  
  1310. void Z8SN_z80_to_sna()
  1311. {
  1312.     unsigned int addr;
  1313.     unsigned int sp;
  1314.  
  1315.     sna.f=z80.f;
  1316.     sna.a=z80.a;
  1317.     sna.b=z80.b;
  1318.     sna.c=z80.c;
  1319.     sna.d=z80.d;
  1320.     sna.e=z80.e;
  1321.     sna.h=z80.h;
  1322.     sna.l=z80.l;
  1323.  
  1324.     sna.fax=z80.fax;
  1325.     sna.aax=z80.aax;
  1326.     sna.bax=z80.bax;
  1327.     sna.cax=z80.cax;
  1328.     sna.dax=z80.dax;
  1329.     sna.eax=z80.eax;
  1330.     sna.hax=z80.hax;
  1331.     sna.lax=z80.lax;
  1332.  
  1333.     sna.ixh=z80.ixh;
  1334.     sna.ixl=z80.ixl;
  1335.     sna.iyh=z80.iyh;
  1336.     sna.iyl=z80.iyl;
  1337.  
  1338.     sna.border=(z80.data/2) & 0x07; 
  1339.  
  1340.     sna.i=z80.i;
  1341.  
  1342.     if(z80.data==0xff) z80.data=0;
  1343.  
  1344.     if((z80.data & 0x01)==1)
  1345.         sna.r=(z80.r & 0x7f)+0x80;
  1346.     else
  1347.         sna.r=z80.r & 0x7f;
  1348.  
  1349.     sna.im=z80.im & 0x03;
  1350.     
  1351.     if(z80.iff2 != 0)
  1352.         sna.iff2=0xff;
  1353.     else
  1354.         sna.iff2=0x00;
  1355.  
  1356.     sp=256*z80.sph+z80.spl;
  1357.     sp=sp-2;
  1358.     addr=sp-0x4000;
  1359.         
  1360.     sna.sph=sp/256;
  1361.     sna.spl=sp%256;
  1362.  
  1363.     image[addr]=z80.pcl;
  1364.     image[addr+1]=z80.pch;
  1365. }
  1366.  
  1367. void PRSN_prg_to_sna()
  1368. {
  1369.     unsigned int addr;
  1370.     unsigned int sp;
  1371.  
  1372.     sna.b=prg.b;
  1373.     sna.c=prg.c;
  1374.     sna.d=prg.d;
  1375.     sna.e=prg.e;
  1376.     sna.h=prg.h;
  1377.     sna.l=prg.l;
  1378.     sna.fax=prg.fax;
  1379.     sna.aax=prg.aax;
  1380.     sna.bax=prg.bax;
  1381.     sna.cax=prg.cax;
  1382.     sna.dax=prg.dax;
  1383.     sna.eax=prg.eax;
  1384.     sna.hax=prg.hax;
  1385.     sna.lax=prg.lax;
  1386.  
  1387.     sna.ixh=prg.ixh;
  1388.     sna.ixl=prg.ixl;
  1389.     sna.iyh=prg.iyh;
  1390.     sna.iyl=prg.iyl;
  1391.  
  1392.     /* Set border by means of BORDCR */
  1393.     sna.border=(image[0x5c48-0x4000] & 0x38)>>3;
  1394.  
  1395.     sna.i=prg.i;
  1396.  
  1397.     if(prg.i==0x3f)
  1398.         sna.im=0x01;
  1399.     else
  1400.         sna.im=0x02;
  1401.  
  1402.     sp=256*prg.sph+prg.spl;
  1403.     sp=sp+4; /* there are two more words on the stack besides PC */
  1404.     addr=sp-0x4000;
  1405.  
  1406.     sna.r=image[addr-3];
  1407.     /* the af combo is on the stack */
  1408.     sna.f=image[addr-2];
  1409.     sna.a=image[addr-1];
  1410.         
  1411.     sna.sph=sp/256;
  1412.     sna.spl=sp%256;
  1413.  
  1414.     /* interrupts always on ??? */
  1415.     sna.iff2=prg.iff2;
  1416. }
  1417.  
  1418. void ACSN_ach_to_sna()
  1419. {
  1420.     unsigned int addr;
  1421.     unsigned int sp;
  1422.  
  1423.     sna.f=ach.f;
  1424.     sna.a=ach.a;
  1425.     sna.b=ach.b;
  1426.     sna.c=ach.c;
  1427.     sna.d=ach.d;
  1428.     sna.e=ach.e;
  1429.     sna.h=ach.h;
  1430.     sna.l=ach.l;
  1431.  
  1432.     sna.fax=ach.fax;
  1433.     sna.aax=ach.aax;
  1434.     sna.bax=ach.bax;
  1435.     sna.cax=ach.cax;
  1436.     sna.dax=ach.dax;
  1437.     sna.eax=ach.eax;
  1438.     sna.hax=ach.hax;
  1439.     sna.lax=ach.lax;
  1440.  
  1441.     sna.ixh=ach.ixh;
  1442.     sna.ixl=ach.ixl;
  1443.     sna.iyh=ach.iyh;
  1444.     sna.iyl=ach.iyl;
  1445.  
  1446.     sna.border=ach.border;
  1447.  
  1448.     sna.i=ach.i;
  1449.  
  1450.     sna.r=ach.r;
  1451.  
  1452.     sna.im=ach.im & 0x03;
  1453.     if(sna.im == 3)
  1454.          sna.im = 0;
  1455.         
  1456.     sna.iff2=ach.iff2;
  1457.  
  1458.     sp=256*ach.sph+ach.spl;
  1459.     sp=sp-2;
  1460.     addr=sp-0x4000;
  1461.         
  1462.     sna.sph=sp/256;
  1463.     sna.spl=sp%256;
  1464.  
  1465.     image[addr]=ach.pcl;
  1466.     image[addr+1]=ach.pch;
  1467. }
  1468.  
  1469. void KGSN_kgb_to_sna()
  1470. {
  1471.     unsigned int addr;
  1472.     unsigned int sp;
  1473.  
  1474.     sna.f=kgb.f;
  1475.     sna.a=kgb.a;
  1476.     sna.b=kgb.b;
  1477.     sna.c=kgb.c;
  1478.     sna.d=kgb.d;
  1479.     sna.e=kgb.e;
  1480.     sna.h=kgb.h;
  1481.     sna.l=kgb.l;
  1482.  
  1483.     sna.fax=kgb.fax;
  1484.     sna.aax=kgb.aax;
  1485.     sna.bax=kgb.bax;
  1486.     sna.cax=kgb.cax;
  1487.     sna.dax=kgb.dax;
  1488.     sna.eax=kgb.eax;
  1489.     sna.hax=kgb.hax;
  1490.     sna.lax=kgb.lax;
  1491.  
  1492.     sna.ixh=kgb.ixh;
  1493.     sna.ixl=kgb.ixl;
  1494.     sna.iyh=kgb.iyh;
  1495.     sna.iyl=kgb.iyl;
  1496.  
  1497.     sna.i=kgb.i;
  1498.     sna.r=kgb.r;
  1499.  
  1500.     /* border-colour not found in KGB image */
  1501.     /* Set border by means of BORDCR */
  1502.     sna.border=(image[0x5c48-0x4000] & 0x38)>>3;
  1503.  
  1504.     /* determine interrupt mode using the value of register I */
  1505.     if (kgb.i_mode_l==0xff)
  1506.         sna.im=0x00;
  1507.     else if(kgb.i_mode_l==1)
  1508.         sna.im=0x02; 
  1509.     else
  1510.         sna.im=0x01;
  1511.         
  1512.     if((kgb.interruptstatus & 0x01) != 0)
  1513.         sna.iff2=0xff;
  1514.     else
  1515.         sna.iff2=0x0;
  1516.  
  1517.     sp=256*kgb.sph+kgb.spl;
  1518.     sp=sp-2;
  1519.     addr=sp-0x4000;
  1520.         
  1521.     sna.sph=sp/256;
  1522.     sna.spl=sp%256;
  1523.  
  1524.     image[addr]=kgb.pcl;
  1525.     image[addr+1]=kgb.pch;
  1526. }
  1527.  
  1528. /* CONVERSION FUNCTIONS - FROM .SNA FORMAT */
  1529.  
  1530. void SNVG_sna_to_vgaspec()
  1531. {
  1532.     unsigned int addr;
  1533.     unsigned int sp;
  1534.     unsigned int pc;
  1535.  
  1536.     sp=256*sna.sph+sna.spl;
  1537.     addr=sp-0x4000;
  1538.     pc=image[addr]+256*image[addr+1];
  1539.     sp=sp+2;
  1540.  
  1541.     vga.S='S';
  1542.     vga.P='P';
  1543.     vga.len_l=0x00;
  1544.     vga.len_h=0xC0;
  1545.     vga.start_l=0x00;
  1546.     vga.start_h=0x40;
  1547.     vga.f=sna.f;
  1548.     vga.a=sna.a;
  1549.     vga.b=sna.b;
  1550.     vga.c=sna.c;
  1551.     vga.d=sna.d;
  1552.     vga.e=sna.e;
  1553.     vga.h=sna.h;
  1554.     vga.l=sna.l;
  1555.  
  1556.     vga.fax=sna.fax;
  1557.     vga.aax=sna.aax;
  1558.     vga.bax=sna.bax;
  1559.     vga.cax=sna.cax;
  1560.     vga.dax=sna.dax;
  1561.     vga.eax=sna.eax;
  1562.     vga.hax=sna.hax;
  1563.     vga.lax=sna.lax;
  1564.  
  1565.     vga.ixh=sna.ixh;
  1566.     vga.ixl=sna.ixl;
  1567.     vga.iyh=sna.iyh;
  1568.     vga.iyl=sna.iyl;
  1569.  
  1570.     vga.i=sna.i;
  1571.     vga.r=sna.r;
  1572.  
  1573.     vga.im=sna.im & 0x02; /* 0 for IM1, 2 for IM2 */
  1574.  
  1575.     /* works? how does it know it was IM1 ? */
  1576.     if((sna.iff2 & 0x04) != 0)
  1577.         vga.im=vga.im | 0x01; 
  1578.  
  1579.     vga.sph=sp/256;
  1580.     vga.spl=sp%256;
  1581.     
  1582.     vga.pch=pc/256;
  1583.     vga.pcl=pc%256;
  1584.  
  1585.     vga.border=sna.border;
  1586.  
  1587.     vga.res2=0;
  1588.     vga.res3=0;
  1589.     vga.res4=0;
  1590.     vga.res5=0;
  1591. }
  1592.  
  1593. void SNZ8_sna_to_z80()
  1594. {
  1595.     unsigned int addr;
  1596.     unsigned int sp;
  1597.     unsigned int pc;
  1598.  
  1599.     sp=256*sna.sph+sna.spl;
  1600.     addr=sp-0x4000;
  1601.     pc=image[addr]+256*image[addr+1];
  1602.     sp=sp+2;
  1603.  
  1604.     z80.f=sna.f;
  1605.     z80.a=sna.a;
  1606.     z80.b=sna.b;
  1607.     z80.c=sna.c;
  1608.     z80.d=sna.d;
  1609.     z80.e=sna.e;
  1610.     z80.h=sna.h;
  1611.     z80.l=sna.l;
  1612.  
  1613.     z80.fax=sna.fax;
  1614.     z80.aax=sna.aax;
  1615.     z80.bax=sna.bax;
  1616.     z80.cax=sna.cax;
  1617.     z80.dax=sna.dax;
  1618.     z80.eax=sna.eax;
  1619.     z80.hax=sna.hax;
  1620.     z80.lax=sna.lax;
  1621.  
  1622.     z80.ixh=sna.ixh;
  1623.     z80.ixl=sna.ixl;
  1624.     z80.iyh=sna.iyh;
  1625.     z80.iyl=sna.iyl;
  1626.  
  1627.     z80.i=sna.i;
  1628.     z80.r=sna.r | 0x080; /* bit 7 is stored somewhere else, always set */
  1629.     z80.im=sna.im & 0x03;
  1630.     z80.im=z80.im + 0x60; /* fixed normal video/kempston joystick */
  1631.  
  1632.     z80.sph=sp/256;
  1633.     z80.spl=sp%256;
  1634.     
  1635.     z80.pch=pc/256;
  1636.     z80.pcl=pc%256;
  1637.  
  1638.     /* all kinds of stuff put in "data" */
  1639.     z80.data=(sna.border & 0x07)*2; 
  1640.     if((sna.r & 0x80)!=0) z80.data=z80.data+1; /* here is bit 7 of r */
  1641.  
  1642.     /* image is not compressed, compression will be done by the */
  1643.     /* z80_write function.                                      */
  1644.     z80.data = z80.data & ~0x20; /* reset compressed mode bit to be sure */
  1645.  
  1646.     if((sna.iff2 & 0x04) != 0) {
  1647.         z80.iff1=0xff;
  1648.         z80.iff2=0xff;
  1649.     } else {
  1650.         z80.iff1=0;
  1651.         z80.iff2=0;
  1652.     }
  1653. }
  1654.  
  1655. void SNPR_sna_to_prg(char * n)
  1656. {
  1657.     unsigned int addr;
  1658.     unsigned int sp;
  1659.     signed   int i;
  1660.     unsigned char * p;
  1661.  
  1662.     /* clean header structure first */
  1663.     p=(unsigned char *) &prg;
  1664.     for(i=0; i < 256; i++)
  1665.         p[i]='\0';
  1666.  
  1667.     prg.c_0x61=0x61; /* size of image in sectors */
  1668.     prg.c_0x35=0x35; /* don't know yet */
  1669.     prg.c_0x03=0x03; /* don't know yet */
  1670.  
  1671.     sp=256*sna.sph+sna.spl;
  1672.     addr=sp-0x4000;
  1673.  
  1674.     /* these are on the stack */
  1675.     image[addr-1]=sna.a;
  1676.     image[addr-2]=sna.f;
  1677.     image[addr-3]=sna.r;
  1678.     image[addr-4]=sna.iff2;
  1679.  
  1680.     sp=sp-4;
  1681.  
  1682.     prg.name[0]='\0';
  1683.     strncpy(prg.name,n,10);
  1684.     prg.name[10]='\0';
  1685.  
  1686.     prg.b=sna.b;
  1687.     prg.c=sna.c;
  1688.     prg.d=sna.d;
  1689.     prg.e=sna.e;
  1690.     prg.h=sna.h;
  1691.     prg.l=sna.l;
  1692.  
  1693.     prg.fax=sna.fax;
  1694.     prg.aax=sna.aax;
  1695.     prg.bax=sna.bax;
  1696.     prg.cax=sna.cax;
  1697.     prg.dax=sna.dax;
  1698.     prg.eax=sna.eax;
  1699.     prg.hax=sna.hax;
  1700.     prg.lax=sna.lax;
  1701.  
  1702.     prg.ixh=sna.ixh;
  1703.     prg.ixl=sna.ixl;
  1704.     prg.iyh=sna.iyh;
  1705.     prg.iyl=sna.iyl;
  1706.  
  1707.     prg.i=sna.i;
  1708.     prg.iff2=sna.iff2;
  1709.  
  1710.     prg.sph=sp/256;
  1711.     prg.spl=sp%256;
  1712.  
  1713.     /* prg.border=sna.border; */
  1714. }
  1715.  
  1716. void SNAC_sna_to_ach()
  1717. {
  1718.     unsigned int addr;
  1719.     unsigned int sp;
  1720.     unsigned int pc;
  1721.     signed   int i;
  1722.     unsigned char * p;
  1723.  
  1724.     /* clean header structure first */
  1725.     p=(unsigned char *) &ach;
  1726.     for(i=0; i < 256; i++)
  1727.         p[i]='\0';
  1728.  
  1729.     sp=256*sna.sph+sna.spl;
  1730.     addr=sp-0x4000;
  1731.     pc=image[addr]+256*image[addr+1];
  1732.     sp=sp+2;
  1733.  
  1734.     ach.f=sna.f;
  1735.     ach.a=sna.a;
  1736.     ach.b=sna.b;
  1737.     ach.c=sna.c;
  1738.     ach.d=sna.d;
  1739.     ach.e=sna.e;
  1740.     ach.h=sna.h;
  1741.     ach.l=sna.l;
  1742.  
  1743.     ach.fax=sna.fax;
  1744.     ach.aax=sna.aax;
  1745.     ach.bax=sna.bax;
  1746.     ach.cax=sna.cax;
  1747.     ach.dax=sna.dax;
  1748.     ach.eax=sna.eax;
  1749.     ach.hax=sna.hax;
  1750.     ach.lax=sna.lax;
  1751.  
  1752.     ach.ixh=sna.ixh;
  1753.     ach.ixl=sna.ixl;
  1754.     ach.iyh=sna.iyh;
  1755.     ach.iyl=sna.iyl;
  1756.  
  1757.     ach.i=sna.i;
  1758.     ach.r=sna.r;
  1759.  
  1760.     ach.border=sna.border;
  1761.  
  1762.     if((sna.iff2 & 0x04) != 0)
  1763.         ach.iff2=0xff;
  1764.     else
  1765.         ach.iff2=0x00;
  1766.  
  1767.     ach.im=sna.im;
  1768.  
  1769.     ach.sph=sp/256;
  1770.     ach.spl=sp%256;
  1771.     
  1772.     ach.pch=pc/256;
  1773.     ach.pcl=pc%256;
  1774. }
  1775.  
  1776. void SNKG_sna_to_kgb()
  1777. {
  1778.     unsigned int addr;
  1779.     unsigned int sp;
  1780.     unsigned int pc;
  1781.     signed   int i;
  1782.     unsigned char * p;
  1783.  
  1784.     /* clean info structure first */
  1785.     p = (unsigned char *) &kgb;
  1786.     for(i=0; i < 202; i++)
  1787.         p[i]='\0';
  1788.  
  1789.     /* make some assumptions here */
  1790.     kgb.is3_1 = 3;        /* always 3, don't ask me why */
  1791.     kgb.colourmode = 1;    /* assume colour */
  1792.     kgb.soundmode = 1;    /* assume simple sound */
  1793.     kgb.haltmode = 1;    /* assume not in halt mode */
  1794.  
  1795.     sp=256*sna.sph+sna.spl;
  1796.     addr=sp-0x4000;
  1797.     pc=image[addr]+256*image[addr+1];
  1798.     sp=sp+2;
  1799.  
  1800.     kgb.f=sna.f;
  1801.     kgb.a=sna.a;
  1802.     kgb.b=sna.b;
  1803.     kgb.c=sna.c;
  1804.     kgb.d=sna.d;
  1805.     kgb.e=sna.e;
  1806.     kgb.h=sna.h;
  1807.     kgb.l=sna.l;
  1808.  
  1809.     kgb.fax=sna.fax;
  1810.     kgb.aax=sna.aax;
  1811.     kgb.bax=sna.bax;
  1812.     kgb.cax=sna.cax;
  1813.     kgb.dax=sna.dax;
  1814.     kgb.eax=sna.eax;
  1815.     kgb.hax=sna.hax;
  1816.     kgb.lax=sna.lax;
  1817.  
  1818.     kgb.ixh=sna.ixh;
  1819.     kgb.ixl=sna.ixl;
  1820.     kgb.iyh=sna.iyh;
  1821.     kgb.iyl=sna.iyl;
  1822.  
  1823.     kgb.i=sna.i;
  1824.  
  1825.     kgb.r=sna.r;
  1826.  
  1827.     /* kgb.border=sna.border; NOT IN KGB IMAGE! */
  1828.  
  1829.     /* Interupt mode is stored in a word in the KGB format. */
  1830.     /* Use byte accesses to be CPU independent              */
  1831.  
  1832.     switch (sna.im & 0x03) {
  1833.     case 0:    kgb.i_mode_h = 0xff;
  1834.         kgb.i_mode_l = 0xff;
  1835.         break;
  1836.     case 2: kgb.i_mode_h = 0;
  1837.         kgb.i_mode_l = 1;
  1838.         break;
  1839.     default:kgb.i_mode_h = 0;
  1840.         kgb.i_mode_l = 0;
  1841.         break;
  1842.     }
  1843.  
  1844.     if((sna.iff2 & 0x04) != 0)
  1845.         kgb.interruptstatus=0x01;
  1846.     else
  1847.         kgb.interruptstatus=0x00;
  1848.  
  1849.     kgb.sph=sp/256;
  1850.     kgb.spl=sp%256;
  1851.     
  1852.     kgb.pch=pc/256;
  1853.     kgb.pcl=pc%256;
  1854. }
  1855.  
  1856. /* 16K PAGE READ FUNCTION FOR .Z80 FORMAT */
  1857.  
  1858. /*
  1859.  * Function returns:
  1860.  *      0: No more pages
  1861.  *    1: Page read
  1862.  */
  1863. signed int RDPG_z80_read_page(char * s, FILE * fd)
  1864. {
  1865.     struct    z80_page_s page_info;
  1866.     unsigned int       len;
  1867.     unsigned int       pos;
  1868.     signed long       f_len;
  1869.  
  1870.     if(fread(&page_info,z80_pg_size,1,fd)!=1)    {
  1871.         return 0;
  1872.     }
  1873.     len = (256 * page_info.blklen_h) + page_info.blklen_l;
  1874.  
  1875.     switch(page_info.page_num) {
  1876.     case 0:    fprintf(stderr,"%s - memory page 0 - 48K rom ignored\n",s);
  1877.         pos=0x0ffff;
  1878.         break;
  1879.     case 1:    fprintf(stderr,"%s - memory page 1 - Interface 1 rom ignored\n",s);
  1880.         pos=0x0ffff;
  1881.         break;
  1882.     case 2:    fprintf(stderr,"%s - memory page 2 - basic samram rom ignored\n",s);
  1883.         pos=0x0ffff;
  1884.         break;
  1885.     case 3:    fprintf(stderr,"%s - memory page 3 - monitor samram rom ignored\n",s);
  1886.         pos=0x0ffff;
  1887.         break;
  1888.     case 4:    pos=0x04000;    /* second 16K of RAM area */
  1889.         break;
  1890.     case 5:    pos=0x08000;    /* third 16K of RAM area */
  1891.         break;
  1892.     case 6:    fprintf(stderr,"%s - memory page 6 - shadow rom 8000-BFFF ignored\n",s);
  1893.         pos=0x0ffff;
  1894.         break;
  1895.     case 7:    fprintf(stderr,"%s - memory page 7 - shadow rom C000-FFFF ignored\n",s);
  1896.         pos=0x0ffff;
  1897.         break;
  1898.     case 8:    pos=0;        /* first 16K of RAM area */
  1899.         break;
  1900.     case 9:    fprintf(stderr,"%s - memory page 8 - 128K page 6 ignored\n",s);
  1901.         pos=0x0ffff;
  1902.         break;
  1903.     case 10:fprintf(stderr,"%s - memory page 10 - 128K page 7 ignored\n",s);
  1904.         pos=0x0ffff;
  1905.         break;
  1906.     case 11:fprintf(stderr,"%s - memory page 11 - Multiface rom ignored\n",s);
  1907.         pos=0x0ffff;
  1908.         break;
  1909.     default:fprintf(stderr,"%s - memory page %d - Unknown page number -ignored-\n",s,page_info.page_num);
  1910.         pos=0x0ffff;
  1911.         break;
  1912.     }
  1913.  
  1914.     if(pos == (unsigned int) 0x0ffff) {
  1915.         /* wrong page, seek over this page */
  1916.         if(fseek(fd, (long) len, SEEK_CUR)!=0)
  1917.             RERR_read_error(s, fd);
  1918.     } else {
  1919.         /* Valid 48K page, read and decompress */
  1920.  
  1921.         f_len = 0 - ftell(fd);
  1922.         Z80D_z80_decompress(fd, pos, 16384);
  1923.         f_len = f_len + ftell(fd);
  1924.  
  1925.         if((signed long) len != f_len) {
  1926.             fprintf(stderr,"Z80 image corrupted, can't convert\n");
  1927.             fclose(fd);
  1928.             exit(EXIT_FILE_ERROR);
  1929.         }
  1930.     }
  1931.     return 1;
  1932. }
  1933.  
  1934. /* COMPRESSION/DECOMPRESSION for .Z80 FORMAT */
  1935.  
  1936. void Z80D_z80_decompress(FILE * fd, unsigned int start, unsigned int imsize)
  1937. {
  1938.     signed int    c,j,k;
  1939.     unsigned char l;
  1940.     unsigned char im;
  1941.  
  1942.     j=start;
  1943.     while(j<(start+imsize)) {
  1944.         c=getc(fd);
  1945.         if(c == -1) return;
  1946.         im = (unsigned char) c;
  1947.  
  1948.         if(im!=0xed) {
  1949.             image[j++]=im;
  1950.         } else {
  1951.             c=getc(fd);
  1952.             if(c == -1) return;
  1953.             im = (unsigned char) c;
  1954.             if(im!=0xed) {
  1955.                 image[j++]=0xed;
  1956.                 ungetc(im,fd);
  1957.             } else {
  1958.                 /* fetch count */
  1959.                 k=getc(fd);
  1960.                 if(k == -1) return;
  1961.                 /* fetch character */
  1962.                 c=getc(fd);
  1963.                 if(c == -1) return;
  1964.                 l = (unsigned char) c;
  1965.                 while(k!=0) {
  1966.                     image[j++]=l;
  1967.                     k--;
  1968.                 }
  1969.             }
  1970.         }
  1971.     }
  1972.  
  1973.     if(j!=(start+imsize)) {
  1974.         fprintf(stderr,"Z80 image corrupted, can't decompress\n");
  1975.         exit(EXIT_FILE_ERROR);
  1976.     }
  1977. }
  1978.  
  1979. int Z80C_z80_compress()
  1980. {
  1981. #ifdef __TURBOC__
  1982.     unsigned char far * comp;
  1983. #else
  1984.     unsigned char * comp;
  1985. #endif
  1986.     unsigned int i,j;
  1987.     unsigned int num;
  1988.     unsigned char c,n;
  1989.     unsigned int ed;
  1990.  
  1991.     z80_size=(unsigned int) IMSIZE;
  1992.  
  1993.     /*
  1994.      * We need an intermediate buffer here, if the compressed image
  1995.      * is bigger than the uncompressed image than the image will
  1996.      * not be compressed to save space (!)
  1997.      */
  1998.  
  1999. #ifdef __TURBOC__
  2000.     comp=(unsigned char far *) farmalloc((unsigned long)(IMSIZE+0x0100));
  2001. #else
  2002.     comp=(unsigned char *) malloc((size_t)(IMSIZE+0x0100));
  2003. #endif
  2004.     if(comp==NULL) {
  2005.         printf("Warning: Not enough memory to compress the image, using uncompressed image\n");
  2006.         return NOTCOMPRESSED;
  2007.     }
  2008.  
  2009.     i=0;
  2010.     j=0;
  2011.     /* ensure 'ed' is not set */
  2012.     ed=NO;
  2013.     while(i<IMSIZE)    {
  2014.         c=image[i];
  2015.         i++;
  2016.         if(i<IMSIZE) {
  2017.             n=image[i];
  2018.         } else {
  2019.             /* force 'n' to be unequal to 'c' */
  2020.             n=c;
  2021.             n++;
  2022.         }
  2023.  
  2024.         if(c!=n) {
  2025.             comp[j]=c;
  2026.             j++;
  2027.             if(c==0xed)
  2028.                 ed=YES;
  2029.             else
  2030.                 ed=NO;
  2031.         } else {
  2032.             if(c==0xed) {
  2033.                 /* two times 0xed - special care */
  2034.                 comp[j]=0xed;
  2035.                 j++;
  2036.                 comp[j]=0xed;
  2037.                 j++;
  2038.                 comp[j]=0x02;
  2039.                 j++;
  2040.                 comp[j]=0xed;
  2041.                 j++;
  2042.                 i++; /* skip second ED */
  2043.  
  2044.                 /* because 0xed is valid compressed we don't
  2045.                    have to watch it! */
  2046.                 ed=NO;
  2047.             } else if(ed==YES) {
  2048.                 /* can't compress now, skip this double pair */
  2049.                 comp[j]=c;
  2050.                 j++;
  2051.                 ed=NO;    /* 'c' can't be 0xed */
  2052.             } else {
  2053.                 num=1;
  2054.                 while(i<IMSIZE) {
  2055.                     if(c!=image[i])
  2056.                         break;
  2057.                     num++;
  2058.                     i++;
  2059.                     if(num==255)
  2060.                         break;
  2061.                 }
  2062.                 if(num <= 4) {
  2063.                     /* no use to compress */
  2064.                     while(num!=0) {
  2065.                         comp[j]=c;
  2066.                         j++;
  2067.                         num--;
  2068.                     }
  2069.                 } else {
  2070.                     comp[j]=0xed;
  2071.                     j++;
  2072.                     comp[j]=0xed;
  2073.                     j++;
  2074.                     comp[j]=(unsigned char) num;
  2075.                     j++;
  2076.                     comp[j]=c;
  2077.                     j++;
  2078.                 }
  2079.             }
  2080.         }
  2081.  
  2082.         if(j >= (IMSIZE-4)) {
  2083.             /* compressed image bigger or same than original */
  2084. #ifdef __TURBOC__
  2085.             farfree((void far *) comp);
  2086. #else
  2087.             free((void *) comp);
  2088. #endif
  2089.             return NOTCOMPRESSED;
  2090.         }
  2091.     }
  2092.     /* append "end of compressed area" mark */
  2093.     comp[j]=0;
  2094.     j++;
  2095.     comp[j]=0xed;
  2096.     j++;
  2097.     comp[j]=0xed;
  2098.     j++;
  2099.     comp[j]=0;
  2100.     j++;
  2101.  
  2102.     z80_size = j;
  2103.  
  2104.     /* copy back */
  2105.     i=0;
  2106.     j=0;
  2107.     while(i<IMSIZE)
  2108.         image[i++]=comp[j++];
  2109. #ifdef __TURBOC__
  2110.     farfree((void far *) comp);
  2111. #else
  2112.     free((void *) comp);
  2113. #endif
  2114.     return COMPRESSED;
  2115. }
  2116.  
  2117. /* SNX to SNA is easy, because the SNX header contains all the stuff in a */
  2118. /* SNA header, it's even in the same order. */
  2119. void SXSN_snx_to_sna(void)
  2120. {
  2121.     sna.i = snx.i;
  2122.     sna.lax = snx.lax;
  2123.     sna.hax = snx.hax;
  2124.     sna.eax = snx.eax;
  2125.     sna.dax = snx.dax;
  2126.     sna.cax = snx.cax;
  2127.     sna.bax = snx.bax;
  2128.     sna.fax = snx.fax;
  2129.     sna.aax = snx.aax;
  2130.     sna.l = snx.l;
  2131.     sna.h = snx.h;
  2132.     sna.e = snx.e;
  2133.     sna.d = snx.d;
  2134.     sna.c = snx.c;
  2135.     sna.b = snx.b;
  2136.     sna.iyl = snx.iyl;
  2137.     sna.iyh = snx.iyh;
  2138.     sna.ixl = snx.ixl;
  2139.     sna.ixh = snx.ixh;
  2140.     sna.iff2 = snx.iff2;
  2141.     sna.r = snx.r;
  2142.     sna.f = snx.f;
  2143.     sna.a = snx.a;
  2144.     sna.spl = snx.spl;
  2145.     sna.sph = snx.sph;
  2146.     sna.im = snx.im;
  2147.     sna.border = snx.border;
  2148. }
  2149.  
  2150. /* SNA to SNX is easy, because they have identical headers apart from the */
  2151. /* extra information present in the SNX header. */
  2152. void SNSX_sna_to_snx(void)
  2153. {
  2154.     snx.signature[0] = 'X';        /* XSNA = eXtended SNA! */
  2155.     snx.signature[1] = 'S';
  2156.     snx.signature[2] = 'N';
  2157.     snx.signature[3] = 'A';
  2158.     snx.headerlenhi = (snx_size - 6) << 8;
  2159.     snx.headerlenlo = (snx_size - 6) & 0xFF;
  2160.  
  2161.     snx.i = sna.i;
  2162.     snx.lax = sna.lax;
  2163.     snx.hax = sna.hax;
  2164.     snx.eax = sna.eax;
  2165.     snx.dax = sna.dax;
  2166.     snx.cax = sna.cax;
  2167.     snx.bax = sna.bax;
  2168.     snx.fax = sna.fax;
  2169.     snx.aax = sna.aax;
  2170.     snx.l = sna.l;
  2171.     snx.h = sna.h;
  2172.     snx.e = sna.e;
  2173.     snx.d = sna.d;
  2174.     snx.c = sna.c;
  2175.     snx.b = sna.b;
  2176.     snx.iyl = sna.iyl;
  2177.     snx.iyh = sna.iyh;
  2178.     snx.ixl = sna.ixl;
  2179.     snx.ixh = sna.ixh;
  2180.     snx.iff2 = sna.iff2;
  2181.     snx.r = sna.r;
  2182.     snx.f = sna.f;
  2183.     snx.a = sna.a;
  2184.     snx.spl = sna.spl;
  2185.     snx.sph = sna.sph;
  2186.     snx.im = sna.im;
  2187.     snx.border = sna.border;
  2188.  
  2189.     /* Set the emulator's switches to some default values. Not sure just
  2190.        what these values mean, but they were like this in most of the SNX
  2191.        files I had to test the program with, so seem safe enough to use */
  2192.     snx.emulator_switches[0] = 0;
  2193.     snx.emulator_switches[1] = 1;
  2194.     snx.emulator_switches[2] = 1;
  2195.     snx.emulator_switches[3] = 0x83;
  2196.     snx.emulator_switches[4] = 1;
  2197.     snx.emulator_switches[5] = 0;
  2198.     snx.emulator_switches[6] = 1;
  2199.     snx.emulator_switches[7] = 0x41;
  2200.     snx.emulator_switches[8] = 0x22;
  2201.     snx.emulator_switches[9] = 0xFF;
  2202. }
  2203.  
  2204.