* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / Compat.ICSharpCode.SharpZipLib / ICSharpCode.SharpZipLib / Tar / TarHeader.cs
1 // TarHeader.cs\r
2 //\r
3 // Copyright (C) 2001 Mike Krueger\r
4 //\r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software\r
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
18 //\r
19 // Linking this library statically or dynamically with other modules is\r
20 // making a combined work based on this library.  Thus, the terms and\r
21 // conditions of the GNU General Public License cover the whole\r
22 // combination.\r
23 // \r
24 // As a special exception, the copyright holders of this library give you\r
25 // permission to link this library with independent modules to produce an\r
26 // executable, regardless of the license terms of these independent\r
27 // modules, and to copy and distribute the resulting executable under\r
28 // terms of your choice, provided that you also meet, for each linked\r
29 // independent module, the terms and conditions of the license of that\r
30 // module.  An independent module is a module which is not derived from\r
31 // or based on this library.  If you modify this library, you may extend\r
32 // this exception to your version of the library, but you are not\r
33 // obligated to do so.  If you do not wish to do so, delete this\r
34 // exception statement from your version.\r
35 \r
36 \r
37 /* The tar format and its POSIX successor PAX have a long history which makes for compatability\r
38    issues when creating and reading files...\r
39   \r
40 This is the ustar (Posix 1003.1) header.\r
41 \r
42 struct header \r
43 {\r
44    char t_name[100];          //   0 Filename               \r
45    char t_mode[8];            // 100 Permissions            \r
46    char t_uid[8];             // 108 Numerical User ID      \r
47    char t_gid[8];             // 116 Numerical Group ID     \r
48    char t_size[12];           // 124 Filesize               \r
49    char t_mtime[12];          // 136 st_mtime               \r
50    char t_chksum[8];          // 148 Checksum               \r
51    char t_typeflag;           // 156 Type of File            \r
52    char t_linkname[100];      // 157 Target of Links        \r
53    char t_magic[6];           // 257 "ustar"                \r
54    char t_version[2];         // 263 Version fixed to 00   \r
55    char t_uname[32];          // 265 User Name              \r
56    char t_gname[32];          // 297 Group Name             \r
57    char t_devmajor[8];        // 329 Major for devices      \r
58    char t_devminor[8];        // 337 Minor for devices      \r
59    char t_prefix[155];        // 345 Prefix for t_name      \r
60                               // 500 End                    \r
61    char t_mfill[12];          // 500 Filler up to 512       \r
62 };\r
63 \r
64 */\r
65 \r
66 using System;\r
67 using System.Text;\r
68 \r
69 namespace ICSharpCode.SharpZipLib.Tar \r
70 {\r
71         \r
72         \r
73         /// <summary>\r
74         /// This class encapsulates the Tar Entry Header used in Tar Archives.\r
75         /// The class also holds a number of tar constants, used mostly in headers.\r
76         /// </summary>\r
77         public class TarHeader : ICloneable\r
78         {\r
79                 /// <summary>\r
80                 /// The length of the name field in a header buffer.\r
81                 /// </summary>\r
82                 public readonly static int NAMELEN = 100;\r
83                 \r
84                 /// <summary>\r
85                 /// The length of the mode field in a header buffer.\r
86                 /// </summary>\r
87                 public readonly static int MODELEN = 8;\r
88                 \r
89                 /// <summary>\r
90                 /// The length of the user id field in a header buffer.\r
91                 /// </summary>\r
92                 public readonly static int UIDLEN = 8;\r
93                 \r
94                 /// <summary>\r
95                 /// The length of the group id field in a header buffer.\r
96                 /// </summary>\r
97                 public readonly static int GIDLEN = 8;\r
98                 \r
99                 /// <summary>\r
100                 /// The length of the checksum field in a header buffer.\r
101                 /// </summary>\r
102                 public readonly static int CHKSUMLEN = 8;\r
103                 \r
104                 /// <summary>\r
105                 /// The length of the size field in a header buffer.\r
106                 /// </summary>\r
107                 public readonly static int SIZELEN = 12;\r
108                 \r
109                 /// <summary>\r
110                 /// The length of the magic field in a header buffer.\r
111                 /// </summary>\r
112                 public readonly static int MAGICLEN = 6;\r
113                 \r
114       /// <summary>\r
115       /// The length of the version field in a header buffer.\r
116       /// </summary>\r
117       public readonly static int VERSIONLEN = 2;\r
118 \r
119                 /// <summary>\r
120                 /// The length of the modification time field in a header buffer.\r
121                 /// </summary>\r
122                 public readonly static int MODTIMELEN = 12;\r
123                 \r
124                 /// <summary>\r
125                 /// The length of the user name field in a header buffer.\r
126                 /// </summary>\r
127                 public readonly static int UNAMELEN = 32;\r
128                 \r
129                 /// <summary>\r
130                 /// The length of the group name field in a header buffer.\r
131                 /// </summary>\r
132                 public readonly static int GNAMELEN = 32;\r
133                 \r
134                 /// <summary>\r
135                 /// The length of the devices field in a header buffer.\r
136                 /// </summary>\r
137                 public readonly static int DEVLEN = 8;\r
138                 \r
139                 /// <summary>\r
140                 /// LF_ constants represents the "type" of an entry\r
141                 /// </summary>\r
142                 /// \r
143 \r
144       /// <summary>\r
145       ///  This is the "old way" of indicating a normal file.\r
146       /// </summary>\r
147       public const byte LF_OLDNORM      = 0;\r
148                 \r
149                 /// <summary>\r
150                 /// Normal file type.\r
151                 /// </summary>\r
152                 public const byte       LF_NORMAL       = (byte) '0';\r
153                 \r
154                 /// <summary>\r
155                 /// Link file type.\r
156                 /// </summary>\r
157                 public const byte       LF_LINK         = (byte) '1';\r
158                 \r
159                 /// <summary>\r
160                 /// Symbolic link file type.\r
161                 /// </summary>\r
162                 public const byte       LF_SYMLINK      = (byte) '2';\r
163                 \r
164                 /// <summary>\r
165                 /// Character device file type.\r
166                 /// </summary>\r
167                 public const byte       LF_CHR          = (byte) '3';\r
168                 \r
169                 /// <summary>\r
170                 /// Block device file type.\r
171                 /// </summary>\r
172                 public const byte       LF_BLK          = (byte) '4';\r
173                 \r
174                 /// <summary>\r
175                 /// Directory file type.\r
176                 /// </summary>\r
177                 public const byte       LF_DIR          = (byte) '5';\r
178                 \r
179                 /// <summary>\r
180                 /// FIFO (pipe) file type.\r
181                 /// </summary>\r
182                 public const byte       LF_FIFO         = (byte) '6';\r
183                 \r
184                 /// <summary>\r
185                 /// Contiguous file type.\r
186                 /// </summary>\r
187                 public const byte       LF_CONTIG       = (byte) '7';\r
188                 \r
189                 /// <summary>\r
190                 /// Posix.1 2001 global extended header\r
191                 /// </summary>\r
192                 ///\r
193                 public const byte   LF_GHDR    = (byte) 'g';\r
194                 \r
195                 /// <summary>\r
196                 /// Posix.1 2001 extended header\r
197                 /// </summary>\r
198                 public readonly static byte   LF_XHDR    = (byte) 'x';\r
199                 \r
200                 \r
201                 \r
202                 \r
203                 // POSIX allows for upper case ascii type as extensions\r
204                 \r
205                 // Solaris access control list\r
206                 public const byte   LF_ACL            = (byte) 'A';\r
207                 \r
208                 // This is a dir entry that contains the names of files that were in the\r
209                 // dir at the time the dump was made\r
210                 public const byte   LF_GNU_DUMPDIR    = (byte) 'D';\r
211                 \r
212                 // Solaris Extended Attribute File\r
213                 public const byte   LF_EXTATTR        = (byte) 'E' ;\r
214                 \r
215                 // Inode (metadata only) no file content\r
216                 public const byte   LF_META           = (byte) 'I';\r
217                 \r
218                 // Identifies the next file on the tape as having a long link name\r
219                 public const byte   LF_GNU_LONGLINK   = (byte) 'K';\r
220                 \r
221                 // Identifies the next file on the tape as having a long name\r
222                 public const byte   LF_GNU_LONGNAME   = (byte) 'L';\r
223                 \r
224                 // Continuation of a file that began on another volume\r
225                 public const byte   LF_GNU_MULTIVOL   = (byte) 'M';\r
226                 \r
227                 // For storing filenames that dont fit in the main header (old GNU)\r
228                 public const byte   LF_GNU_NAMES      = (byte) 'N';\r
229                 \r
230                 // Sparse file\r
231                 public const byte   LF_GNU_SPARSE     = (byte) 'S';\r
232                 \r
233                 // Tape/volume header ignore on extraction\r
234                 public const byte   LF_GNU_VOLHDR     = (byte) 'V';\r
235                 \r
236                 /// <summary>\r
237                 /// The magic tag representing a POSIX tar archive.  (includes trailing NULL)\r
238                 /// </summary>\r
239                 public readonly static string   TMAGIC          = "ustar ";\r
240                 \r
241                 /// <summary>\r
242                 /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it\r
243                 /// </summary>\r
244                 public readonly static string   GNU_TMAGIC      = "ustar  ";\r
245                 \r
246                 /// <summary>\r
247                 /// The entry's name.\r
248                 /// </summary>\r
249                 public StringBuilder name;\r
250                 \r
251                 /// <summary>\r
252                 /// The entry's permission mode.\r
253                 /// </summary>\r
254                 public int mode;\r
255                 \r
256                 /// <summary>\r
257                 /// The entry's user id.\r
258                 /// </summary>\r
259                 public int userId;\r
260                 \r
261                 /// <summary>\r
262                 /// The entry's group id.\r
263                 /// </summary>\r
264                 public int groupId;\r
265                 \r
266                 /// <summary>\r
267                 /// The entry's size.\r
268                 /// </summary>\r
269                 public long size;\r
270                 \r
271                 /// <summary>\r
272                 /// The entry's modification time.\r
273                 /// </summary>\r
274                 public DateTime modTime;\r
275                 \r
276                 /// <summary>\r
277                 /// The entry's checksum.\r
278                 /// </summary>\r
279                 public int checkSum;\r
280                 \r
281                 /// <summary>\r
282                 /// The entry's type flag.\r
283                 /// </summary>\r
284                 public byte typeFlag;\r
285                 \r
286                 /// <summary>\r
287                 /// The entry's link name.\r
288                 /// </summary>\r
289                 public StringBuilder linkName;\r
290                 \r
291                 /// <summary>\r
292                 /// The entry's magic tag.\r
293                 /// </summary>\r
294                 public StringBuilder magic;\r
295                 \r
296                 /// <summary>\r
297                 /// The entry's version.\r
298                 /// </summary>\r
299                 public StringBuilder version;\r
300                 \r
301                 /// <summary>\r
302                 /// The entry's user name.\r
303                 /// </summary>\r
304                 public StringBuilder userName;\r
305                 \r
306                 /// <summary>\r
307                 /// The entry's group name.\r
308                 /// </summary>\r
309                 public StringBuilder groupName;\r
310                 \r
311                 /// <summary>\r
312                 /// The entry's major device number.\r
313                 /// </summary>\r
314                 public int devMajor;\r
315                 \r
316                 /// <summary>\r
317                 /// The entry's minor device number.\r
318                 /// </summary>\r
319                 public int devMinor;\r
320                 \r
321                 public TarHeader()\r
322                 {\r
323                         this.magic = new StringBuilder(TarHeader.TMAGIC);\r
324                         this.version = new StringBuilder(" ");\r
325                         \r
326                         this.name     = new StringBuilder();\r
327                         this.linkName = new StringBuilder();\r
328                         \r
329                         string user = Environment.UserName;\r
330                         //         string user = "PocketPC";\r
331                         //         string user = "Everyone";\r
332                         \r
333                         if (user.Length > 31) {\r
334                                 user = user.Substring(0, 31);\r
335                         }\r
336                         \r
337                         this.userId    = 1003;  // -jr- was 0\r
338                         this.groupId   = 513;   // -jr- was 0\r
339                         this.userName  = new StringBuilder(user);\r
340 // -jr-\r
341 //                      this.groupName = new StringBuilder(String.Empty);\r
342 //         this.groupName = new StringBuilder("Everyone");  Attempt2\r
343          this.groupName = new StringBuilder("None"); // Gnu compatible\r
344          this.size      = 0;\r
345                 }\r
346                 \r
347                 /// <summary>\r
348                 /// TarHeaders can be cloned.\r
349                 /// </summary>\r
350                 public object Clone()\r
351                 {\r
352                         TarHeader hdr = new TarHeader();\r
353                         \r
354                         hdr.name      = (this.name == null) ? null : new StringBuilder(this.name.ToString());\r
355                         hdr.mode      = this.mode;\r
356                         hdr.userId    = this.userId;\r
357                         hdr.groupId   = this.groupId;\r
358                         hdr.size      = this.size;\r
359                         hdr.modTime   = this.modTime;\r
360                         hdr.checkSum  = this.checkSum;\r
361                         hdr.typeFlag  = this.typeFlag;\r
362                         hdr.linkName  = (this.linkName == null)  ? null : new StringBuilder(this.linkName.ToString());\r
363                         hdr.magic     = (this.magic == null)     ? null : new StringBuilder(this.magic.ToString());\r
364          hdr.version   = (this.version == null)   ? null : new StringBuilder(this.version.ToString());\r
365                         hdr.userName  = (this.userName == null)  ? null : new StringBuilder(this.userName.ToString());\r
366                         hdr.groupName = (this.groupName == null) ? null : new StringBuilder(this.groupName.ToString());\r
367                         hdr.devMajor  = this.devMajor;\r
368                         hdr.devMinor  = this.devMinor;\r
369                         \r
370                         return hdr;\r
371                 }\r
372                 \r
373                 /// <summary>\r
374                 /// Get the name of this entry.\r
375                 /// </summary>\r
376                 /// <returns>\r
377                 /// The entry's name.\r
378                 /// </returns>\r
379                 public string GetName()\r
380                 {\r
381                         return this.name.ToString();\r
382                 }\r
383                 \r
384                 /// <summary>\r
385                 /// Parse an octal string from a header buffer. This is used for the\r
386                 /// file permission mode value.\r
387                 /// </summary>\r
388                 /// <param name = "header">\r
389                 /// The header buffer from which to parse.\r
390                 /// </param>\r
391                 /// <param name = "offset">\r
392                 /// The offset into the buffer from which to parse.\r
393                 /// </param>\r
394                 /// <param name = "length">\r
395                 /// The number of header bytes to parse.\r
396                 /// </param>\r
397                 /// <returns>\r
398                 /// The long value of the octal string.\r
399                 /// </returns>\r
400                 public static long ParseOctal(byte[] header, int offset, int length)\r
401                 {\r
402                         long result = 0;\r
403                         bool stillPadding = true;\r
404                         \r
405                         int end = offset + length;\r
406                         for (int i = offset; i < end ; ++i) \r
407                         {\r
408                                 if (header[i] == 0) \r
409                                 {\r
410                                         break;\r
411                                 }\r
412                                 \r
413                                 if (header[i] == (byte)' ' || header[i] == '0') \r
414                                 {\r
415                                         if (stillPadding) \r
416                                         {\r
417                                                 continue;\r
418                                         }\r
419                                         \r
420                                         if (header[i] == (byte)' ') \r
421                                         {\r
422                                                 break;\r
423                                         }\r
424                                 }\r
425                                 \r
426                                 stillPadding = false;\r
427                                 \r
428                                 result = (result << 3) + (header[i] - '0');\r
429                         }\r
430                         \r
431                         return result;\r
432                 }\r
433                 \r
434                 /// <summary>\r
435                 /// Parse an entry name from a header buffer.\r
436                 /// </summary>\r
437                 /// <param name="header">\r
438                 /// The header buffer from which to parse.\r
439                 /// </param>\r
440                 /// <param name="offset">\r
441                 /// The offset into the buffer from which to parse.\r
442                 /// </param>\r
443                 /// <param name="length">\r
444                 /// The number of header bytes to parse.\r
445                 /// </param>\r
446                 /// <returns>\r
447                 /// The header's entry name.\r
448                 /// </returns>\r
449                 public static StringBuilder ParseName(byte[] header, int offset, int length)\r
450                 {\r
451                         StringBuilder result = new StringBuilder(length);\r
452                         \r
453                         for (int i = offset; i < offset + length; ++i) \r
454                         {\r
455                                 if (header[i] == 0) \r
456                                 {\r
457                                         break;\r
458                                 }\r
459                                 result.Append((char)header[i]);\r
460                         }\r
461                         \r
462                         return result;\r
463                 }\r
464                 \r
465       public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buf, int bufferOffset, int length)\r
466       {\r
467          int i;\r
468                         \r
469          for (i = 0 ; i < length && nameOffset + i < name.Length; ++i) \r
470          {\r
471             buf[bufferOffset + i] = (byte)name[nameOffset + i];\r
472          }\r
473                         \r
474          for (; i < length ; ++i) \r
475          {\r
476             buf[bufferOffset + i] = 0;\r
477          }\r
478                         \r
479          return bufferOffset + length;\r
480       }\r
481 \r
482       /// <summary>\r
483                 /// Determine the number of bytes in an entry name.\r
484                 /// </summary>\r
485                 /// <param name="name">\r
486                 /// </param>\r
487                 /// <param name="buf">\r
488                 /// The header buffer from which to parse.\r
489                 /// </param>\r
490                 /// <param name="offset">\r
491                 /// The offset into the buffer from which to parse.\r
492                 /// </param>\r
493                 /// <param name="length">\r
494                 /// The number of header bytes to parse.\r
495                 /// </param>\r
496                 /// <returns>\r
497                 /// The number of bytes in a header's entry name.\r
498                 /// </returns>\r
499                 public static int GetNameBytes(StringBuilder name, byte[] buf, int offset, int length)\r
500                 {\r
501          return GetNameBytes(name, 0, buf, offset, length);\r
502                 }\r
503                 \r
504                 /// <summary>\r
505                 /// Parse an octal integer from a header buffer.\r
506                 /// </summary>\r
507                 /// <param name = "val">\r
508                 /// </param>\r
509                 /// <param name = "buf">\r
510                 /// The header buffer from which to parse.\r
511                 /// </param>\r
512                 /// <param name = "offset">\r
513                 /// The offset into the buffer from which to parse.\r
514                 /// </param>\r
515                 /// <param name = "length">\r
516                 /// The number of header bytes to parse.\r
517                 /// </param>\r
518                 /// <returns>\r
519                 /// The integer value of the octal bytes.\r
520                 /// </returns>\r
521                 public static int GetOctalBytes(long val, byte[] buf, int offset, int length)\r
522                 {\r
523          // TODO check for values too large...\r
524 \r
525                         int idx = length - 1;\r
526 \r
527                         // Either a space or null is valid here.  We use NULL as per GNUTar\r
528                         buf[offset + idx] = 0;\r
529                         --idx;\r
530 \r
531          if (val > 0)\r
532                         {\r
533                                 for (long v = val; idx >= 0 && v > 0; --idx) \r
534                                 {\r
535                                         buf[offset + idx] = (byte)((byte)'0' + (byte)(v & 7));\r
536                                         v >>= 3;\r
537                                 }\r
538                         }\r
539                                 \r
540                         for (; idx >= 0; --idx) \r
541                         {\r
542             buf[offset + idx] = (byte)'0';\r
543                         }\r
544                         \r
545                         return offset + length;\r
546                 }\r
547                 \r
548                 /// <summary>\r
549                 /// Parse an octal long integer from a header buffer.\r
550                 /// </summary>\r
551                 /// <param name = "val">\r
552                 /// </param>\r
553                 /// <param name = "buf">\r
554                 /// The header buffer from which to parse.\r
555                 /// </param>\r
556                 /// <param name = "offset">\r
557                 /// The offset into the buffer from which to parse.\r
558                 /// </param>\r
559                 /// <param name = "length">\r
560                 /// The number of header bytes to parse.\r
561                 /// </param>\r
562                 /// <returns>\r
563                 /// The long value of the octal bytes.\r
564                 /// </returns>\r
565                 public static int GetLongOctalBytes(long val, byte[] buf, int offset, int length)\r
566                 {\r
567          return GetOctalBytes(val, buf, offset, length);\r
568                 }\r
569                 \r
570                 /// <summary>\r
571                 /// Add the checksum octal integer to header buffer.\r
572                 /// </summary>\r
573                 /// <param name = "val">\r
574                 /// </param>\r
575                 /// <param name = "buf">\r
576                 /// The header buffer to set the checksum for\r
577                 /// </param>\r
578                 /// <param name = "offset">\r
579                 /// The offset into the buffer for the checksum\r
580                 /// </param>\r
581                 /// <param name = "length">\r
582                 /// The number of header bytes to update.\r
583       /// It's formatted differently from the other fields: it has 6 digits, a\r
584       /// null, then a space -- rather than digits, a space, then a null.\r
585       /// The final space is already there, from checksumming\r
586 \r
587                 /// </param>\r
588                 /// <returns>\r
589                 /// The modified buffer offset\r
590                 /// </returns>\r
591                 private static int GetCheckSumOctalBytes(long val, byte[] buf, int offset, int length)\r
592                 {\r
593                         TarHeader.GetOctalBytes(val, buf, offset, length - 1);\r
594 //                      buf[offset + length - 1] = (byte)' ';  -jr- 23-Jan-2004 this causes failure!!!\r
595 //                      buf[offset + length - 2] = 0;\r
596                         return offset + length;\r
597                 }\r
598                 \r
599       /// <summary>\r
600       /// Compute the checksum for a tar entry header.  \r
601       /// The checksum field must be all spaces prior to this happening\r
602       /// </summary>\r
603       /// <param name = "buf">\r
604       /// The tar entry's header buffer.\r
605       /// </param>\r
606       /// <returns>\r
607       /// The computed checksum.\r
608       /// </returns>\r
609       private static long ComputeCheckSum(byte[] buf)\r
610       {\r
611          long sum = 0;\r
612          for (int i = 0; i < buf.Length; ++i) \r
613          {\r
614             sum += buf[i];\r
615          }\r
616          return sum;\r
617       }\r
618 \r
619       readonly static long     timeConversionFactor = 10000000L;                                    // -jr- 1 tick == 100 nanoseconds\r
620       readonly static DateTime datetTime1970        = new DateTime(1970, 1, 1, 0, 0, 0, 0); \r
621 //      readonly static DateTime datetTime1970        = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime(); // -jr- Should be UTC?  doesnt match Gnutar if this is so though, why?\r
622                 \r
623       static int GetCTime(System.DateTime dateTime)\r
624       {\r
625          return (int)((dateTime.Ticks - datetTime1970.Ticks) / timeConversionFactor);\r
626       }\r
627                 \r
628       static DateTime GetDateTimeFromCTime(long ticks)\r
629       {\r
630          return new DateTime(datetTime1970.Ticks + ticks * timeConversionFactor);\r
631       }\r
632 \r
633       /// <summary>\r
634       /// Parse TarHeader information from a header buffer.\r
635       /// </summary>\r
636       /// <param name = "header">\r
637       /// The tar entry header buffer to get information from.\r
638       /// </param>\r
639       public void ParseBuffer(byte[] header)\r
640       {\r
641          int offset = 0;\r
642                         \r
643          name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);\r
644          offset += TarHeader.NAMELEN;\r
645                         \r
646          mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN);\r
647          offset += TarHeader.MODELEN;\r
648                         \r
649          userId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN);\r
650          offset += TarHeader.UIDLEN;\r
651                         \r
652          groupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN);\r
653          offset += TarHeader.GIDLEN;\r
654                         \r
655          size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN);\r
656          offset += TarHeader.SIZELEN;\r
657                         \r
658          modTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN));\r
659          offset += TarHeader.MODTIMELEN;\r
660                         \r
661          checkSum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN);\r
662          offset += TarHeader.CHKSUMLEN;\r
663                         \r
664          typeFlag = header[ offset++ ];\r
665 \r
666          linkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);\r
667          offset += TarHeader.NAMELEN;\r
668                         \r
669          magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN);\r
670          offset += TarHeader.MAGICLEN;\r
671 \r
672          version = TarHeader.ParseName(header, offset, TarHeader.VERSIONLEN);\r
673          offset += TarHeader.VERSIONLEN;\r
674                         \r
675          userName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN);\r
676          offset += TarHeader.UNAMELEN;\r
677                         \r
678          groupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN);\r
679          offset += TarHeader.GNAMELEN;\r
680                         \r
681          devMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);\r
682          offset += TarHeader.DEVLEN;\r
683                         \r
684          devMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);\r
685 \r
686          // Fields past this point not currently parsed or used...\r
687       }\r
688 \r
689       /// <summary>\r
690       /// 'Write' header information to buffer provided\r
691       /// </summary>\r
692       /// <param name="outbuf">output buffer for header information</param>\r
693       public void WriteHeader(byte[] outbuf)\r
694       {\r
695          int offset = 0;\r
696                         \r
697          offset = GetNameBytes(this.name, outbuf, offset, TarHeader.NAMELEN);\r
698          offset = GetOctalBytes(this.mode, outbuf, offset, TarHeader.MODELEN);\r
699          offset = GetOctalBytes(this.userId, outbuf, offset, TarHeader.UIDLEN);\r
700          offset = GetOctalBytes(this.groupId, outbuf, offset, TarHeader.GIDLEN);\r
701                         \r
702          long size = this.size;\r
703                         \r
704          offset = GetLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);\r
705          offset = GetLongOctalBytes(GetCTime(this.modTime), outbuf, offset, TarHeader.MODTIMELEN);\r
706                         \r
707          int csOffset = offset;\r
708          for (int c = 0; c < TarHeader.CHKSUMLEN; ++c) \r
709          {\r
710             outbuf[offset++] = (byte)' ';\r
711          }\r
712                         \r
713          outbuf[offset++] = this.typeFlag;\r
714                         \r
715          offset = GetNameBytes(this.linkName, outbuf, offset, NAMELEN);\r
716          offset = GetNameBytes(this.magic, outbuf, offset, MAGICLEN);\r
717          offset = GetNameBytes(this.version, outbuf, offset, VERSIONLEN);\r
718          offset = GetNameBytes(this.userName, outbuf, offset, UNAMELEN);\r
719          offset = GetNameBytes(this.groupName, outbuf, offset, GNAMELEN);\r
720 \r
721          if (this.typeFlag == LF_CHR || this.typeFlag == LF_BLK)\r
722          {\r
723             offset = GetOctalBytes(this.devMajor, outbuf, offset, DEVLEN);\r
724             offset = GetOctalBytes(this.devMinor, outbuf, offset, DEVLEN);\r
725          }\r
726                         \r
727          for ( ; offset < outbuf.Length; ) \r
728          {\r
729             outbuf[offset++] = 0;\r
730          }\r
731                         \r
732          long checkSum = ComputeCheckSum(outbuf);\r
733                         \r
734          GetCheckSumOctalBytes(checkSum, outbuf, csOffset, CHKSUMLEN);\r
735       }\r
736    }\r
737 }\r
738 \r
739 /* The original Java file had this header:\r
740  * \r
741 ** Authored by Timothy Gerard Endres\r
742 ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
743 ** \r
744 ** This work has been placed into the public domain.\r
745 ** You may use this work in any way and for any purpose you wish.\r
746 **\r
747 ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
748 ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
749 ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
750 ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
751 ** REDISTRIBUTION OF THIS SOFTWARE. \r
752 ** \r
753 */\r