root/trunk/BazaReklam.Updater/ICSharpCode.SharpZipLib/Tar/TarHeader.cs @ 725

Wersja 597, 32.8 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1// TarHeader.cs
2//
3// Copyright (C) 2001 Mike Krueger
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 2
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18//
19// Linking this library statically or dynamically with other modules is
20// making a combined work based on this library.  Thus, the terms and
21// conditions of the GNU General Public License cover the whole
22// combination.
23//
24// As a special exception, the copyright holders of this library give you
25// permission to link this library with independent modules to produce an
26// executable, regardless of the license terms of these independent
27// modules, and to copy and distribute the resulting executable under
28// terms of your choice, provided that you also meet, for each linked
29// independent module, the terms and conditions of the license of that
30// module.  An independent module is a module which is not derived from
31// or based on this library.  If you modify this library, you may extend
32// this exception to your version of the library, but you are not
33// obligated to do so.  If you do not wish to do so, delete this
34// exception statement from your version.
35
36
37/* The tar format and its POSIX successor PAX have a long history which makes for compatability
38   issues when creating and reading files.
39
40   This is further complicated by a large number of programs with variations on formats
41   One common issue is the handling of names longer than 100 characters.
42   GNU style long names are currently supported.
43
44This is the ustar (Posix 1003.1) header.
45
46struct header
47{
48        char t_name[100];          //   0 Filename
49        char t_mode[8];            // 100 Permissions
50        char t_uid[8];             // 108 Numerical User ID
51        char t_gid[8];             // 116 Numerical Group ID
52        char t_size[12];           // 124 Filesize
53        char t_mtime[12];          // 136 st_mtime
54        char t_chksum[8];          // 148 Checksum
55        char t_typeflag;           // 156 Type of File
56        char t_linkname[100];      // 157 Target of Links
57        char t_magic[6];           // 257 "ustar" or other...
58        char t_version[2];         // 263 Version fixed to 00
59        char t_uname[32];          // 265 User Name
60        char t_gname[32];          // 297 Group Name
61        char t_devmajor[8];        // 329 Major for devices
62        char t_devminor[8];        // 337 Minor for devices
63        char t_prefix[155];        // 345 Prefix for t_name
64        char t_mfill[12];          // 500 Filler up to 512
65};
66
67*/
68
69using System;
70using System.Text;
71
72namespace ICSharpCode.SharpZipLib.Tar
73{
74       
75       
76        /// <summary>
77        /// This class encapsulates the Tar Entry Header used in Tar Archives.
78        /// The class also holds a number of tar constants, used mostly in headers.
79        /// </summary>
80        public class TarHeader : ICloneable
81        {
82                #region Constants
83                /// <summary>
84                /// The length of the name field in a header buffer.
85                /// </summary>
86                public const int NAMELEN = 100;
87               
88                /// <summary>
89                /// The length of the mode field in a header buffer.
90                /// </summary>
91                public const int MODELEN = 8;
92               
93                /// <summary>
94                /// The length of the user id field in a header buffer.
95                /// </summary>
96                public const int UIDLEN = 8;
97               
98                /// <summary>
99                /// The length of the group id field in a header buffer.
100                /// </summary>
101                public const int GIDLEN = 8;
102               
103                /// <summary>
104                /// The length of the checksum field in a header buffer.
105                /// </summary>
106                public const int CHKSUMLEN = 8;
107
108                /// <summary>
109                /// Offset of checksum in a header buffer.
110                /// </summary>
111                public const int CHKSUMOFS = 148;
112               
113                /// <summary>
114                /// The length of the size field in a header buffer.
115                /// </summary>
116                public const int SIZELEN = 12;
117               
118                /// <summary>
119                /// The length of the magic field in a header buffer.
120                /// </summary>
121                public const int MAGICLEN = 6;
122               
123                /// <summary>
124                /// The length of the version field in a header buffer.
125                /// </summary>
126                public const int VERSIONLEN = 2;
127
128                /// <summary>
129                /// The length of the modification time field in a header buffer.
130                /// </summary>
131                public const int MODTIMELEN = 12;
132               
133                /// <summary>
134                /// The length of the user name field in a header buffer.
135                /// </summary>
136                public const int UNAMELEN = 32;
137               
138                /// <summary>
139                /// The length of the group name field in a header buffer.
140                /// </summary>
141                public const int GNAMELEN = 32;
142               
143                /// <summary>
144                /// The length of the devices field in a header buffer.
145                /// </summary>
146                public const int DEVLEN = 8;
147               
148                //
149                // LF_ constants represent the "type" of an entry
150                //
151
152                /// <summary>
153                ///  The "old way" of indicating a normal file.
154                /// </summary>
155                public const byte       LF_OLDNORM      = 0;
156               
157                /// <summary>
158                /// Normal file type.
159                /// </summary>
160                public const byte       LF_NORMAL       = (byte) '0';
161               
162                /// <summary>
163                /// Link file type.
164                /// </summary>
165                public const byte       LF_LINK         = (byte) '1';
166               
167                /// <summary>
168                /// Symbolic link file type.
169                /// </summary>
170                public const byte       LF_SYMLINK      = (byte) '2';
171               
172                /// <summary>
173                /// Character device file type.
174                /// </summary>
175                public const byte       LF_CHR          = (byte) '3';
176               
177                /// <summary>
178                /// Block device file type.
179                /// </summary>
180                public const byte       LF_BLK          = (byte) '4';
181               
182                /// <summary>
183                /// Directory file type.
184                /// </summary>
185                public const byte       LF_DIR          = (byte) '5';
186               
187                /// <summary>
188                /// FIFO (pipe) file type.
189                /// </summary>
190                public const byte       LF_FIFO         = (byte) '6';
191               
192                /// <summary>
193                /// Contiguous file type.
194                /// </summary>
195                public const byte       LF_CONTIG       = (byte) '7';
196               
197                /// <summary>
198                /// Posix.1 2001 global extended header
199                /// </summary>
200                public const byte   LF_GHDR    = (byte) 'g';
201               
202                /// <summary>
203                /// Posix.1 2001 extended header
204                /// </summary>
205                public const byte   LF_XHDR    = (byte) 'x';
206               
207                // POSIX allows for upper case ascii type as extensions
208               
209                /// <summary>
210                /// Solaris access control list file type
211                /// </summary>
212                public const byte   LF_ACL            = (byte) 'A';
213               
214                /// <summary>
215                /// GNU dir dump file type
216                /// This is a dir entry that contains the names of files that were in the
217                /// dir at the time the dump was made
218                /// </summary>
219                public const byte   LF_GNU_DUMPDIR    = (byte) 'D';
220               
221                /// <summary>
222                /// Solaris Extended Attribute File
223                /// </summary>
224                public const byte   LF_EXTATTR        = (byte) 'E' ;
225               
226                /// <summary>
227                /// Inode (metadata only) no file content
228                /// </summary>
229                public const byte   LF_META           = (byte) 'I';
230               
231                /// <summary>
232                /// Identifies the next file on the tape as having a long link name
233                /// </summary>
234                public const byte   LF_GNU_LONGLINK   = (byte) 'K';
235               
236                /// <summary>
237                /// Identifies the next file on the tape as having a long name
238                /// </summary>
239                public const byte   LF_GNU_LONGNAME   = (byte) 'L';
240               
241                /// <summary>
242                /// Continuation of a file that began on another volume
243                /// </summary>
244                public const byte   LF_GNU_MULTIVOL   = (byte) 'M';
245               
246                /// <summary>
247                /// For storing filenames that dont fit in the main header (old GNU)
248                /// </summary>
249                public const byte   LF_GNU_NAMES      = (byte) 'N';
250               
251                /// <summary>
252                /// GNU Sparse file
253                /// </summary>
254                public const byte   LF_GNU_SPARSE     = (byte) 'S';
255               
256                /// <summary>
257                /// GNU Tape/volume header ignore on extraction
258                /// </summary>
259                public const byte   LF_GNU_VOLHDR     = (byte) 'V';
260               
261                /// <summary>
262                /// The magic tag representing a POSIX tar archive.  (includes trailing NULL)
263                /// </summary>
264                public const string     TMAGIC          = "ustar ";
265               
266                /// <summary>
267                /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it
268                /// </summary>
269                public const string     GNU_TMAGIC      = "ustar  ";
270
271                const long     timeConversionFactor = 10000000L;           // 1 tick == 100 nanoseconds
272                readonly static DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
273                #endregion
274
275                #region Constructors
276                /// <summary>
277                /// Initialise a default TarHeader instance
278                /// </summary>
279                public TarHeader()
280                {
281                        this.Magic = TarHeader.TMAGIC;
282                        this.Version = " ";
283                       
284                        this.Name     = "";
285                        this.LinkName = "";
286                       
287                        this.UserId    = defaultUserId;
288                        this.GroupId   = defaultGroupId;
289                        this.UserName  = defaultUser;
290                        this.GroupName = defaultGroupName;
291                        this.Size      = 0;
292                }
293                #endregion
294
295                #region Properties
296                /// <summary>
297                /// Get/set the name for this tar entry.
298                /// </summary>
299                /// <exception cref="ArgumentNullException">Thrown when attempting to set the property to null.</exception>
300                public string Name
301                {
302                        get { return name; }
303                        set {
304                                if ( value == null ) {
305                                        throw new ArgumentNullException("value");
306                                }
307                                name = value;   
308                        }
309                }
310
311                /// <summary>
312                /// Get the name of this entry.
313                /// </summary>
314                /// <returns>The entry's name.</returns>
315                [Obsolete("Use the Name property instead", true)]
316                public string GetName()
317                {
318                        return name;
319                }
320               
321                /// <summary>
322                /// Get/set the entry's Unix style permission mode.
323                /// </summary>
324                public int Mode
325                {
326                        get { return mode; }
327                        set { mode = value; }
328                }
329               
330               
331                /// <summary>
332                /// The entry's user id.
333                /// </summary>
334                /// <remarks>
335                /// This is only directly relevant to unix systems.
336                /// The default is zero.
337                /// </remarks>
338                public int UserId
339                {
340                        get { return userId; }
341                        set { userId = value; }
342                }
343               
344               
345                /// <summary>
346                /// Get/set the entry's group id.
347                /// </summary>
348                /// <remarks>
349                /// This is only directly relevant to linux/unix systems.
350                /// The default value is zero.
351                /// </remarks>
352                public int GroupId
353                {
354                        get { return groupId; }
355                        set { groupId = value; }
356                }
357               
358
359                /// <summary>
360                /// Get/set the entry's size.
361                /// </summary>
362                /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the size to less than zero.</exception>
363                public long Size
364                {
365                        get { return size; }
366                        set {
367                                if ( value < 0 ) {
368#if NETCF_1_0
369                                        throw new ArgumentOutOfRangeException("value");
370#else
371                                        throw new ArgumentOutOfRangeException("value", "Cannot be less than zero");
372#endif                                 
373                                }
374                                size = value;
375                        }
376                }
377               
378               
379                /// <summary>
380                /// Get/set the entry's modification time.
381                /// </summary>
382                /// <remarks>
383                /// The modification time is only accurate to within a second.
384                /// </remarks>
385                /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the date time to less than 1/1/1970.</exception>
386                public DateTime ModTime
387                {
388                        get { return modTime; }
389                        set {
390                                if ( value < dateTime1970 )
391                                {
392#if NETCF_1_0
393                                        throw new ArgumentOutOfRangeException("value");
394#else
395                                        throw new ArgumentOutOfRangeException("value", "ModTime cannot be before Jan 1st 1970");
396#endif                                 
397                                }
398                                modTime = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second);
399                        }
400                }
401               
402               
403                /// <summary>
404                /// Get the entry's checksum.  This is only valid/updated after writing or reading an entry.
405                /// </summary>
406                public int Checksum
407                {
408                        get { return checksum; }
409                }
410               
411               
412                /// <summary>
413                /// Get value of true if the header checksum is valid, false otherwise.
414                /// </summary>
415                public bool IsChecksumValid
416                {
417                        get { return isChecksumValid; }
418                }
419               
420               
421                /// <summary>
422                /// Get/set the entry's type flag.
423                /// </summary>
424                public byte TypeFlag
425                {
426                        get { return typeFlag; }
427                        set { typeFlag = value; }
428                }
429
430               
431                /// <summary>
432                /// The entry's link name.
433                /// </summary>
434                /// <exception cref="ArgumentNullException">Thrown when attempting to set LinkName to null.</exception>
435                public string LinkName
436                {
437                        get { return linkName; }
438                        set {
439                                if ( value == null ) {
440                                        throw new ArgumentNullException("value");
441                                }
442                                linkName = value;
443                        }
444                }
445               
446               
447                /// <summary>
448                /// Get/set the entry's magic tag.
449                /// </summary>
450                /// <exception cref="ArgumentNullException">Thrown when attempting to set Magic to null.</exception>
451                public string Magic
452                {
453                        get { return magic; }
454                        set {
455                                if ( value == null ) {
456                                        throw new ArgumentNullException("value");
457                                }
458                                magic = value;
459                        }
460                }
461               
462               
463                /// <summary>
464                /// The entry's version.
465                /// </summary>
466                /// <exception cref="ArgumentNullException">Thrown when attempting to set Version to null.</exception>
467                public string Version
468                {
469                        get {
470                                return version;
471                        }
472
473                        set {
474                                if ( value == null ) {
475                                        throw new ArgumentNullException("value");
476                                }
477                                version = value;
478                        }
479                }
480               
481               
482                /// <summary>
483                /// The entry's user name.
484                /// </summary>
485                public string UserName
486                {
487                        get { return userName; }
488                        set {
489                                if (value != null) {
490                                        userName = value.Substring(0, Math.Min(UNAMELEN, value.Length));
491                                }
492                                else {
493#if NETCF_1_0 || NETCF_2_0
494                                        string currentUser = "PocketPC";
495#else
496                                        string currentUser = Environment.UserName;
497#endif
498                                        if (currentUser.Length > UNAMELEN) {
499                                                currentUser = currentUser.Substring(0, UNAMELEN);
500                                        }
501                                        userName = currentUser;
502                                }
503                        }
504                }
505               
506               
507                /// <summary>
508                /// Get/set the entry's group name.
509                /// </summary>
510                /// <remarks>
511                /// This is only directly relevant to unix systems.
512                /// </remarks>
513                public string GroupName
514                {
515                        get { return groupName; }
516                        set {
517                                if ( value == null ) {
518                                        groupName = "None";
519                                }
520                                else {
521                                        groupName = value;
522                                }
523                        }
524                }
525               
526               
527                /// <summary>
528                /// Get/set the entry's major device number.
529                /// </summary>
530                public int DevMajor
531                {
532                        get { return devMajor; }
533                        set { devMajor = value; }
534                }
535               
536               
537                /// <summary>
538                /// Get/set the entry's minor device number.
539                /// </summary>
540                public int DevMinor
541                {
542                        get { return devMinor; }
543                        set { devMinor = value; }
544                }
545               
546                #endregion
547
548                #region ICloneable Members
549                /// <summary>
550                /// Create a new <see cref="TarHeader"/> that is a copy of the current instance.
551                /// </summary>
552                /// <returns>A new <see cref="Object"/> that is a copy of the current instance.</returns>
553                public object Clone()
554                {
555                        return this.MemberwiseClone();
556                }
557                #endregion
558
559                /// <summary>
560                /// Parse TarHeader information from a header buffer.
561                /// </summary>
562                /// <param name = "header">
563                /// The tar entry header buffer to get information from.
564                /// </param>
565                public void ParseBuffer(byte[] header)
566                {
567                        if ( header == null )
568                        {
569                                throw new ArgumentNullException("header");
570                        }
571
572                        int offset = 0;
573                       
574                        name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN).ToString();
575                        offset += TarHeader.NAMELEN;
576                       
577                        mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN);
578                        offset += TarHeader.MODELEN;
579                       
580                        UserId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN);
581                        offset += TarHeader.UIDLEN;
582                       
583                        GroupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN);
584                        offset += TarHeader.GIDLEN;
585                       
586                        Size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN);
587                        offset += TarHeader.SIZELEN;
588                       
589                        ModTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN));
590                        offset += TarHeader.MODTIMELEN;
591                       
592                        checksum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN);
593                        offset += TarHeader.CHKSUMLEN;
594                       
595                        TypeFlag = header[ offset++ ];
596
597                        LinkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN).ToString();
598                        offset += TarHeader.NAMELEN;
599                       
600                        Magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN).ToString();
601                        offset += TarHeader.MAGICLEN;
602                       
603                        Version = TarHeader.ParseName(header, offset, TarHeader.VERSIONLEN).ToString();
604                        offset += TarHeader.VERSIONLEN;
605                       
606                        UserName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN).ToString();
607                        offset += TarHeader.UNAMELEN;
608                       
609                        GroupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN).ToString();
610                        offset += TarHeader.GNAMELEN;
611                       
612                        DevMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
613                        offset += TarHeader.DEVLEN;
614                       
615                        DevMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
616                       
617                        // Fields past this point not currently parsed or used...
618                       
619                        isChecksumValid = Checksum == TarHeader.MakeCheckSum(header);
620                }
621
622                /// <summary>
623                /// 'Write' header information to buffer provided, updating the <see cref="Checksum">check sum</see>.
624                /// </summary>
625                /// <param name="outBuffer">output buffer for header information</param>
626                public void WriteHeader(byte[] outBuffer)
627                {
628                        if ( outBuffer == null )
629                        {
630                                throw new ArgumentNullException("outBuffer");
631                        }
632
633                        int offset = 0;
634                       
635                        offset = GetNameBytes(this.Name, outBuffer, offset, TarHeader.NAMELEN);
636                        offset = GetOctalBytes(this.mode, outBuffer, offset, TarHeader.MODELEN);
637                        offset = GetOctalBytes(this.UserId, outBuffer, offset, TarHeader.UIDLEN);
638                        offset = GetOctalBytes(this.GroupId, outBuffer, offset, TarHeader.GIDLEN);
639                       
640                        long size = this.Size;
641                       
642                        offset = GetLongOctalBytes(size, outBuffer, offset, TarHeader.SIZELEN);
643                        offset = GetLongOctalBytes(GetCTime(this.ModTime), outBuffer, offset, TarHeader.MODTIMELEN);
644                       
645                        int csOffset = offset;
646                        for (int c = 0; c < TarHeader.CHKSUMLEN; ++c)
647                        {
648                                outBuffer[offset++] = (byte)' ';
649                        }
650                       
651                        outBuffer[offset++] = this.TypeFlag;
652                       
653                        offset = GetNameBytes(this.LinkName, outBuffer, offset, NAMELEN);
654                        offset = GetAsciiBytes(this.Magic, 0, outBuffer, offset, MAGICLEN);
655                        offset = GetNameBytes(this.Version, outBuffer, offset, VERSIONLEN);
656                        offset = GetNameBytes(this.UserName, outBuffer, offset, UNAMELEN);
657                        offset = GetNameBytes(this.GroupName, outBuffer, offset, GNAMELEN);
658                       
659                        if (this.TypeFlag == LF_CHR || this.TypeFlag == LF_BLK)
660                        {
661                                offset = GetOctalBytes(this.DevMajor, outBuffer, offset, DEVLEN);
662                                offset = GetOctalBytes(this.DevMinor, outBuffer, offset, DEVLEN);
663                        }
664                       
665                        for ( ; offset < outBuffer.Length; )
666                        {
667                                outBuffer[offset++] = 0;
668                        }
669                       
670                        checksum = ComputeCheckSum(outBuffer);
671                       
672                        GetCheckSumOctalBytes(checksum, outBuffer, csOffset, CHKSUMLEN);
673                        isChecksumValid = true;
674                }
675
676                /// <summary>
677                /// Get a hash code for the current object.
678                /// </summary>
679                /// <returns>A hash code for the current object.</returns>
680                public override int GetHashCode()
681                {
682                        return Name.GetHashCode();
683                }
684               
685                /// <summary>
686                /// Determines if this instance is equal to the specified object.
687                /// </summary>
688                /// <param name="obj">The object to compare with.</param>
689                /// <returns>true if the objects are equal, false otherwise.</returns>
690                public override bool Equals(object obj)
691                {
692                        TarHeader localHeader = obj as TarHeader;
693
694                        if ( localHeader != null )
695                        {
696                                return name == localHeader.name
697                                        && mode == localHeader.mode
698                                        && UserId == localHeader.UserId
699                                        && GroupId == localHeader.GroupId
700                                        && Size == localHeader.Size
701                                        && ModTime == localHeader.ModTime
702                                        && Checksum == localHeader.Checksum
703                                        && TypeFlag == localHeader.TypeFlag
704                                        && LinkName == localHeader.LinkName
705                                        && Magic == localHeader.Magic
706                                        && Version == localHeader.Version
707                                        && UserName == localHeader.UserName
708                                        && GroupName == localHeader.GroupName
709                                        && DevMajor == localHeader.DevMajor
710                                        && DevMinor == localHeader.DevMinor;
711                        }
712                        else
713                        {
714                                return false;
715                        }
716                }
717               
718                /// <summary>
719                /// Set defaults for values used when constructing a TarHeader instance.
720                /// </summary>
721                /// <param name="userId">Value to apply as a default for userId.</param>
722                /// <param name="userName">Value to apply as a default for userName.</param>
723                /// <param name="groupId">Value to apply as a default for groupId.</param>
724                /// <param name="groupName">Value to apply as a default for groupName.</param>
725                static internal void SetValueDefaults(int userId, string userName, int groupId, string groupName)
726                {
727                        defaultUserId = userIdAsSet = userId;
728                        defaultUser = userNameAsSet = userName;
729                        defaultGroupId = groupIdAsSet = groupId;
730                        defaultGroupName = groupNameAsSet = groupName;
731                }
732
733                static internal void RestoreSetValues()
734                {
735                        defaultUserId = userIdAsSet;
736                        defaultUser = userNameAsSet;
737                        defaultGroupId = groupIdAsSet;
738                        defaultGroupName = groupNameAsSet;
739                }
740
741                /// <summary>
742                /// Parse an octal string from a header buffer.
743                /// </summary>
744                /// <param name = "header">The header buffer from which to parse.</param>
745                /// <param name = "offset">The offset into the buffer from which to parse.</param>
746                /// <param name = "length">The number of header bytes to parse.</param>
747                /// <returns>The long equivalent of the octal string.</returns>
748                static public long ParseOctal(byte[] header, int offset, int length)
749                {
750                        if ( header == null ) {
751                                throw new ArgumentNullException("header");
752                        }
753
754                        long result = 0;
755                        bool stillPadding = true;
756                       
757                        int end = offset + length;
758                        for (int i = offset; i < end ; ++i) {
759                                if (header[i] == 0) {
760                                        break;
761                                }
762                               
763                                if (header[i] == (byte)' ' || header[i] == '0') {
764                                        if (stillPadding) {
765                                                continue;
766                                        }
767                                       
768                                        if (header[i] == (byte)' ') {
769                                                break;
770                                        }
771                                }
772                               
773                                stillPadding = false;
774                               
775                                result = (result << 3) + (header[i] - '0');
776                        }
777                       
778                        return result;
779                }
780               
781                /// <summary>
782                /// Parse a name from a header buffer.
783                /// </summary>
784                /// <param name="header">
785                /// The header buffer from which to parse.
786                /// </param>
787                /// <param name="offset">
788                /// The offset into the buffer from which to parse.
789                /// </param>
790                /// <param name="length">
791                /// The number of header bytes to parse.
792                /// </param>
793                /// <returns>
794                /// The name parsed.
795                /// </returns>
796                static public StringBuilder ParseName(byte[] header, int offset, int length)
797                {
798                        if ( header == null ) {
799                                throw new ArgumentNullException("header");
800                        }
801
802                        if ( offset < 0 ) {
803#if NETCF_1_0
804                                throw new ArgumentOutOfRangeException("offset");
805#else
806                                throw new ArgumentOutOfRangeException("offset", "Cannot be less than zero");
807#endif                         
808                        }
809
810                        if ( length < 0 )
811                        {
812#if NETCF_1_0
813                                throw new ArgumentOutOfRangeException("length");
814#else
815                                throw new ArgumentOutOfRangeException("length", "Cannot be less than zero");
816#endif                         
817                        }
818
819                        if ( offset + length > header.Length )
820                        {
821                                throw new ArgumentException("Exceeds header size", "length");
822                        }
823
824                        StringBuilder result = new StringBuilder(length);
825                       
826                        for (int i = offset; i < offset + length; ++i) {
827                                if (header[i] == 0) {
828                                        break;
829                                }
830                                result.Append((char)header[i]);
831                        }
832                       
833                        return result;
834                }
835               
836                /// <summary>
837                /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
838                /// </summary>
839                /// <param name="name">The name to add</param>
840                /// <param name="nameOffset">The offset of the first character</param>
841                /// <param name="buffer">The buffer to add to</param>
842                /// <param name="bufferOffset">The index of the first byte to add</param>
843                /// <param name="length">The number of characters/bytes to add</param>
844                /// <returns>The next free index in the <paramref name="buf">buffer</paramref></returns>
845                public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buffer, int bufferOffset, int length)
846                {
847                        if ( name == null ) {
848                                throw new ArgumentNullException("name");
849                        }
850
851                        if ( buffer == null ) {
852                                throw new ArgumentNullException("buffer");
853                        }
854
855                        return GetNameBytes(name.ToString(), nameOffset, buffer, bufferOffset, length);
856                }
857               
858                /// <summary>
859                /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
860                /// </summary>
861                /// <param name="name">The name to add</param>
862                /// <param name="nameOffset">The offset of the first character</param>
863                /// <param name="buffer">The buffer to add to</param>
864                /// <param name="bufferOffset">The index of the first byte to add</param>
865                /// <param name="length">The number of characters/bytes to add</param>
866                /// <returns>The next free index in the <paramref name="buf">buffer</paramref></returns>
867                public static int GetNameBytes(string name, int nameOffset, byte[] buffer, int bufferOffset, int length)
868                {
869                        if ( name == null )
870                        {
871                                throw new ArgumentNullException("name");
872                        }
873
874                        if ( buffer == null )
875                        {
876                                throw new ArgumentNullException("buffer");
877                        }
878
879                        int i;
880                       
881                        for (i = 0 ; i < length - 1 && nameOffset + i < name.Length; ++i) {
882                                buffer[bufferOffset + i] = (byte)name[nameOffset + i];
883                        }
884                       
885                        for (; i < length ; ++i) {
886                                buffer[bufferOffset + i] = 0;
887                        }
888                       
889                        return bufferOffset + length;
890                }
891
892                /// <summary>
893                /// Add an entry name to the buffer
894                /// </summary>
895                /// <param name="name">
896                /// The name to add
897                /// </param>
898                /// <param name="buffer">
899                /// The buffer to add to
900                /// </param>
901                /// <param name="offset">
902                /// The offset into the buffer from which to start adding
903                /// </param>
904                /// <param name="length">
905                /// The number of header bytes to add
906                /// </param>
907                /// <returns>
908                /// The index of the next free byte in the buffer
909                /// </returns>
910                public static int GetNameBytes(StringBuilder name, byte[] buffer, int offset, int length)
911                {
912
913                        if ( name == null ) {
914                                throw new ArgumentNullException("name");
915                        }
916
917                        if ( buffer == null ) {
918                                throw new ArgumentNullException("buffer");
919                        }
920
921                        return GetNameBytes(name.ToString(), 0, buffer, offset, length);
922                }
923               
924                /// <summary>
925                /// Add an entry name to the buffer
926                /// </summary>
927                /// <param name="name">The name to add</param>
928                /// <param name="buffer">The buffer to add to</param>
929                /// <param name="offset">The offset into the buffer from which to start adding</param>
930                /// <param name="length">The number of header bytes to add</param>
931                /// <returns>The index of the next free byte in the buffer</returns>
932                public static int GetNameBytes(string name, byte[] buffer, int offset, int length)
933                {
934
935                        if ( name == null ) {
936                                throw new ArgumentNullException("name");
937                        }
938
939                        if ( buffer == null )
940                        {
941                                throw new ArgumentNullException("buffer");
942                        }
943
944                        return GetNameBytes(name, 0, buffer, offset, length);
945                }
946               
947                /// <summary>
948                /// Add a string to a buffer as a collection of ascii bytes.
949                /// </summary>
950                /// <param name="toAdd">The string to add</param>
951                /// <param name="nameOffset">The offset of the first character to add.</param>
952                /// <param name="buffer">The buffer to add to.</param>
953                /// <param name="bufferOffset">The offset to start adding at.</param>
954                /// <param name="length">The number of ascii characters to add.</param>
955                /// <returns>The next free index in the buffer.</returns>
956                public static int GetAsciiBytes(string toAdd, int nameOffset, byte[] buffer, int bufferOffset, int length )
957                {
958                        if ( toAdd == null ) {
959                                throw new ArgumentNullException("toAdd");
960                        }
961
962                        if ( buffer == null ) {
963                                throw new ArgumentNullException("buffer");
964                        }
965
966                        for (int i = 0 ; i < length && nameOffset + i < toAdd.Length; ++i)
967                        {
968                                buffer[bufferOffset + i] = (byte)toAdd[nameOffset + i];
969                        }
970                        return bufferOffset + length;
971                }
972
973                /// <summary>
974                /// Put an octal representation of a value into a buffer
975                /// </summary>
976                /// <param name = "value">
977                /// the value to be converted to octal
978                /// </param>
979                /// <param name = "buffer">
980                /// buffer to store the octal string
981                /// </param>
982                /// <param name = "offset">
983                /// The offset into the buffer where the value starts
984                /// </param>
985                /// <param name = "length">
986                /// The length of the octal string to create
987                /// </param>
988                /// <returns>
989                /// The offset of the character next byte after the octal string
990                /// </returns>
991                public static int GetOctalBytes(long value, byte[] buffer, int offset, int length)
992                {
993                        if ( buffer == null ) {
994                                throw new ArgumentNullException("buffer");
995                        }
996
997                        int localIndex = length - 1;
998
999                        // Either a space or null is valid here.  We use NULL as per GNUTar
1000                        buffer[offset + localIndex] = 0;
1001                        --localIndex;
1002
1003                        if (value > 0) {
1004                                for ( long v = value; (localIndex >= 0) && (v > 0); --localIndex ) {
1005                                        buffer[offset + localIndex] = (byte)((byte)'0' + (byte)(v & 7));
1006                                        v >>= 3;
1007                                }
1008                        }
1009                               
1010                        for ( ; localIndex >= 0; --localIndex ) {
1011                                buffer[offset + localIndex] = (byte)'0';
1012                        }
1013                       
1014                        return offset + length;
1015                }
1016               
1017                /// <summary>
1018                /// Put an octal representation of a value into a buffer
1019                /// </summary>
1020                /// <param name = "value">Value to be convert to octal</param>
1021                /// <param name = "buffer">The buffer to update</param>
1022                /// <param name = "offset">The offset into the buffer to store the value</param>
1023                /// <param name = "length">The length of the octal string</param>
1024                /// <returns>Index of next byte</returns>
1025                public static int GetLongOctalBytes(long value, byte[] buffer, int offset, int length)
1026                {
1027                        return GetOctalBytes(value, buffer, offset, length);
1028                }
1029               
1030                /// <summary>
1031                /// Add the checksum integer to header buffer.
1032                /// </summary>
1033                /// <param name = "value"></param>
1034                /// <param name = "buffer">The header buffer to set the checksum for</param>
1035                /// <param name = "offset">The offset into the buffer for the checksum</param>
1036                /// <param name = "length">The number of header bytes to update.
1037                /// It's formatted differently from the other fields: it has 6 digits, a
1038                /// null, then a space -- rather than digits, a space, then a null.
1039                /// The final space is already there, from checksumming
1040                /// </param>
1041                /// <returns>The modified buffer offset</returns>
1042                static int GetCheckSumOctalBytes(long value, byte[] buffer, int offset, int length)
1043                {
1044                        TarHeader.GetOctalBytes(value, buffer, offset, length - 1);
1045                        return offset + length;
1046                }
1047               
1048                /// <summary>
1049                /// Compute the checksum for a tar entry header. 
1050                /// The checksum field must be all spaces prior to this happening
1051                /// </summary>
1052                /// <param name = "buffer">The tar entry's header buffer.</param>
1053                /// <returns>The computed checksum.</returns>
1054                static int ComputeCheckSum(byte[] buffer)
1055                {
1056                        int sum = 0;
1057                        for (int i = 0; i < buffer.Length; ++i) {
1058                                sum += buffer[i];
1059                        }
1060                        return sum;
1061                }
1062               
1063                /// <summary>
1064                /// Make a checksum for a tar entry ignoring the checksum contents.
1065                /// </summary>
1066                /// <param name = "buffer">The tar entry's header buffer.</param>
1067                /// <returns>The checksum for the buffer</returns>
1068                static int MakeCheckSum(byte[] buffer)
1069                {
1070                        int sum = 0;
1071                        for ( int i = 0; i < CHKSUMOFS; ++i )
1072                        {
1073                                sum += buffer[i];
1074                        }
1075               
1076                        for ( int i = 0; i < TarHeader.CHKSUMLEN; ++i)
1077                        {
1078                                sum += (byte)' ';
1079                        }
1080               
1081                        for (int i = CHKSUMOFS + CHKSUMLEN; i < buffer.Length; ++i)
1082                        {
1083                                sum += buffer[i];
1084                        }
1085                        return sum;
1086                }
1087               
1088                static int GetCTime(System.DateTime dateTime)
1089                {
1090                        return unchecked((int)((dateTime.Ticks - dateTime1970.Ticks) / timeConversionFactor));
1091                }
1092               
1093                static DateTime GetDateTimeFromCTime(long ticks)
1094                {
1095                        DateTime result;
1096                       
1097                        try {
1098                                result = new DateTime(dateTime1970.Ticks + ticks * timeConversionFactor);
1099                        }
1100                        catch(ArgumentOutOfRangeException) {
1101                                result = dateTime1970;
1102                        }
1103                        return result;
1104                }
1105
1106                #region Instance Fields
1107                string name;
1108                int mode;
1109                int userId;
1110                int groupId;
1111                long size;
1112                DateTime modTime;
1113                int checksum;
1114                bool isChecksumValid;
1115                byte typeFlag;
1116                string linkName;
1117                string magic;
1118                string version;
1119                string userName;
1120                string groupName;
1121                int devMajor;
1122                int devMinor;
1123                #endregion
1124
1125                #region Class Fields
1126                // Values used during recursive operations.
1127                static internal int userIdAsSet;
1128                static internal int groupIdAsSet;
1129                static internal string userNameAsSet;
1130                static internal string groupNameAsSet = "None";
1131               
1132                static internal int defaultUserId;
1133                static internal int defaultGroupId;
1134                static internal string defaultGroupName = "None";
1135                static internal string defaultUser;
1136                #endregion
1137        }
1138}
1139
1140/* The original Java file had this header:
1141 *
1142** Authored by Timothy Gerard Endres
1143** <mailto:time@gjt.org>  <http://www.trustice.com>
1144**
1145** This work has been placed into the public domain.
1146** You may use this work in any way and for any purpose you wish.
1147**
1148** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
1149** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
1150** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
1151** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
1152** REDISTRIBUTION OF THIS SOFTWARE.
1153**
1154*/
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.