home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / PPCUnACE.lha / PPCUnACE / source.lha / Src / Unace.c < prev    next >
C/C++ Source or Header  |  1997-12-10  |  16KB  |  573 lines

  1. /* ------------------------------------------------------------------------ */
  2. /*                                                                          */
  3. /*      Main file of public UNACE.                                          */
  4. /*                                                                          */
  5. /* ------------------------------------------------------------------------ */
  6.  
  7.  
  8. //--------------- include general files ------------------------------------//
  9. #include <ctype.h>      // tolower()
  10. #include <fcntl.h>      // open()
  11. #include <stdio.h>      // printf() sprintf() remove()
  12. #include <stdlib.h>     // malloc()
  13. #include <string.h>     // str*()
  14. #include <sys/stat.h>   // S_I*  AMIGA: fstat()
  15.  
  16. #if defined(AMIGA)
  17.  #include <error.h>     // errno
  18.  #include <proto/dos.h>
  19. #endif
  20. #if defined(DOS) || defined(WIN32) || defined(WIN16)
  21.  #include <io.h>       // lseek() open() read() write() eof() tell() close()
  22. #if defined(WATCOM_C) 
  23.  #include <dos.h>      // lseek() open() read() write() eof() tell() close()
  24. #endif
  25. #endif
  26.  
  27.  
  28. //--------------- include unace specific header files ----------------------//
  29. #include "os.h"
  30.  
  31. #include "globals.h"
  32. #include "portable.h"
  33. #include "uac_comm.h"
  34. #include "uac_crc.h"
  35. #include "uac_crt.h"
  36. #include "uac_dcpr.h"
  37. #include "uac_sys.h"
  38.  
  39. #ifdef CRYPT
  40.  #include "unace_ps.h"
  41. #endif /* CRYPT */
  42.  
  43.  
  44. //--------------- BEGIN OF UNACE ROUTINES ----------------------------------//
  45.  
  46. void init_unace(void)           // initializes unace
  47. {
  48.    buf_rd =malloc(size_rdb * sizeof(ULONG));  // Allocate buffers: increase
  49.    buf    =malloc(size_buf);                  // sizes when possible to speed
  50.    buf_wr =malloc(size_wrb);                  // up the program
  51.    readbuf=malloc(size_headrdb);
  52.  
  53.    if (buf_rd ==NULL ||
  54.        buf    ==NULL ||
  55.        buf_wr ==NULL ||
  56.        readbuf==NULL )
  57.       f_err = ERR_MEM;
  58.  
  59.    make_crctable();             // initialize CRC table
  60.    dcpr_init();                 // initialize decompression
  61.  
  62.    set_handler();               // ctrl+break etc.
  63. }
  64.  
  65. void done_unace(void)
  66. {
  67.    if (buf_rd   ) free(buf_rd   );
  68.    if (buf      ) free(buf      );
  69.    if (buf_wr   ) free(buf_wr   );
  70.    if (readbuf  ) free(readbuf  );
  71.    if (dcpr_text) free(dcpr_text);
  72. }
  73.  
  74. INT  read_header(INT print_err)         // reads any header from archive
  75. {
  76.    USHORT rd,
  77.         head_size,
  78.         crc_ok;
  79.    LONG crc;
  80.    UCHAR *tp=readbuf;
  81.  
  82.    lseek(archan, skipsize, SEEK_CUR);   // skip ADDSIZE block
  83.  
  84.    if (read(archan, &head, 4)<4)
  85.       return (0);                       // read CRC and header size
  86.  
  87. #ifdef HI_LO_BYTE_ORDER
  88.    WORDswap(&head.HEAD_CRC);
  89.    WORDswap(&head.HEAD_SIZE);
  90. #endif
  91.                                         // read size_headrdb bytes into 
  92.    head_size = head.HEAD_SIZE;          // header structure 
  93.    rd = (head_size > size_headrdb) ? size_headrdb : head_size;
  94.    if (read(archan, readbuf, rd) < rd)
  95.       return (0);
  96.    head_size -= rd;
  97.    crc = getcrc(CRC_MASK, readbuf, rd);
  98.  
  99.    while (head_size)                    // skip rest of header
  100.    {                            
  101.       rd = (head_size > size_buf) ? size_buf : head_size;
  102.       if (read(archan, buf, rd) < rd)
  103.          return (0);
  104.       head_size -= rd;
  105.       crc = getcrc(crc, buf, rd);
  106.    }
  107.  
  108.    head.HEAD_TYPE =*tp++;               // generic buffer to head conversion
  109.    head.HEAD_FLAGS=BUFP2WORD(tp);
  110.  
  111.    if (head.HEAD_FLAGS & ACE_ADDSIZE)
  112.       skipsize = head.ADDSIZE = BUF2LONG(tp);   // get ADDSIZE
  113.    else
  114.       skipsize = 0;
  115.  
  116.                                                 // check header CRC 
  117.    if (!(crc_ok = head.HEAD_CRC == (crc & 0xffff)) && print_err)
  118.       printf("\nError: archive is broken\n");
  119.    else
  120.    switch (head.HEAD_TYPE)              // specific buffer to head conversion
  121.    {
  122.       case MAIN_BLK:
  123.          memcpy(mhead.ACESIGN, tp, acesign_len); tp+=acesign_len;
  124.          mhead.VER_MOD=*tp++;
  125.          mhead.VER_CR =*tp++;
  126.          mhead.HOST_CR=*tp++;
  127.          mhead.VOL_NUM=*tp++;
  128.          mhead.TIME_CR=BUFP2LONG(tp);
  129.          mhead.RES1   =BUFP2WORD(tp);
  130.          mhead.RES2   =BUFP2WORD(tp);
  131.          mhead.RES    =BUFP2LONG(tp);
  132.          mhead.AV_SIZE=*tp++;
  133.          memcpy(mhead.AV, tp, rd-(USHORT)(tp-readbuf));
  134.          break;
  135.       case FILE_BLK:
  136.          fhead.PSIZE     =BUFP2LONG(tp);
  137.          fhead.SIZE      =BUFP2LONG(tp);
  138.          fhead.FTIME     =BUFP2LONG(tp);
  139.          fhead.ATTR      =BUFP2LONG(tp);
  140.          fhead.CRC32     =BUFP2LONG(tp);
  141.          fhead.TECH.TYPE =*tp++;
  142.          fhead.TECH.QUAL =*tp++;
  143.          fhead.TECH.PARM =BUFP2WORD(tp);
  144.          fhead.RESERVED  =BUFP2WORD(tp);
  145.          fhead.FNAME_SIZE=BUFP2WORD(tp);
  146.          memcpy(fhead.FNAME, tp, rd-(USHORT)(tp-readbuf));
  147.          break;
  148. //    default: (REC_BLK and future things): 
  149. //              do nothing 'cause isn't needed for extraction
  150.    }
  151.  
  152.    return (crc_ok);
  153. }
  154.                                 // maximum SFX module size 
  155. #define max_sfx_size 65536      // (needed by read_arc_head)
  156.  
  157. INT read_arc_head(void)         // searches for the archive header and reads it
  158. {
  159.    INT  i,
  160.         flags,
  161.         buf_pos = 0;
  162.    LONG arc_head_pos,
  163.         old_fpos,
  164.         fpos = 0;
  165.    struct stat st;
  166.  
  167.    fstat(archan, &st);
  168.  
  169.    memset(buf, 0, size_buf);
  170.  
  171.    while (tell(archan)<st.st_size && fpos < max_sfx_size)
  172.    {
  173.       old_fpos = fpos;
  174.       fpos += read(archan, &buf[buf_pos], size_buf - buf_pos);
  175.  
  176.       for (i = 0; i < size_buf; i++)    // look for the acesign
  177.       {                         
  178.          if (!memcmp(acesign, &buf[i], acesign_len))
  179.          {             
  180.                                         // seek to the probable begin 
  181.                                         // of the archive
  182.             arc_head_pos = old_fpos + i - buf_pos -  bytes_before_acesign;
  183.             lseek(archan, arc_head_pos, SEEK_SET);
  184.             if (read_header(0))         // try to read archive header
  185.             {                           
  186.                flags = mhead.HEAD_FLAGS;
  187.                adat.sol     = (flags & ACE_SOLID) > 0;
  188.                adat.vol     = (flags & ACE_MULT_VOL) > 0;
  189.                adat.vol_num = mhead.VOL_NUM;
  190.                adat.time_cr = mhead.TIME_CR;
  191.                return (1);
  192.             }
  193.          }
  194.       }
  195.                                         // was no archive header,
  196.                                         // continue search
  197.       lseek(archan, fpos, SEEK_SET);
  198.       memcpy(buf, &buf[size_buf - 512], 512);
  199.       buf_pos = 512;                    // keep 512 old bytes
  200.    }
  201.    return (0);
  202. }
  203.  
  204. INT  open_archive(INT print_err)        // opens archive (or volume)
  205. {
  206.    CHAR av_str[80];
  207.  
  208.    archan = open(aname, O_RDONLY | O_BINARY);   // open file
  209.  
  210.    if (archan == -1)
  211.    {
  212.       printf("\nError opening file %s", aname);
  213.       return (0);
  214.    }
  215.    if (!read_arc_head())                        // read archive header
  216.    {                            
  217.       if (print_err)
  218.          printf("\nInvalid archive file: %s\n", aname);
  219.       close(archan);
  220.       return (0);
  221.    }
  222.  
  223.    printf("\nProcessing archive: %s\n\n", aname);
  224.    if (head.HEAD_FLAGS & ACE_AV)
  225.    {
  226.       printf("Authenticity Verification:");   // print the AV
  227.       sprintf(av_str, "\ncreated on %d.%d.%d by ",
  228.               ts_day(adat.time_cr), ts_month(adat.time_cr), ts_year(adat.time_cr));
  229.       printf(av_str);
  230.       strncpy(av_str, mhead.AV, mhead.AV_SIZE);
  231.       av_str[mhead.AV_SIZE] = 0;
  232.       printf("%s\n\n", av_str);
  233.    }
  234.    comment_out("Main comment:");        // print main comment
  235.    return (1);
  236. }
  237.  
  238. void get_next_volname(void)             // get file name of next volume
  239. {
  240.    CHAR *cp;
  241.    INT  num;
  242.  
  243.    if ((cp = (CHAR *) strrchr(aname, '.')) == NULL || !*(cp + 1))
  244.       num = -1;
  245.    else
  246.    {
  247.       cp++;
  248.       num = (*(cp + 1) - '0') * 10 + *(cp + 2) - '0';
  249.       if (!in(num, 0, 99))
  250.          num = -1;
  251.       if (in(*cp, '0', '9'))
  252.          num += (*cp - '0') * 100;
  253.    }
  254.    num++;
  255.  
  256.    if (num < 100)
  257.       *cp = 'C';
  258.    else
  259.       *cp = num / 100 + '0';
  260.    *(cp + 1) = (num / 10) % 10 + '0';
  261.    *(cp + 2) = num % 10 + '0';
  262. }
  263.  
  264. INT  proc_vol(void)                     // opens volume
  265. {
  266.    INT  i;
  267.    CHAR s[80];
  268.  
  269.    if (!fileexists(aname) || !f_allvol_pr)
  270.    {
  271.       do
  272.       {
  273.          sprintf(s, "Ready to process %s?", aname);
  274.          beep();
  275.          i = wrask(s);                  // ask whether ready or not
  276.          f_allvol_pr = (i == 1);        // "Always" --> process all volumes
  277.          if (i >= 2)
  278.          {
  279.             f_err = ERR_FOUND;
  280.             return (0);
  281.          }
  282.       }
  283.       while (!fileexists(aname));
  284.    }
  285.  
  286.    if (!open_archive(1))                // open volume
  287.    {                            
  288.       printf("\nError while opening archive. File not found or archive broken.\n");
  289.       f_err = ERR_OPEN;
  290.       return (0);
  291.    }
  292.  
  293.    return (1);
  294. }
  295.  
  296. INT  proc_next_vol(void)        // opens next volume to process
  297. {
  298.    close(archan);               // close handle
  299.    get_next_volname();          // get file name of next volume
  300.  
  301.    if (!proc_vol())             // try to open volume, read archive header
  302.       return 0;
  303.    if (!read_header(1))         // read 2nd header
  304.    {
  305.       f_err=ERR_READ;
  306.       return 0;
  307.    }
  308.    return 1;
  309. }
  310.  
  311. INT  read_adds_blk(CHAR * buffer, INT len)      // reads part of ADD_SIZE block
  312. {
  313.    INT  rd = 0,
  314.         l = len;
  315.    LONG i;
  316.  
  317. #ifdef CRYPT
  318.    char *cbuffer=buffer;
  319.  
  320.    if (head.HEAD_TYPE == FILE_BLK && (head.HEAD_FLAGS & ACE_PASSW))
  321.       len = crypt_len(len);
  322. #endif /* CRYPT */
  323.    while (!f_err && len && skipsize)
  324.    {
  325.       i = (skipsize > len) ? len : skipsize;
  326.       skipsize -= i;
  327.  
  328.       errno = 0;
  329.       rd += read(archan, buffer, i);
  330.       if (errno)
  331.       {
  332.          printf("\nRead error\n");
  333.          f_err = ERR_READ;
  334.       }
  335.  
  336.       buffer += i;
  337.       len -= i;
  338.  
  339.       if (!skipsize)            // if block is continued on next volume
  340.          if (head.HEAD_FLAGS & ACE_SP_AFTER && !proc_next_vol())
  341.             break;
  342.    }
  343. #ifdef CRYPT
  344.    if (head.HEAD_TYPE == FILE_BLK && (head.HEAD_FLAGS & ACE_PASSW))
  345.       decrypt(cbuffer, rd);
  346. #endif /* CRYPT */
  347.  
  348.    return (rd > l ? l : rd);
  349. }
  350.  
  351. void crc_print(void)            // checks CRC, prints message
  352. {
  353.    INT  crc_not_ok = rd_crc != fhead.CRC32;  /* check CRC of file */
  354.  
  355.    if (!f_err)                  // print message
  356.    {                            
  357.       printf(crc_not_ok ? "          CRC-check error" : "          CRC OK");
  358.       flush;
  359.    }
  360. }
  361.  
  362. void analyze_file(void)         // analyzes one file (for solid archives)
  363. {
  364.    printf("\n Analyzing");
  365.    flush;
  366.    while (!cancel() && (dcpr_adds_blk(buf_wr, size_wrb))) // decompress only
  367.       ;
  368.    crc_print();
  369. }
  370.  
  371. void extract_file(void)         // extracts one file
  372. {
  373.    INT  rd;
  374.  
  375.    printf("\n Extracting");
  376.    flush;                       // decompress block
  377.    while (!cancel() && (rd = dcpr_adds_blk(buf_wr, size_wrb)))
  378.    {
  379.       if (write(wrhan, buf_wr, rd) != rd)       // write block
  380.       {                         
  381.          printf("\nWrite error\n");
  382.          f_err = ERR_WRITE;
  383.       }
  384.    }
  385.    crc_print();
  386. }
  387.  
  388. /* extracts or tests all files of the archive
  389.  */
  390. void extract_files(int nopath, int test)
  391. {
  392.    CHAR file[PATH_MAX];
  393.  
  394.    while (!cancel() && read_header(1))
  395.    {
  396.       if (head.HEAD_TYPE == FILE_BLK)
  397.       {
  398.          comment_out("File comment:");   // show file comment
  399.          ace_fname(file, &head, nopath); // get file name
  400.          printf("\n%s", file);
  401.          flush;
  402.          dcpr_init_file();               // initialize decompression of file
  403.          if (!f_err)
  404.          {
  405.             if (test || 
  406.                 (wrhan = create_dest_file(file, (INT) fhead.ATTR))<0)
  407.             {
  408.                if (test || adat.sol)
  409.                   analyze_file();        // analyze file
  410.             }
  411.             else
  412.             {
  413.                extract_file();           // extract it
  414. #ifdef DOS                               // set file time
  415.                _dos_setftime(wrhan, (USHORT) (fhead.FTIME >> 16), (USHORT) fhead.FTIME);
  416. #endif
  417.                close(wrhan);
  418. #ifdef DOS                               // set file attributes
  419.                _dos_setfileattr(file, (UINT) fhead.ATTR);
  420. #endif
  421. #ifdef AMIGA
  422.                {                         // set file date and time
  423.                   struct DateTime dt;
  424.                   char Date[9], Time[9];
  425.                   ULONG tstamp=fhead.FTIME;
  426.  
  427.                   sprintf(Date, "%02d-%02d-%02d", ts_year(tstamp)-1900, ts_month(tstamp), ts_day(tstamp));
  428.                   sprintf(Time, "%02d:%02d:%02d", ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  429.  
  430.                   dt.dat_Format = FORMAT_INT;
  431.                   dt.dat_Flags  = 0;
  432.                   dt.dat_StrDate= Date;
  433.                   dt.dat_StrTime= Time;
  434.  
  435.                   if (StrToDate(&dt))
  436.                      SetFileDate(file, &dt.dat_Stamp);
  437.                }
  438. #endif
  439.                if (f_err)
  440.                   remove(file);
  441.             }
  442.          }
  443.       }
  444.    }
  445. }
  446.  
  447. unsigned percentage(ULONG p, ULONG d)
  448. {
  449.    return (unsigned)( d ? (d/2+p*100)/d : 100 );
  450. }
  451.  
  452. void list_files(int verbose)
  453. {
  454.    unsigned files=0;
  455.    ULONG    size =0,
  456.             psize=0,
  457.             tpsize;
  458.    CHAR     file[PATH_MAX];
  459.  
  460.    printf("Date    |Time |Packed     |Size     |Ratio|File\n");
  461.  
  462.    while (!cancel() && read_header(1))
  463.    {
  464.       if (head.HEAD_TYPE == FILE_BLK)
  465.       {
  466.          ULONG ti=fhead.FTIME;
  467.          ace_fname(file, &head, verbose ? 0 : 1); // get file name
  468.  
  469.          size  += fhead.SIZE;
  470.          psize +=
  471.          tpsize = fhead.PSIZE;
  472.          files++;
  473.  
  474.          while (head.HEAD_FLAGS & ACE_SP_AFTER)
  475.          {
  476.             skipsize=0;
  477.             if (!proc_next_vol())
  478.                break;
  479.             psize += fhead.PSIZE;
  480.             tpsize+= fhead.PSIZE;
  481.          }
  482.          if (!f_err)
  483.             printf("%02u.%02u.%02u|%02u:%02u|%c%c%9lu|%9lu|%4u%%|%c%s\n",
  484.                    ts_day (ti), ts_month(ti), ts_year(ti)%100,
  485.                    ts_hour(ti), ts_min  (ti),
  486.                    fhead.HEAD_FLAGS & ACE_SP_BEF   ? '<' : ' ',
  487.                    fhead.HEAD_FLAGS & ACE_SP_AFTER ? '>' : ' ',
  488.                    tpsize, fhead.SIZE, percentage(tpsize, fhead.SIZE),
  489.                    fhead.HEAD_FLAGS & ACE_PASSW    ? '*'    : ' ',
  490.                    file
  491.                   );
  492.       }
  493.    }
  494.    if (!f_err)
  495.    {
  496.       printf("\n                 %9lu|%9lu|%4u%%| %u file%s",
  497.              psize,
  498.              size,
  499.              percentage(psize, size),
  500.              files,
  501.              (char*)(files == 1 ? "" : "s")
  502.             );
  503.    }
  504. }
  505.  
  506. void showhelp(void)
  507. {
  508.    printf("\n"
  509.           "Usage: UNACE <command> <archive[.ace]>\n"
  510.           "\n"
  511.           "Where <command> is one of:\n"
  512.           "\n"
  513.           "  e   Extract files\n"
  514.           "  l   List archive\n"
  515.           "  t   Test archive integrity\n"
  516.           "  v   List archive (verbose)\n"
  517.           "  x   Extract files with full path"
  518.          );
  519. }
  520.  
  521. int main(INT argc, CHAR * argv[])              // processes the archive
  522. {
  523.    printf(version);
  524.  
  525.    if (argc<3 || strlen(argv[1])>1)
  526.       showhelp();
  527.    else
  528.    {
  529.       CHAR *s;
  530.  
  531.       init_unace();                              // initialize unace
  532.  
  533.       strcpy(aname, argv[2]);                    // get archive name
  534.       if (!(s = (CHAR *) strrchr(aname, DIRSEP)))
  535.          s = aname;
  536.       if (!strrchr(s, '.'))
  537.          strcat(aname, ".ACE");
  538.  
  539.       if (open_archive(1))                       // open archive to process
  540.       {
  541.          if (adat.vol_num)
  542.             printf("\nFirst volume of archive required!\n");
  543.          else
  544.             switch(tolower(*argv[1]))
  545.             {
  546.                case 'e': extract_files(1, 0); break;  // extract files without path
  547.                case 'x': extract_files(0, 0); break;  // extract files with path
  548.                case 'l': list_files   (0   ); break;  // list files
  549.                case 'v': list_files   (1   ); break;  // list files verbose
  550.                case 't': extract_files(0, 1); break;  // test archive integrity.
  551.                default : showhelp();                  // Wrong command!
  552.             }
  553.  
  554.          close(archan);
  555.          if (f_err)
  556.          {
  557.             printf("\nError occurred\n");
  558.             if (f_criterr)
  559.                printf("Critical error on drive %c\n", f_criterr);
  560.          }
  561.       }
  562.       else
  563.          f_err = ERR_CLINE;
  564.  
  565.       done_unace();
  566.    }
  567.  
  568.    putchar('\n');
  569.    putc   ('\n', stderr);
  570.    return (f_err);
  571. }
  572.  
  573.