home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #3 / amigamamagazinepolishissue1998.iso / ppc / lha_ppc / src / header.c < prev    next >
C/C++ Source or Header  |  1997-12-04  |  19KB  |  767 lines

  1. /*----------------------------------------------------------------------*/
  2. /*    header.c (from lharc.c)    -- header manipulate functions        */
  3. /*    Original                    by Y.Tagawa    */
  4. /*    modified  Dec 16 1991                by M.Oki    */
  5. /*----------------------------------------------------------------------*/
  6.  
  7. #include "lharc.h"
  8. extern int header_level;
  9.  
  10. int
  11. calc_sum (p, len)
  12.      register char *p;
  13.      register int len;
  14. {
  15.   register int sum;
  16.  
  17.   for (sum = 0; len; len --)
  18.     sum += *p++;
  19.  
  20.   return sum & 0xff;
  21. }
  22.  
  23. static char *get_ptr;
  24. #define setup_get(PTR)        (get_ptr = (PTR))
  25. #define get_byte()        (*get_ptr++ & 0xff)
  26. #define put_ptr            get_ptr
  27. #define setup_put(PTR)        (put_ptr = (PTR))
  28. #define put_byte(c)        (*put_ptr++ = (char)(c))
  29.  
  30. static unsigned short get_word(void)
  31. {
  32.   int b0, b1;
  33.  
  34.   b0 = get_byte();
  35.   b1 = get_byte();
  36.   return (unsigned short)((b1 << 8) + b0);
  37. }
  38.  
  39. static void put_word(unsigned int v)
  40. {
  41.   put_byte (v);
  42.   put_byte (v >> 8);
  43. }
  44.  
  45. static long get_longword(void)
  46. {
  47.   long b0, b1, b2, b3;
  48.  
  49.   b0 = get_byte ();
  50.   b1 = get_byte ();
  51.   b2 = get_byte ();
  52.   b3 = get_byte ();
  53.   return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  54. }
  55.  
  56. static void put_longword(long v)
  57. {
  58.   put_byte (v);
  59.   put_byte (v >> 8);
  60.   put_byte (v >> 16);
  61.   put_byte (v >> 24);
  62. }
  63.  
  64.  
  65. static void msdos_to_unix_filename(char *name, int len)
  66. {
  67.   register int i;
  68.  
  69. #ifdef MULTIBYTE_CHAR
  70.   for (i = 0; i < len; i ++)
  71.     {
  72.       if (MULTIBYTE_FIRST_P (name[i]) &&
  73.       MULTIBYTE_SECOND_P (name[i+1]))
  74.     i ++;
  75.       else if (name[i] == '\\')
  76.     name[i] = '/';
  77.       else if (isupper (name[i]))
  78.     name[i] = tolower (name[i]);
  79.     }
  80. #else
  81.   for (i = 0; i < len; i ++)
  82.     {
  83.       if (name[i] == '\\')
  84.     name[i] = '/';
  85.       else if (isupper (name[i]))
  86.     name[i] = tolower (name[i]);
  87.     }
  88. #endif
  89. }
  90.  
  91. static void generic_to_unix_filename(char *name, int len)
  92. {
  93.   register int i;
  94.   boolean lower_case_used = FALSE;
  95.  
  96. #ifdef MULTIBYTE_CHAR
  97.   for (i = 0; i < len; i ++)
  98.     {
  99.       if (MULTIBYTE_FIRST_P (name[i]) &&
  100.           MULTIBYTE_SECOND_P (name[i+1]))
  101.         i ++;
  102.       else if (islower (name[i]))
  103.         {
  104.           lower_case_used = TRUE;
  105.           break;
  106.         }
  107.     }
  108.   for (i = 0; i < len; i ++)
  109.     {
  110.       if (MULTIBYTE_FIRST_P (name[i]) &&
  111.           MULTIBYTE_SECOND_P (name[i+1]))
  112.         i ++;
  113.       else if (name[i] == '\\')
  114.         name[i] = '/';
  115.       else if (!lower_case_used && isupper (name[i]))
  116.         name[i] = tolower (name[i]);
  117.     }
  118. #else
  119.   for (i = 0; i < len; i ++)
  120.     if (islower (name[i]))
  121.       {
  122.         lower_case_used = TRUE;
  123.         break;
  124.       }
  125.   for (i = 0; i < len; i ++)
  126.     {
  127.       if (name[i] == '\\')
  128.         name[i] = '/';
  129.       else if (!lower_case_used && isupper (name[i]))
  130.         name[i] = tolower (name[i]);
  131.     }
  132. #endif
  133. }
  134.  
  135. static void macos_to_unix_filename(char *name, int len)
  136. {
  137.   register int i;
  138.  
  139.   for (i = 0; i < len; i ++)
  140.     {
  141.       if (name[i] == ':')
  142.     name[i] = '/';
  143.       else if (name[i] == '/')
  144.     name[i] = ':';
  145.     }
  146. }
  147.  
  148. static void unix_to_generic_filename(char *name, int len)
  149. {
  150.   register int i;
  151.  
  152.   for (i = 0; i < len; i ++)
  153.     {
  154.       if (name[i] == '/')
  155.         name[i] = '\\';
  156.       else if (islower (name[i]))
  157.         name[i] = toupper (name[i]);
  158.     }
  159. }
  160.  
  161. /*----------------------------------------------------------------------*/
  162. /*                                    */
  163. /*    Generic stamp format:                        */
  164. /*                                    */
  165. /*     31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16        */
  166. /*    |<-------- year ------->|<- month ->|<-- day -->|        */
  167. /*                                    */
  168. /*     15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0        */
  169. /*    |<--- hour --->|<---- minute --->|<- second*2 ->|        */
  170. /*                                    */
  171. /*----------------------------------------------------------------------*/
  172.  
  173. /* NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
  174.    returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or
  175.    TZSET. */
  176.  
  177. /* choose one */
  178. #if defined(MKTIME)
  179. #ifdef TIMELOCAL
  180. #undef TIMELOCAL
  181. #endif
  182. #endif /* defined(MKTIME) */
  183.  
  184. #if defined(MKTIME) || defined(TIMELOCAL)
  185. #ifdef TZSET
  186. #undef TZSET
  187. #endif
  188. #endif /* defined(MKTIME) || defined(TIMELOCAL) */
  189.  
  190. #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET)
  191. #ifdef FTIME
  192. #undef FTIME
  193. #endif
  194. #endif
  195.  
  196. #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET) || defined(FTIME)
  197. #ifdef GETTIMEOFDAY
  198. #undef GETTIMEOFDAY
  199. #endif
  200. #else
  201. #ifndef GETTIMEOFDAY
  202. #define GETTIMEOFDAY    /* use gettimeofday() */
  203. #endif
  204. #endif
  205.  
  206. #ifdef FTIME
  207. #include <sys/timeb.h>
  208. #endif
  209.  
  210. /* You may define as : 
  211.     #define TIMEZONE_HOOK        \
  212.         extern long timezone ;    \
  213.         extern void tzset();
  214. */
  215. #ifdef TIMEZONE_HOOK
  216. TIMEZONE_HOOK
  217. /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
  218. #endif
  219.  
  220. #if defined(TZSET) && defined(_MINIX)
  221. extern long timezone;    /* not defined in time.h */
  222. #endif
  223.  
  224. #if defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET)
  225. static long gettz(void)
  226. #ifdef TZSET
  227. {
  228.    tzset();
  229.    return timezone;
  230. }
  231. #endif
  232. #if !defined(TZSET) && defined(FTIME)
  233. {
  234.    struct timeb buf;
  235.  
  236.    ftime(&buf);
  237.    return buf.timezone * 60L;
  238. }
  239. #endif
  240. #if !defined(TZSET) && !defined(FTIME) /* maybe defined(GETTIMEOFDAY) */
  241. {
  242.    struct timeval tp;
  243.    struct timezone tzp;
  244.    gettimeofday (&tp, &tzp);    /* specific to 4.3BSD */
  245. /* return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L * 60L : 0));*/
  246.    return (tzp.tz_minuteswest * 60L);
  247. }
  248. #endif
  249. #endif /* defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET) */
  250.  
  251. #ifdef NOT_USED
  252. static struct tm *msdos_to_unix_stamp_tm(long a)
  253. {
  254.   static struct tm t;
  255.  
  256.   t.tm_sec    = ( a          & 0x1f) * 2;
  257.   t.tm_min    =  (a >>    5) & 0x3f;
  258.   t.tm_hour    =  (a >>   11) & 0x1f;
  259.   t.tm_mday    =  (a >>   16) & 0x1f;
  260.   t.tm_mon    = ((a >> 16+5) & 0x0f) - 1;
  261.   t.tm_year    = ((a >> 16+9) & 0x7f) + 80;
  262.   return &t;
  263. }
  264. #endif
  265.  
  266. static time_t generic_to_unix_stamp(long t)
  267. #if defined(MKTIME) || defined(TIMELOCAL)
  268. {
  269.   struct tm dostm;
  270.  
  271.   /* special case:  if MSDOS format date and time were zero, then we set
  272.      time to be zero here too. */
  273.   if (t == 0)
  274.     return (time_t)0;
  275.  
  276.   dostm.tm_sec     = (t         & 0x1f) * 2;
  277.   dostm.tm_min     =  t >> 5    & 0x3f;
  278.   dostm.tm_hour     =  t >> 11   & 0x1f;
  279.   dostm.tm_mday     =  t >> 16   & 0x1f;
  280.   dostm.tm_mon     = (t >> 16+5 & 0x0f) - 1;    /* 0..11 */
  281.   dostm.tm_year     = (t >> 16+9 & 0x7f) + 80;
  282.   dostm.tm_isdst = 0;                /* correct? */
  283. #ifdef MKTIME
  284.   return (time_t)mktime(&dostm);
  285. #else /* maybe defined(TIMELOCAL) */
  286.   return (time_t)timelocal(&dostm);
  287. #endif
  288. }
  289. #else /* defined(MKTIME) || defined(TIMELOCAL) */
  290. {
  291.   int year, month, day, hour, min, sec;
  292.   long longtime;
  293.   static unsigned int dsboy[12] = { 0, 31, 59, 90, 120, 151,
  294.                       181, 212, 243, 273, 304, 334};
  295.   unsigned int days;
  296.  
  297.   /* special case:  if MSDOS format date and time were zero, then we set
  298.      time to be zero here too. */
  299.   if (t == 0)
  300.     return (time_t)0;
  301.  
  302.   year  = ((int)(t >> 16+9) & 0x7f) + 1980;
  303.   month =  (int)(t >> 16+5) & 0x0f;    /* 1..12 means Jan..Dec */
  304.   day   =  (int)(t >> 16)   & 0x1f;    /* 1..31 means 1st,...31st */
  305.  
  306.   hour  =  ((int)t >> 11) & 0x1f;
  307.   min   =  ((int)t >> 5)  & 0x3f;
  308.   sec   = ((int)t         & 0x1f) * 2;
  309.  
  310.                 /* Calculate days since 1970.01.01 */
  311.   days = (365 * (year - 1970) + /* days due to whole years */
  312.       (year - 1970 + 1) / 4 + /* days due to leap years */
  313.       dsboy[month-1] +    /* days since beginning of this year */
  314.       day-1);        /* days since beginning of month */
  315.  
  316.   if ((year % 4 == 0) &&
  317.       (year % 400 != 0) &&
  318.       (month >= 3))        /* if this is a leap year and month */
  319.     days ++;            /* is March or later, add a day */
  320.  
  321.   /* Knowing the days, we can find seconds */
  322.   longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
  323.   longtime += gettz ();      /* adjust for timezone */
  324.  
  325.   /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00.  */
  326.   return (time_t)longtime;
  327. }
  328. #endif /* defined(MKTIME) || defined(TIMELOCAL) */
  329.  
  330. static long unix_to_generic_stamp(time_t t)
  331. {
  332.   struct tm *tm = localtime (&t);
  333.  
  334.   return ((((long)(tm->tm_year - 80)) << 25) +
  335.       (((long)(tm->tm_mon + 1)) << 21) +
  336.       (((long)tm->tm_mday) << 16) +
  337.       (long)((tm->tm_hour << 11) +
  338.          (tm->tm_min << 5) +
  339.          (tm->tm_sec / 2)));
  340. }
  341.  
  342. /*----------------------------------------------------------------------*/
  343. /*            build header functions                */
  344. /*----------------------------------------------------------------------*/
  345.  
  346. boolean
  347. get_header (fp, hdr)
  348.      FILE *fp;
  349.      register LzHeader *hdr;
  350. {
  351.   int header_size;
  352.   int name_length;
  353.   char data[LZHEADER_STRAGE];
  354.   char dirname[FILENAME_LENGTH];
  355.   int dir_length = 0;
  356.   int checksum;
  357.   int i;
  358.   char *ptr;
  359.  
  360.   bzero (hdr, sizeof (LzHeader));
  361.  
  362.   if (((header_size = getc (fp)) == EOF) || (header_size == 0))
  363.     {
  364.       return FALSE;        /* finish */
  365.     }
  366.  
  367.   if (fread (data + I_HEADER_CHECKSUM,
  368.           sizeof (char), header_size - 1, fp) < header_size - 1)
  369.     {
  370.       fatal_error ("Invalid header (LHarc file ?)");
  371.       return FALSE;        /* finish */
  372.     }
  373.   setup_get(data + I_HEADER_LEVEL);
  374.   hdr->header_level = get_byte();
  375.   if (hdr->header_level != 2 &&
  376.       fread (data + header_size, sizeof (char), 2, fp) < 2)
  377.     {
  378.       fatal_error ("Invalid header (LHarc file ?)");
  379.       return FALSE;        /* finish */
  380.     }
  381.  
  382.   setup_get (data + I_HEADER_CHECKSUM);
  383.   checksum = get_byte();
  384.  
  385.   hdr->header_size = header_size;
  386.   bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  387. #ifdef OLD
  388.   if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  389.       (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  390.       (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  391.       (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0))
  392.     {
  393.       warning ("Unknown method (LHarc file ?)", "");
  394.       return FALSE;        /* invalid method */
  395.     }
  396. #endif
  397.   setup_get (data + I_PACKED_SIZE);
  398.   hdr->packed_size    = get_longword ();
  399.   hdr->original_size    = get_longword ();
  400.   hdr->last_modified_stamp = get_longword ();
  401.   hdr->attribute    = get_byte ();
  402.  
  403.   if ((hdr->header_level = get_byte ()) != 2) {
  404.     if (calc_sum (data + I_METHOD, header_size) != checksum)
  405.       warning ("Checksum error (LHarc file?)", "");
  406.     name_length    = get_byte ();
  407.     for (i = 0; i < name_length; i ++)
  408.       hdr->name[i] =(char)get_byte ();
  409.     hdr->name[name_length] = '\0';
  410.   } else {
  411.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  412.     name_length = 0;
  413.   }
  414.  
  415.   /* defaults for other type */
  416.   hdr->unix_mode    = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
  417.   hdr->unix_gid     = 0;
  418.   hdr->unix_uid        = 0;
  419.  
  420.   if (header_size - name_length >= 24)
  421.     {                /* EXTEND FORMAT */
  422.       hdr->crc                = get_word ();
  423.       hdr->extend_type            = get_byte ();
  424.       hdr->has_crc = TRUE;
  425.     }
  426.   else if (header_size - name_length == 22)
  427.     {                /* Generic with CRC */
  428.       hdr->crc                = get_word ();
  429.       hdr->extend_type            = EXTEND_GENERIC;
  430.       hdr->has_crc = TRUE;
  431.     }
  432.   else if (header_size - name_length == 20)
  433.     {                /* Generic no CRC */
  434.       hdr->extend_type            = EXTEND_GENERIC;
  435.       hdr->has_crc = FALSE;
  436.     }
  437.   else
  438.     {
  439.       warning ("Unknown header (LHarc file ?)", "");
  440.       return FALSE;
  441.     }
  442.  
  443.   if (hdr->extend_type == EXTEND_UNIX && hdr->header_level == 0)
  444.     {
  445.       hdr->minor_version        = get_byte ();
  446.       hdr->unix_last_modified_stamp    = (time_t)get_longword ();
  447.       hdr->unix_mode            = get_word ();
  448.       hdr->unix_uid            = get_word ();
  449.       hdr->unix_gid            = get_word ();
  450.       return TRUE;
  451.     }
  452.  
  453.   if (hdr->header_level > 0) {
  454.     /* Extend Header */
  455.     if (hdr->header_level != 2) setup_get(data + hdr->header_size);
  456.     ptr = get_ptr;
  457.     while((header_size = get_word()) != 0)
  458.       {
  459.     if (hdr->header_level != 2 &&
  460.         ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
  461.          fread(get_ptr, sizeof(char), header_size, fp) < header_size))
  462.       {
  463.         fatal_error ("Invalid header (LHa file ?)");
  464.         return FALSE;
  465.       }
  466.     switch (get_byte()) {
  467.     case 0:
  468.       /*
  469.        * header crc
  470.        */
  471.       setup_get(get_ptr + header_size - 3);
  472.       break;
  473.     case 1:
  474.       /*
  475.        * filename
  476.        */
  477.       for (i = 0; i < header_size - 3; i++)
  478.         hdr->name[i] =(char)get_byte ();
  479.       hdr->name[header_size - 3] = '\0';
  480.       break;
  481.     case 2:
  482.       /*
  483.        * directory
  484.        */
  485.       for (i = 0; i < header_size - 3; i++)
  486.         dirname[i] = (char)get_byte ();
  487.       dirname[header_size - 3] = '\0';
  488.       convdelim(dirname, DELIM);
  489.       dir_length = header_size-3;
  490.       break;
  491.     case 0x40:
  492.       /*
  493.        * MS-DOS attribute
  494.        */
  495.       if (hdr->extend_type == EXTEND_MSDOS ||
  496.           hdr->extend_type == EXTEND_HUMAN ||
  497.           hdr->extend_type == EXTEND_GENERIC)
  498.         hdr->attribute = get_word();
  499.       break;
  500.     case 0x50:
  501.       /*
  502.        * UNIX permission
  503.        */
  504.       if (hdr->extend_type == EXTEND_UNIX)
  505.         hdr->unix_mode = get_word();
  506.       break;
  507.     case 0x51:
  508.       /*
  509.        * UNIX gid and uid
  510.        */
  511.       if (hdr->extend_type == EXTEND_UNIX)
  512.         {
  513.           hdr->unix_gid = get_word();
  514.           hdr->unix_uid = get_word();
  515.         }
  516.       break;
  517.     case 0x52:
  518.       /*
  519.        * UNIX group name
  520.        */
  521.       setup_get(get_ptr + header_size - 3);
  522.       break;
  523.     case 0x53:
  524.       /*
  525.        * UNIX user name
  526.        */
  527.       setup_get(get_ptr + header_size - 3);
  528.       break;
  529.     case 0x54:
  530.       /*
  531.        * UNIX last modified time
  532.        */
  533.       if (hdr->extend_type == EXTEND_UNIX)
  534.         hdr->unix_last_modified_stamp = (time_t)get_longword();
  535.       break;
  536.     default:
  537.       /*
  538.        * other headers
  539.        */
  540.       setup_get(get_ptr + header_size - 3);
  541.       break;
  542.     }
  543.       }
  544.     if (hdr->header_level != 2 && get_ptr - ptr != 2) {
  545.       hdr->packed_size -= get_ptr - ptr - 2;
  546.       hdr->header_size += get_ptr - ptr - 2;
  547.     }
  548.   }
  549.   if (dir_length)
  550.     {
  551.       strcat(dirname, hdr->name);
  552.       strcpy(hdr->name, dirname);
  553.       name_length += dir_length;
  554.     }
  555.  
  556.   switch (hdr->extend_type)
  557.     {
  558.     case EXTEND_MSDOS:
  559.       msdos_to_unix_filename (hdr->name, name_length);
  560.     case EXTEND_HUMAN:
  561.       if (hdr->header_level == 2)
  562.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  563.       else
  564.     hdr->unix_last_modified_stamp    =
  565.       generic_to_unix_stamp (hdr->last_modified_stamp);
  566.       break;
  567.  
  568. #ifdef OSK
  569.     case EXTEND_OS68K:
  570.     case EXTEND_XOSK:
  571. #endif
  572.     case EXTEND_UNIX:
  573.       break;
  574.  
  575.     case EXTEND_MACOS:
  576.       macos_to_unix_filename (hdr->name, name_length);
  577.       hdr->unix_last_modified_stamp    =
  578.         generic_to_unix_stamp (hdr->last_modified_stamp);
  579.       break;
  580.  
  581.     default:
  582.       generic_to_unix_filename (hdr->name, name_length);
  583.       if (hdr->header_level == 2)
  584.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  585.       else
  586.     hdr->unix_last_modified_stamp    =
  587.       generic_to_unix_stamp (hdr->last_modified_stamp);
  588.     }
  589.  
  590.   return TRUE;
  591. }
  592.  
  593. void
  594. init_header (name, v_stat, hdr)
  595.      char *name;
  596.      struct stat *v_stat;
  597.      LzHeader *hdr;
  598. {
  599.   int len;
  600.  
  601.   if ( compress_method == 5 )
  602.           bcopy (LZHUFF5_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  603.   else if ( compress_method )
  604.           bcopy (LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  605.   else
  606.         bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  607.  
  608.   hdr->packed_size        = 0;
  609.   hdr->original_size        = v_stat->st_size;
  610.   hdr->last_modified_stamp    = unix_to_generic_stamp (v_stat->st_mtime);
  611.   hdr->attribute        = GENERIC_ATTRIBUTE;
  612.   hdr->header_level        = header_level;
  613.   strcpy (hdr->name, name);
  614.   len = strlen (name);
  615.   hdr->crc            = 0x0000;
  616.   hdr->extend_type        = EXTEND_UNIX;
  617.   hdr->unix_last_modified_stamp    = v_stat->st_mtime;
  618.                 /* since 00:00:00 JAN.1.1970 */
  619. #ifdef NOT_COMPATIBLE_MODE
  620. /*  Please need your modification in this space. */
  621. #else
  622.   hdr->unix_mode        = v_stat->st_mode;
  623. #endif
  624.  
  625.   hdr->unix_uid            = v_stat->st_uid;
  626.   hdr->unix_gid            = v_stat->st_gid;
  627.  
  628.   if (is_directory (v_stat))
  629.     {
  630.       bcopy (LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  631.       hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
  632.       hdr->original_size = 0;
  633.       if (len > 0 && hdr->name[len-1] != '/')
  634.         strcpy (&hdr->name[len++], "/");
  635.     }
  636.   if (generic_format)
  637.     unix_to_generic_filename (hdr->name, len);
  638. }
  639.  
  640. /* Write unix extended header or generic header. */
  641. void write_header(FILE *nafp, LzHeader *hdr)
  642. {
  643.   int header_size = 0;
  644.   int name_length = 0;
  645.   char data[LZHEADER_STRAGE];
  646.   char *p;
  647.  
  648.   bzero (data, LZHEADER_STRAGE);
  649.   bcopy (hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
  650.   setup_put (data + I_PACKED_SIZE);
  651.   put_longword (hdr->packed_size);
  652.   put_longword (hdr->original_size);
  653.  
  654.   if (hdr->header_level == HEADER_LEVEL2)
  655.       put_longword ((long)hdr->unix_last_modified_stamp);
  656.   else
  657.       put_longword (hdr->last_modified_stamp);
  658.  
  659.   switch (hdr->header_level)
  660.     {
  661.     case HEADER_LEVEL0:
  662.       put_byte (hdr->attribute);
  663.       break;
  664.     case HEADER_LEVEL1:
  665.     case HEADER_LEVEL2:
  666.       put_byte (0x20);
  667.       break;
  668.     }
  669.  
  670.   put_byte(hdr->header_level);
  671.  
  672.   convdelim(hdr->name, DELIM2);
  673.   if (hdr->header_level != HEADER_LEVEL2)
  674.     {
  675.       if (p = (char *)rindex(hdr->name, DELIM2))
  676.     name_length = strlen(++p);
  677.       else
  678.     name_length = strlen(hdr->name);
  679.       put_byte (name_length);
  680.       bcopy (p ? p : hdr->name, data + I_NAME, name_length);
  681.       setup_put (data + I_NAME + name_length);
  682.     }
  683.  
  684.   put_word (hdr->crc);
  685.   if (generic_format)
  686.     {
  687.       header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
  688.       data[I_HEADER_SIZE] = header_size;
  689.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  690.     }
  691.   else if (header_level == HEADER_LEVEL0)
  692.     {
  693.       /* write old-style extend header */
  694.       put_byte (EXTEND_UNIX);
  695.       put_byte (CURRENT_UNIX_MINOR_VERSION);
  696.       put_longword ((long)hdr->unix_last_modified_stamp);
  697.       put_word (hdr->unix_mode);
  698.       put_word (hdr->unix_uid);
  699.       put_word (hdr->unix_gid);
  700.       header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
  701.       data[I_HEADER_SIZE] = header_size;
  702.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  703.     }
  704.   else
  705.     {
  706.       /* write extend header. */
  707.       char *ptr;
  708.       put_byte (EXTEND_UNIX);
  709.       ptr = put_ptr;
  710.       put_word(5);
  711.       if (hdr->header_level == HEADER_LEVEL1)
  712.     header_size = put_ptr - data - 2;
  713.       put_byte(0x50);        /* permission */
  714.       put_word(hdr->unix_mode);
  715.       put_word(7);
  716.       put_byte(0x51);        /* gid and uid */
  717.       put_word(hdr->unix_gid);
  718.       put_word(hdr->unix_uid);
  719.       if (p = (char *)rindex(hdr->name, DELIM2))
  720.     {
  721.       int i;
  722.       name_length = p - hdr->name + 1;
  723.       put_word(name_length + 3);
  724.       put_byte(2);        /* dirname */
  725.       for (i = 0; i < name_length; i++)
  726.         put_byte(hdr->name[i]);
  727.     }
  728.       if (header_level != HEADER_LEVEL2)
  729.     {
  730.       put_word(7);
  731.       put_byte(0x54);    /* time stamp */
  732.       put_longword(hdr->unix_last_modified_stamp);
  733.       hdr->packed_size += put_ptr - ptr;
  734.       ptr = put_ptr;
  735.       setup_put (data + I_PACKED_SIZE);
  736.       put_longword (hdr->packed_size);
  737.       put_ptr = ptr;
  738.       data[I_HEADER_SIZE] = header_size;
  739.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  740.     }
  741.       else
  742.     {
  743.       int i;
  744.       if (p = (char *)rindex(hdr->name, DELIM2))
  745.         name_length = strlen(++p);
  746.       else
  747.         {
  748.           p = hdr->name;
  749.           name_length = strlen(hdr->name);
  750.         }
  751.       put_word(name_length + 3);
  752.       put_byte(1);        /* filename */
  753.       for (i = 0; i < name_length; i++)
  754.         put_byte(*p++);
  755.     }
  756.       header_size = put_ptr - data;
  757.     }
  758.   if (header_level == HEADER_LEVEL2)
  759.     {
  760.       setup_put(data + I_HEADER_SIZE);
  761.       put_word(header_size + 2);
  762.     }
  763.   if (fwrite (data, sizeof (char), header_size + 2, nafp) == 0)
  764.     fatal_error ("Cannot write to temporary file");
  765.   convdelim(hdr->name, DELIM);
  766. }
  767.