Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/Packaging/DotNetZip/ZipDirEntry.cs @ 13401

Last change on this file since 13401 was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 15.8 KB
Line 
1// ZipDirEntry.cs
2// ------------------------------------------------------------------
3//
4// Copyright (c) 2006-2011 Dino Chiesa .
5// All rights reserved.
6//
7// This code module is part of DotNetZip, a zipfile class library.
8//
9// ------------------------------------------------------------------
10//
11// This code is licensed under the Microsoft Public License.
12// See the file License.txt for the license details.
13// More info on: http://dotnetzip.codeplex.com
14//
15// ------------------------------------------------------------------
16//
17// last saved (in emacs):
18// Time-stamp: <2011-July-11 12:03:03>
19//
20// ------------------------------------------------------------------
21//
22// This module defines members of the ZipEntry class for reading the
23// Zip file central directory.
24//
25// Created: Tue, 27 Mar 2007  15:30
26//
27// ------------------------------------------------------------------
28
29
30using System;
31using System.Collections.Generic;
32
33namespace OfficeOpenXml.Packaging.Ionic.Zip
34{
35
36    partial class ZipEntry
37    {
38        /// <summary>
39        /// True if the referenced entry is a directory.
40        /// </summary>
41        internal bool AttributesIndicateDirectory
42        {
43            get { return ((_InternalFileAttrs == 0) && ((_ExternalFileAttrs & 0x0010) == 0x0010)); }
44        }
45
46
47        internal void ResetDirEntry()
48        {
49            // __FileDataPosition is the position of the file data for an entry.
50            // It is _RelativeOffsetOfLocalHeader + size of local header.
51
52            // We cannot know the __FileDataPosition until we read the local
53            // header.
54
55            // The local header is not necessarily the same length as the record
56            // in the central directory.
57
58            // Set to -1, to indicate we need to read this later.
59            this.__FileDataPosition = -1;
60
61            // set _LengthOfHeader to 0, to indicate we need to read later.
62            this._LengthOfHeader = 0;
63        }
64
65        /// <summary>
66        /// Provides a human-readable string with information about the ZipEntry.
67        /// </summary>
68        public string Info
69        {
70            get
71            {
72                var builder = new System.Text.StringBuilder();
73                builder
74                    .Append(string.Format("          ZipEntry: {0}\n", this.FileName))
75                    .Append(string.Format("   Version Made By: {0}\n", this._VersionMadeBy))
76                    .Append(string.Format(" Needed to extract: {0}\n", this.VersionNeeded));
77
78                if (this._IsDirectory)
79                    builder.Append("        Entry type: directory\n");
80                else
81                {
82                    builder.Append(string.Format("         File type: {0}\n", this._IsText? "text":"binary"))
83                        .Append(string.Format("       Compression: {0}\n", this.CompressionMethod))
84                        .Append(string.Format("        Compressed: 0x{0:X}\n", this.CompressedSize))
85                        .Append(string.Format("      Uncompressed: 0x{0:X}\n", this.UncompressedSize))
86                        .Append(string.Format("             CRC32: 0x{0:X8}\n", this._Crc32));
87                }
88                builder.Append(string.Format("       Disk Number: {0}\n", this._diskNumber));
89                if (this._RelativeOffsetOfLocalHeader > 0xFFFFFFFF)
90                    builder
91                        .Append(string.Format("   Relative Offset: 0x{0:X16}\n", this._RelativeOffsetOfLocalHeader));
92                        else
93                    builder
94                        .Append(string.Format("   Relative Offset: 0x{0:X8}\n", this._RelativeOffsetOfLocalHeader));
95
96                    builder
97                    .Append(string.Format("         Bit Field: 0x{0:X4}\n", this._BitField))
98                    .Append(string.Format("        Encrypted?: {0}\n", this._sourceIsEncrypted))
99                    .Append(string.Format("          Timeblob: 0x{0:X8}\n", this._TimeBlob))
100                        .Append(string.Format("              Time: {0}\n", Ionic.Zip.SharedUtilities.PackedToDateTime(this._TimeBlob)));
101
102                builder.Append(string.Format("         Is Zip64?: {0}\n", this._InputUsesZip64));
103                if (!string.IsNullOrEmpty(this._Comment))
104                {
105                    builder.Append(string.Format("           Comment: {0}\n", this._Comment));
106                }
107                builder.Append("\n");
108                return builder.ToString();
109            }
110        }
111
112
113        // workitem 10330
114        private class CopyHelper
115        {
116            private static System.Text.RegularExpressions.Regex re =
117                new System.Text.RegularExpressions.Regex(" \\(copy (\\d+)\\)$");
118
119            private static int callCount = 0;
120
121            internal static string AppendCopyToFileName(string f)
122            {
123                callCount++;
124                if (callCount > 25)
125                    throw new OverflowException("overflow while creating filename");
126
127                int n = 1;
128                int r = f.LastIndexOf(".");
129
130                if (r == -1)
131                {
132                    // there is no extension
133                    System.Text.RegularExpressions.Match m = re.Match(f);
134                    if (m.Success)
135                    {
136                        n = Int32.Parse(m.Groups[1].Value) + 1;
137                        string copy = String.Format(" (copy {0})", n);
138                        f = f.Substring(0, m.Index) + copy;
139                    }
140                    else
141                    {
142                        string copy = String.Format(" (copy {0})", n);
143                        f = f + copy;
144                    }
145                }
146                else
147                {
148                    //System.Console.WriteLine("HasExtension");
149                    System.Text.RegularExpressions.Match m = re.Match(f.Substring(0, r));
150                    if (m.Success)
151                    {
152                        n = Int32.Parse(m.Groups[1].Value) + 1;
153                        string copy = String.Format(" (copy {0})", n);
154                        f = f.Substring(0, m.Index) + copy + f.Substring(r);
155                    }
156                    else
157                    {
158                        string copy = String.Format(" (copy {0})", n);
159                        f = f.Substring(0, r) + copy + f.Substring(r);
160                    }
161
162                    //System.Console.WriteLine("returning f({0})", f);
163                }
164                return f;
165            }
166        }
167
168
169
170        /// <summary>
171        ///   Reads one entry from the zip directory structure in the zip file.
172        /// </summary>
173        ///
174        /// <param name="zf">
175        ///   The zipfile for which a directory entry will be read.  From this param, the
176        ///   method gets the ReadStream and the expected text encoding
177        ///   (ProvisionalAlternateEncoding) which is used if the entry is not marked
178        ///   UTF-8.
179        /// </param>
180        ///
181        /// <param name="previouslySeen">
182        ///   a list of previously seen entry names; used to prevent duplicates.
183        /// </param>
184        ///
185        /// <returns>the entry read from the archive.</returns>
186        internal static ZipEntry ReadDirEntry(ZipFile zf,
187                                              Dictionary<String,Object> previouslySeen)
188        {
189            System.IO.Stream s = zf.ReadStream;
190            System.Text.Encoding expectedEncoding = (zf.AlternateEncodingUsage == ZipOption.Always)
191                ? zf.AlternateEncoding
192                : ZipFile.DefaultEncoding;
193
194            int signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
195            // return null if this is not a local file header signature
196            if (IsNotValidZipDirEntrySig(signature))
197            {
198                s.Seek(-4, System.IO.SeekOrigin.Current);
199                // workitem 10178
200                Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
201
202                // Getting "not a ZipDirEntry signature" here is not always wrong or an
203                // error.  This can happen when walking through a zipfile.  After the
204                // last ZipDirEntry, we expect to read an
205                // EndOfCentralDirectorySignature.  When we get this is how we know
206                // we've reached the end of the central directory.
207                if (signature != ZipConstants.EndOfCentralDirectorySignature &&
208                    signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature &&
209                    signature != ZipConstants.ZipEntrySignature  // workitem 8299
210                    )
211                {
212                    throw new BadReadException(String.Format("  Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position));
213                }
214                return null;
215            }
216
217            int bytesRead = 42 + 4;
218            byte[] block = new byte[42];
219            int n = s.Read(block, 0, block.Length);
220            if (n != block.Length) return null;
221
222            int i = 0;
223            ZipEntry zde = new ZipEntry();
224            zde.AlternateEncoding = expectedEncoding;
225            zde._Source = ZipEntrySource.ZipFile;
226            zde._container = new ZipContainer(zf);
227
228            unchecked
229            {
230                zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256);
231                zde._VersionNeeded = (short)(block[i++] + block[i++] * 256);
232                zde._BitField = (short)(block[i++] + block[i++] * 256);
233                zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
234                zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
235                zde._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob);
236                zde._timestamp |= ZipEntryTimestamp.DOS;
237
238                zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
239                zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
240                zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
241            }
242
243            // preserve
244            zde._CompressionMethod_FromZipFile = zde._CompressionMethod;
245
246            zde._filenameLength = (short)(block[i++] + block[i++] * 256);
247            zde._extraFieldLength = (short)(block[i++] + block[i++] * 256);
248            zde._commentLength = (short)(block[i++] + block[i++] * 256);
249            zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256);
250
251            zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256);
252            zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
253
254            zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
255
256            // workitem 7801
257            zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01);
258
259            block = new byte[zde._filenameLength];
260            n = s.Read(block, 0, block.Length);
261            bytesRead += n;
262            if ((zde._BitField & 0x0800) == 0x0800)
263            {
264                // UTF-8 is in use
265                zde._FileNameInArchive = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
266            }
267            else
268            {
269                zde._FileNameInArchive = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
270            }
271
272            // workitem 10330
273            // insure unique entry names
274            while (previouslySeen.ContainsKey(zde._FileNameInArchive))
275            {
276                zde._FileNameInArchive = CopyHelper.AppendCopyToFileName(zde._FileNameInArchive);
277                zde._metadataChanged = true;
278            }
279
280            if (zde.AttributesIndicateDirectory)
281                zde.MarkAsDirectory();  // may append a slash to filename if nec.
282            // workitem 6898
283            else if (zde._FileNameInArchive.EndsWith("/")) zde.MarkAsDirectory();
284
285            zde._CompressedFileDataSize = zde._CompressedSize;
286            if ((zde._BitField & 0x01) == 0x01)
287            {
288                // this may change after processing the Extra field
289                zde._Encryption_FromZipFile = zde._Encryption =
290                    EncryptionAlgorithm.PkzipWeak;
291                zde._sourceIsEncrypted = true;
292            }
293
294            if (zde._extraFieldLength > 0)
295            {
296                zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF ||
297                      zde._UncompressedSize == 0xFFFFFFFF ||
298                      zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF);
299
300                // Console.WriteLine("  Input uses Z64?:      {0}", zde._InputUsesZip64);
301
302                bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength);
303                zde._CompressedFileDataSize = zde._CompressedSize;
304            }
305
306            // we've processed the extra field, so we know the encryption method is set now.
307            if (zde._Encryption == EncryptionAlgorithm.PkzipWeak)
308            {
309                // the "encryption header" of 12 bytes precedes the file data
310                zde._CompressedFileDataSize -= 12;
311            }
312#if AESCRYPTO
313            else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 ||
314                        zde.Encryption == EncryptionAlgorithm.WinZipAes256)
315            {
316                zde._CompressedFileDataSize = zde.CompressedSize -
317                    (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10);
318                zde._LengthOfTrailer = 10;
319            }
320#endif
321
322            // tally the trailing descriptor
323            if ((zde._BitField & 0x0008) == 0x0008)
324            {
325                // sig, CRC, Comp and Uncomp sizes
326                if (zde._InputUsesZip64)
327                    zde._LengthOfTrailer += 24;
328                else
329                    zde._LengthOfTrailer += 16;
330            }
331
332            // workitem 12744
333            zde.AlternateEncoding = ((zde._BitField & 0x0800) == 0x0800)
334                ? System.Text.Encoding.UTF8
335                :expectedEncoding;
336
337            zde.AlternateEncodingUsage = ZipOption.Always;
338
339            if (zde._commentLength > 0)
340            {
341                block = new byte[zde._commentLength];
342                n = s.Read(block, 0, block.Length);
343                bytesRead += n;
344                if ((zde._BitField & 0x0800) == 0x0800)
345                {
346                    // UTF-8 is in use
347                    zde._Comment = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
348                }
349                else
350                {
351                    zde._Comment = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
352                }
353            }
354            //zde._LengthOfDirEntry = bytesRead;
355            return zde;
356        }
357
358
359        /// <summary>
360        /// Returns true if the passed-in value is a valid signature for a ZipDirEntry.
361        /// </summary>
362        /// <param name="signature">the candidate 4-byte signature value.</param>
363        /// <returns>true, if the signature is valid according to the PKWare spec.</returns>
364        internal static bool IsNotValidZipDirEntrySig(int signature)
365        {
366            return (signature != ZipConstants.ZipDirEntrySignature);
367        }
368
369
370        private Int16 _VersionMadeBy;
371        private Int16 _InternalFileAttrs;
372        private Int32 _ExternalFileAttrs;
373
374        //private Int32 _LengthOfDirEntry;
375        private Int16 _filenameLength;
376        private Int16 _extraFieldLength;
377        private Int16 _commentLength;
378    }
379
380
381}
Note: See TracBrowser for help on using the repository browser.