home *** CD-ROM | disk | FTP | other *** search
/ 64'er / 64ER_CD.iso / utilpc / c64dearc / ax.c < prev    next >
C/C++ Source or Header  |  1989-10-10  |  25KB  |  940 lines

  1. /*  ax.c
  2.     ===========================================================================
  3.     No Frills un-compactor for C64/C128 style archives           06Jun89  - CS
  4.     ===========================================================================
  5.     This is a simple program to allow users of non-Commodore machines to get
  6.     access to the contents of SDA's or archives as created by the Commodore
  7.     64 or 128. Its no speedster, but then its not the kind of program you or I
  8.     will be using 100 times a day so what the heck.
  9.  
  10.     Compiles succesfully with Lattice 5.0 on the Amiga, or with any PC ANSI
  11.     compiler. (I used Zortech for the EXE file included here because it gave
  12.     the fastest executable)
  13.  
  14.     This file and derivatives thereof are placed into the public domain.
  15. */
  16.  
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20.  
  21. #define ULONG unsigned long
  22. #define BYTE  unsigned char
  23. #define WORD  unsigned short 
  24.  
  25. #ifdef  MPU8086         /* If Manx PC */
  26. #define RB   "r"
  27. #define WB   "w"
  28. #else                   /* If the rest of the civilized world */
  29. #define RB   "rb"
  30. #define WB   "wb"
  31. #endif
  32.  
  33. #ifdef  AMIGA           /* Compiled with Lattice 5.0 on the Amiga    */
  34. #undef  NORMAL          /* undefine if reverse byte ordering (68000) */
  35. #else
  36. #define NORMAL
  37. #endif
  38.  
  39.  
  40. int         Status;     /* I/O status. 0=ok, or EOF */
  41. ULONG       FilePos;    /* Current offset from ARC or SDA file's beginning */
  42. FILE *      fp;         /* archive */
  43. int         BitPos;     /* Bit position within one byte bit buffer */
  44. WORD        crc;        /* checksum */
  45. BYTE        crc2;       /* used in checksum calculation */
  46. ULONG       hc[256];    /* Huffman codes */
  47. BYTE        hl[256];    /* Lengths of huffman codes */
  48. BYTE        hv[256];    /* Character associated with Huffman code */
  49. WORD        hcount;     /* Number of Huffman codes */
  50. WORD        ctrl;       /* Run-Length control character */
  51. WORD        loadaddr;   /* Load address if CBM PRG file */
  52. long        truesize;   /* True file size */
  53. char        RealName[17];   /* True name for BASIC file */
  54.  
  55.  
  56. /* Archive entry header */
  57.  
  58. struct ARC64Header {
  59.     BYTE    version;    /* Version number, must be 1 or 2 */
  60.     BYTE    mode;       /* 0=store, 1=pack, 2=squeeze, 3=crunch, 4=squeeze+pack, 5=crunch in one pass */
  61.     WORD    check;      /* Checksum */
  62.     long    size;       /* Original size. Only three bytes are stored */
  63.     WORD    blocks;     /* Compressed size in CBM disk blocks */
  64.     BYTE    type;       /* File type. P,S,U or R */
  65.     BYTE    fnlen;      /* Filename length */
  66.     char    name[17];   /* Filename. Only fnlen bytes are stored */
  67.     BYTE    rl;         /* Record length if relative file */
  68.     WORD    date;       /* Date archive was created. Same format as in MS-DOS directories */
  69. } entry;
  70.  
  71. /* Lempel Zev compression string table entry */
  72.  
  73. struct LZ {
  74.     WORD    prefix;     /* Prefix code */
  75.     BYTE    ext;        /* Extension character */
  76. };
  77.  
  78. /* LZ globals */
  79.  
  80. #define LZSTKSIZ 512        /* Actually only 40 or 50 bytes is sufficient */
  81.  
  82. int         State = 0;      /* Set to 0 to reset un-crunch */
  83. struct LZ   lztab[4096];    /* String table */
  84. BYTE        stack[LZSTKSIZ];/* Stack for push/pop */
  85. int         lzstack;        /* Stack pointer */
  86. int         cdlen,          /* Current code size */
  87.             code,           /* Last code rec'd  */
  88.             wtcl;           /* Bump cdlen when code reaches this value */
  89. int         ncodes,         /* Current # of codes in table */
  90.             wttcl;          /* Copy of wtcl */
  91.  
  92.  
  93.  
  94.  
  95.  
  96. /*  --------------------------------------------------------------------------
  97.     Shell Sort.  From "C Programmer's Library" by Purdum, Leslie & Stegemoller
  98.  
  99.     'swap' and 'comp' functions vary depending on the data type being sorted.
  100.  
  101.     swp(i,j)  - simply swaps array elements i and j.
  102.     cmp(i,j)  - returns 0 if elements are equal.
  103.                       >0 if element[i] > element[j]
  104.                       <0 if    ''      <    ''
  105.     --------------------------------------------------------------------------
  106.     n   = Number of elements to be sorted. (0 is 1st, n-1 is last)
  107.     cmp = Compare two elements. Return result like strcmp()
  108.     swp = Swap to elements
  109. */
  110.  
  111. void ssort(unsigned n, int (*cmp)(int,int), void (*swp)(int,int))
  112. {
  113.     int m;
  114.     int h,i,j,k;
  115.  
  116.     m=n;
  117.  
  118.     while( (m /= 2) != 0) {
  119.         k = n-m;
  120.         j = 1;
  121.         do {
  122.             i=j;
  123.             do {
  124.                 h=i+m;
  125.                 if ((*cmp)(i-1,h-1) >0 ) {
  126.                     (*swp)(i-1,h-1);
  127.                     i -= m;
  128.                 }
  129.                 else
  130.                     break;
  131.             } while (i >= 1);
  132.             j += 1;
  133.         } while(j <= k);
  134.     }
  135. }
  136.  
  137.  
  138. /*  ------------------------------------------------
  139.     Compare function for Shell Sort of Huffman codes
  140.     Set up to sort them in reverse order by length
  141.     ------------------------------------------------
  142. */
  143.     
  144. int hcomp(int x, int y)
  145. {
  146.     return ( hl[y] - hl[x] );
  147. }
  148.  
  149. void hswap(int x, int y)
  150. {
  151.     unsigned long t0;
  152.     unsigned char t1, t2;
  153.  
  154.     t0    = hc[x];
  155.     t1    = hv[x];
  156.     t2    = hl[x];
  157.     hc[x] = hc[y];
  158.     hv[x] = hv[y];
  159.     hl[x] = hl[y];
  160.     hc[y] = t0;
  161.     hv[y] = t1;
  162.     hl[y] = t2;
  163. }
  164.  
  165.  
  166. /*  -------------------------------------
  167.     Convert CBM ASCII to 'Standard' ASCII
  168.     -------------------------------------
  169. */
  170.  
  171. char p2a(int c)
  172. {
  173.     static unsigned cc;
  174.     static unsigned oldcc;
  175.  
  176.     c &= 0xff;
  177.  
  178.     oldcc = cc;
  179.     cc    = c;
  180.  
  181.     switch (cc) {
  182.  
  183.        case 10: {                                   /* LF           */
  184.                 if (oldcc!=13)
  185.                    return 10;
  186.                 else
  187.                    return '\0';
  188.                 }
  189.        case 13:  return '\n';                       /* CR           */
  190.        case 160: return ' ';                        /* Shift+space  */
  191.        case 164: return '_';
  192.        case 171: return '╠';
  193.        case 173: return '╚';
  194.        case 174: return '╗';
  195.        case 175: return '~';
  196.        case 176: return '╔';
  197.        case 177: return '╩';
  198.        case 178: return '╦';
  199.        case 179: return '╣';
  200.        case 189: return '╝';
  201.        case 192: return '═';
  202.        case 219: return '╬';
  203.        case 221: return '║';
  204.        case 223: return '|';
  205.        default:  {
  206.             if (cc<65 || cc>219)
  207.                 return (char) cc;
  208.             if (cc<91)
  209.                 return (char) (cc|0x20);
  210.             if (cc<193)
  211.                 return (char) cc;
  212.             else
  213.                 return (char) (cc&0x7f);
  214.        }
  215.    }
  216. }
  217.  
  218.  
  219. /*  -----------------
  220.     Input Subroutines
  221.     -----------------
  222.     These are terribly inefficient
  223. */
  224.  
  225.  
  226. BYTE GetByte()
  227. {
  228.     int c;
  229.  
  230.     if (Status == EOF)
  231.         return 0;
  232.  
  233.     if ( (c=fgetc(fp)) == EOF) {
  234.         Status = c;
  235.     }
  236.     return (BYTE) (c & 0xff);
  237. }
  238.  
  239. WORD GetWord()
  240. {
  241.     union {
  242.         WORD u;
  243.         char c[2];
  244.     } x;
  245.  
  246.     int i;
  247.  
  248.     x.u = 0;
  249.  
  250. #ifdef NORMAL
  251.     for (i=0; i<2; i++)
  252. #else
  253.     for (i=1; i>=0; i--)
  254. #endif
  255.         x.c[i] = GetByte();
  256.  
  257.     return x.u;
  258. }
  259.  
  260. long GetThree()
  261. {
  262.     union {
  263.         long u;
  264.         char c[4];
  265.     } x;
  266.  
  267.     int i;
  268.  
  269.     x.u = 0;
  270.  
  271. #ifdef NORMAL
  272.     for (i=0; i<3; i++)
  273. #else
  274.     for (i=3; i; i--)
  275. #endif
  276.         x.c[i] = GetByte();
  277.  
  278.     return x.u;
  279.  
  280. }
  281.  
  282.   
  283. int GetBit()
  284. {
  285.     static int Byte;
  286.     int c;
  287.  
  288.     if (!BitPos)
  289.         Byte = GetByte();
  290.  
  291.     c    = Byte & 1;
  292.     Byte = Byte >>1;
  293.     BitPos++;
  294.  
  295.     if (BitPos == 8)
  296.         BitPos = 0;
  297.  
  298.     return c;
  299. }
  300.  
  301. #ifdef AMIGA    /* Lattice doesn't seem to have one of these  */
  302.  
  303. /*  6502 wants words low to high */
  304.  
  305. void putw(unsigned cc, FILE * fp)
  306. {
  307.     fputc((cc & 0xff), fp);
  308.     fputc((cc/256),fp);
  309. }
  310.  
  311. #endif
  312.  
  313. /*  --------------------------------------------------------
  314.     Fetch huffman code and convert it to what it represents
  315.     --------------------------------------------------------
  316.     I wrote this a long time ago when I thought binary trees
  317.     were things that grew in northern Saskatchewan.
  318. */
  319.  
  320. int Huffin()
  321. {
  322.     long hcode = 0;
  323.     long mask  = 1;
  324.     int  size  = 1;
  325.     int  now;
  326.  
  327.     now = hcount;       /* First non=zero Huffman code */
  328.  
  329.     do {
  330.         if (GetBit())
  331.             hcode |= mask;
  332.  
  333.         while( hl[now] == size) {
  334.  
  335.             if (hc[now] == hcode)
  336.                 return hv[now];
  337.  
  338.             if (--now < 0) {         /* Error in decode table */
  339.                 Status = EOF;
  340.                 return EOF;
  341.             }
  342.         }
  343.         size++;
  344.         mask = mask << 1;
  345.     } while(size < 24);
  346.  
  347.     Status = EOF;
  348.     return EOF;                      /* Error. Huffman code too big */
  349. }
  350.  
  351. /*  ------------------------------------------------------------------
  352.     Fetch ARC64 header. Returns 1 if header is ok, otherwise returns 0
  353.     ------------------------------------------------------------------
  354. */
  355.  
  356. int GetHeader()
  357. {
  358.     WORD    w, i;
  359.     char *  LegalTypes = "SPUR";
  360.     ULONG   mask;
  361.  
  362.     if (feof(fp) || ferror(fp))
  363.         return 0;
  364.  
  365.     BitPos        = 0;              /* Bit buffer pointer */
  366.     crc           = 0;              /* checksum */
  367.     crc2          = 0;              /* Used in checksum calculation */
  368.     State         = 0;              /* LZW state */
  369.     ctrl          = 254;            /* Run-Length control character */
  370.  
  371.     entry.version = GetByte();
  372.     entry.mode    = GetByte();
  373.     entry.check   = GetWord();
  374.     entry.size    = GetThree();
  375.     entry.blocks  = GetWord();
  376.     entry.type    = p2a(GetByte());
  377.     entry.type    = toupper(entry.type);
  378.     entry.fnlen   = GetByte();
  379.  
  380.     /* Check for invalid header, If invalid, then we've input past the end  */
  381.     /* Possibly due to XMODEM padding or whatever                           */
  382.  
  383.     if  (entry.fnlen > 16)
  384.         return 0;
  385.  
  386.     for (w=0; w < entry.fnlen; w++) {
  387.         RealName[w] = GetByte();
  388.         entry.name[w] = p2a(RealName[w]);
  389.     }
  390.  
  391.     RealName[entry.fnlen] = 0;
  392.     entry.name[entry.fnlen] = 0;
  393.  
  394.     if (entry.version > 1) {
  395.         entry.rl  = GetByte();
  396.         entry.date= GetWord();
  397.     }
  398.  
  399.     if (Status == EOF)
  400.         return 0;
  401.  
  402.     if ( (entry.version == 0) || (entry.version >2) )
  403.         return 0;
  404.  
  405.     if ( entry.version == 1) {                  /* If ARC64 version 1.xx */
  406.         if (entry.mode > 2)                     /* Only store, pack, squeeze */
  407.             return 0;
  408.     }
  409.     if (entry.mode == 1)                        /* If packed get control char */
  410.         ctrl = GetByte();                       /* V2 always uses 0xfe V1 varies */
  411.  
  412.     if (entry.mode > 5)
  413.         return 0;
  414.  
  415.     if (entry.blocks > 4133)                    /* Largest CBM disk is 8250 */
  416.         return 0;
  417.  
  418.     if ( (entry.mode == 2) || (entry.mode == 4) ) {   /* if squeezed or squashed */
  419.  
  420.         hcount = 255;                                 /* Will be first code */
  421.         for (w=0; w<256; w++) {                       /* Fetch Huffman codes */
  422.  
  423.             hv[w] = w;
  424.  
  425.             hl[w]=0;
  426.             mask = 1;
  427.             for (i=1; i<6; i++) {
  428.                 if (GetBit())
  429.                     hl[w] |= mask;
  430.                 mask = mask << 1;
  431.             }
  432.  
  433.             if (hl[w] > 24)
  434.                 return 0;                             /* Code too big */
  435.  
  436.             hc[w] = 0;
  437.             if (hl[w]) {
  438.                 i = 0;
  439.                 mask = 1;
  440.                 while (i<hl[w]) {
  441.                     if (GetBit())
  442.                         hc[w] |= mask;
  443.                     i++;
  444.                     mask = mask << 1;
  445.                 }
  446.             }
  447.             else
  448.                 hcount--;
  449.         }
  450.         ssort(256,hcomp,hswap);
  451.     }
  452.  
  453.     if (strchr(LegalTypes, entry.type) == 0)
  454.         return 0;
  455.  
  456.     return 1;
  457. }
  458.  
  459.  
  460.  
  461.  
  462.  
  463. /*  --------------------------------------------------------------------------
  464.      Get start of data. Ignores SDA header, and returns -1 if not an archive.
  465.      Otherwise return value is the starting position of useful data within the
  466.      file. (Normally 0)
  467.     --------------------------------------------------------------------------
  468. */
  469.  
  470. int GetStartPos()
  471. {
  472.     int c;                      /* Temp */
  473.     int cpu;                    /* C64 or C128 if SDA */
  474.     int linenum;                /* Sys line number */
  475.     int skip;                   /* Size of SDA header in bytes */
  476.  
  477.     fseek(fp,(long) 0,0);       /* Goto start of file */
  478.  
  479.     if ( (c=GetByte()) == 2)    /* Probably type 2 archive */
  480.         return 0;               /* Data starts at offset 0 */
  481.  
  482.     if (c != 1)                 /* IBM archive, or not an archive at all */
  483.         return -1;
  484.  
  485.     /* Check if its an SDA */
  486.  
  487.     GetByte();                  /* Skip to line number (which is # of header blocks) */
  488.     GetWord();
  489.     linenum = GetWord();
  490.     c = GetByte();
  491.  
  492.     if (c != 0x9e)              /* Must be BASIC SYS token */
  493.         return 0;               /* Else probably type 1 archive */
  494.  
  495.     c = GetByte();              /* Get SYS address */
  496.     cpu = GetByte();            /* '2' for C64, '7' for C128 */
  497.  
  498.     skip = (linenum-6)*254;     /* True except for SDA232.128  */
  499.  
  500.     if ( (linenum==15) && (cpu=='7') )   /* handle the special case */
  501.         skip -= 1;
  502.  
  503.     return skip;
  504. }
  505.  
  506.  
  507. /*  ----------------------------------------------------------------------
  508.     Un-Crunch a byte
  509.     ----------------------------------------------------------------------
  510.     This is pretty straight forward if you have Terry Welch's article
  511.     "A Technique for High Performance Data Compression" from IEEE Computer
  512.     June 1984
  513.  
  514.     This implemention reserves code 256 to indicate the end of a crunched
  515.     file, and code 257 was reserved for future considerations. Codes grow
  516.     up to 12 bits and then stay there. There is no reset of the string
  517.     table.
  518. */
  519.  
  520.     /* PUSH/POP LZ stack */
  521.  
  522. void push(int c)
  523. {
  524.     if (lzstack > LZSTKSIZ-1) {
  525.         printf("Lempel Zev Stack Overflow\n");
  526.         exit(1);
  527.     }
  528.     else
  529.         stack[lzstack++] = c;
  530. }
  531.  
  532. int pop()
  533. {
  534.     if ( !lzstack ) {
  535.         printf("Lempel Zev stack underflow.\n");
  536.         exit(1);
  537.     }
  538.     else
  539.         return stack[--lzstack];
  540. }
  541.  
  542.  
  543. int unc()
  544. {
  545.     static int  oldcode, incode;
  546.     static BYTE kay;
  547.     static int  omega;
  548.     static BYTE finchar;
  549.  
  550.     switch (State) {
  551.  
  552.         case 0: {                       /* First time. Reset. */
  553.  
  554.             lzstack = 0;
  555.             ncodes  = 258;              /* 2 reserved codes */
  556.             wtcl    = 256;              /* 256 Bump code size when we get here */
  557.             wttcl   = 254;              /* 1st time only 254 due to resvd codes */
  558.             cdlen   = 9;                /* Start with 9 bit codes */
  559.             oldcode = getcode();
  560.  
  561.             if (oldcode == 256) {       /* code 256 marks end of this entry */
  562.                 Status = EOF;
  563.                 return EOF;
  564.             }
  565.             kay = oldcode & 0xff;
  566.             finchar = kay;
  567.             State = 1;
  568.             return kay;
  569.         }
  570.         case 1: {
  571.  
  572.             incode = getcode();
  573.  
  574.             if (incode == 256) {
  575.                 State = 0;
  576.                 Status = EOF;
  577.                 return EOF;
  578.             }
  579.  
  580.             if (incode >= ncodes) {     /* Undefined code, special case */
  581.                 kay = finchar;
  582.                 push(kay);
  583.                 code = oldcode;
  584.                 omega = oldcode;
  585.                 incode = ncodes;
  586.             }
  587.             while ( code > 255 ) {      /* Decompose string */
  588.                 push(lztab[code].ext);
  589.                 code = lztab[code].prefix;
  590.             }
  591.             kay = code;
  592.             finchar = code;
  593.             State = 2;
  594.             return kay & 0xff;
  595.         }
  596.         case 2: {
  597.  
  598.             if (lzstack == 0) {         /* Empty stack */
  599.                 omega = oldcode;
  600.                 if (ncodes < 4096) {
  601.                     lztab[ncodes].prefix = omega;
  602.                     lztab[ncodes].ext = kay;
  603.                     ncodes++;
  604.                 }
  605.                 oldcode = incode;
  606.                 State = 1;
  607.                 return unc();
  608.             }
  609.             else
  610.                 return pop();
  611.         }
  612.     }
  613. }
  614.  
  615.  
  616.  
  617.  
  618.  
  619. /*  -------------
  620.     Fetch LZ code
  621.     -------------
  622. */
  623.  
  624. int getcode()
  625. {
  626.     register i;
  627.  
  628.     code = 0;
  629.     i = cdlen;
  630.  
  631.     while(i--)
  632.         code = (code << 1) | GetBit();
  633.  
  634.     /*  Special case of 1 pass crunch. Checksum and size are at the end */
  635.  
  636.     if ( (code == 256) && (entry.mode == 5) ) {
  637.         i = 16;
  638.         while(i--)
  639.             entry.check = (entry.check << 1) | GetBit();
  640.         i = 24;
  641.         while(i--)
  642.             entry.size = (entry.size << 1) | GetBit();
  643.     }
  644.  
  645.     /* Get ready for next time */
  646.  
  647.     if ( (cdlen<12) ) {
  648.         if ( !(--wttcl) ) {
  649.             wtcl = wtcl << 1;
  650.             cdlen++;
  651.             wttcl = wtcl;
  652.         }
  653.     }
  654.  
  655.     return code;
  656. }
  657.  
  658. void UpdateChecksum(int c)
  659. {
  660.     truesize++;
  661.  
  662.     c &= 0xff;
  663.  
  664.     if (entry.version == 1)         /* Simple checksum for version 1 */
  665.         crc += c;
  666.     else
  667.         crc += (c ^ (++crc2));      /* A slightly better checksum for version 2 */
  668. }
  669.  
  670.  
  671. int UnPack()
  672. {
  673.     switch (entry.mode) {
  674.  
  675.         case 0:             /* Stored */
  676.         case 1:             /* Packed (Run-Length) */
  677.  
  678.             return GetByte();
  679.  
  680.         case 2:             /* Squeezed (Huffman only) */
  681.         case 4:             /* Squashed (Huffman + Run-Length */
  682.  
  683.             return Huffin();
  684.  
  685.         case 3:             /* Crunched */
  686.         case 5:             /* Crunched in one pass */
  687.  
  688.             return unc();
  689.  
  690.         default:            /* Otherwise ERROR */
  691.  
  692.             Status = EOF;
  693.             return EOF;
  694.     }
  695. }
  696.  
  697.  
  698. /*  ----------------------------------------------
  699.     Try a few default extensions if none was given
  700.     ----------------------------------------------
  701. */
  702.  
  703. int MakeName(char * buf, char * arg)
  704. {
  705.     strcpy(buf,arg);
  706.  
  707.     if (strchr(buf,'.') != NULL)
  708.         return 0;
  709.  
  710.     strcat(buf,".sda");
  711.  
  712.     if (!access(buf,0))
  713.         return 0;
  714.  
  715.     strcpy(buf,arg);
  716.     strcat(buf,".ark");
  717.  
  718.     if (!access(buf,0))
  719.         return 0;
  720.  
  721.     strcpy(buf,arg);
  722.     strcat(buf,".arc");
  723.  
  724.     if (!access(buf,0))
  725.         return 0;
  726.  
  727.     strcpy(buf,arg);
  728.     return 1;
  729. }
  730.  
  731. /*  Finally */
  732.  
  733. void main(int argc, char ** argv)
  734. {
  735.     int     temp, count, i;
  736.     WORD    c;
  737.     BYTE    prev;           /* previous byte for Run Length */
  738.     FILE *  op,             /* File being extracted */
  739.          *  contents,       /* Summary of contents  */
  740.          *  basic,          /* CBM BASIC program to rename to correct names */
  741.          *  batch;          /* Batch file to RENAME for MS-DOS */
  742.  
  743.     char *  tempname   = "File.001";
  744.     int     filecount  = 0;
  745.     long    bytecount  = 0;
  746.     long    filesize;
  747.     char    sdaname[64];
  748.     WORD    linnum = 1000;      /* For BASIC file */
  749.     WORD    linptr = 0x0801;    /* BASIC line link */
  750.  
  751.     FilePos = 0;
  752.     Status  = 0;
  753.  
  754.     if (argc < 2) {
  755.         printf("Usage:   %s filename[.sda | .arc]\n\n",argv[0]);
  756.         printf("Purpose: Dissolves archives made by ARC64/128 on the Commodore 64/128\n");
  757.         exit(1);
  758.     }
  759.  
  760.     MakeName(sdaname,argv[1]);
  761.  
  762.     if ( (fp=fopen(sdaname, RB)) == 0 ) {
  763.         printf("\nCan't open '%s'\n",sdaname);
  764.         exit(1);
  765.     }
  766.  
  767.     if ( (temp=GetStartPos()) < 0 ) {
  768.         printf("\nThis doesn't look like a C64 archive or an SDA\n");
  769.         printf("Perhaps its an IBM or AMIGA archive, or not an archive at all\n");
  770.         exit(1);
  771.     }
  772.     else {
  773.         fseek(fp,(long) temp, 0);
  774.         FilePos = temp;
  775.     }
  776.  
  777.     if ( (contents = fopen("Contents","w")) == 0) {
  778.         printf("File I/O error\n");
  779.         fclose(fp);
  780.         exit(1);
  781.     }
  782.  
  783.     if ( (basic = fopen("re-name.bas", WB)) == NULL) {
  784.         printf("File I/O error\n");
  785.         fclose(fp);
  786.         fclose(contents);
  787.         exit(1);
  788.     }
  789.  
  790.     fputc(0x01,basic);  /* CBM BASIC Load address */
  791.     fputc(0x08,basic);
  792.     linptr = 0x080f;    /* 1000 open 15,8,15 */
  793.     putw(linptr,basic);
  794.     putw(linnum,basic);
  795.     fputc(0x9f,basic);
  796.     fputs(" 15,8,15",basic);
  797.     fputc(0,basic);
  798.  
  799.     if ( (batch = fopen("re-name.bat","w")) == NULL) {
  800.         printf("File I/O error\n");
  801.         fclose(fp);
  802.         fclose(contents);
  803.         fclose(basic);
  804.         exit(1);
  805.     }
  806.  
  807.     fprintf(contents,"--------------------------------------------------\n");
  808.     fprintf(contents,"           True Name     Type Bytes\n");
  809.     fprintf(contents,"--------------------------------------------------\n");
  810.  
  811.     while(GetHeader()) {
  812.  
  813.         truesize = 0;
  814.  
  815.         printf("%-16s ",entry.name);
  816.  
  817.         filesize = entry.size;
  818.  
  819.         if (entry.mode == 5)        /* If 1 pass crunch size is unknown */
  820.             filesize = 10000000;
  821.  
  822.         if ( (op = fopen(tempname, WB)) == NULL) {
  823.             printf("File I/O error ... Aborting\n");
  824.             fclose(contents);
  825.             fclose(fp);
  826.             exit(2);
  827.         }
  828.  
  829.         while( filesize && (Status != EOF) && !feof(fp) ) {
  830.  
  831.             c = UnPack();
  832.  
  833.             if (Status == EOF)
  834.                 break;
  835.  
  836.             /* If Run Length is needed */
  837.  
  838.             if ( (entry.mode != 0) && (entry.mode != 2) ) {
  839.  
  840.                 if ( (c & 0xff) == ctrl) {
  841.  
  842.                     count = UnPack();
  843.                     prev  = UnPack();
  844.                     c     = prev;
  845.  
  846.                     if (count == 0) {
  847.                         count = 256;
  848.                         if (entry.version == 1)  /* version 1 problem */
  849.                             count--;
  850.                     }
  851.  
  852.                     while(count > 1) {
  853.                         fputc(c,op);
  854.                         UpdateChecksum(c);
  855.                         filesize--;
  856.                         if (filesize == 1) {   
  857.                             break;
  858.                         }
  859.                         count--;
  860.                     }
  861.                 }
  862.             }
  863.             fputc(c,op);
  864.             filesize--;
  865.             UpdateChecksum(c);
  866.         }
  867.  
  868.         if (crc != entry.check)
  869.             printf(" <Checksum Error>\n");
  870.         else
  871.             printf(" OK.\n");
  872.  
  873.         fclose(op);
  874.  
  875.         bytecount += entry.size;
  876.         filecount ++;
  877.  
  878.         fprintf(contents,"%-10s %-16s %c %7lu ",tempname,entry.name,entry.type,entry.size);
  879.  
  880.         if (toupper(entry.type) == 'R')
  881.             fprintf(contents,"Record Length = %d",entry.rl);
  882.  
  883.         if (crc != entry.check)
  884.             fprintf(contents,"Checksum Error\n");
  885.         else
  886.             fprintf(contents,"Checksum OK\n");
  887.  
  888. #ifdef AMIGA
  889.         fprintf(batch,"RENAME \"%s\" \"%s\"\n",tempname,entry.name);
  890. #else
  891.         fprintf(batch,"REN %s %s\n",tempname,entry.name);
  892. #endif
  893.  
  894.         linnum += 10;
  895.         putw(linptr,basic);
  896.         putw(linnum,basic);
  897.         fputc(0x98,basic);
  898.         fputs("15,\"R0:",basic);
  899.         fputs(RealName,basic);
  900.         fputc('=',basic);
  901.         for (i=0; tempname[i]; i++)
  902.             fputc(toupper(tempname[i]),basic);
  903.         fputc('\"',basic);
  904.         fputc(0,basic);
  905.         linptr += (15+strlen(entry.name)+strlen(RealName));
  906.  
  907.         tempname[7] += 1;
  908.         if (tempname[7] > '9') {
  909.             tempname[7] = '0';
  910.             tempname[6] += 1;
  911.             if (tempname[6] >'9') {
  912.                 tempname[6] = '0';
  913.                 tempname[5] += 1;
  914.             }
  915.         }
  916.  
  917.         FilePos += 254*(long)entry.blocks;
  918.         fseek(fp,FilePos,0);
  919.  
  920.     }
  921.  
  922.     fprintf(contents,"--------------------------------------------------\n");
  923.     fprintf(contents,"%lu Bytes in %u files.\n",bytecount,filecount);
  924.     fclose(contents);
  925.  
  926.     linnum += 10;
  927.     putw(linptr,basic);
  928.     putw(linnum,basic);
  929.     fputc(0xa0,basic);              /* close 15 */
  930.     fputs(" 15",basic);
  931.     for (i=0; i<4; i++)
  932.         fputc(0,basic);
  933.  
  934.     fclose(basic);
  935.     fclose(batch);
  936.     exit(0);
  937. }
  938.  
  939.  
  940.