home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1997 March / VPR9703A.ISO / OLS / Os2 / LHA2P205 / LHA2P205.LZH / lha2-2.05pre / source.lzh / src / header.c < prev    next >
C/C++ Source or Header  |  1996-02-25  |  32KB  |  1,240 lines

  1. /*
  2.  * header.c
  3.  *   Copyright (C) 1988-1994, Haruyasu YOSHIZAKI
  4.  *   Copyright (C) 1991-1996, Satoshi HIRAMATSU
  5.  *
  6.  * $Log$
  7.  */
  8.  
  9.  
  10. #include <sys/types.h>
  11. #include <stdio.h>
  12. #include <io.h>
  13. #include <time.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <limits.h>
  17. #include "typedef.h"
  18. #include "port2.h"
  19. #include "lh.h"
  20. #include "intrface.h"
  21. #include "errmes.h"
  22. #include "header.h"
  23.  
  24.  
  25. HEADER hpb;
  26.  
  27.  
  28. #define HDR_READ_SIZE    21    /* 初回読み込み時の読み込みサイズ */
  29. /* ヘッダのサイズ */
  30. #define HDRsize(a)    (byte *)((a) + 0)
  31. /* ヘッダのサイズ */
  32. #define HDRsize2(a)    (hword *)((a) + 0)
  33. /* チェックサム */
  34. #define HDRsum(a)    (byte *)((a) + 1)
  35. /* 圧縮法 */
  36. #define HDRmethod(a)    (byte *)((a) + 2)
  37. /* 圧縮後のサイズ */
  38. #define HDRpacked(a)    (word *)((a) + 7)
  39. /* 元のサイズ */
  40. #define HDRoriginal(a)    (word *)((a) + 11)
  41. /* 最終更新日時 */
  42. #define HDRmtime(a)    (hword *)((a) + 15)
  43. /* MS-DOSファイル属性 */
  44. #define HDRattribute(a)    (byte *)((a) + 19)
  45. /* ヘッダレベル */
  46. #define HDRlevel(a)    (byte *)((a) + 20)
  47. /* ファイル名長 */
  48. #define HDRnamelen(a)    (byte *)((a) + 21)
  49. /* CRC-16 */
  50. #define HDRcrc(a)    (hword *)((a) + 21)
  51. /* ファイル名 */
  52. #define HDRname(a)    (byte *)((a) + 22)
  53. /* 作成OS識別子 */
  54. #define HDRcreator(a)    (byte *)((a) + 23)
  55. /* 先頭拡張ヘッダサイズ(2bytes) */
  56. #define HDRnext(a)    (hword *)((a) + 24)
  57. /* 全ヘッダサイズ(Level3のみ) */
  58. #define HDRsize3(a)    (word *)((a) + 24)
  59. /* 先頭拡張ヘッダサイズ(Level3のみ) */
  60. #define HDRnext3(a)    (word *)((a) + 28)
  61.  
  62. #ifdef LITTLE_ENDIAN
  63. #define GetHWord(p)    (0xffff & (*(hword *)(p)))
  64. #define GetWord(p)    (*(word *)(p))
  65. #define SetHWord(p,q)    (*(hword *)(p) = (0xffff & (uint)(q)))
  66. #define SetWord(p,q)    (*(word *)(p) = (q))
  67. #else
  68. #ifdef BIG_ENDIAN
  69. #define GetHWord(p)    (*(p) + ((hword)*((p) + 1) << 8))
  70. #define GetWord(p)    (GetHWord(p) + ((word)GetHWord((p) + 2) << 16))
  71. #define SetHWord(p,q) \
  72. { \
  73.     register hword a = q; \
  74.     *(p)[0] = 0xff & (uint)a; \
  75.     *(p)[1] = 0xff & ((uint)a >> 8); \
  76. }
  77. #define SetWord(p,q) \
  78. { \
  79.     register word a = q; \
  80.     (p)[0] = 0xff & (uint)a; \
  81.     (p)[1] = 0xff & ((uint)a >> 8); \
  82.     (p)[2] = 0xff & ((uint)a >> 16); \
  83.     (p)[3] = 0xff & ((uint)a >> 24); \
  84. }
  85. #endif
  86. #endif
  87.  
  88.  
  89. /* compression method strings */
  90. char methods[11][5] =
  91. {
  92.   "-lh0-", "-lh1-", "-lh2-", "-lh3-", "-lh4-", 
  93.   "-lh5-", "-lzs-", "-lz5-", "-lz4-", "-lhd-", "\0\0\0\0\0"
  94. };
  95.  
  96.  
  97. /*
  98.  * nextpos --- save/load next header position
  99.  */
  100. #define NEXTPOS_SET 0
  101. #define NEXTPOS_GET 1
  102. static off_t
  103. nextpos(sw, pos)
  104.      bool sw;
  105.      off_t pos;
  106. {
  107.   static off_t current;
  108.  
  109.   if(sw == NEXTPOS_SET)
  110.     current = pos;
  111.   else if(sw == NEXTPOS_GET)
  112.     return current;
  113.   else
  114.     return -1;
  115.  
  116.   return 0;
  117. }
  118.  
  119.  
  120. /*
  121.  * calcsum --- caculate header check-sum
  122.  */
  123. static byte
  124. calcsum(base)
  125.      register byte *base;
  126. {
  127.   register byte *end, sum = 0;
  128.  
  129.   end = base + *HDRsize(base) + 2; /* set end point */
  130.   base += 2;            /* skip 2bytes */
  131.   do
  132.     sum += *base++;
  133.   while(base < end);
  134.  
  135.   return sum;
  136. }
  137.  
  138.  
  139. /*
  140.  * getext --- read extend header
  141.  */
  142. static off_t
  143. getext(fp, headersize, header, wordsize, hcrc)
  144.      FILE *fp;
  145.      off_t headersize;
  146.      HEADER *header;
  147.      size_t wordsize;
  148.      hword *hcrc;
  149. {
  150.   register off_t rsize;
  151.   off_t read;
  152.   byte *buffer;
  153.  
  154.   rsize = headersize - wordsize;
  155.   if((ulong)headersize > (ulong)READ_MAX)
  156.     return crcfread(fp, rsize, hcrc);
  157.  
  158.   buffer = (byte *)e_malloc(rsize);
  159.   if((read = fread(buffer, 1, rsize, fp)) < rsize)
  160.     {
  161.       free(buffer);
  162.       return 0;
  163.     }
  164.  
  165.   switch(0xff & (uint)*buffer)
  166.     {
  167.     case 0x00:            /* common */
  168.       header->crcpos = TRUE;    /* for level-1 header */
  169.       header->headercrc = GetHWord(buffer + 1);
  170.       if((headersize >= 6) || (headersize >= 8)) /* additional information */
  171.     header->info = (int)*(buffer + 3);
  172.       SetHWord(buffer + 1, 0);
  173.       *hcrc = calccrc(buffer, rsize, *hcrc);
  174.       free(buffer);
  175.  
  176.       return read;
  177.  
  178.     case 0x01:            /* filename */
  179.       *hcrc = calccrc(buffer, rsize, *hcrc);
  180.       memmove(buffer, buffer + 1, --rsize);
  181.       if(header->filename)
  182.     free(header->filename);
  183.       header->filename = buffer;
  184.       header->filename[rsize] = '\0';
  185.       header->namelen = rsize;
  186.  
  187.       return read;
  188.  
  189.     case 0x02:            /* directory name */
  190.       *hcrc = calccrc(buffer, rsize, *hcrc);
  191.       memmove(buffer, buffer + 1, --rsize);
  192.       header->pathname = buffer;
  193.       header->pathname[rsize] = '\0';
  194.       header->pathlen = rsize;
  195.  
  196.       return read;
  197.  
  198.     case 0x3f:            /* comment */
  199.       break;
  200.  
  201.     case 0x40:            /* MS-DOS dependent */
  202.       if((header->creator == CREATOR_OS2)
  203.      || (header->creator == CREATOR_MSDOS))/* implementer dependent */
  204.     header->attr = (uint)GetHWord(buffer + 1);
  205.       break;
  206.  
  207. #ifdef __SUPPORT_PERMISSION__
  208.     case 0x50:            /* permission */
  209.       header->mode = (word)GetHWord(buffer + 1);
  210.       break;
  211. #endif
  212.  
  213. #ifdef __SUPPORT_UID_GID__
  214.     case 0x51:            /* UID and GID */
  215.       header->gid =  (word)GetHWord(buffer + 1);
  216.       header->uid =  (word)GetHWord(buffer + 3);
  217.       break;
  218. #endif
  219.  
  220. #ifdef __SUPPORT_MTIME__
  221.     case 0x54:            /* for UNIX */
  222.       header->mtime = (time_t)GetWord(buffer + 1);
  223.       break;
  224. #endif
  225.  
  226.     case 0x7f:            /* information */
  227.       header->mode = GetHWord(buffer + 1);
  228. #ifdef __SUPPORT_UID_GID__
  229.       header->gid = GetHWord(buffer + 5);
  230.       header->uid = GetHWord(buffer + 7);
  231. #endif
  232. #ifdef __SUPPORT_CTIME_ATIME__
  233.       header->ctime = GetWord(buffer + 9);
  234.       header->atime = GetWord(buffer + 13);
  235. #endif
  236.       break;
  237.  
  238. #ifdef __SUPPORT_EA__
  239.     case 0x7e:            /* EA */
  240. #ifdef __OS2__            /* Sample implementation */
  241.       *hcrc = calccrc(buffer, rsize, *hcrc);
  242.       if(header->creator == CREATOR_OS2) /* implementer dependent */
  243.     {
  244.       register uint os = (uint)*(buffer + 2);
  245.  
  246.       if((os == 4) && !memcmp(buffer + 3, "OS/2", 4))
  247.         {
  248.           if(*(buffer + 1) == __TYPE_EA__)
  249.         {
  250.           if((uint)*(buffer + 3 + os) >= (uint)0x02)
  251.             {
  252.               memmove(buffer, buffer + 3 + os, rsize - 3 - os);
  253.               header->ea = (FEA2LIST *)buffer;
  254.  
  255.               return read;
  256.             }
  257.         }
  258.         }
  259.     }
  260.       free(buffer);
  261.       return read;
  262. #else
  263.       break;
  264. #endif
  265. #endif
  266.  
  267. #ifdef __SUPPORT_KAPSEL__
  268.     case 0x7d:            /* MacBinary like kapsel */
  269.       header->kapselheadersize = GetWord(buffer + 1);
  270.       header->filesize = GetWord(buffer + 5);
  271.       break;
  272. #endif
  273.  
  274.     default:
  275.       break;
  276.     }
  277.  
  278.   *hcrc = calccrc(buffer, rsize, *hcrc);
  279.   free(buffer);
  280.  
  281.   return read;
  282. }
  283.  
  284.  
  285. /*
  286.  * level0r --- read level-0 header
  287.  */
  288. static off_t
  289. level0r(fp, baseheader, header)
  290.      FILE *fp;
  291.      byte *baseheader;
  292.      HEADER *header;
  293. {
  294.   size_t read, hsize;
  295.   char *p;
  296.  
  297.   header->headersize = (word)*HDRsize(baseheader) + 2;
  298.   if((hsize = header->headersize - HDR_READ_SIZE) <= 0)
  299.     return 0;
  300.  
  301.   if((read = fread(baseheader + HDR_READ_SIZE, 1, hsize, fp)) - hsize)
  302.     return 0;
  303.  
  304.   header->dostime.u = GetWord(HDRmtime(baseheader));
  305.   header->mtime = dos2unix(&(header->dostime.s));
  306. #ifdef __SUPPORT_CTIME_ATIME__
  307.   header->ctime = header->atime = header->mtime;
  308. #endif
  309.  
  310.   if(calcsum(baseheader) != *HDRsum(baseheader))
  311.     {
  312.       if(*baseheader == 0x1a)
  313.     return read;        /* for LArc & XMODEM */
  314.       return 0;            /* Checksum error */
  315.     }
  316.  
  317.   if(read < 3)            /* ファイル名長が0でも可 */
  318.     return 0;            /* illegal */
  319.  
  320.   header->pathlen = (int)*HDRnamelen(baseheader);
  321.   header->filecrc =
  322.     GetHWord(HDRnamelen(baseheader) + (uint)header->pathlen + 1);
  323.   header->pathname = (char *)e_malloc(header->pathlen + 1);
  324.   memcpy(header->pathname, HDRname(baseheader), header->pathlen);
  325.   header->pathname[header->pathlen] = '\0';
  326.   convdelim(header->pathname, DELIM);
  327.   if(p = strrchr(header->pathname, DELIM))
  328.     {
  329.       if(*++p)
  330.     {
  331.       header->namelen = strlen(p);
  332.       header->filename = (char *)e_malloc(header->namelen + 1);
  333.       strcpy(header->filename, p);
  334.     }
  335.       *p = '\0';
  336.       header->pathlen = strlen(header->pathname);
  337.     }
  338.  
  339.   return (off_t)read;
  340. }
  341.  
  342.  
  343. /*
  344.  * level1r --- read level-1 header
  345.  */
  346. static off_t
  347. level1r(fp, baseheader, header)
  348.      FILE *fp;
  349.      byte *baseheader;
  350.      HEADER *header;
  351. {
  352.   off_t read, hsize, next;
  353.   register byte *address;
  354.   byte buffer[sizeof(hword)];
  355.   hword hcrc;
  356.   word basesize;
  357.  
  358.   basesize = header->headersize = (word)*HDRsize(baseheader) + 2;
  359.   if((hsize = header->headersize - HDR_READ_SIZE) < 6)
  360.     return 0;
  361.  
  362.   if((read = fread(baseheader + HDR_READ_SIZE, 1, hsize, fp)) - hsize)
  363.     return 0;
  364.  
  365.   if(calcsum(baseheader) != *HDRsum(baseheader))
  366.     return 0;            /* Checksum error */
  367.  
  368.   header->dostime.u = GetWord(HDRmtime(baseheader));
  369.   header->mtime = dos2unix(&(header->dostime.s));
  370. #ifdef __SUPPORT_CTIME_ATIME__
  371.   header->ctime = header->atime = header->mtime;
  372. #endif
  373.  
  374.   header->namelen = (int)*HDRnamelen(baseheader);
  375.   address = HDRnamelen(baseheader) + (uint)header->namelen + 1;
  376.   header->filecrc = GetHWord(address);
  377.   header->creator = *(address + 2);
  378.  
  379.   if(header->namelen)
  380.     {
  381.       header->filename = (char *)e_malloc(header->namelen + 1);
  382.       strncpy(header->filename, HDRname(baseheader), header->namelen);
  383.       header->filename[header->namelen] = '\0';
  384.       header->filename = convdelim(header->filename, DELIM);
  385.     }
  386.  
  387.   /* calculate header-CRC */
  388.   header->crcpos = FALSE;
  389.   hcrc = calccrc(baseheader, header->headersize, 0);
  390.  
  391.   /* read next extend header size */
  392.   next = (size_t)GetHWord(address + 3);
  393.   while(next)
  394.     {
  395.       header->headersize += next;
  396.       if(!(hsize = getext(fp, next, header, sizeof(hword), &hcrc)))
  397.     return 0;
  398.       read += hsize;
  399.       if(fread(buffer, 1, sizeof(hword), fp) != sizeof(hword))
  400.     return 0;
  401.       read += sizeof(hword);
  402.       next = (off_t)GetHWord(buffer);
  403.  
  404.       /* calculate header-CRC */
  405.       hcrc = calccrc(buffer, sizeof(hword), hcrc);
  406.     }
  407.  
  408.   /* check header-CRC */
  409.   if(header->crcpos)
  410.     if(header->headercrc != hcrc)
  411.       return (off_t)0;
  412.  
  413.   /* adjust packed size */
  414.   header->packed -= (header->headersize - basesize);
  415.  
  416.   return (off_t)read;
  417. }
  418.  
  419.  
  420. /*
  421.  * level2r --- read level-2 header
  422.  */
  423. static off_t
  424. level2r(fp, baseheader, header)
  425.      FILE *fp;
  426.      byte *baseheader;
  427.      HEADER *header;
  428. {
  429.   off_t read, hsize, next;
  430.   byte buffer[sizeof(hword)];
  431.   hword hcrc;
  432.  
  433.   if((read = fread(baseheader + HDR_READ_SIZE, 1, 5, fp)) - 5)
  434.     return 0;
  435.  
  436.   header->headersize = (word)GetHWord(HDRsize2(baseheader));
  437.   header->mtime = GetWord(HDRmtime(baseheader));
  438. #ifdef __SUPPORT_CTIME_ATIME__
  439.   header->ctime = header->atime = header->mtime;
  440. #endif
  441.   header->filecrc = GetHWord(HDRcrc(baseheader));
  442.   header->creator = *HDRcreator(baseheader);
  443.  
  444.   /* calculate header-CRC */
  445.   hcrc = calccrc(baseheader, HDR_READ_SIZE + 5, 0);
  446.  
  447.   /* read next extend header size */
  448.   next = (off_t)GetHWord(HDRnext(baseheader));
  449.   while(next)
  450.     {
  451.       if(!(hsize = getext(fp, next, header, sizeof(hword), &hcrc)))
  452.     return 0;
  453.       read += hsize;
  454.       if(fread(buffer, 1, sizeof(hword), fp) != sizeof(hword))
  455.     return 0;
  456.       read += sizeof(hword);
  457.       next = (off_t)GetHWord(buffer);
  458.  
  459.       /* calculate header-CRC */
  460.       hcrc = calccrc(buffer, sizeof(hword), hcrc);
  461.     }
  462.   
  463.   if(header->headersize == read + HDR_READ_SIZE + 1)
  464.     {
  465.       read += fread(&(header->dummy), 1, 1, fp);
  466.       hcrc = calccrc(&(header->dummy), 1, hcrc);
  467.     }
  468.       
  469.   /* check header-CRC */
  470.   if(header->headercrc != hcrc)
  471.     return (off_t)0;
  472.  
  473.   return (off_t)read;
  474. }
  475.  
  476.  
  477. /*
  478.  * level3r --- read level-3 header
  479.  */
  480. static off_t
  481. level3r(fp, baseheader, header)
  482.      FILE *fp;
  483.      byte *baseheader;
  484.      HEADER *header;
  485. {
  486.   off_t read, hsize, next;
  487.   byte buffer[sizeof(word)];
  488.   hword hcrc;
  489.  
  490.   if((read = fread(baseheader + HDR_READ_SIZE, 1, 11, fp)) - 11)
  491.     return 0;
  492.  
  493.   header->mtime = GetWord(HDRmtime(baseheader));
  494. #ifdef __SUPPORT_CTIME_ATIME__
  495.   header->ctime = header->atime = header->mtime;
  496. #endif
  497.   header->filecrc = GetHWord(HDRcrc(baseheader));
  498.   header->creator = *HDRcreator(baseheader);
  499.   header->headersize = GetWord(HDRsize3(baseheader));
  500.  
  501.   /* calculate header-CRC */
  502.   hcrc = calccrc(baseheader, HDR_READ_SIZE + 11, 0);
  503.  
  504.   /* read next extend header size */
  505.   next = (off_t)GetWord(HDRnext3(baseheader));
  506.   while(next)
  507.     {
  508.       if(!(hsize = getext(fp, (off_t)next, header, sizeof(word), &hcrc)))
  509.     return 0;
  510.       read += hsize;
  511.       if(fread(buffer, 1, sizeof(word), fp) != sizeof(word))
  512.     return 0;
  513.       read += sizeof(word);
  514.       next = (off_t)GetWord(buffer);
  515.  
  516.       /* calculate header-CRC */
  517.       hcrc = calccrc(buffer, sizeof(word), hcrc);
  518.     }
  519.   
  520.   /* check header-CRC */
  521.   if(header->headercrc != hcrc)
  522.     return (off_t)0;
  523.  
  524.   return (off_t)read;
  525. }
  526.  
  527.  
  528. /*
  529.  * gethdr --- get information from LHA header.
  530.  */
  531. char *
  532. gethdr(fp, header)
  533.      FILE *fp;
  534.      HEADER *header;
  535. {
  536.   static byte buffer[257];
  537.   byte *baseheader = &buffer[0];
  538.   off_t read;
  539.   int method;
  540.   static off_t (*decodeheader[4])() = {level0r, level1r, level2r, level3r};
  541.  
  542.   fseek(fp, nextpos(NEXTPOS_GET, 0), SEEK_SET);
  543.  
  544.   /* read common part */
  545.   if((read = fread(baseheader, 1, HDR_READ_SIZE, fp)) - HDR_READ_SIZE)
  546.     return (char *)NULL;
  547.  
  548.   /* common part */
  549.   memcpy(header->method, HDRmethod(baseheader), 5);
  550.   memcpy(methods[SENTINEL], header->method, 5);
  551.   for(method = 0; memcmp(header->method, methods[method], 5); method++)
  552.     ;
  553.   if(method == SENTINEL)
  554.     return (char *)NULL;    /* unsupported method */
  555.  
  556.   header->packed = header->skip = GetWord(HDRpacked(baseheader));
  557.   header->original = GetWord(HDRoriginal(baseheader));
  558.   header->attr = (uint)*HDRattribute(baseheader);
  559.   header->level = (uint)*HDRlevel(baseheader);
  560.   if(header->level > (uint)3)
  561.     return (char *)NULL;    /* unsupported header level */
  562.  
  563.   /* initialize */
  564.   header->pathlen = 0;
  565.   header->namelen = 0;
  566.   header->pathname = (char *)NULL;
  567.   header->filename = (char *)NULL;
  568. #ifdef __SUPPORT_EA__
  569. #ifdef __OS2__
  570.   header->ea = (FEA2LIST *)NULL;
  571. #endif
  572. #endif
  573. #ifdef __SUPPORT_CTIME_ATIME__
  574.   header->ctime = header->atime = 0;
  575. #endif
  576.  
  577.   /* switch header level */
  578.   if((read += (*decodeheader[header->level])(fp, baseheader, header))
  579.      == HDR_READ_SIZE)
  580.     return (char *)NULL;    /* unrecognized header */
  581.  
  582.   /* make pathname */
  583.   if(header->pathlen && header->namelen)
  584.     {
  585.       register char *p;
  586.  
  587.       p = (char *)e_malloc(header->pathlen + header->namelen + 1);
  588.       strcpy(p, header->pathname);
  589.       free(header->pathname);
  590.       header->pathname = p;
  591.       strcat(p, header->filename);
  592.       header->pathlen += header->namelen; /* adjust */
  593.     }
  594.   else if(header->namelen)
  595.     {
  596.       header->pathname = header->filename;
  597.       header->pathlen = header->namelen;
  598.     }
  599.   else if(header->pathlen)
  600.     {
  601.       /* for level0 header */
  602.       header->filename = header->pathname;
  603.       header->namelen = header->pathlen;
  604.     }
  605.   convdelim(header->pathname, DELIM);
  606.  
  607.   /* set next header position */
  608.   header->offset = read;
  609.   nextpos(NEXTPOS_SET, nextpos(NEXTPOS_GET, 0) + read + header->packed);
  610.  
  611.   /* return path name */
  612.   return header->pathname;
  613. }
  614.  
  615.  
  616. /*
  617.  * inithdr --- initialize LHA header
  618.  */
  619. bool
  620. inithdr(fp)
  621.      FILE *fp;
  622. {
  623.   nextpos(NEXTPOS_SET, 0);    /* initialize */
  624.   rewind(fp);
  625.   if(!fgetc(fp))
  626.     return TRUE;        /* illegal header */
  627.   fgetc(fp);
  628.   if((fgetc(fp) == (int)'-') && (fgetc(fp) == (int)'l'))
  629.     {
  630.       fgetc(fp);
  631.       fgetc(fp);
  632.       if(fgetc(fp) == (int)'-')
  633.     return FALSE;        /* perhaps legal header */
  634.     }
  635.  
  636.   return TRUE;            /* illegal header */
  637. }
  638.  
  639.  
  640. /*
  641.  * makeext --- make extend header for level-1, level-2 base header
  642.  */
  643. static bool
  644. makeext(baseheader, header)
  645.      HEADERLINK *baseheader;
  646.      HEADER *header;
  647. {
  648.   register byte *address;
  649.   register int need = 0;
  650.  
  651.   /* filename */
  652.   if(header->needfname)
  653.     {
  654.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  655.       baseheader = baseheader->next;
  656.       baseheader->size = 3 + header->namelen;
  657.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  658.       *address++ = 0x01;
  659.       memcpy(address, header->filename, header->namelen);
  660.       address += header->namelen;
  661.       SetHWord(address, 0);
  662.       ++need;
  663.     }
  664.  
  665.   /* directoryname */
  666.   if(header->pathname != header->filename)
  667.     {
  668.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  669.       baseheader = baseheader->next;
  670.       baseheader->size = 3 + header->pathlen - header->namelen;
  671.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  672.       *address++ = 0x02;
  673.       convdelim(header->pathname, DELIM2);
  674.       memcpy(address, header->pathname, baseheader->size - 3);
  675.       convdelim(header->pathname, DELIM);
  676.       address += baseheader->size - 3;
  677.       SetHWord(address, 0);
  678.       ++need;
  679.     }
  680.  
  681.   /* comment (unsupport) */
  682.  
  683.   /* MS-DOS dependent */
  684.   if(header->attr != 0x20)
  685.     {
  686.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  687.       baseheader = baseheader->next;
  688.       baseheader->size = 5;
  689.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  690.       *address++ = 0x40;
  691.       SetHWord(address, header->attr);
  692.       address += 2;
  693.       SetHWord(address, 0);
  694.       ++need;
  695.     }
  696.  
  697. #ifdef __SUPPORT_PERMISSION__
  698.   /* UNIX dependent */
  699.   baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  700.   baseheader = baseheader->next;
  701.   baseheader->size = 5;
  702.   address = baseheader->header = (byte *)e_malloc(baseheader->size);
  703.   *address++ = 0x50;
  704.   SetHWord(address, header->mode);
  705.   address += 2;
  706.   SetHWord(address, 0);
  707.   ++need;
  708. #endif
  709.  
  710. #ifdef __SUPPORT_UID_GID__
  711.   /* UNIX dependent */
  712.   baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  713.   baseheader = baseheader->next;
  714.   baseheader->size = 7;
  715.   address = baseheader->header = (byte *)e_malloc(baseheader->size);
  716.   *address++ = 0x51;
  717. #ifndef __OS2__
  718.   SetHWord(address, header->gid);
  719. #else
  720.   SetHWord(address, gid);    /* __OS2__ */
  721. #endif
  722.   address += 2;
  723. #ifndef __OS2__
  724.   SetHWord(address, header->uid);
  725. #else
  726.   SetHWord(address, uid);    /* __OS2__ */
  727. #endif
  728.   address += 2;
  729.   SetHWord(address, 0);
  730.   ++need;
  731. #endif
  732.  
  733. #ifdef __SUPPORT_MTIME__
  734.   /* UNIX dependent */
  735.   if(header->level == 1)
  736.     {
  737.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  738.       baseheader = baseheader->next;
  739.       baseheader->size = 7;
  740.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  741.       *address++ = 0x54;
  742.       SetWord(address, header->mtime);
  743.       address += 2;
  744.       SetHWord(address, 0);
  745.       ++need;
  746.     }
  747. #endif
  748.  
  749.   /* common */
  750.   if(((uint)header->level > 1) || need)
  751.     {
  752.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  753.       baseheader = baseheader->next;
  754.       baseheader->size = 5 + (header->info ? 1 : 0);
  755.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  756.       header->crcpos = TRUE;
  757.       *address++ = 0x00;
  758.       SetHWord(address, 0);
  759.       address += 2;
  760.       if(header->info)
  761.     *address++ = header->info;
  762.       SetHWord(address, 0);
  763.     }
  764.  
  765.   baseheader->next = (HEADERLINK *)NULL;
  766.  
  767.   return FALSE;
  768. }
  769.  
  770.  
  771. /*
  772.  * makeext3 --- make extend header for level-3 base header
  773.  */
  774. static bool
  775. makeext3(baseheader, header)
  776.      HEADERLINK *baseheader;
  777.      HEADER *header;
  778. {
  779.   register byte *address;
  780.   register hword unixmode;
  781.  
  782.   /* common */
  783.   baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  784.   baseheader = baseheader->next;
  785.   baseheader->size = 7 + (header->info ? 1 : 0);
  786.   address = baseheader->header = (byte *)e_malloc(baseheader->size);
  787.   header->crcpos = TRUE;    /* offset of header-CRC */
  788.   *address++ = 0x00;
  789.   SetHWord(address, 0);
  790.   address += 2;
  791.   if(header->info)
  792.     *address++ = header->info;
  793.   SetWord(address, 0);
  794.  
  795.   /* filename */
  796.   baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  797.   baseheader = baseheader->next;
  798.   baseheader->size = 5 + header->namelen;
  799.   SetWord(address, baseheader->size);
  800.   address = baseheader->header = (byte *)e_malloc(baseheader->size);
  801.   *address++ = 0x01;
  802.   memcpy(address, header->filename, header->namelen);
  803.   address += header->namelen;
  804.   SetWord(address, 0);
  805.  
  806.   /* directoryname */
  807.   if(header->pathname != header->filename)
  808.     {
  809.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  810.       baseheader = baseheader->next;
  811.       baseheader->size = 5 + header->pathlen - header->namelen;
  812.       SetWord(address, baseheader->size);
  813.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  814.       *address++ = 0x02;
  815.       convdelim(header->pathname, DELIM2);
  816.       memcpy(address, header->pathname, baseheader->size - 5);
  817.       convdelim(header->pathname, DELIM);
  818.       address += baseheader->size - 5;
  819.       SetWord(address, 0);
  820.     }
  821.  
  822.   /* comment (unsupport) */
  823.  
  824.   /* Attribute header */
  825.   baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  826.   baseheader = baseheader->next;
  827.   baseheader->size = 21;
  828.   SetWord(address, baseheader->size);
  829.   address = baseheader->header = (byte *)e_malloc(baseheader->size);
  830.   *address++ = 0x7f;
  831.  
  832.   /* set MS-DOS dependent attribute */
  833.   SetHWord(address, header->mode);
  834.   address += 2;
  835.   /* set UNIX dependent permission */
  836.   unixmode = 0;
  837.   if(header->mode & _A_RDONLY)
  838.     unixmode |= 0000440;    /* -r--r----- */
  839.   else
  840.     unixmode |= 0000660;    /* -rw-rw---- */
  841.   if(header->mode & _A_SUBDIR)
  842.     unixmode |= 0040550;    /* dr-xr-x--- */
  843.   if(header->mode & (_A_HIDDEN | _A_SYSTEM))
  844.     unixmode &= 0177700;    /* ????------ */
  845.   SetHWord(address, unixmode);
  846.   address += 2;
  847. #ifdef __SUPPORT_UID_GID__
  848. #ifndef __OS2__
  849.   SetHWord(address, header->gid);
  850. #else
  851.   SetHWord(address, gid);    /* __OS2__ */
  852. #endif
  853.   address += 2;
  854. #ifndef __OS2__
  855.   SetHWord(address, header->uid);
  856. #else
  857.   SetHWord(address, uid);    /* __OS2__ */
  858. #endif
  859.   address += 2;
  860. #else
  861.   SetHWord(address, 0);
  862.   address += 2;
  863.   SetHWord(address, 0);
  864.   address += 2;
  865. #endif
  866. #ifdef __SUPPORT_CTIME_ATIME__
  867.   SetWord(address, header->ctime);
  868.   address += 4;
  869.   SetWord(address, header->atime);
  870.   address += 4;
  871. #else
  872.   SetWord(address, header->mtime);
  873.   address += 4;
  874.   SetWord(address, header->mtime);
  875.   address += 4;
  876. #endif
  877.   SetWord(address, 0);
  878.   
  879. #ifdef __SUPPORT_EA__
  880. #ifdef __OS2__
  881.   /* EA header sample implememtation */
  882.   if(header->ea)
  883.     {
  884.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  885.       baseheader = baseheader->next;
  886.       baseheader->size = 7 + strlen(EA_CREATOR_OS2) + header->ea->cbList;
  887.       SetWord(address, baseheader->size);
  888.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  889.       *address++ = 0x7e;
  890.       *address++ = __TYPE_EA__;
  891.       *address++ = 0xff & strlen(EA_CREATOR_OS2);
  892.       memcpy(address, EA_CREATOR_OS2, strlen(EA_CREATOR_OS2));
  893.       address += strlen(EA_CREATOR_OS2);
  894.       memcpy(address, header->ea, header->ea->cbList);
  895.       address += header->ea->cbList;
  896.       SetWord(address, 0);
  897.     }
  898. #endif
  899. #endif
  900.  
  901. #ifdef __SUPPORT_KAPSEL__
  902.   /* KAPSEL */
  903.   if(header->filesize)
  904.     {
  905.       baseheader->next = (HEADERLINK *)e_malloc(sizeof(HEADERLINK));
  906.       baseheader = baseheader->next;
  907.       baseheader->size = 13;
  908.       SetWord(address, baseheader->size);
  909.       address = baseheader->header = (byte *)e_malloc(baseheader->size);
  910.       *address++ = 0x7d;
  911.       SetWord(address, header->kapselheadersize);
  912.       address += 4;
  913.       SetWord(address, header->filesize);
  914.       address += 4;
  915.       SetWord(address, 0);
  916.     }
  917. #endif
  918.  
  919.   baseheader->next = (HEADERLINK *)NULL;
  920.  
  921.   return FALSE;
  922. }
  923.  
  924.  
  925. /*
  926.  * level0w --- write level-0 header
  927.  */
  928. static bool
  929. level0w(baseheader, header)
  930.      HEADERLINK *baseheader;
  931.      HEADER *header;
  932. {
  933.   register byte *address;
  934.  
  935.   /* check path length */
  936.   if((uint)header->pathlen > (uint)233) /* 0xff - 0x16 */
  937.     return TRUE;
  938.   address = HDRnamelen(baseheader->header);
  939.   *address++ = 0xff & (uint)header->pathlen;
  940.   strcpy(address, header->pathname);
  941.   convdelim(address, '\\');
  942.   baseheader->size = header->headersize = *HDRsize(baseheader->header) = 
  943.     0x16 + (uint)header->pathlen;
  944.   baseheader->size += 2;
  945.   address += (uint)header->pathlen;
  946.  
  947.   *HDRattribute(baseheader->header) = (byte)(0xff & (uint)header->attr);
  948.   header->dostime.s = *unix2dos(header->mtime);
  949.   SetWord(HDRmtime(baseheader->header), header->dostime.u);
  950.   SetHWord(address, header->filecrc);
  951.  
  952.   return FALSE;
  953. }
  954.  
  955.  
  956. /*
  957.  * level1w --- write level-1 header
  958.  */
  959. static bool
  960. level1w(baseheader, header)
  961.      HEADERLINK *baseheader;
  962.      HEADER *header;
  963. {
  964.   register byte *address;
  965.   register HEADERLINK *tsize = baseheader;
  966.  
  967.   /* check path length */
  968.   address = HDRnamelen(baseheader->header);
  969.   if((uint)header->namelen > (uint)230) /* 0xff - 0x19 */
  970.     {
  971.       /* use extend header */
  972.       *address++ = 0;
  973.       header->needfname = TRUE;
  974.     }
  975.   else
  976.     {
  977.       strcpy(address + 1, header->filename);
  978.       *address++ = 0xff & (uint)header->namelen;
  979.   }
  980.   baseheader->size = *HDRsize(baseheader->header) = 
  981.     0x19 + (uint)header->namelen;
  982.   address += (uint)header->namelen;
  983.  
  984.   header->dostime.s = *unix2dos(header->mtime);
  985.   SetWord(HDRmtime(baseheader->header), header->dostime.u);
  986.   SetHWord(address, header->filecrc);
  987.   *(address + 2) = CREATOR_OS2;
  988.  
  989.   /* make extend header */
  990.   if(makeext(baseheader, header))
  991.     return TRUE;
  992.   if(baseheader->next)
  993.     SetHWord(address + 3, baseheader->next->size);
  994.   else
  995.     SetHWord(address + 3, 0);
  996.  
  997.   /* calculate total header size */
  998.   baseheader->size += 2;
  999.   while(tsize = tsize->next)
  1000.     {
  1001.       header->headersize += tsize->size;
  1002.       if(tsize->next)
  1003.     SetHWord(tsize->header + tsize->size - 2, tsize->next->size);
  1004.     }
  1005.  
  1006.   return FALSE;
  1007. }
  1008.  
  1009.  
  1010. /*
  1011.  * level2w --- write level-2 header
  1012.  */
  1013. static bool
  1014. level2w(baseheader, header)
  1015.      HEADERLINK *baseheader;
  1016.      HEADER *header;
  1017. {
  1018.   register HEADERLINK *tsize = baseheader;
  1019.  
  1020.   SetWord(HDRmtime(baseheader->header), header->mtime);
  1021.   *HDRcreator(baseheader->header) = CREATOR_OS2;
  1022.   SetHWord(HDRcrc(baseheader->header), header->filecrc);
  1023.  
  1024.   /* make extend header */
  1025.   header->needfname = TRUE;
  1026.   if(makeext(baseheader, header))
  1027.     return TRUE;
  1028.   SetHWord(HDRnext(baseheader->header), baseheader->next->size);
  1029.  
  1030.   /* calculate total header size */
  1031.   baseheader->size = header->headersize = 0x1a;    /* base header size */
  1032.   while(tsize = tsize->next)
  1033.     {
  1034.       header->headersize += tsize->size;
  1035.       if(tsize->next)
  1036.     SetHWord(tsize->header + tsize->size - 2, tsize->next->size);
  1037.     }
  1038.   if(header->headersize & 0xffff0000)
  1039.     return TRUE;        /* excced 64K */
  1040.   SetHWord(HDRsize2(baseheader->header), header->headersize);
  1041.  
  1042.   return FALSE;
  1043. }
  1044.  
  1045.  
  1046. /*
  1047.  * level3w --- write level-3 header
  1048.  */
  1049. static bool
  1050. level3w(baseheader, header)
  1051.      HEADERLINK *baseheader;
  1052.      HEADER *header;
  1053. {
  1054.   register HEADERLINK *tsize = baseheader;
  1055.  
  1056.   SetHWord(HDRsize2(baseheader->header), 0x0004);
  1057.   SetWord(HDRmtime(baseheader->header), header->mtime);
  1058.   *HDRcreator(baseheader->header) = CREATOR_OS2;
  1059.   SetHWord(HDRcrc(baseheader->header), header->filecrc);
  1060.  
  1061.   /* make extend header */
  1062.   if(makeext3(baseheader, header))
  1063.     return TRUE;
  1064.   SetWord(HDRnext3(baseheader->header), baseheader->next->size);
  1065.  
  1066.   /* calculate total header size */
  1067.   baseheader->size = header->headersize = 0x20;    /* base header size */
  1068.   while(tsize = tsize->next)
  1069.     header->headersize += tsize->size;
  1070.   SetWord(HDRsize3(baseheader->header), header->headersize);
  1071.  
  1072.   return FALSE;
  1073. }
  1074.  
  1075.  
  1076. /*
  1077.  * makehdr --- make LHA header
  1078.  */
  1079. HEADERLINK *
  1080. makehdr(header)
  1081.      HEADER *header;
  1082. {
  1083.   static HEADERLINK baseheader;
  1084.   static byte buffer[257];
  1085.   static bool (*encodeheader[4])() = {level0w, level1w, level2w, level3w};
  1086.  
  1087.   /* initialize */
  1088.   baseheader.header = &buffer[0];
  1089.   header->needfname = FALSE;
  1090.   header->crcpos = FALSE;
  1091.  
  1092.   /* common part */
  1093.   memcpy(HDRmethod(baseheader.header), header->method, 5);
  1094.   header->skip = header->packed;
  1095.   header->headersize = 0;
  1096.   SetWord(HDRpacked(baseheader.header), header->packed);
  1097.   SetWord(HDRoriginal(baseheader.header), header->original);
  1098.   *HDRattribute(baseheader.header) = 0x20;
  1099.   *HDRlevel(baseheader.header) = 0xff & header->level;
  1100.   if(header->level > (uint)3)
  1101.     return (HEADERLINK *)NULL;
  1102.  
  1103.   /* switch header level */
  1104.   if((*encodeheader[header->level])(&baseheader, header))
  1105.     return (HEADERLINK *)NULL;
  1106.  
  1107.   return &baseheader;
  1108. }
  1109.  
  1110.  
  1111. /*
  1112.  * writehdr --- write header to disk
  1113.  */
  1114. bool
  1115. writehdr(fp, baseheader, header)
  1116.      FILE *fp;
  1117.      HEADERLINK *baseheader;
  1118.      HEADER *header;
  1119. {
  1120.   header->dummy = 0xff;
  1121.   header->currentpos = ftell(fp);
  1122.   if(!(header->headersize & 0xff) && (header->level == 2))
  1123.     {
  1124.       header->dummy = 0x00;
  1125.       header->headersize++;
  1126.       SetHWord(HDRsize2(baseheader->header), header->headersize);
  1127.     }
  1128.  
  1129.   do
  1130.     {
  1131.       if(!fwrite(baseheader->header, baseheader->size, 1, fp))
  1132.     return TRUE;
  1133.     }
  1134.   while(baseheader = baseheader->next);
  1135.  
  1136.   if(!header->dummy)
  1137.     if(!fwrite(&(header->dummy), 1, 1, fp))
  1138.       return TRUE;
  1139.  
  1140.   return FALSE;
  1141. }
  1142.  
  1143.  
  1144. /*
  1145.  * copyhdr --- copy header
  1146.  */
  1147. bool
  1148. copyhdr(fps, fpd, header)
  1149.      FILE *fps;
  1150.      FILE *fpd;
  1151.      HEADER *header;
  1152. {
  1153.   off_t src = ftell(fps);
  1154.   byte *buffer;
  1155.  
  1156.   fseek(fps, src - header->offset, SEEK_SET);
  1157.   header->currentpos = ftell(fpd);
  1158.  
  1159.   buffer = (byte *)e_malloc(header->offset);
  1160.   fread(buffer, 1, header->offset, fps);
  1161.   fwrite(buffer, 1, header->offset, fpd);
  1162.   free(buffer);
  1163.   
  1164.   if(ftell(fps) != src)
  1165.     {
  1166.       fseek(fps, src, SEEK_SET);
  1167.  
  1168.       return TRUE;
  1169.     }
  1170.  
  1171.   return FALSE;
  1172. }
  1173.  
  1174.  
  1175. /*
  1176.  * adjusthdr --- adjust header
  1177.  */
  1178. bool
  1179. adjusthdr(fp, baseheader, header)
  1180.      FILE *fp;
  1181.      HEADERLINK *baseheader;
  1182.      HEADER *header;
  1183. {
  1184.   byte *address;
  1185.   HEADERLINK *save = (HEADERLINK *)NULL, *prev;
  1186.   hword hcrc;
  1187.   off_t wcrcpos = 0;
  1188.  
  1189.   off_t current = ftell(fp);
  1190.  
  1191.   fseek(fp, header->currentpos, SEEK_SET);
  1192.   if(header->level == 1)
  1193.     {
  1194.       header->skip = header->headersize + header->packed;
  1195.       SetWord(HDRpacked(baseheader->header), header->skip);
  1196.     }
  1197.   else
  1198.     SetWord(HDRpacked(baseheader->header), header->packed);
  1199.  
  1200.   address = HDRnamelen(baseheader->header);
  1201.   if((uint)header->level <= (uint)1)
  1202.     address += (0xff & (uint)*address) + 1;
  1203.   SetHWord(address, header->filecrc);
  1204.   memcpy(HDRmethod(baseheader->header), header->method, 5);
  1205.   if((uint)header->level <= (uint)1)
  1206.     *HDRsum(baseheader->header) = calcsum(baseheader->header);
  1207.   fwrite(baseheader->header, baseheader->size, 1, fp);
  1208.  
  1209.   if(header->crcpos)
  1210.     {
  1211.       hcrc = calccrc(baseheader->header, baseheader->size, 0);
  1212.       baseheader = baseheader->next;
  1213.       do
  1214.     {
  1215.       hcrc = calccrc(baseheader->header, baseheader->size, hcrc);
  1216.       prev = baseheader;
  1217.       baseheader = baseheader->next;
  1218.       if(*(prev->header) == 0x00) /* common header */
  1219.         save = prev;
  1220.       else
  1221.         {
  1222.           if(!save)
  1223.         wcrcpos += prev->size;
  1224.           free(prev);
  1225.         }
  1226.     }
  1227.       while(baseheader);
  1228.  
  1229.       if(!header->dummy)
  1230.     hcrc = calccrc(&(header->dummy), 1, hcrc);
  1231.       SetHWord(save->header + 1, hcrc);
  1232.       fseek(fp, wcrcpos, SEEK_CUR);
  1233.       fwrite(save->header, save->size, 1, fp);
  1234.       free(save);
  1235.     }
  1236.   fseek(fp, current, SEEK_SET);
  1237.  
  1238.   return TRUE;
  1239. }
  1240.