home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNZP50P1.ZIP / VMS / vms.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  25KB  |  1,084 lines

  1. /*************************************************************************
  2.  *                                                                       *
  3.  * Copyright (C) 1992 Igor Mandrichenko.                                 *
  4.  * Permission is granted to any individual or institution to use, copy,  *
  5.  * or redistribute this software so long as all of the original files    *
  6.  * are included unmodified, that it is not sold for profit, and that     *
  7.  * this copyright notice is retained.                                    *
  8.  *                                                                       *
  9.  *************************************************************************/
  10.  
  11. /*
  12.  *    vms.c  by Igor Mandrichenko
  13.  *    version 1.2-1
  14.  *
  15.  *    This module contains routines to extract VMS file attributes
  16.  *    from extra field and create file with these attributes.  This
  17.  *    source is mainly based on sources of file_io.c from UNZIP 4.1
  18.  *    by Info-ZIP.  [Info-ZIP note:  very little of this code is from
  19.  *    file_io.c; it has virtually been written from the ground up.
  20.  *    Of the few lines which are from the older code, most are mine
  21.  *    (G. Roelofs) and I make no claims upon them.  On the contrary,
  22.  *    my/our thanks to Igor for his contributions!]
  23.  */
  24.  
  25. /*
  26.  *      Revision history:
  27.  *      1.0-1   Mandrichenko    16-feb-1992
  28.  *              Recognize -c option
  29.  *      1.0-2   Mandrichenko    17-feb-1992
  30.  *              Do not use ASYnchroneous mode.
  31.  *      1.0-3   Mandrichenko    2-mar-1992
  32.  *              Make code more standard
  33.  *              Use lrec instead of crec -- unzip4.2p does not provide
  34.  *              crec now.
  35.  *      1.1     Mandrichenko    5-mar-1992
  36.  *              Make use of asynchronous output.
  37.  *              Be ready to extract RMS blocks of invalid size (because diff
  38.  *              VMS version used to compress).
  39.  *      1.1-1   Mandrichenko    11-mar-1992
  40.  *              Use internal file attributes saved in pInfo to decide
  41.  *              if the file is text.  [GRR:  temporarily disabled, since
  42.  *              no way to override and force binary extraction]
  43.  *      1.1-2   Mandrichenko    13-mar-1992
  44.  *              Do not restore owner/protection info if -X not specified.
  45.  *      1.1-3   Mandrichenko    30-may-1992
  46.  *              Set revision date/time to creation date/time if none specified
  47.  *              Take quiet flag into account.
  48.  *      1.1-4   Cave Newt       14-jun-1992
  49.  *              Check zipfile for variable-length format (unzip and zipinfo).
  50.  *    1.2    Mandrichenko    21-jun-1992
  51.  *        Use deflation/inflation for compression of extra blocks
  52.  *        Free all allocated space
  53.  *    1.2-1    Mandrichenko    23-jun-1992
  54.  *        Interactively select an action when file exists
  55.  */
  56.  
  57. #ifdef VMS            /*      VMS only !      */
  58.  
  59. #ifndef SYI$_VERSION
  60. #define SYI$_VERSION 4096    /* VMS 5.4 definition */
  61. #endif
  62.  
  63. #ifndef VAXC
  64.                 /* This definition may be missed */
  65. struct XAB {
  66.     unsigned char xab$b_cod;
  67.     unsigned char xab$b_bln;
  68.     short int xabdef$$_fill_1;
  69.     char *xab$l_nxt;
  70. };
  71.  
  72. #endif
  73.  
  74. #include "unzip.h"
  75. #include <ctype.h>
  76. #include <descrip.h>
  77. #include <syidef.h>
  78.  
  79. #define ERR(s) !((s) & 1)
  80.  
  81. #define BUFS512 8192*2        /* Must be a multiple of 512 */
  82.  
  83. /*
  84. *   Local static storage
  85. */
  86. static struct FAB fileblk;
  87. static struct XABDAT dattim;
  88. static struct XABRDT rdt;
  89. static struct RAB rab;
  90.  
  91. static struct FAB *outfab = 0;
  92. static struct RAB *outrab = 0;
  93. static struct XABFHC *xabfhc = 0;
  94. static struct XABDAT *xabdat = 0;
  95. static struct XABRDT *xabrdt = 0;
  96. static struct XABPRO *xabpro = 0;
  97. static struct XABKEY *xabkey = 0;
  98. static struct XABALL *xaball = 0;
  99. struct XAB *first_xab = 0L, *last_xab = 0L;
  100.  
  101. static char query = 0;
  102. static int text_file = 0;
  103.  
  104. static char locbuf[BUFS512];
  105. static int loccnt = 0;
  106. static char *locptr;
  107.  
  108. static int WriteBuffer();
  109. static int _flush_blocks();
  110. static int _flush_records();
  111. static byte *extract_block();
  112. static void message();
  113. static int get_vms_version();
  114. static void free_up();
  115. static int replace();
  116.  
  117. struct bufdsc
  118. {
  119.     struct bufdsc *next;
  120.     byte *buf;
  121.     int bufcnt;
  122. };
  123.  
  124. static struct bufdsc b1, b2, *curbuf;
  125. static byte buf1[BUFS512], buf2[BUFS512];
  126.  
  127.  
  128. int check_format()        /* return non-0 if format is variable-length */
  129. {
  130.     int rtype;
  131.     struct FAB fab;
  132.  
  133.     fab = cc$rms_fab;
  134.     fab.fab$l_fna = zipfn;
  135.     fab.fab$b_fns = strlen(zipfn);
  136.     sys$open(&fab);
  137.     rtype = fab.fab$b_rfm;
  138.     sys$close(&fab);
  139.  
  140.     if (rtype == FAB$C_VAR || rtype == FAB$C_VFC)
  141.     {
  142.     fprintf(stderr,
  143.         "\n     Error:  zipfile is in variable-length record format.  Please\n\
  144.      run \"bilf l %s\" to convert the zipfile to stream-LF\n\
  145.      record format.  (Bilf.exe, bilf.c and make_bilf.com are included\n\
  146.      in the VMS UnZip source distribution.)\n\n", zipfn);
  147.     return 2;        /* 2:  error in zipfile */
  148.     }
  149.  
  150.     return 0;
  151. }
  152.  
  153.  
  154. #ifndef ZIPINFO
  155.  
  156. int create_output_file()
  157. {                /* return non-0 if sys$create failed */
  158.     int ierr, yr, mo, dy, hh, mm, ss;
  159.     char timbuf[24];        /* length = first entry in "stupid" + 1 */
  160.     int attr_given = 0;        /* =1 if VMS attributes are present in
  161.                 *     extra_field */
  162.  
  163.     rab = cc$rms_rab;        /* fill FAB & RAB with default values */
  164.     fileblk = cc$rms_fab;
  165.  
  166.     text_file =/* pInfo->text || */aflag || cflag;
  167.  
  168.     if (attr_given = find_vms_attrs())
  169.     {
  170.     text_file = 0;
  171.     if (cflag)
  172.     {
  173.         printf("Cannot put VMS file %s to stdout.\n",
  174.            filename);
  175.         free_up();
  176.         return 50;
  177.     }
  178.     }
  179.  
  180.     if (!attr_given)
  181.     {
  182.     outfab = &fileblk;
  183.     outfab->fab$l_xab = 0L;
  184.     if (text_file)
  185.     {
  186.         outfab->fab$b_rfm = FAB$C_VAR;    /* variable length records */
  187.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  188.     }
  189.     else
  190.     {
  191.         outfab->fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
  192.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  193.     }
  194.     }
  195.  
  196.     if (!cflag)
  197.     outfab->fab$l_fna = filename;
  198.     else
  199.     outfab->fab$l_fna = "sys$output:";
  200.  
  201.     outfab->fab$b_fns = strlen(outfab->fab$l_fna);
  202.  
  203.     if ((!attr_given) || xabdat == 0 || xabrdt == 0)    /* Use date/time info
  204.                              *  from zipfile if
  205.                              *  no attributes given
  206.                              */
  207.     {
  208.     static char *month[] =
  209.         {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  210.          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  211.  
  212.     /*  fixed-length string descriptor: */
  213.     struct dsc$descriptor stupid =
  214.         {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  215.  
  216.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
  217.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  218.     dy = (lrec.last_mod_file_date & 0x1f);
  219.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  220.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  221.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  222.  
  223.     dattim = cc$rms_xabdat;    /* fill XABs with default values */
  224.     rdt = cc$rms_xabrdt;
  225.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  226.         hh, mm, ss);
  227.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  228.     memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
  229.  
  230.     if ((!attr_given) || xabdat == 0L)
  231.     {
  232.         dattim.xab$l_nxt = outfab->fab$l_xab;
  233.         outfab->fab$l_xab = &dattim;
  234.     }
  235.     }
  236.  
  237.     outfab->fab$w_ifi = 0;    /* Clear IFI. It may be nonzero after ZIP */
  238.  
  239.     ierr = sys$create(outfab);
  240.     if (ierr == RMS$_FEX)
  241.     ierr = replace();
  242.  
  243.     if (ierr == 0)        /* Canceled */
  244.     return free_up(), 1;
  245.  
  246.     if (ERR(ierr))
  247.     {
  248.     char buf[256];
  249.  
  250.     sprintf(buf, "[ Cannot create output file %s ]\n", filename);
  251.     message(buf, ierr);
  252.     message("", outfab->fab$l_stv);
  253.     free_up();
  254.     return (1);
  255.     }
  256.  
  257.     if (!text_file && !cflag)    /* Do not reopen text files and stdout
  258.                 *  Just open them in right mode         */
  259.     {
  260.     /*
  261.     *       Reopen file for Block I/O with no XABs.
  262.     */
  263.     if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
  264.     {
  265. #ifdef DEBUG
  266.         message("[ create_output_file: sys$close failed ]\n", ierr);
  267.         message("", outfab->fab$l_stv);
  268. #endif
  269.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  270.         free_up();
  271.         return (1);
  272.     }
  273.  
  274.  
  275.     outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;    /* Get ready for block
  276.                              * output */
  277.     outfab->fab$l_xab = 0L;    /* Unlink all XABs */
  278.  
  279.     if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
  280.     {
  281.         char buf[256];
  282.  
  283.         sprintf(buf, "[ Cannot open output file %s ]\n", filename);
  284.         message(buf, ierr);
  285.         message("", outfab->fab$l_stv);
  286.         free_up();
  287.         return (1);
  288.     }
  289.     }
  290.  
  291.     outrab = &rab;
  292.     rab.rab$l_fab = outfab;
  293.     if (!text_file) rab.rab$l_rop |= RAB$M_BIO;
  294.     if (!text_file) rab.rab$l_rop |= RAB$M_ASY;
  295.     rab.rab$b_rac = RAB$C_SEQ;
  296.  
  297.     if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
  298.     {
  299. #ifdef DEBUG
  300.     message("create_output_file: sys$connect failed.\n", ierr);
  301.     message("", outfab->fab$l_stv);
  302. #endif
  303.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  304.     free_up();
  305.     return (1);
  306.     }
  307.  
  308.     locptr = &locbuf[0];
  309.     loccnt = 0;
  310.  
  311.     b1.buf = &buf1[0];
  312.     b1.bufcnt = 0;
  313.     b1.next = &b2;
  314.     b2.buf = &buf2[0];
  315.     b2.bufcnt = 0;
  316.     b2.next = &b1;
  317.     curbuf = &b1;
  318.  
  319.     return (0);
  320. }
  321.  
  322. static int replace()
  323. {                /*
  324.                 *    File exists. Inquire user about futher action.
  325.                 */
  326.     char answ[10];
  327.     struct NAM nam;
  328.     int ierr;
  329.  
  330.     if (query == 0)
  331.     {
  332.     do
  333.     {
  334.         fprintf(stderr,
  335.             "Replace %s : [o]verwrite, new [v]ersion or [c]ancel (O,V,C - all) ? ",
  336.             filename);
  337.         fflush(stderr);
  338.     } while (fgets(answ, 9, stderr) == NULL && !isalpha(answ[0])
  339.          && tolower(answ[0]) != 'o'
  340.          && tolower(answ[0]) != 'v'
  341.          && tolower(answ[0]) != 'c');
  342.  
  343.     if (isupper(answ[0]))
  344.         query = answ[0] = tolower(answ[0]);
  345.     }
  346.     else
  347.     answ[0] = query;
  348.  
  349.     switch (answ[0])
  350.     {
  351.     case 'c':
  352.         ierr = 0;
  353.         break;
  354.     case 'v':
  355.         nam = cc$rms_nam;
  356.         nam.nam$l_rsa = filename;
  357.         nam.nam$b_rss = FILNAMSIZ - 1;
  358.  
  359.         outfab->fab$l_fop |= FAB$M_MXV;
  360.         outfab->fab$l_nam = &nam;
  361.  
  362.         ierr = sys$create(outfab);
  363.         if (!ERR(ierr))
  364.         {
  365.         outfab->fab$l_nam = 0L;
  366.         filename[outfab->fab$b_fns = nam.nam$b_rsl] = 0;
  367.         }
  368.         break;
  369.     case 'o':
  370.         outfab->fab$l_fop |= FAB$M_SUP;
  371.         ierr = sys$create(outfab);
  372.         break;
  373.     }
  374.     return ierr;
  375. }
  376.  
  377. /*
  378. *   Extra record format
  379. *   ===================
  380. *   signature       (2 bytes)   = 'I','M'
  381. *   size            (2 bytes)
  382. *   block signature (4 bytes)
  383. *   flags           (2 bytes)
  384. *   uncomprssed size(2 bytes)
  385. *   reserved        (4 bytes)
  386. *   data            ((size-12) bytes)
  387. *   ....
  388. */
  389.  
  390. #define BC_MASK     07    /* 3 bits for compression type */
  391. #define BC_STORED    0    /* Stored */
  392. #define BC_00        1    /* 0byte -> 0bit compression */
  393. #define BC_DEFL        2    /* Deflated */
  394.  
  395. struct extra_block
  396. {
  397.     UWORD sig;            /* Extra field block header structure */
  398.     UWORD size;
  399.     ULONG bid;
  400.     UWORD flags;
  401.     UWORD length;
  402.     ULONG reserved;
  403.     byte body[1];
  404. };
  405.  
  406. /*
  407.  *   Extra field signature and block signatures
  408.  */
  409.  
  410. #define SIGNATURE "IM"
  411. #define FABL    (cc$rms_fab.fab$b_bln)
  412. #define RABL    (cc$rms_rab.rab$b_bln)
  413. #define XALLL   (cc$rms_xaball.xab$b_bln)
  414. #define XDATL   (cc$rms_xabdat.xab$b_bln)
  415. #define XFHCL   (cc$rms_xabfhc.xab$b_bln)
  416. #define XKEYL   (cc$rms_xabkey.xab$b_bln)
  417. #define XPROL   (cc$rms_xabpro.xab$b_bln)
  418. #define XRDTL   (cc$rms_xabrdt.xab$b_bln)
  419. #define XSUML   (cc$rms_xabsum.xab$b_bln)
  420. #define EXTBSL  4        /* Block signature length   */
  421. #define RESL    8        /* Rserved 8 bytes  */
  422. #define EXTHL   (4+EXTBSL)
  423. #define FABSIG  "VFAB"
  424. #define XALLSIG "VALL"
  425. #define XFHCSIG "VFHC"
  426. #define XDATSIG "VDAT"
  427. #define XRDTSIG "VRDT"
  428. #define XPROSIG "VPRO"
  429. #define XKEYSIG "VKEY"
  430. #define XNAMSIG "VNAM"
  431. #define VERSIG  "VMSV"
  432.  
  433.  
  434.  
  435. #define W(p)    (*(unsigned short*)(p))
  436. #define L(p)    (*(unsigned long*)(p))
  437. #define EQL_L(a,b)      ( L(a) == L(b) )
  438. #define EQL_W(a,b)      ( W(a) == W(b) )
  439.  
  440. /****************************************************************
  441.  * Function find_vms_attrs scans ZIP entry extra field if any   *
  442.  * and looks for VMS attribute records. Returns 0 if either no  *
  443.  * attributes found or no fab given.                            *
  444.  ****************************************************************/
  445. int find_vms_attrs()
  446. {
  447.     byte *scan = extra_field;
  448.     struct extra_block *blk;
  449.     int len;
  450.  
  451.     outfab = xabfhc = xabdat = xabrdt = xabpro = first_xab = last_xab = 0L;
  452.  
  453.     if (scan == NULL)
  454.     return 0;
  455.     len = lrec.extra_field_length;
  456.  
  457. #define LINK(p) {    /* Link xaballs and xabkeys into chain */    \
  458.                 if( first_xab == 0L )                   \
  459.                         first_xab = p;                  \
  460.                 if( last_xab != 0L )                    \
  461.                         last_xab -> xab$l_nxt = p;      \
  462.                 last_xab = p;                           \
  463.                 p -> xab$l_nxt = 0;                     \
  464.         }
  465.     /* End of macro LINK */
  466.  
  467.     while (len > 0)
  468.     {
  469.     blk = (struct block *) scan;
  470.     if (EQL_W(&blk->sig, SIGNATURE))
  471.     {
  472.         byte *block_id;
  473.  
  474.         block_id = &blk->bid;
  475.         if (EQL_L(block_id, FABSIG))
  476.         {
  477.         outfab = (struct FAB *) extract_block(blk, 0,
  478.                               &cc$rms_fab, FABL);
  479.         }
  480.         else if (EQL_L(block_id, XALLSIG))
  481.         {
  482.         xaball = (struct XABALL *) extract_block(blk, 0,
  483.                              &cc$rms_xaball, XALLL);
  484.         LINK(xaball);
  485.         }
  486.         else if (EQL_L(block_id, XKEYSIG))
  487.         {
  488.         xabkey = (struct XABKEY *) extract_block(blk, 0,
  489.                              &cc$rms_xabkey, XKEYL);
  490.         LINK(xabkey);
  491.         }
  492.         else if (EQL_L(block_id, XFHCSIG))
  493.         {
  494.         xabfhc = (struct XABFHC *) extract_block(blk, 0,
  495.                              &cc$rms_xabfhc, XFHCL);
  496.         }
  497.         else if (EQL_L(block_id, XDATSIG))
  498.         {
  499.         xabdat = (struct XABDAT *) extract_block(blk, 0,
  500.                              &cc$rms_xabdat, XDATL);
  501.         }
  502.         else if (EQL_L(block_id, XRDTSIG))
  503.         {
  504.         xabrdt = (struct XABRDT *) extract_block(blk, 0,
  505.                              &cc$rms_xabrdt, XRDTL);
  506.         }
  507.         else if (EQL_L(block_id, XPROSIG))
  508.         {
  509.         xabpro = (struct XABPRO *) extract_block(blk, 0,
  510.                              &cc$rms_xabpro, XPROL);
  511.         }
  512.         else if (EQL_L(block_id, VERSIG))
  513.         {
  514.         char verbuf[80];
  515.         int verlen = 0;
  516.         byte *vers;
  517.         char *m;
  518.  
  519.         get_vms_version(verbuf, 80);
  520.         vers = extract_block(blk, &verlen, 0, 0);
  521.         if ((m = strrchr(vers, '-')) != NULL)
  522.             *m = 0;    /* Cut out release number */
  523.         if (strcmp(verbuf, vers) && quietflg == 0)
  524.         {
  525.             printf("[ Warning: VMS version mismatch.");
  526.  
  527.             printf("   This version %s --", verbuf);
  528.             strncpy(verbuf, vers, verlen);
  529.             verbuf[verlen] = 0;
  530.             printf(" version made by %s ]\n", verbuf);
  531.         }
  532.         free(vers);
  533.         }
  534.         else if (quietflg == 0)
  535.         fprintf(stderr, "[ Warning: Unknown block signature %s ]\n",
  536.             block_id);
  537.     }
  538.     len -= blk->size + 4;
  539.     scan += blk->size + 4;
  540.     }
  541.  
  542.  
  543.     if (outfab != 0)
  544.     {                /* Do not link XABPRO,XABRDT now. Leave them for sys$close() */
  545.  
  546.     outfab->fab$l_xab = 0L;
  547.     if (xabfhc != 0L)
  548.     {
  549.         xabfhc->xab$l_nxt = outfab->fab$l_xab;
  550.         outfab->fab$l_xab = xabfhc;
  551.     }
  552.     if (xabdat != 0L)
  553.     {
  554.         xabdat->xab$l_nxt = outfab->fab$l_xab;
  555.         outfab->fab$l_xab = xabdat;
  556.     }
  557.     if (first_xab != 0L)    /* Link xaball,xabkey subchain */
  558.     {
  559.         last_xab->xab$l_nxt = outfab->fab$l_xab;
  560.         outfab->fab$l_xab = first_xab;
  561.     }
  562.     return 1;
  563.     }
  564.     else
  565.     return 0;
  566. }
  567.  
  568. static void free_up()
  569. {                /*
  570.                 *    Free up all allocated xabs
  571.                 */
  572.     if (xabdat != 0L) free(xabdat);
  573.     if (xabpro != 0L) free(xabpro);
  574.     if (xabrdt != 0L) free(xabrdt);
  575.     if (xabfhc != 0L) free(xabfhc);
  576.     while (first_xab != 0L)
  577.     {
  578.     struct XAB *x;
  579.  
  580.     x = first_xab->xab$l_nxt;
  581.     free(first_xab);
  582.     first_xab = x;
  583.     }
  584.     if (outfab != 0L && outfab != &fileblk)
  585.     free(outfab);
  586. }
  587.  
  588. static int get_vms_version(verbuf, len)
  589.     char *verbuf;
  590. int len;
  591. {
  592.     int i = SYI$_VERSION;
  593.     int verlen = 0;
  594.     struct dsc$descriptor version;
  595.     char *m;
  596.  
  597.     version.dsc$a_pointer = verbuf;
  598.     version.dsc$w_length = len - 1;
  599.     version.dsc$b_dtype = DSC$K_DTYPE_B;
  600.     version.dsc$b_class = DSC$K_CLASS_S;
  601.  
  602.     if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
  603.     return 0;
  604.  
  605.     /* Cut out trailing spaces "V5.4-3   " -> "V5.4-3" */
  606.     for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
  607.     --m;
  608.     *m = 0;
  609.  
  610.     /* Cut out release number "V5.4-3" -> "V5.4" */
  611.     if ((m = strrchr(verbuf, '-')) != NULL)
  612.     *m = 0;
  613.     return strlen(verbuf) + 1;    /* Transmit ending 0 too */
  614. }
  615.  
  616. /******************************
  617.  *   Function extract_block   *
  618.  ******************************/
  619. /*
  620.  * Extracts block from p. If resulting length is less then needed, fill
  621.  * extra space with corresponding bytes from 'init'.
  622.  * Currently understands 3 formats of block compression:
  623.  * - Simple storing
  624.  * - Compression of zero bytes to zero bits
  625.  * - Deflation. See memextract() from extract.c
  626.  */
  627. static byte *extract_block(p, retlen, init, needlen)
  628.     struct extra_block *p;
  629. int *retlen;
  630. byte *init;
  631. int needlen;
  632. {
  633.     byte *block;        /* Pointer to block allocated */
  634.     int cmptype;
  635.     int usiz, csiz, max;
  636.  
  637.     cmptype = p->flags & BC_MASK;
  638.     csiz = p->size - EXTBSL - RESL;
  639.     usiz = (cmptype == BC_STORED ? csiz : p->length);
  640.  
  641.     if (needlen == 0)
  642.     needlen = usiz;
  643.  
  644.     if (retlen)
  645.     *retlen = usiz;
  646.  
  647. #ifndef MAX
  648. #define MAX(a,b)    ( (a) > (b) ? (a) : (b) )
  649. #endif
  650.  
  651.     if ((block = (byte *) malloc(MAX(needlen, usiz))) == NULL)
  652.     return NULL;
  653.  
  654.     if (init && (usiz < needlen))
  655.     memcpy(block, init, needlen);
  656.  
  657.     switch (cmptype)
  658.     {
  659.     case BC_STORED:    /* The simplest case */
  660.         memcpy(block, &(p->body[0]), usiz);
  661.         break;
  662.     case BC_00:
  663.         decompress_bits(block, usiz, &(p->body[0]));
  664.         break;
  665.     case BC_DEFL:
  666.         memextract(block, usiz, &(p->body[0]), csiz);
  667.         break;
  668.     default:
  669.         free(block);
  670.         block = NULL;
  671.     }
  672.     return block;
  673. }
  674.  
  675. /*
  676.  *  Simple uncompression routine. The compression uses bit stream.
  677.  *  Compression scheme:
  678.  *
  679.  *  if(byte!=0)
  680.  *      putbit(1),putbyte(byte)
  681.  *  else
  682.  *      putbit(0)
  683.  */
  684. static void decompress_bits(outptr, needlen, bitptr)
  685.     byte *bitptr;
  686.  
  687. /* Pointer into compressed data */
  688. byte *outptr;            /* Pointer into output block */
  689. int needlen;            /* Size of uncompressed block */
  690. {
  691.     ULONG bitbuf = 0;
  692.     int bitcnt = 0;
  693.  
  694. #define _FILL   if(bitcnt+8 <= 32)                      \
  695.                 {       bitbuf |= (*bitptr++) << bitcnt;\
  696.                         bitcnt += 8;                    \
  697.                 }
  698.  
  699.     while (needlen--)
  700.     {
  701.     if (bitcnt <= 0)
  702.         _FILL;
  703.  
  704.     if (bitbuf & 1)
  705.     {
  706.         bitbuf >>= 1;
  707.         if ((bitcnt -= 1) < 8)
  708.         _FILL;
  709.         *outptr++ = (byte) bitbuf;
  710.         bitcnt -= 8;
  711.         bitbuf >>= 8;
  712.     }
  713.     else
  714.     {
  715.         *outptr++ = 0;
  716.         bitcnt -= 1;
  717.         bitbuf >>= 1;
  718.     }
  719.     }
  720. }
  721.  
  722. /***************************/
  723. /*  Function FlushOutput() */
  724. /***************************/
  725.  
  726. int FlushOutput()
  727. {
  728.     if (mem_mode)
  729.     {                /* Hope, mem_mode stays constant during
  730.                  * extraction */
  731.     int rc = FlushMemory();    /* For mem_extract() */
  732.  
  733.     outpos += outcnt;
  734.     outcnt = 0;
  735.     outptr = outbuf;
  736.     return rc;
  737.     }
  738.  
  739.     /* return PK-type error code */
  740.     /* flush contents of output buffer */
  741.     if (tflag)
  742.     {                /* Do not output. Update CRC only */
  743.     UpdateCRC(outbuf, outcnt);
  744.     outpos += outcnt;
  745.     outcnt = 0;
  746.     outptr = outbuf;
  747.     return 0;
  748.     }
  749.     else
  750.     return text_file ? _flush_records(0) : _flush_blocks(0);
  751. }
  752.  
  753. static int _flush_blocks(final_flag)    /* Asynchronous version */
  754.     int final_flag;
  755.  
  756. /* 1 if this is the final flushout */
  757. {
  758.     int round;
  759.     int rest;
  760.     int off = 0;
  761.     int out_count = outcnt;
  762.     int status;
  763.  
  764.     while (out_count > 0)
  765.     {
  766.     if (curbuf->bufcnt < BUFS512)
  767.     {
  768.         int ncpy;
  769.  
  770.         ncpy = out_count > (BUFS512 - curbuf->bufcnt) ?
  771.                 BUFS512 - curbuf->bufcnt :
  772.                 out_count;
  773.         memcpy(curbuf->buf + curbuf->bufcnt, outbuf + off, ncpy);
  774.         out_count -= ncpy;
  775.         curbuf->bufcnt += ncpy;
  776.         off += ncpy;
  777.     }
  778.     if (curbuf->bufcnt == BUFS512)
  779.     {
  780.         status = WriteBuffer(curbuf->buf, curbuf->bufcnt);
  781.         if (status)
  782.         return status;
  783.         curbuf = curbuf->next;
  784.         curbuf->bufcnt = 0;
  785.     }
  786.     }
  787.  
  788.     UpdateCRC(outbuf, outcnt);
  789.     outpos += outcnt;
  790.     outcnt = 0;
  791.     outptr = outbuf;
  792.  
  793.     return (final_flag && (curbuf->bufcnt > 0)) ?
  794.     WriteBuffer(curbuf->buf, curbuf->bufcnt) :
  795.     0;
  796.     /* 0:  no error */
  797. }
  798.  
  799. #define RECORD_END(c) ((c) == CR || (c) == LF || (c) == CTRLZ)
  800.  
  801. static int _flush_records(final_flag)
  802.     int final_flag;
  803.  
  804. /* 1 if this is the final flushout */
  805. {
  806.     int rest;
  807.     int end = 0, start = 0;
  808.     int off = 0;
  809.  
  810.     if (outcnt == 0 && loccnt == 0)
  811.     return 0;        /* Nothing to do ... */
  812.  
  813.     if (loccnt)
  814.     {
  815.     for (end = 0; end < outcnt && !RECORD_END(outbuf[end]);)
  816.         ++end;
  817.  
  818.     if (end >= outcnt && !final_flag)
  819.     {
  820.         if (WriteRecord(locbuf, loccnt))
  821.         return (50);
  822.         fprintf(stderr, "[ Warning: Record too long (%d) ]\n",
  823.             outcnt + loccnt);
  824.         memcpy(locbuf, outbuf, outcnt);
  825.         locptr = &locbuf[loccnt = outcnt];
  826.     }
  827.     else
  828.     {
  829.         memcpy(locptr, outbuf, end);
  830.         if (WriteRecord(locbuf, loccnt + end))
  831.         return (50);
  832.         loccnt = 0;
  833.         locptr = &locbuf;
  834.     }
  835.     start = end + 1;
  836.  
  837.     if (start < outcnt && outbuf[end] == CR && outbuf[start] == LF)
  838.         ++start;
  839.     }
  840.  
  841.     do
  842.     {
  843.     while (start < outcnt && outbuf[start] == CR)    /* Skip CR's at the
  844.                             *  beginning of rec. */
  845.         ++start;
  846.     /* Find record end */
  847.     for (end = start; end < outcnt && !RECORD_END(outbuf[end]);)
  848.         ++end;
  849.  
  850.     if (end < outcnt)
  851.     {            /* Record end found, write the record */
  852.         if (WriteRecord(outbuf + start, end - start))
  853.         return (50);
  854.         /* Shift to the begining of the next record */
  855.         start = end + 1;
  856.     }
  857.  
  858.     if (start < outcnt && outbuf[end] == CR && outbuf[start] == LF)
  859.         ++start;
  860.  
  861.     } while (start < outcnt && end < outcnt);
  862.  
  863.     rest = outcnt - start;
  864.  
  865.     if (rest > 0)
  866.     if (final_flag)
  867.     {
  868.         /* This is a final flush. Put out all remaining in
  869.         *  the buffer                               */
  870.         if (loccnt && WriteRecord(locbuf, loccnt))
  871.         return (50);
  872.     }
  873.     else
  874.     {
  875.         memcpy(locptr, outbuf + start, rest);
  876.         locptr += rest;
  877.         loccnt += rest;
  878.     }
  879.     UpdateCRC(outbuf, outcnt);
  880.     outpos += outcnt;
  881.     outcnt = 0;
  882.     outptr = outbuf;
  883.     return (0);            /* 0:  no error */
  884. }
  885.  
  886. /***************************/
  887. /*  Function WriteBuffer() */
  888. /***************************/
  889.  
  890. static int WriteBuffer(buf, len)/* return 0 if successful, 1 if not */
  891.     unsigned char *buf;
  892. int len;
  893. {
  894.     int status;
  895.  
  896.     status = sys$wait(outrab);
  897. #ifdef DEBUG
  898.     if (ERR(status))
  899.     {
  900.     message("[ WriteBuffer: sys$wait failed ]\n", status);
  901.     message("", outrab->rab$l_stv);
  902.     }
  903. #endif
  904.     outrab->rab$w_rsz = len;
  905.     outrab->rab$l_rbf = buf;
  906.  
  907.     if (ERR(status = sys$write(outrab)))
  908.     {
  909.     message("[ WriteBuffer: sys$write failed ]\n", status);
  910.     message("", outrab->rab$l_stv);
  911.     return 50;
  912.     }
  913.     return (0);
  914. }
  915.  
  916. /***************************/
  917. /*  Function WriteRecord() */
  918. /***************************/
  919.  
  920. static int WriteRecord(rec, len)/* return 0 if successful, 1 if not */
  921.     unsigned char *rec;
  922. int len;
  923. {
  924.     int status;
  925.  
  926.     sys$wait(outrab);
  927. #ifdef DEBUG
  928.     if (ERR(status))
  929.     {
  930.     message("[ WriteRecord: sys$wait faled ]\n", status);
  931.     message("", outrab->rab$l_stv);
  932.     }
  933. #endif
  934.     outrab->rab$w_rsz = len;
  935.     outrab->rab$l_rbf = rec;
  936.  
  937.     if (ERR(status = sys$put(outrab)))
  938.     {
  939.     message("[ WriteRecord: sys$put failed ]\n", status);
  940.     message("", outrab->rab$l_stv);
  941.     return 50;
  942.     }
  943.     return (0);
  944. }
  945.  
  946. /********************************/
  947. /*  Function CloseOutputFile()  */
  948. /********************************/
  949.  
  950. int CloseOutputFile()
  951. {
  952.     int status;
  953.  
  954.     if (text_file) _flush_records(1);
  955.     else
  956.     _flush_blocks(1);
  957.     /* Link XABRDT,XABDAT and optionaly XABPRO */
  958.     if (xabrdt != 0L)
  959.     {
  960.     xabrdt->xab$l_nxt = 0L;
  961.     outfab->fab$l_xab = xabrdt;
  962.     }
  963.     else
  964.     {
  965.     rdt.xab$l_nxt = 0L;
  966.     outfab->fab$l_xab = &rdt;
  967.     }
  968.     if (xabdat != 0L)
  969.     {
  970.     xabdat->xab$l_nxt = outfab->fab$l_xab;
  971.     outfab->fab$l_xab = xabdat;
  972.     }
  973.     if (secinf && xabpro != 0L)
  974.     {
  975.     xabpro->xab$l_nxt = outfab->fab$l_xab;
  976.     outfab->fab$l_xab = xabpro;
  977.     }
  978.  
  979.     sys$wait(outrab);
  980.  
  981.     status = sys$close(outfab);
  982. #ifdef DEBUG
  983.     if (ERR(status))
  984.     {
  985.     message("\r[ Warning: cannot set owner/protection/time attributes ]\n", status);
  986.     message("", outfab->fab$l_stv);
  987.     }
  988. #endif
  989.     free_up();
  990. }
  991.  
  992. #ifdef DEBUG
  993. dump_rms_block(p)
  994.     unsigned char *p;
  995. {
  996.     unsigned char bid, len;
  997.     int err;
  998.     char *type;
  999.     char buf[132];
  1000.     int i;
  1001.  
  1002.     err = 0;
  1003.     bid = p[0];
  1004.     len = p[1];
  1005.     switch (bid)
  1006.     {
  1007.     case FAB$C_BID:
  1008.         type = "FAB";
  1009.         break;
  1010.     case XAB$C_ALL:
  1011.         type = "xabALL";
  1012.         break;
  1013.     case XAB$C_KEY:
  1014.         type = "xabKEY";
  1015.         break;
  1016.     case XAB$C_DAT:
  1017.         type = "xabDAT";
  1018.         break;
  1019.     case XAB$C_RDT:
  1020.         type = "xabRDT";
  1021.         break;
  1022.     case XAB$C_FHC:
  1023.         type = "xabFHC";
  1024.         break;
  1025.     case XAB$C_PRO:
  1026.         type = "xabPRO";
  1027.         break;
  1028.     default:
  1029.         type = "Unknown";
  1030.         err = 1;
  1031.         break;
  1032.     }
  1033.     printf("Block @%08X of type %s (%d).", p, type, bid);
  1034.     if (err)
  1035.     {
  1036.     printf("\n");
  1037.     return;
  1038.     }
  1039.     printf(" Size = %d\n", len);
  1040.     printf(" Offset - Hex - Dec\n");
  1041.     for (i = 0; i < len; i += 8)
  1042.     {
  1043.     int j;
  1044.  
  1045.     printf("%3d - ", i);
  1046.     for (j = 0; j < 8; j++)
  1047.         if (i + j < len)
  1048.         printf("%02X ", p[i + j]);
  1049.         else
  1050.         printf("   ");
  1051.     printf(" - ");
  1052.     for (j = 0; j < 8; j++)
  1053.         if (i + j < len)
  1054.         printf("%03d ", p[i + j]);
  1055.         else
  1056.         printf("    ");
  1057.     printf("\n");
  1058.     }
  1059. }
  1060.  
  1061. #endif                /* DEBUG */
  1062.  
  1063. static void message(string, status)
  1064.     int status;
  1065. char *string;
  1066. {
  1067.     char msgbuf[256];
  1068.  
  1069.     $DESCRIPTOR(msgd, msgbuf);
  1070.     int msglen = 0;
  1071.  
  1072.     if (ERR(lib$sys_getmsg(&status, &msglen, &msgd, 0, 0)))
  1073.     fprintf(stderr, "%s[ VMS status = %d ]\n", string, status);
  1074.     else
  1075.     {
  1076.     msgbuf[msglen] = 0;
  1077.     fprintf(stderr, "%s[ %s ]\n", string, msgbuf);
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. #endif                /* !ZIPINFO */
  1083. #endif                /* VMS */
  1084.