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

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