root/branches/Abonament/BazaReklam.Updater/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs @ 759

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

re #165

Line 
1// ZipEntry.cs
2//
3// Copyright (C) 2001 Mike Krueger
4// Copyright (C) 2004 John Reilly
5//
6// This file was translated from java, it was part of the GNU Classpath
7// Copyright (C) 2001 Free Software Foundation, Inc.
8//
9// This program is free software; you can redistribute it and/or
10// modify it under the terms of the GNU General Public License
11// as published by the Free Software Foundation; either version 2
12// of the License, or (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22//
23// Linking this library statically or dynamically with other modules is
24// making a combined work based on this library.  Thus, the terms and
25// conditions of the GNU General Public License cover the whole
26// combination.
27//
28// As a special exception, the copyright holders of this library give you
29// permission to link this library with independent modules to produce an
30// executable, regardless of the license terms of these independent
31// modules, and to copy and distribute the resulting executable under
32// terms of your choice, provided that you also meet, for each linked
33// independent module, the terms and conditions of the license of that
34// module.  An independent module is a module which is not derived from
35// or based on this library.  If you modify this library, you may extend
36// this exception to your version of the library, but you are not
37// obligated to do so.  If you do not wish to do so, delete this
38// exception statement from your version.
39
40using System;
41using System.IO;
42
43namespace ICSharpCode.SharpZipLib.Zip
44{
45
46        /// <summary>
47        /// Defines known values for the <see cref="HostSystemID"/> property.
48        /// </summary>
49        public enum HostSystemID
50        {
51                /// <summary>
52                /// Host system = MSDOS
53                /// </summary>
54                Msdos = 0,
55                /// <summary>
56                /// Host system = Amiga
57                /// </summary>
58                Amiga = 1,
59                /// <summary>
60                /// Host system = Open VMS
61                /// </summary>
62                OpenVms = 2,
63                /// <summary>
64                /// Host system = Unix
65                /// </summary>
66                Unix = 3,
67                /// <summary>
68                /// Host system = VMCms
69                /// </summary>
70                VMCms = 4,
71                /// <summary>
72                /// Host system = Atari ST
73                /// </summary>
74                AtariST = 5,
75                /// <summary>
76                /// Host system = OS2
77                /// </summary>
78                OS2 = 6,
79                /// <summary>
80                /// Host system = Macintosh
81                /// </summary>
82                Macintosh = 7,
83                /// <summary>
84                /// Host system = ZSystem
85                /// </summary>
86                ZSystem = 8,
87                /// <summary>
88                /// Host system = Cpm
89                /// </summary>
90                Cpm = 9,
91                /// <summary>
92                /// Host system = Windows NT
93                /// </summary>
94                WindowsNT = 10,
95                /// <summary>
96                /// Host system = MVS
97                /// </summary>
98                MVS = 11,
99                /// <summary>
100                /// Host system = VSE
101                /// </summary>
102                Vse = 12,
103                /// <summary>
104                /// Host system = Acorn RISC
105                /// </summary>
106                AcornRisc = 13,
107                /// <summary>
108                /// Host system = VFAT
109                /// </summary>
110                Vfat = 14,
111                /// <summary>
112                /// Host system = Alternate MVS
113                /// </summary>
114                AlternateMvs = 15,
115                /// <summary>
116                /// Host system = BEOS
117                /// </summary>
118                BeOS = 16,
119                /// <summary>
120                /// Host system = Tandem
121                /// </summary>
122                Tandem = 17,
123                /// <summary>
124                /// Host system = OS400
125                /// </summary>
126                OS400 = 18,
127                /// <summary>
128                /// Host system = OSX
129                /// </summary>
130                OSX = 19,
131                /// <summary>
132                /// Host system = WinZIP AES
133                /// </summary>
134                WinZipAES = 99,
135        }
136       
137        /// <summary>
138        /// This class represents an entry in a zip archive.  This can be a file
139        /// or a directory
140        /// ZipFile and ZipInputStream will give you instances of this class as
141        /// information about the members in an archive.  ZipOutputStream
142        /// uses an instance of this class when creating an entry in a Zip file.
143        /// <br/>
144        /// <br/>Author of the original java version : Jochen Hoenicke
145        /// </summary>
146        public class ZipEntry : ICloneable
147        {
148                [Flags]
149                enum Known : byte
150                {
151                        None = 0,
152                        Size = 0x01,
153                        CompressedSize = 0x02,
154                        Crc = 0x04,
155                        Time = 0x08,
156                        ExternalAttributes = 0x10,
157                }
158               
159                #region Constructors
160                /// <summary>
161                /// Creates a zip entry with the given name.
162                /// </summary>
163                /// <param name="name">
164                /// The name for this entry. Can include directory components.
165                /// The convention for names is 'unix' style paths with relative names only.
166                /// There are with no device names and path elements are separated by '/' characters.
167                /// </param>
168                /// <exception cref="ArgumentNullException">
169                /// The name passed is null
170                /// </exception>
171                public ZipEntry(string name)
172                        : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)
173                {
174                }
175
176                /// <summary>
177                /// Creates a zip entry with the given name and version required to extract
178                /// </summary>
179                /// <param name="name">
180                /// The name for this entry. Can include directory components.
181                /// The convention for names is 'unix'  style paths with no device names and
182                /// path elements separated by '/' characters.  This is not enforced see <see cref="CleanName(string)">CleanName</see>
183                /// on how to ensure names are valid if this is desired.
184                /// </param>
185                /// <param name="versionRequiredToExtract">
186                /// The minimum 'feature version' required this entry
187                /// </param>
188                /// <exception cref="ArgumentNullException">
189                /// The name passed is null
190                /// </exception>
191                internal ZipEntry(string name, int versionRequiredToExtract)
192                        : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy,
193                        CompressionMethod.Deflated)
194                {
195                }
196               
197                /// <summary>
198                /// Initializes an entry with the given name and made by information
199                /// </summary>
200                /// <param name="name">Name for this entry</param>
201                /// <param name="madeByInfo">Version and HostSystem Information</param>
202                /// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</param>
203                /// <param name="method">Compression method for this entry.</param>
204                /// <exception cref="ArgumentNullException">
205                /// The name passed is null
206                /// </exception>
207                /// <exception cref="ArgumentOutOfRangeException">
208                /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
209                /// </exception>
210                /// <remarks>
211                /// This constructor is used by the ZipFile class when reading from the central header
212                /// It is not generally useful, use the constructor specifying the name only.
213                /// </remarks>
214                internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
215                        CompressionMethod method)
216                {
217                        if (name == null) {
218                                throw new System.ArgumentNullException("name");
219                        }
220
221                        if ( name.Length > 0xffff )     {
222                                throw new ArgumentException("Name is too long", "name");
223                        }
224
225                        if ( (versionRequiredToExtract != 0) && (versionRequiredToExtract < 10) ) {
226                                throw new ArgumentOutOfRangeException("versionRequiredToExtract");
227                        }
228                       
229                        this.DateTime = System.DateTime.Now;
230                        this.name = name;
231                        this.versionMadeBy = (ushort)madeByInfo;
232                        this.versionToExtract = (ushort)versionRequiredToExtract;
233                        this.method = method;
234                }
235               
236                /// <summary>
237                /// Creates a deep copy of the given zip entry.
238                /// </summary>
239                /// <param name="entry">
240                /// The entry to copy.
241                /// </param>
242                [Obsolete("Use Clone instead")]
243                public ZipEntry(ZipEntry entry)
244                {
245                        if ( entry == null ) {
246                                throw new ArgumentNullException("entry");
247                        }
248
249                        known                  = entry.known;
250                        name                   = entry.name;
251                        size                   = entry.size;
252                        compressedSize         = entry.compressedSize;
253                        crc                    = entry.crc;
254                        dosTime                = entry.dosTime;
255                        method                 = entry.method;
256                        comment                = entry.comment;
257                        versionToExtract       = entry.versionToExtract;
258                        versionMadeBy          = entry.versionMadeBy;
259                        externalFileAttributes = entry.externalFileAttributes;
260                        flags                  = entry.flags;
261
262                        zipFileIndex           = entry.zipFileIndex;
263                        offset                 = entry.offset;
264
265                        forceZip64_                        = entry.forceZip64_;
266
267                        if ( entry.extra != null ) {
268                                extra = new byte[entry.extra.Length];
269                                Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
270                        }
271                }
272
273                #endregion
274               
275                /// <summary>
276                /// Get a value indicating wether the entry has a CRC value available.
277                /// </summary>
278                public bool HasCrc
279                {
280                        get {
281                                return (known & Known.Crc) != 0;
282                        }
283                }
284
285                /// <summary>
286                /// Get/Set flag indicating if entry is encrypted.
287                /// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>
288                /// </summary>
289                /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
290                public bool IsCrypted
291                {
292                        get {
293                                return (flags & 1) != 0;
294                        }
295                        set {
296                                if (value) {
297                                        flags |= 1;
298                                }
299                                else {
300                                        flags &= ~1;
301                                }
302                        }
303                }
304
305                /// <summary>
306                /// Get / set a flag indicating wether entry name and comment text are
307                /// encoded in <a href="http://www.unicode.org">unicode UTF8</a>.
308                /// </summary>
309                /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
310                public bool IsUnicodeText
311                {
312                        get {
313                                return ( flags & (int)GeneralBitFlags.UnicodeText ) != 0;
314                        }
315                        set {
316                                if ( value ) {
317                                        flags |= (int)GeneralBitFlags.UnicodeText;
318                                }
319                                else {
320                                        flags &= ~(int)GeneralBitFlags.UnicodeText;
321                                }
322                        }
323                }
324               
325                /// <summary>
326                /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.
327                /// </summary>
328                internal byte CryptoCheckValue
329                {
330                        get {
331                                return cryptoCheckValue_;
332                        }
333
334                        set     {
335                                cryptoCheckValue_ = value;
336                        }
337                }
338
339                /// <summary>
340                /// Get/Set general purpose bit flag for entry
341                /// </summary>
342                /// <remarks>
343                /// General purpose bit flag<br/>
344                /// <br/>
345                /// Bit 0: If set, indicates the file is encrypted<br/>
346                /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>
347                /// Imploding:<br/>
348                /// Bit 1 if set indicates an 8K sliding dictionary was used.  If clear a 4k dictionary was used<br/>
349                /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>
350                /// <br/>
351                /// Deflating:<br/>
352                ///   Bit 2    Bit 1<br/>
353                ///     0        0       Normal compression was used<br/>
354                ///     0        1       Maximum compression was used<br/>
355                ///     1        0       Fast compression was used<br/>
356                ///     1        1       Super fast compression was used<br/>
357                /// <br/>
358                /// Bit 3: If set, the fields crc-32, compressed size
359                /// and uncompressed size are were not able to be written during zip file creation
360                /// The correct values are held in a data descriptor immediately following the compressed data. <br/>
361                /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
362                /// Bit 5: If set indicates the file contains compressed patch data<br/>
363                /// Bit 6: If set indicates strong encryption was used.<br/>
364                /// Bit 7-10: Unused or reserved<br/>
365                /// Bit 11: If set the name and comments for this entry are in <a href="http://www.unicode.org">unicode</a>.<br/>
366                /// Bit 12-15: Unused or reserved<br/>
367                /// </remarks>
368                /// <seealso cref="IsUnicodeText"></seealso>
369                /// <seealso cref="IsCrypted"></seealso>
370                public int Flags
371                {
372                        get {
373                                return flags;
374                        }
375                        set {
376                                flags = value;
377                        }
378                }
379
380                /// <summary>
381                /// Get/Set index of this entry in Zip file
382                /// </summary>
383                /// <remarks>This is only valid when the entry is part of a <see cref="ZipFile"></see></remarks>
384                public long ZipFileIndex
385                {
386                        get {
387                                return zipFileIndex;
388                        }
389                        set {
390                                zipFileIndex = value;
391                        }
392                }
393               
394                /// <summary>
395                /// Get/set offset for use in central header
396                /// </summary>
397                public long Offset
398                {
399                        get {
400                                return offset;
401                        }
402                        set {
403                                offset = value;
404                        }
405                }
406
407                /// <summary>
408                /// Get/Set external file attributes as an integer.
409                /// The values of this are operating system dependant see
410                /// <see cref="HostSystem">HostSystem</see> for details
411                /// </summary>
412                public int ExternalFileAttributes
413                {
414                        get {
415                                if ((known & Known.ExternalAttributes) == 0) {
416                                        return -1;
417                                }
418                                else {
419                                        return externalFileAttributes;
420                                }
421                        }
422                       
423                        set {
424                                externalFileAttributes = value;
425                                known |= Known.ExternalAttributes;
426                        }
427                }
428
429                /// <summary>
430                /// Get the version made by for this entry or zero if unknown.
431                /// The value / 10 indicates the major version number, and
432                /// the value mod 10 is the minor version number
433                /// </summary>
434                public int VersionMadeBy
435                {
436                        get {
437                                return (versionMadeBy & 0xff);
438                        }
439                }
440
441                /// <summary>
442                /// Get a value indicating this entry is for a DOS/Windows system.
443                /// </summary>
444                public bool IsDOSEntry
445                {
446                        get {
447                                return ((HostSystem == ( int )HostSystemID.Msdos) ||
448                                        (HostSystem == ( int )HostSystemID.WindowsNT));
449                        }
450                }
451
452                /// <summary>
453                /// Test the external attributes for this <see cref="ZipEntry"/> to
454                /// see if the external attributes are Dos based (including WINNT and variants)
455                /// and match the values
456                /// </summary>
457                /// <param name="attributes">The attributes to test.</param>
458                /// <returns>Returns true if the external attributes are known to be DOS/Windows
459                /// based and have the same attributes set as the value passed.</returns>
460                bool HasDosAttributes(int attributes)
461                {
462                        bool result = false;
463                        if ( (known & Known.ExternalAttributes) != 0 ) {
464                                if ( ((HostSystem == (int)HostSystemID.Msdos) ||
465                                        (HostSystem == (int)HostSystemID.WindowsNT)) &&
466                                        (ExternalFileAttributes & attributes) == attributes) {
467                                        result = true;
468                                }
469                        }
470                        return result;
471                }
472
473                /// <summary>
474                /// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>
475                /// If the external file attributes are compatible with MS-DOS and can be read
476                /// by PKZIP for DOS version 2.04g then this value will be zero.  Otherwise the value
477                /// will be non-zero and identify the host system on which the attributes are compatible.
478                /// </summary>
479                ///             
480                /// <remarks>
481                /// The values for this as defined in the Zip File format and by others are shown below.  The values are somewhat
482                /// misleading in some cases as they are not all used as shown.  You should consult the relevant documentation
483                /// to obtain up to date and correct information.  The modified appnote by the infozip group is
484                /// particularly helpful as it documents a lot of peculiarities.  The document is however a little dated.
485                /// <list type="table">
486                /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
487                /// <item>1 - Amiga</item>
488                /// <item>2 - OpenVMS</item>
489                /// <item>3 - Unix</item>
490                /// <item>4 - VM/CMS</item>
491                /// <item>5 - Atari ST</item>
492                /// <item>6 - OS/2 HPFS</item>
493                /// <item>7 - Macintosh</item>
494                /// <item>8 - Z-System</item>
495                /// <item>9 - CP/M</item>
496                /// <item>10 - Windows NTFS</item>
497                /// <item>11 - MVS (OS/390 - Z/OS)</item>
498                /// <item>12 - VSE</item>
499                /// <item>13 - Acorn Risc</item>
500                /// <item>14 - VFAT</item>
501                /// <item>15 - Alternate MVS</item>
502                /// <item>16 - BeOS</item>
503                /// <item>17 - Tandem</item>
504                /// <item>18 - OS/400</item>
505                /// <item>19 - OS/X (Darwin)</item>
506                /// <item>99 - WinZip AES</item>
507                /// <item>remainder - unused</item>
508                /// </list>
509                /// </remarks>
510                public int HostSystem
511                {
512                        get {
513                                return (versionMadeBy >> 8) & 0xff;
514                        }
515
516                        set {
517                                versionMadeBy &= 0xff;
518                                versionMadeBy |= (ushort)((value & 0xff) << 8);
519                        }
520                }
521               
522                /// <summary>
523                /// Get minimum Zip feature version required to extract this entry
524                /// </summary>         
525                /// <remarks>
526                /// Minimum features are defined as:<br/>
527                /// 1.0 - Default value<br/>
528                /// 1.1 - File is a volume label<br/>
529                /// 2.0 - File is a folder/directory<br/>
530                /// 2.0 - File is compressed using Deflate compression<br/>
531                /// 2.0 - File is encrypted using traditional encryption<br/>
532                /// 2.1 - File is compressed using Deflate64<br/>
533                /// 2.5 - File is compressed using PKWARE DCL Implode<br/>
534                /// 2.7 - File is a patch data set<br/>
535                /// 4.5 - File uses Zip64 format extensions<br/>
536                /// 4.6 - File is compressed using BZIP2 compression<br/>
537                /// 5.0 - File is encrypted using DES<br/>
538                /// 5.0 - File is encrypted using 3DES<br/>
539                /// 5.0 - File is encrypted using original RC2 encryption<br/>
540                /// 5.0 - File is encrypted using RC4 encryption<br/>
541                /// 5.1 - File is encrypted using AES encryption<br/>
542                /// 5.1 - File is encrypted using corrected RC2 encryption<br/>
543                /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
544                /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
545                /// 6.2 - Central directory encryption (not confirmed yet)<br/>
546                /// 6.3 - File is compressed using LZMA<br/>
547                /// 6.3 - File is compressed using PPMD+<br/>
548                /// 6.3 - File is encrypted using Blowfish<br/>
549                /// 6.3 - File is encrypted using Twofish<br/>
550                /// </remarks>
551                /// <seealso cref="CanDecompress"></seealso>
552                public int Version
553                {
554                        get {
555                                // Return recorded version if known.
556                                if (versionToExtract != 0) {
557                                        return versionToExtract;
558                                }
559                                else {
560                                        int result = 10;
561                                        if ( CentralHeaderRequiresZip64 ) {
562                                                result = ZipConstants.VersionZip64;     
563                                        }
564                                        else if (CompressionMethod.Deflated == method) {
565                                                result = 20;
566                                        }
567                                        else if (IsDirectory == true) {
568                                                result = 20;
569                                        }
570                                        else if (IsCrypted == true) {
571                                                result = 20;
572                                        }
573                                        else if (HasDosAttributes(0x08) ) {
574                                                result = 11;
575                                        }
576                                        return result;
577                                }
578                        }
579                }
580
581                /// <summary>
582                /// Get a value indicating wether this entry can be decompressed by the library.
583                /// </summary>
584                /// <remarks>This is based on the <see cref="Version"></see> and
585                /// wether the <see cref="IsCompressionMethodSupported()">compression method</see> is supported.</remarks>
586                public bool CanDecompress
587                {
588                        get {
589                                return (Version <= ZipConstants.VersionMadeBy) &&
590                                        ((Version == 10) ||
591                                        (Version == 11) ||
592                                        (Version == 20) ||
593                                        (Version == 45)) &&
594                                        IsCompressionMethodSupported();
595                        }
596                }
597
598                /// <summary>
599                /// Force this entry to be recorded using Zip64 extensions.
600                /// </summary>
601                public void ForceZip64()
602                {
603                        forceZip64_ = true;
604                }
605               
606                /// <summary>
607                /// Get a value indicating wether Zip64 extensions were forced.
608                /// </summary>
609                /// <returns>A <see cref="bool"/> value of true if Zip64 extensions have been forced on; false if not.</returns>
610                public bool IsZip64Forced()
611                {
612                        return forceZip64_;
613                }
614
615                /// <summary>
616                /// Gets a value indicating if the entry requires Zip64 extensions
617                /// to store the full entry values.
618                /// </summary>
619                /// <value>A <see cref="bool"/> value of true if a local header requires Zip64 extensions; false if not.</value>
620                public bool LocalHeaderRequiresZip64
621                {
622                        get {
623                                bool result = forceZip64_;
624
625                                if ( !result ) {
626                                        ulong trueCompressedSize = compressedSize;
627
628                                        if ( (versionToExtract == 0) && IsCrypted ) {
629                                                trueCompressedSize += ZipConstants.CryptoHeaderSize;
630                                        }
631
632                                        // TODO: A better estimation of the true limit based on compression overhead should be used
633                                        // to determine when an entry should use Zip64.
634                                        result =
635                                                ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) &&
636                                                ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64));
637                                }
638
639                                return result;
640                        }
641                }
642               
643                /// <summary>
644                /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored.
645                /// </summary>
646                public bool CentralHeaderRequiresZip64
647                {
648                        get {
649                                return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue);
650                        }
651                }
652               
653                /// <summary>
654                /// Get/Set DosTime value.
655                /// </summary>
656                /// <remarks>
657                /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107.
658                /// </remarks>
659                public long DosTime
660                {
661                        get {
662                                if ((known & Known.Time) == 0) {
663                                        return 0;
664                                }
665                                else {
666                                        return dosTime;
667                                }
668                        }
669                       
670                        set {
671                                unchecked {
672                                        dosTime = (uint)value;
673                                }
674
675                                known |= Known.Time;
676                        }
677                }
678                       
679                /// <summary>
680                /// Gets/Sets the time of last modification of the entry.
681                /// </summary>
682                /// <remarks>
683                /// The <see cref="DosTime"></see> property is updated to match this as far as possible.
684                /// </remarks>
685                public DateTime DateTime
686                {
687                        get {
688                                uint sec  = Math.Min(59, 2 * (dosTime & 0x1f));
689                                uint min  = Math.Min(59, (dosTime >> 5) & 0x3f);
690                                uint hrs  = Math.Min(23, (dosTime >> 11) & 0x1f);
691                                uint mon  = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
692                                uint year = ((dosTime >> 25) & 0x7f) + 1980;
693                                int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
694                                return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec);
695                        }
696
697                        set {
698                                uint year = (uint) value.Year;
699                                uint month = (uint) value.Month;
700                                uint day = (uint) value.Day;
701                                uint hour = (uint) value.Hour;
702                                uint minute = (uint) value.Minute;
703                                uint second = (uint) value.Second;
704                               
705                                if ( year < 1980 ) {
706                                        year = 1980;
707                                        month = 1;
708                                        day = 1;
709                                        hour = 0;
710                                        minute = 0;
711                                        second = 0;
712                                }
713                                else if ( year > 2107 ) {
714                                        year = 2107;
715                                        month = 12;
716                                        day = 31;
717                                        hour = 23;
718                                        minute = 59;
719                                        second = 59;
720                                }
721                               
722                                DosTime = ((year - 1980) & 0x7f) << 25 |
723                                        (month << 21) |
724                                        (day << 16) |
725                                        (hour << 11) |
726                                        (minute << 5) |
727                                        (second >> 1);
728                        }
729                }
730               
731                /// <summary>
732                /// Returns the entry name.
733                /// </summary>
734                /// <remarks>
735                /// The unix naming convention is followed.
736                /// Path components in the entry should always separated by forward slashes ('/').
737                /// Dos device names like C: should also be removed.
738                /// See the <see cref="ZipNameTransform"/> class, or <see cref="CleanName(string)"/>
739                ///</remarks>
740                public string Name
741                {
742                        get {
743                                return name;
744                        }
745                }
746               
747                /// <summary>
748                /// Gets/Sets the size of the uncompressed data.
749                /// </summary>
750                /// <returns>
751                /// The size or -1 if unknown.
752                /// </returns>
753                /// <remarks>Setting the size before adding an entry to an archive can help
754                /// avoid compatability problems with some archivers which dont understand Zip64 extensions.</remarks>
755                public long Size
756                {
757                        get {
758                                return (known & Known.Size) != 0 ? (long)size : -1L;
759                        }
760                        set {
761                                this.size  = (ulong)value;
762                                this.known |= Known.Size;
763                        }
764                }
765               
766                /// <summary>
767                /// Gets/Sets the size of the compressed data.
768                /// </summary>
769                /// <returns>
770                /// The compressed entry size or -1 if unknown.
771                /// </returns>
772                public long CompressedSize
773                {
774                        get {
775                                return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L;
776                        }
777                        set {
778                                this.compressedSize = (ulong)value;
779                                this.known |= Known.CompressedSize;
780                        }
781                }
782
783                /// <summary>
784                /// Gets/Sets the crc of the uncompressed data.
785                /// </summary>
786                /// <exception cref="System.ArgumentOutOfRangeException">
787                /// Crc is not in the range 0..0xffffffffL
788                /// </exception>
789                /// <returns>
790                /// The crc value or -1 if unknown.
791                /// </returns>
792                public long Crc
793                {
794                        get {
795                                return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L;
796                        }
797                        set {
798                                if (((ulong)crc & 0xffffffff00000000L) != 0) {
799                                        throw new ArgumentOutOfRangeException("value");
800                                }
801                                this.crc = (uint)value;
802                                this.known |= Known.Crc;
803                        }
804                }
805               
806                /// <summary>
807                /// Gets/Sets the compression method. Only Deflated and Stored are supported.
808                /// </summary>
809                /// <returns>
810                /// The compression method for this entry
811                /// </returns>
812                /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Deflated"/>
813                /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Stored"/>
814                public CompressionMethod CompressionMethod {
815                        get {
816                                return method;
817                        }
818
819                        set {
820                                if ( !IsCompressionMethodSupported(value) ) {
821                                        throw new NotSupportedException("Compression method not supported");
822                                }
823                                this.method = value;
824                        }
825                }
826               
827                /// <summary>
828                /// Gets/Sets the extra data.
829                /// </summary>
830                /// <exception cref="System.ArgumentOutOfRangeException">
831                /// Extra data is longer than 64KB (0xffff) bytes.
832                /// </exception>
833                /// <returns>
834                /// Extra data or null if not set.
835                /// </returns>
836                public byte[] ExtraData {
837                       
838                        get {
839// TODO: This is slightly safer but less efficient.  Think about wether it should change.
840//                              return (byte[]) extra.Clone();
841                                return extra;
842                        }
843
844                        set {
845                                if (value == null) {
846                                        extra = null;
847                                }
848                                else {
849                                        if (value.Length > 0xffff) {
850                                                throw new System.ArgumentOutOfRangeException("value");
851                                        }
852                               
853                                        extra = new byte[value.Length];
854                                        Array.Copy(value, 0, extra, 0, value.Length);
855                                }
856                        }
857                }
858               
859                /// <summary>
860                /// Process extra data fields updating the entry based on the contents.
861                /// </summary>
862                /// <param name="localHeader">True if the extra data fields should be handled
863                /// for a local header, rather than for a central header.
864                /// </param>
865                internal void ProcessExtraData(bool localHeader)
866                {
867                        ZipExtraData extraData = new ZipExtraData(this.extra);
868
869                        if ( extraData.Find(0x0001) ) {
870                                if ( (versionToExtract & 0xff) < ZipConstants.VersionZip64 ) {
871                                        throw new ZipException("Zip64 Extended information found but version is not valid");
872                                }
873
874                                // The recorded size will change but remember that this is zip64.
875                                forceZip64_ = true;
876
877                                if ( extraData.ValueLength < 4 ) {
878                                        throw new ZipException("Extra data extended Zip64 information length is invalid");
879                                }
880
881                                if ( localHeader || (size == uint.MaxValue) ) {
882                                        size = (ulong)extraData.ReadLong();
883                                }
884
885                                if ( localHeader || (compressedSize == uint.MaxValue) ) {
886                                        compressedSize = (ulong)extraData.ReadLong();
887                                }
888
889                                if ( !localHeader && (offset == uint.MaxValue) ) {
890                                        offset = extraData.ReadLong();
891                                }
892                        }
893                        else {
894                                if (
895                                        ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
896                                        ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
897                                ) {
898                                        throw new ZipException("Zip64 Extended information required but is missing.");
899                                }
900                        }
901
902                        if ( extraData.Find(10) ) {
903                                // No room for any tags.
904                                if ( extraData.ValueLength < 8 ) {
905                                        throw new ZipException("NTFS Extra data invalid");
906                                }
907
908                                extraData.ReadInt(); // Reserved
909
910                                while ( extraData.UnreadCount >= 4 ) {
911                                        int ntfsTag = extraData.ReadShort();
912                                        int ntfsLength = extraData.ReadShort();
913                                        if ( ntfsTag == 1 ) {
914                                                if ( ntfsLength >= 24 ) {
915                                                        long lastModification = extraData.ReadLong();
916                                                        long lastAccess = extraData.ReadLong();
917                                                        long createTime = extraData.ReadLong();
918
919                                                        DateTime = System.DateTime.FromFileTime(lastModification);
920                                                }
921                                                break;
922                                        }
923                                        else {
924                                                // An unknown NTFS tag so simply skip it.
925                                                extraData.Skip(ntfsLength);
926                                        }
927                                }
928                        }
929                        else if ( extraData.Find(0x5455) ) {
930                                int length = extraData.ValueLength;     
931                                int flags = extraData.ReadByte();
932                                       
933                                // Can include other times but these are ignored.  Length of data should
934                                // actually be 1 + 4 * no of bits in flags.
935                                if ( ((flags & 1) != 0) && (length >= 5) ) {
936                                        int iTime = extraData.ReadInt();
937
938                                        DateTime = (new System.DateTime ( 1970, 1, 1, 0, 0, 0 ).ToUniversalTime() +
939                                                new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime();
940                                }
941                        }
942                }
943
944                /// <summary>
945                /// Gets/Sets the entry comment.
946                /// </summary>
947                /// <exception cref="System.ArgumentOutOfRangeException">
948                /// If comment is longer than 0xffff.
949                /// </exception>
950                /// <returns>
951                /// The comment or null if not set.
952                /// </returns>
953                /// <remarks>
954                /// A comment is only available for entries when read via the <see cref="ZipFile"/> class.
955                /// The <see cref="ZipInputStream"/> class doesnt have the comment data available.
956                /// </remarks>
957                public string Comment {
958                        get {
959                                return comment;
960                        }
961                        set {
962                                // This test is strictly incorrect as the length is in characters
963                                // while the storage limit is in bytes.
964                                // While the test is partially correct in that a comment of this length or greater
965                                // is definitely invalid, shorter comments may also have an invalid length
966                                // where there are multi-byte characters
967                                // The full test is not possible here however as the code page to apply conversions with
968                                // isnt available.
969                                if ( (value != null) && (value.Length > 0xffff) ) {
970#if NETCF_1_0
971                                        throw new ArgumentOutOfRangeException("value");
972#else
973                                        throw new ArgumentOutOfRangeException("value", "cannot exceed 65535");
974#endif
975                                }
976                               
977                                comment = value;
978                        }
979                }
980               
981                /// <summary>
982                /// Gets a value indicating if the entry is a directory.
983                /// however.
984                /// </summary>
985                /// <remarks>
986                /// A directory is determined by an entry name with a trailing slash '/'.
987                /// The external file attributes can also indicate an entry is for a directory.
988                /// Currently only dos/windows attributes are tested in this manner.
989                /// The trailing slash convention should always be followed.
990                /// </remarks>
991                public bool IsDirectory
992                {
993                        get {
994                                int nameLength = name.Length;
995                                bool result =
996                                        ((nameLength > 0) &&
997                                        ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) ||
998                                        HasDosAttributes(16)
999                                        ;
1000                                return result;
1001                        }
1002                }
1003               
1004                /// <summary>
1005                /// Get a value of true if the entry appears to be a file; false otherwise
1006                /// </summary>
1007                /// <remarks>
1008                /// This only takes account of DOS/Windows attributes.  Other operating systems are ignored.
1009                /// For linux and others the result may be incorrect.
1010                /// </remarks>
1011                public bool IsFile
1012                {
1013                        get {
1014                                return !IsDirectory && !HasDosAttributes(8);
1015                        }
1016                }
1017               
1018                /// <summary>
1019                /// Test entry to see if data can be extracted.
1020                /// </summary>
1021                /// <returns>Returns true if data can be extracted for this entry; false otherwise.</returns>
1022                public bool IsCompressionMethodSupported()
1023                {
1024                        return IsCompressionMethodSupported(CompressionMethod);
1025                }
1026               
1027                #region ICloneable Members
1028                /// <summary>
1029                /// Creates a copy of this zip entry.
1030                /// </summary>
1031                /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>
1032                public object Clone()
1033                {
1034                        ZipEntry result = (ZipEntry)this.MemberwiseClone();
1035
1036                        // Ensure extra data is unique if it exists.
1037                        if ( extra != null ) {
1038                                result.extra = new byte[extra.Length];
1039                                Array.Copy(extra, 0, result.extra, 0, extra.Length);
1040                        }
1041
1042                        return result;
1043                }
1044               
1045                #endregion
1046
1047                /// <summary>
1048                /// Gets a string representation of this ZipEntry.
1049                /// </summary>
1050                /// <returns>A readable textual representation of this <see cref="ZipEntry"/></returns>
1051                public override string ToString()
1052                {
1053                        return name;
1054                }
1055
1056                /// <summary>
1057                /// Test a <see cref="CompressionMethod">compression method</see> to see if this library
1058                /// supports extracting data compressed with that method
1059                /// </summary>
1060                /// <param name="method">The compression method to test.</param>
1061                /// <returns>Returns true if the compression method is supported; false otherwise</returns>
1062                public static bool IsCompressionMethodSupported(CompressionMethod method)
1063                {
1064                        return
1065                                ( method == CompressionMethod.Deflated ) ||
1066                                ( method == CompressionMethod.Stored );
1067                }
1068               
1069                /// <summary>
1070                /// Cleans a name making it conform to Zip file conventions.
1071                /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
1072                /// and forward slashes ('\') are converted to back slashes ('/').
1073                /// Names are made relative by trimming leading slashes which is compatible
1074                /// with the ZIP naming convention.
1075                /// </summary>
1076                /// <param name="name">The name to clean</param>
1077                /// <returns>The 'cleaned' name.</returns>
1078                /// <remarks>
1079                /// The <seealso cref="ZipNameTransform">Zip name transform</seealso> class is more flexible.
1080                /// </remarks>
1081                public static string CleanName(string name)
1082                {
1083                        if (name == null) {
1084                                return string.Empty;
1085                        }
1086                       
1087                        if (Path.IsPathRooted(name) == true) {
1088                                // NOTE:
1089                                // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
1090                                name = name.Substring(Path.GetPathRoot(name).Length);
1091                        }
1092
1093                        name = name.Replace(@"\", "/");
1094                       
1095                        while ( (name.Length > 0) && (name[0] == '/')) {
1096                                name = name.Remove(0, 1);
1097                        }
1098                        return name;
1099                }
1100
1101                #region Instance Fields
1102                Known known;
1103                int    externalFileAttributes = -1;     // contains external attributes (O/S dependant)
1104               
1105                ushort versionMadeBy;                                   // Contains host system and version information
1106                                                                                                // only relevant for central header entries
1107               
1108                string name;
1109                ulong  size;
1110                ulong  compressedSize;
1111                ushort versionToExtract;                // Version required to extract (library handles <= 2.0)
1112                uint   crc;
1113                uint   dosTime;
1114               
1115                CompressionMethod  method = CompressionMethod.Deflated;
1116                byte[] extra;
1117                string comment;
1118               
1119                int flags;                             // general purpose bit flags
1120
1121                long zipFileIndex = -1;                // used by ZipFile
1122                long offset;                           // used by ZipFile and ZipOutputStream
1123               
1124                bool forceZip64_;
1125                byte cryptoCheckValue_;
1126                #endregion
1127        }
1128}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.