home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / slfinsta.zip / packinst / unace.c < prev   
C/C++ Source or Header  |  2000-03-26  |  16KB  |  565 lines

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