home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / PPCxDMSWOS.lha / source.lha / src / pfile.c < prev    next >
C/C++ Source or Header  |  1998-02-17  |  12KB  |  457 lines

  1.  
  2. /*
  3.  *     xDMS  v1.0  -  Portable DMS archive unpacker  -  Public Domain
  4.  *     Written by     Andre R. de la Rocha  <adlroc@usa.net>
  5.  *
  6.  *     Handles the processing of a single DMS archive
  7.  *
  8.  */
  9.  
  10.  
  11. #define HEADLEN 56
  12. #define THLEN 20
  13. #define TRACK_BUFFER_LEN 32768
  14. #define TEMP_BUFFER_LEN 32768
  15.  
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <time.h>
  21.  
  22. #include "cdata.h"
  23. #include "u_rle.h"
  24. #include "u_quick.h"
  25. #include "u_medium.h"
  26. #include "u_deep.h"
  27. #include "u_heavy.h"
  28. #include "crc_csum.h"
  29. #include "pfile.h"
  30.  
  31.  
  32.  
  33. static USHORT Process_Track(FILE *, FILE *, UCHAR *, UCHAR *, USHORT, USHORT, USHORT);
  34. static USHORT Unpack_Track(UCHAR *, UCHAR *, USHORT, USHORT, UCHAR, UCHAR);
  35. static void printbandiz(UCHAR *, USHORT);
  36. static void dms_decrypt(UCHAR *, USHORT);
  37.  
  38.  
  39. static char modes[7][7]={"NOCOMP","SIMPLE","QUICK ","MEDIUM","DEEP  ","HEAVY1","HEAVY2"};
  40. static USHORT PWDCRC;
  41.  
  42. UCHAR *text;
  43.  
  44.  
  45.  
  46. USHORT Process_File(char *iname, char *oname, USHORT cmd, USHORT opt, USHORT PCRC, USHORT pwd){
  47.     FILE *fi, *fo=NULL;
  48.     USHORT from, to, geninfo, c_version, cmode, hcrc, disktype, pv, ret;
  49.     ULONG pkfsize, unpkfsize;
  50.     UCHAR *b1, *b2;
  51.     time_t date;
  52.  
  53.  
  54.     b1 = (UCHAR *)calloc(TRACK_BUFFER_LEN,1);
  55.     if (b1==NULL) return ERR_NOMEMORY;
  56.     b2 = (UCHAR *)calloc(TRACK_BUFFER_LEN,1);
  57.     if (b2==NULL) {
  58.         free(b1);
  59.         return ERR_NOMEMORY;
  60.     }
  61.     text = (UCHAR *)calloc(TEMP_BUFFER_LEN,1);
  62.     if (text==NULL) {
  63.         free(b1);
  64.         free(b2);
  65.         return ERR_NOMEMORY;
  66.     }
  67.  
  68.     /* if iname is NULL, input is stdin;   if oname is NULL, output is stdout */
  69.  
  70.     if (iname){
  71.         fi = fopen(iname,"rb");
  72.         if (fi==NULL) {
  73.             free(b1);
  74.             free(b2);
  75.             free(text);
  76.             return ERR_CANTOPENIN;
  77.         }
  78.     } else {
  79.         fi = stdin;
  80.     }
  81.  
  82.     if (fread(b1,1,HEADLEN,fi) != HEADLEN) {
  83.         if (iname) fclose(fi);
  84.         free(b1);
  85.         free(b2);
  86.         free(text);
  87.         return ERR_SREAD;
  88.     }
  89.  
  90.     if ( (b1[0] != 'D') || (b1[1] != 'M') || (b1[2] != 'S') || (b1[3] != '!') ) {
  91.         /*  Check the first 4 bytes of file to see if it is "DMS!"  */
  92.         if (iname) fclose(fi);
  93.         free(b1);
  94.         free(b2);
  95.         free(text);
  96.         return ERR_NOTDMS;
  97.     }
  98.  
  99.     hcrc = (USHORT)((b1[HEADLEN-2]<<8) | b1[HEADLEN-1]);
  100.     /* Header CRC */
  101.  
  102.     if (hcrc != CreateCRC(b1+4,(ULONG)(HEADLEN-6))) {
  103.         if (iname) fclose(fi);
  104.         free(b1);
  105.         free(b2);
  106.         free(text);
  107.         return ERR_HCRC;
  108.     }
  109.     
  110.     geninfo = (USHORT) ((b1[10]<<8) | b1[11]);    /* General info about archive */
  111.     date = (time_t) ((((ULONG)b1[12])<<24) | (((ULONG)b1[13])<<16) | (((ULONG)b1[14])<<8) | (ULONG)b1[15]);    /* date in standard UNIX/ANSI format */
  112.     from = (USHORT) ((b1[16]<<8) | b1[17]);        /*  Lowest track in archive. May be incorrect if archive is "appended" */
  113.     to = (USHORT) ((b1[18]<<8) | b1[19]);        /*  Highest track in archive. May be incorrect if archive is "appended" */
  114.  
  115.     pkfsize = (ULONG) ((((ULONG)b1[21])<<16) | (((ULONG)b1[22])<<8) | (ULONG)b1[23]);    /*  Length of total packed data as in archive   */
  116.     unpkfsize = (ULONG) ((((ULONG)b1[25])<<16) | (((ULONG)b1[26])<<8) | (ULONG)b1[27]);    /*  Length of unpacked data. Usually 901120 bytes  */
  117.  
  118.     c_version = (USHORT) ((b1[46]<<8) | b1[47]);    /*  version of DMS used to generate it  */
  119.     disktype = (USHORT) ((b1[50]<<8) | b1[51]);        /*  Type of compressed disk  */
  120.     cmode = (USHORT) ((b1[52]<<8) | b1[53]);        /*  Compression mode mostly used in this archive  */
  121.  
  122.     PWDCRC = PCRC;
  123.  
  124.     if ( (cmd == CMD_VIEW) || (cmd == CMD_VIEWFULL) ) {
  125.  
  126.         if (iname)
  127.             printf("\n File : %s\n",iname);
  128.         else
  129.             printf("\n Data from stdin\n");
  130.  
  131.  
  132.         pv = (USHORT)(c_version/100);
  133.         printf(" Created with DMS version %d.%02d ",pv,c_version-pv*100);
  134.         if (geninfo & 0x80)
  135.             printf("Registered\n");
  136.         else
  137.             printf("Evaluation\n");
  138.  
  139.         printf(" Creation date : %s",ctime(&date));
  140.         printf(" Lowest track in archive : %d\n",from);
  141.         printf(" Highest track in archive : %d\n",to);
  142.         printf(" Packed data size : %lu\n",pkfsize);
  143.         printf(" Unpacked data size : %lu\n",unpkfsize);
  144.         printf(" Disk type of archive : ");
  145.  
  146.         /*  The original DMS from SDS software (DMS up to 1.11) used other values    */
  147.         /*  in disk type to indicate formats as MS-DOS, AMax and Mac, but it was     */
  148.         /*  not suported for compression. It was for future expansion and was never  */
  149.         /*  used. The newer versions of DMS made by ParCon Software changed it to    */
  150.         /*  add support for new Amiga disk types.                                    */
  151.         switch (disktype) {
  152.             case 0:
  153.             case 1:
  154.                 /* Can also be a non-dos disk */
  155.                 printf("AmigaOS 1.0 OFS\n");
  156.                 break;
  157.             case 2:
  158.                 printf("AmigaOS 2.0 FFS\n");
  159.                 break;
  160.             case 3:
  161.                 printf("AmigaOS 3.0 OFS / International\n");
  162.                 break;
  163.             case 4:
  164.                 printf("AmigaOS 3.0 FFS / International\n");
  165.                 break;
  166.             case 5:
  167.                 printf("AmigaOS 3.0 OFS / Dir Cache\n");
  168.                 break;
  169.             case 6:
  170.                 printf("AmigaOS 3.0 FFS / Dir Cache\n");
  171.                 break;
  172.             case 7:
  173.                 printf("FMS Amiga System File\n");
  174.                 break;
  175.             default:
  176.                 printf("Unknown\n");
  177.         }
  178.  
  179.         printf(" Compression mode used : ");
  180.         if (cmode>6)
  181.             printf("Unknown !\n");
  182.         else
  183.             printf("%s\n",modes[cmode]);
  184.  
  185.         printf(" General info : ");
  186.         if ((geninfo==0)||(geninfo==0x80)) printf("None");
  187.         if (geninfo & 1) printf("NoZero ");
  188.         if (geninfo & 2) printf("Encrypted ");
  189.         if (geninfo & 4) printf("Appends ");
  190.         if (geninfo & 8) printf("Banner ");
  191.         if (geninfo & 16) printf("HD ");
  192.         if (geninfo & 32) printf("MS-DOS ");
  193.         if (geninfo & 64) printf("DMS_DEV_Fixed ");
  194.         if (geninfo & 256) printf("FILEID.DIZ");
  195.         printf("\n");
  196.  
  197.         printf(" Info Header CRC : %04X\n\n",hcrc);
  198.  
  199.     }
  200.  
  201.     if (disktype == 7) {
  202.         /*  It's not a DMS compressed disk image, but a FMS archive  */
  203.         if (iname) fclose(fi);
  204.         free(b1);
  205.         free(b2);
  206.         free(text);
  207.         return ERR_FMS;
  208.     }
  209.  
  210.  
  211.     if (cmd == CMD_VIEWFULL)    {
  212.         printf(" Track   Plength  Ulength  Cmode   USUM  HCRC  DCRC Cflag\n");
  213.         printf(" ------  -------  -------  ------  ----  ----  ---- -----\n");
  214.     }
  215.  
  216.     if (((cmd==CMD_UNPACK) || (cmd==CMD_SHOWBANNER)) && (geninfo & 2) && (pwd==0))
  217.         return ERR_NOPASSWD;
  218.  
  219.     if (cmd == CMD_UNPACK) {
  220.         if (oname){
  221.             fo = fopen(oname,"wb");
  222.             if (fo==NULL) {
  223.                 if (iname) fclose(fi);
  224.                 free(b1);
  225.                 free(b2);
  226.                 free(text);
  227.                 return ERR_CANTOPENOUT;
  228.             }
  229.         } else {
  230.             fo = stdout;
  231.         }
  232.     }
  233.  
  234.     ret=NO_PROBLEM;
  235.  
  236.     Init_QUICK();
  237.     Init_MEDIUM();
  238.     Init_DEEP();
  239.     Init_HEAVY();
  240.  
  241.     if (cmd != CMD_VIEW) {
  242.         if (cmd == CMD_SHOWBANNER) /*  Banner is in the first track  */
  243.             ret = Process_Track(fi,NULL,b1,b2,cmd,opt,(geninfo & 2)?pwd:0);
  244.         else {
  245.             while ( (ret=Process_Track(fi,fo,b1,b2,cmd,opt,(geninfo & 2)?pwd:0)) == NO_PROBLEM ) ;
  246.             if ((cmd == CMD_UNPACK) && (opt == OPT_VERBOSE)) fprintf(stderr,"\n");
  247.         }
  248.     }
  249.  
  250.     if ((cmd == CMD_VIEWFULL) || (cmd == CMD_SHOWDIZ) || (cmd == CMD_SHOWBANNER)) printf("\n");
  251.  
  252.     if (ret == FILE_END) ret = NO_PROBLEM;
  253.  
  254.  
  255.     /*  Used to give an error message, but I have seen some DMS  */
  256.     /*  files with texts or zeros at the end of the valid data   */
  257.     /*  So, when we find something that is not a track header,   */
  258.     /*  we suppose that the valid data is over. And say it's ok. */
  259.     if (ret == ERR_NOTTRACK) ret = NO_PROBLEM;
  260.  
  261.  
  262.     if (iname) fclose(fi);
  263.     if ((cmd == CMD_UNPACK) && oname) fclose(fo);
  264.  
  265.     free(b1);
  266.     free(b2);
  267.     free(text);
  268.  
  269.     return ret;
  270. }
  271.  
  272.  
  273.  
  274. static USHORT Process_Track(FILE *fi, FILE *fo, UCHAR *b1, UCHAR *b2, USHORT cmd, USHORT opt, USHORT pwd){
  275.     USHORT hcrc, dcrc, usum, number, pklen1, pklen2, unpklen, l, r;
  276.     UCHAR cmode, flags;
  277.  
  278.  
  279.     l = (USHORT)fread(b1,1,THLEN,fi);
  280.  
  281.     if (l != THLEN) {
  282.         if (l == 0)
  283.             return FILE_END;
  284.         else
  285.             return ERR_SREAD;
  286.     }
  287.  
  288.     /*  "TR" identifies a Track Header  */
  289.     if ((b1[0] != 'T')||(b1[1] != 'R')) return ERR_NOTTRACK;
  290.  
  291.     /*  Track Header CRC  */
  292.     hcrc = (USHORT)((b1[THLEN-2] << 8) | b1[THLEN-1]);
  293.  
  294.     if (CreateCRC(b1,(ULONG)(THLEN-2)) != hcrc) return ERR_THCRC;
  295.  
  296.     number = (USHORT)((b1[2] << 8) | b1[3]);    /*  Number of track  */
  297.     pklen1 = (USHORT)((b1[6] << 8) | b1[7]);    /*  Length of packed track data as in archive  */
  298.     pklen2 = (USHORT)((b1[8] << 8) | b1[9]);    /*  Length of data after first unpacking  */
  299.     unpklen = (USHORT)((b1[10] << 8) | b1[11]);    /*  Length of data after subsequent rle unpacking */
  300.     flags = b1[12];        /*  control flags  */
  301.     cmode = b1[13];        /*  compression mode used  */
  302.     usum = (USHORT)((b1[14] << 8) | b1[15]);    /*  Track Data CheckSum AFTER unpacking  */
  303.     dcrc = (USHORT)((b1[16] << 8) | b1[17]);    /*  Track Data CRC BEFORE unpacking  */
  304.  
  305.     if (cmd == CMD_VIEWFULL) {
  306.         if (number==80)
  307.             printf(" FileID   ");
  308.         else if (number==0xffff)
  309.             printf(" Banner   ");
  310.         else if ((number==0) && (unpklen==1024))
  311.             printf(" FakeBB   ");
  312.         else
  313.             printf("   %2d     ",(short)number);
  314.  
  315.         printf("%5d    %5d   %s  %04X  %04X  %04X    %0d\n", pklen1, unpklen, modes[cmode], usum, hcrc, dcrc, flags);
  316.     }
  317.  
  318.     if ((pklen1 > TRACK_BUFFER_LEN) || (pklen2 >TRACK_BUFFER_LEN) || (unpklen > TRACK_BUFFER_LEN)) return ERR_BIGTRACK;
  319.  
  320.     if (fread(b1,1,(size_t)pklen1,fi) != pklen1) return ERR_SREAD;
  321.  
  322.     if (CreateCRC(b1,(ULONG)pklen1) != dcrc) return ERR_TDCRC;
  323.  
  324.     /*  track 80 is FILEID.DIZ, track 0xffff (-1) is Banner  */
  325.     /*  and track 0 with 1024 bytes only is a fake boot block with more advertising */
  326.     /*  FILE_ID.DIZ is never encrypted  */
  327.  
  328.     if (pwd && (number!=80)) dms_decrypt(b1,pklen1);
  329.  
  330.     if ((cmd == CMD_UNPACK) && (number<80) && (unpklen>2048)) {
  331.         r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
  332.         if (r != NO_PROBLEM) 
  333.             if (pwd)
  334.                 return ERR_BADPASSWD;
  335.             else
  336.                 return r;
  337.         if (usum != Calc_CheckSum(b2,(ULONG)unpklen))
  338.             if (pwd)
  339.                 return ERR_BADPASSWD;
  340.             else
  341.                 return ERR_CSUM;
  342.         if (fwrite(b2,1,(size_t)unpklen,fo) != unpklen) return ERR_CANTWRITE;
  343.         if (opt == OPT_VERBOSE) {
  344.             fprintf(stderr,"#");
  345.             fflush(stderr);
  346.         }
  347.     }
  348.  
  349.     if ((cmd == CMD_SHOWBANNER) && (number == 0xffff)){
  350.         r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
  351.         if (r != NO_PROBLEM) 
  352.             if (pwd)
  353.                 return ERR_BADPASSWD;
  354.             else
  355.                 return r;
  356.         if (usum != Calc_CheckSum(b2,(ULONG)unpklen))
  357.             if (pwd)
  358.                 return ERR_BADPASSWD;
  359.             else
  360.                 return ERR_CSUM;
  361.         printbandiz(b2,unpklen);
  362.     }
  363.  
  364.     if ((cmd == CMD_SHOWDIZ) && (number == 80)) {
  365.         r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
  366.         if (r != NO_PROBLEM) return r;
  367.         if (usum != Calc_CheckSum(b2,(ULONG)unpklen)) return ERR_CSUM;
  368.         printbandiz(b2,unpklen);
  369.     }
  370.  
  371.     return NO_PROBLEM;
  372.  
  373. }
  374.  
  375.  
  376.  
  377. static USHORT Unpack_Track(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, UCHAR cmode, UCHAR flags){
  378.     switch (cmode){
  379.         case 0:
  380.             /*   No Compression   */
  381.             memcpy(b2,b1,(size_t)unpklen);
  382.             return NO_PROBLEM;
  383.         case 1:
  384.             /*   Simple Compression   */
  385.             if (Unpack_RLE(b1,b2,unpklen)) return ERR_BADDECR;
  386.             return NO_PROBLEM;
  387.         case 2:
  388.             /*   Quick Compression   */
  389.             if (Unpack_QUICK(b1,b2,flags,pklen2)) return ERR_BADDECR;
  390.             if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
  391.             memcpy(b2,b1,(size_t)unpklen);
  392.             return NO_PROBLEM;
  393.         case 3:
  394.             /*   Medium Compression   */
  395.             if (Unpack_MEDIUM(b1,b2,flags,pklen2)) return ERR_BADDECR;
  396.             if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
  397.             memcpy(b2,b1,(size_t)unpklen);
  398.             return NO_PROBLEM;
  399.         case 4:
  400.             /*   Deep Compression   */
  401.             if (Unpack_DEEP(b1,b2,flags,pklen2)) return ERR_BADDECR;
  402.             if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
  403.             memcpy(b2,b1,(size_t)unpklen);
  404.             return NO_PROBLEM;
  405.         case 5:
  406.         case 6:
  407.             /*   Heavy Compression   */
  408.             if (cmode==5) {
  409.                 /*   Heavy 1   */
  410.                 if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR;
  411.             } else {
  412.                 /*   Heavy 2   */
  413.                 if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR;
  414.             }
  415.             if (flags & 4) {
  416.                 /*  Unpack with RLE only if this flag is set  */
  417.                 if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
  418.                 memcpy(b2,b1,(size_t)unpklen);
  419.             }
  420.             return NO_PROBLEM;
  421.         default:
  422.             return ERR_UNKNMODE;
  423.     }
  424.  
  425. }
  426.  
  427.  
  428. /*  DMS uses a lame encryption  */
  429. static void dms_decrypt(UCHAR *p, USHORT len){
  430.     USHORT t;
  431.  
  432.     while (len--){
  433.         t = (USHORT) *p;
  434.         *p++ ^= (UCHAR)PWDCRC;
  435.         PWDCRC = (USHORT)((PWDCRC >> 1) + t);
  436.     }
  437. }
  438.  
  439.  
  440.  
  441. static void printbandiz(UCHAR *m, USHORT len){
  442.     UCHAR *i,*j;
  443.  
  444.     i=j=m;
  445.     while (i<m+len) {
  446.         if (*i == 10) {
  447.             *i=0;
  448.             printf("%s\n",j);
  449.             j=i+1;
  450.         }
  451.         i++;
  452.     }
  453.  
  454. }
  455.  
  456.  
  457.