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