예제 #1
0
        /// <summary>
        /// Reads one <c>ZipEntry</c> from the given stream.  If the entry is encrypted, we don't
        /// decrypt at this point.  We also do not decompress.  Mostly we read metadata.
        /// </summary>
        /// <param name="zc">the ZipContainer this entry belongs to.</param>
        /// <param name="first">true of this is the first entry being read from the stream.</param>
        /// <returns>the <c>ZipEntry</c> read from the stream.</returns>
        internal static ZipEntry ReadEntry(ZipContainer zc, bool first)
        {
            ZipFile zf = zc.ZipFile;

            Stream s = zc.ReadStream;

            System.Text.Encoding defaultEncoding = zc.ProvisionalAlternateEncoding;
            ZipEntry entry = new ZipEntry();
            entry._Source = ZipEntrySource.ZipFile;
            entry._container = zc;
            entry._archiveStream = s;
            if (zf != null)
                zf.OnReadEntry(true, null);

            if (first) HandlePK00Prefix(s);

            // Read entry header, including any encryption header
            if (!ReadHeader(entry, defaultEncoding)) return null;

            // Store the position in the stream for this entry
            // change for workitem 8098
            entry.__FileDataPosition = entry.ArchiveStream.Position;

            // seek past the data without reading it. We will read on Extract()
            s.Seek(entry._CompressedFileDataSize + entry._LengthOfTrailer, SeekOrigin.Current);

            // ReadHeader moves the file pointer to the end of the entry header,
            // as well as any encryption header.

            // CompressedFileDataSize includes:
            //   the maybe compressed, maybe encrypted file data
            //   the encryption trailer, if any
            //   the bit 3 descriptor, if any

            // workitem 5306
            // http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=5306
            HandleUnexpectedDataDescriptor(entry);

            if (zf != null)
            {
                zf.OnReadBytes(entry);
                zf.OnReadEntry(false, entry);
            }

            return entry;
        }
예제 #2
0
 /// <summary>
 /// Copy metadata that may have been changed by the app.  We do this when
 /// resetting the zipFile instance.  If the app calls Save() on a ZipFile, then
 /// tries to party on that file some more, we may need to Reset() it , which
 /// means re-reading the entries and then copying the metadata.  I think.
 /// </summary>
 internal void CopyMetaData(ZipEntry source)
 {
     this.__FileDataPosition = source.__FileDataPosition;
     this.CompressionMethod = source.CompressionMethod;
     this._CompressionMethod_FromZipFile = source._CompressionMethod_FromZipFile;
     this._CompressedFileDataSize = source._CompressedFileDataSize;
     this._UncompressedSize = source._UncompressedSize;
     this._BitField = source._BitField;
     this._Source = source._Source;
     this._LastModified = source._LastModified;
     this._Mtime = source._Mtime;
     this._Atime = source._Atime;
     this._Ctime = source._Ctime;
     this._ntfsTimesAreSet = source._ntfsTimesAreSet;
     this._emitUnixTimes = source._emitUnixTimes;
     this._emitNtfsTimes = source._emitNtfsTimes;
 }
예제 #3
0
        private static ZipEntry Create(string nameInArchive, ZipEntrySource source, Object arg1, Object arg2)
        {
            if (String.IsNullOrEmpty(nameInArchive))
                throw new PMDCP.Compression.Zip.ZipException("The entry name must be non-null and non-empty.");

            ZipEntry entry = new ZipEntry();

            // workitem 7071
            // workitem 7926 - "version made by" OS should be zero for compat with WinZip
            entry._VersionMadeBy = (0 << 8) + 45; // indicates the attributes are FAT Attributes, and v4.5 of the spec
            entry._Source = source;
            entry._Mtime = entry._Atime = entry._Ctime = DateTime.UtcNow;

            if (source == ZipEntrySource.Stream)
            {
                entry._sourceStream = (arg1 as Stream);         // may  or may not be null
            }
            else if (source == ZipEntrySource.WriteDelegate)
            {
                entry._WriteDelegate = (arg1 as WriteDelegate); // may  or may not be null
            }
            else if (source == ZipEntrySource.JitStream)
            {
                entry._OpenDelegate = (arg1 as OpenDelegate);   // may  or may not be null
                entry._CloseDelegate = (arg2 as CloseDelegate); // may  or may not be null
            }
            else if (source == ZipEntrySource.ZipOutputStream)
            {
            }
            // workitem 9073
            else if (source == ZipEntrySource.None)
            {
                // make this a valid value, for later.
                entry._Source = ZipEntrySource.FileSystem;
            }
            else
            {
                String filename = (arg1 as String);   // must not be null

                if (String.IsNullOrEmpty(filename))
                    throw new PMDCP.Compression.Zip.ZipException("The filename must be non-null and non-empty.");

                // The named file may or may not exist at this time.  For example, when
                // adding a directory by name.  We test existence when necessary:
                // when saving the ZipFile, or when getting the attributes, and so on.

#if NETCF
                // workitem 6878
                // PMDCP.Compression.Zip.SharedUtilities.AdjustTime_Win32ToDotNet
                entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime();
                entry._Ctime = File.GetCreationTime(filename).ToUniversalTime();
                entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime();

                // workitem 7071
                // can only get attributes of files that exist.
                if (File.Exists(filename) || Directory.Exists(filename))
                    entry._ExternalFileAttrs = (int)NetCfFile.GetAttributes(filename);

#else
                // workitem 6878??
                // PMDCP.Compression.Zip.SharedUtilities.AdjustTime_Win32ToDotNet
                entry._Mtime = File.GetLastWriteTimeUtc(filename);
                entry._Ctime = File.GetCreationTimeUtc(filename);
                entry._Atime = File.GetLastAccessTimeUtc(filename);

                // workitem 7071
                // can only get attributes on files that exist.
                if (File.Exists(filename) || Directory.Exists(filename))
                    entry._ExternalFileAttrs = (int)File.GetAttributes(filename);

#endif
                entry._ntfsTimesAreSet = true;

                entry._LocalFileName = Path.GetFullPath(filename); // workitem 8813
            }

            entry._LastModified = entry._Mtime;
            entry._FileNameInArchive = SharedUtilities.NormalizePathForUseInZipFile(nameInArchive);
            // We don't actually slurp in the file data until the caller invokes Write on this entry.

            return entry;
        }
예제 #4
0
 internal static ZipErrorEventArgs Saving(string archiveName, ZipEntry entry, Exception exception)
 {
     var x = new ZipErrorEventArgs
         {
             EventType = ZipProgressEventType.Error_Saving,
             ArchiveName = archiveName,
             CurrentEntry = entry,
             _exc = exception
         };
     return x;
 }
예제 #5
0
 /// <summary>
 /// Constructor for the SaveProgressEventArgs.
 /// </summary>
 /// <param name="archiveName">the name of the zip archive.</param>
 /// <param name="before">whether this is before saving the entry, or after</param>
 /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
 /// <param name="entriesSaved">Number of entries that have been saved.</param>
 /// <param name="entry">The entry involved in the event.</param>
 internal SaveProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesSaved, ZipEntry entry)
     : base(archiveName, (before) ? ZipProgressEventType.Saving_BeforeWriteEntry : ZipProgressEventType.Saving_AfterWriteEntry)
 {
     this.EntriesTotal = entriesTotal;
     this.CurrentEntry = entry;
     this._entriesSaved = entriesSaved;
 }
예제 #6
0
 internal static ExtractProgressEventArgs ExtractExisting(string archiveName, ZipEntry entry, string extractLocation)
 {
     var x = new ExtractProgressEventArgs
         {
             ArchiveName = archiveName,
             EventType = ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite,
             CurrentEntry = entry,
             _target = extractLocation,
         };
     return x;
 }
예제 #7
0
 internal static ExtractProgressEventArgs BeforeExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
 {
     var x = new ExtractProgressEventArgs
         {
             ArchiveName = archiveName,
             EventType = ZipProgressEventType.Extracting_BeforeExtractEntry,
             CurrentEntry = entry,
             _target = extractLocation,
         };
     return x;
 }
예제 #8
0
        public static ZipCrypto ForRead(string password, ZipEntry e)
        {
            System.IO.Stream s = e._archiveStream;
            e._WeakEncryptionHeader = new byte[12];
            byte[] eh = e._WeakEncryptionHeader;
            ZipCrypto z = new ZipCrypto();

            if (password == null)
                throw new BadPasswordException("This entry requires a password.");

            z.InitCipher(password);

            ZipEntry.ReadWeakEncryptionHeader(s, eh);

            // Decrypt the header.  This has a side effect of "further initializing the
            // encryption keys" in the traditional zip encryption.
            byte[] DecryptedHeader = z.DecryptMessage(eh, eh.Length);

            // CRC check
            // According to the pkzip spec, the final byte in the decrypted header
            // is the highest-order byte in the CRC. We check it here.
            if (DecryptedHeader[11] != (byte)((e._Crc32 >> 24) & 0xff))
            {
                // In the case that bit 3 of the general purpose bit flag is set to
                // indicate the presence of an 'Extended File Header' or a 'data
                // descriptor' (signature 0x08074b50), the last byte of the decrypted
                // header is sometimes compared with the high-order byte of the
                // lastmodified time, rather than the high-order byte of the CRC, to
                // verify the password.
                //
                // This is not documented in the PKWare Appnote.txt.
                // This was discovered this by analysis of the Crypt.c source file in the InfoZip library
                // http://www.info-zip.org/pub/infozip/

                if ((e._BitField & 0x0008) != 0x0008)
                {
                    throw new BadPasswordException("The password did not match.");
                }
                else if (DecryptedHeader[11] != (byte)((e._TimeBlob >> 8) & 0xff))
                {
                    throw new BadPasswordException("The password did not match.");
                }

                // We have a good password.
            }
            else
            {
                // A-OK
            }
            return z;
        }
예제 #9
0
 internal void InternalAddEntry(String name, ZipEntry entry)
 {
     _entries.Add(name, entry);
     _zipEntriesAsList = null;
     _contentsChanged = true;
 }
예제 #10
0
 // Can be called from within ZipEntry.InternalExtract.
 internal bool OnSingleEntryExtract(ZipEntry entry, string path, bool before)
 {
     if (ExtractProgress != null)
     {
         lock (LOCK)
         {
             var e = (before)
     ? ExtractProgressEventArgs.BeforeExtractEntry(ArchiveNameForEvent, entry, path)
     : ExtractProgressEventArgs.AfterExtractEntry(ArchiveNameForEvent, entry, path);
             ExtractProgress(this, e);
             if (e.Cancel)
                 _extractOperationCanceled = true;
         }
     }
     return _extractOperationCanceled;
 }
예제 #11
0
 internal bool OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer)
 {
     if (SaveProgress != null)
     {
         lock (LOCK)
         {
             var e = SaveProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
                           bytesXferred, totalBytesToXfer);
             SaveProgress(this, e);
             if (e.Cancel)
                 _saveOperationCanceled = true;
         }
     }
     return _saveOperationCanceled;
 }
예제 #12
0
 internal void OnReadEntry(bool before, ZipEntry entry)
 {
     if (ReadProgress != null)
     {
         lock (LOCK)
         {
             ReadProgressEventArgs e = (before)
             ? ReadProgressEventArgs.Before(ArchiveNameForEvent, _entries.Count)
             : ReadProgressEventArgs.After(ArchiveNameForEvent, entry, _entries.Count);
             ReadProgress(this, e);
         }
     }
 }
예제 #13
0
        private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding)
        {
            int bytesRead = 0;

            // change for workitem 8098
            ze._RelativeOffsetOfLocalHeader = ze.ArchiveStream.Position;

            int signature = PMDCP.Compression.Zip.SharedUtilities.ReadEntrySignature(ze.ArchiveStream);
            bytesRead += 4;

            // Return false if this is not a local file header signature.
            if (ZipEntry.IsNotValidSig(signature))
            {
                // Getting "not a ZipEntry signature" is not always wrong or an error.
                // This will happen after the last entry in a zipfile.  In that case, we
                // expect to read :
                //    a ZipDirEntry signature (if a non-empty zip file) or
                //    a ZipConstants.EndOfCentralDirectorySignature.
                //
                // Anything else is a surprise.

                ze.ArchiveStream.Seek(-4, SeekOrigin.Current); // unread the signature
                if (ZipEntry.IsNotValidZipDirEntrySig(signature) && (signature != ZipConstants.EndOfCentralDirectorySignature))
                {
                    throw new BadReadException(String.Format("  ZipEntry::ReadHeader(): Bad signature (0x{0:X8}) at position  0x{1:X8}", signature, ze.ArchiveStream.Position));
                }
                return false;
            }

            byte[] block = new byte[26];
            int n = ze.ArchiveStream.Read(block, 0, block.Length);
            if (n != block.Length) return false;
            bytesRead += n;

            int i = 0;
            ze._VersionNeeded = (Int16)(block[i++] + block[i++] * 256);
            ze._BitField = (Int16)(block[i++] + block[i++] * 256);
            ze._CompressionMethod_FromZipFile = ze._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
            ze._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
            // transform the time data into something usable (a DateTime)
            ze._LastModified = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(ze._TimeBlob);
            ze._timestamp |= ZipEntryTimestamp.DOS;

            if ((ze._BitField & 0x01) == 0x01)
            {
                ze._Encryption_FromZipFile = ze._Encryption = EncryptionAlgorithm.PkzipWeak; // this *may* change after processing the Extra field
                ze._sourceIsEncrypted = true;
            }

            // NB: if ((ze._BitField & 0x0008) != 0x0008), then the Compressed, uncompressed and
            // CRC values are not true values; the true values will follow the entry data.
            // But, regardless of the status of bit 3 in the bitfield, the slots for
            // the three amigos may contain marker values for ZIP64.  So we must read them.
            {
                ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);

                if ((uint)ze._CompressedSize == 0xFFFFFFFF ||
                    (uint)ze._UncompressedSize == 0xFFFFFFFF)

                    ze._InputUsesZip64 = true;
            }

            Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
            Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);

            block = new byte[filenameLength];
            n = ze.ArchiveStream.Read(block, 0, block.Length);
            bytesRead += n;

            // if the UTF8 bit is set for this entry, override the encoding the application requested.
            ze._actualEncoding = ((ze._BitField & 0x0800) == 0x0800)
                ? System.Text.Encoding.UTF8
                : defaultEncoding;

            // need to use this form of GetString() for .NET CF
            ze._FileNameInArchive = ze._actualEncoding.GetString(block, 0, block.Length);

            // when creating an entry by reading, the LocalFileName is the same as the FileNameInArchive
            // No, on second thought, I think it should be empty (null).
            //ze._LocalFileName = ze._FileNameInArchive;

            // workitem 6898
            if (ze._FileNameInArchive.EndsWith("/")) ze.MarkAsDirectory();

            bytesRead += ze.ProcessExtraField(ze.ArchiveStream, extraFieldLength);

            ze._LengthOfTrailer = 0;

            // workitem 6607 - don't read for directories
            // actually get the compressed size and CRC if necessary
            if (!ze._FileNameInArchive.EndsWith("/") && (ze._BitField & 0x0008) == 0x0008)
            {
                // This descriptor exists only if bit 3 of the general
                // purpose bit flag is set (see below).  It is byte aligned
                // and immediately follows the last byte of compressed data,
                // as well as any encryption trailer, as with AES.
                // This descriptor is used only when it was not possible to
                // seek in the output .ZIP file, e.g., when the output .ZIP file
                // was standard output or a non-seekable device.  For ZIP64(tm) format
                // archives, the compressed and uncompressed sizes are 8 bytes each.

                // workitem 8098: ok (restore)
                long posn = ze.ArchiveStream.Position;

                // Here, we're going to loop until we find a ZipEntryDataDescriptorSignature and
                // a consistent data record after that.   To be consistent, the data record must
                // indicate the length of the entry data.
                bool wantMore = true;
                long SizeOfDataRead = 0;
                int tries = 0;
                while (wantMore)
                {
                    tries++;
                    // We call the FindSignature shared routine to find the specified signature
                    // in the already-opened zip archive, starting from the current cursor
                    // position in that filestream.  If we cannot find the signature, then the
                    // routine returns -1, and the ReadHeader() method returns false,
                    // indicating we cannot read a legal entry header.  If we have found it,
                    // then the FindSignature() method returns the number of bytes in the
                    // stream we had to seek forward, to find the sig.  We need this to
                    // determine if the zip entry is valid, later.

                    if (ze._container.ZipFile != null)
                        ze._container.ZipFile.OnReadBytes(ze);

                    long d = PMDCP.Compression.Zip.SharedUtilities.FindSignature(ze.ArchiveStream, ZipConstants.ZipEntryDataDescriptorSignature);
                    if (d == -1) return false;

                    // total size of data read (through all loops of this).
                    SizeOfDataRead += d;

                    if (ze._InputUsesZip64)
                    {
                        // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size)
                        block = new byte[20];
                        n = ze.ArchiveStream.Read(block, 0, block.Length);
                        if (n != 20) return false;

                        // do not increment bytesRead - it is for entry header only.
                        // the data we have just read is a footer (falls after the file data)
                        //bytesRead += n;

                        i = 0;
                        ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                        ze._CompressedSize = BitConverter.ToInt64(block, i);
                        i += 8;
                        ze._UncompressedSize = BitConverter.ToInt64(block, i);
                        i += 8;

                        ze._LengthOfTrailer += 24;  // bytes including sig, CRC, Comp and Uncomp sizes
                    }
                    else
                    {
                        // read 3x 4-byte fields (CRC, Compressed Size, Uncompressed Size)
                        block = new byte[12];
                        n = ze.ArchiveStream.Read(block, 0, block.Length);
                        if (n != 12) return false;

                        // do not increment bytesRead - it is for entry header only.
                        // the data we have just read is a footer (falls after the file data)
                        //bytesRead += n;

                        i = 0;
                        ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                        ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                        ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);

                        ze._LengthOfTrailer += 16;  // bytes including sig, CRC, Comp and Uncomp sizes

                    }

                    wantMore = (SizeOfDataRead != ze._CompressedSize);

                    if (wantMore)
                    {
                        // Seek back to un-read the last 12 bytes  - maybe THEY contain
                        // the ZipEntryDataDescriptorSignature.
                        // (12 bytes for the CRC, Comp and Uncomp size.)
                        ze.ArchiveStream.Seek(-12, SeekOrigin.Current);

                        // Adjust the size to account for the false signature read in
                        // FindSignature().
                        SizeOfDataRead += 4;
                    }
                }

                // seek back to previous position, to prepare to read file data
                // workitem 8098: ok (restore)
                ze.ArchiveStream.Seek(posn, SeekOrigin.Begin);
            }

            ze._CompressedFileDataSize = ze._CompressedSize;

            // bit 0 set indicates that some kind of encryption is in use
            if ((ze._BitField & 0x01) == 0x01)
            {
            #if AESCRYPTO
                if (ze.Encryption == EncryptionAlgorithm.WinZipAes128 ||
                    ze.Encryption == EncryptionAlgorithm.WinZipAes256)
                {
                    int bits = ZipEntry.GetKeyStrengthInBits(ze._Encryption_FromZipFile);
                    // read in the WinZip AES metadata: salt + PV. 18 bytes for AES256. 10 bytes for AES128.
                    ze._aesCrypto_forExtract = WinZipAesCrypto.ReadFromStream(null, bits, ze.ArchiveStream);
                    bytesRead += ze._aesCrypto_forExtract.SizeOfEncryptionMetadata - 10; // MAC (follows crypto bytes)
                    // according to WinZip, the CompressedSize includes the AES Crypto framing data.
                    ze._CompressedFileDataSize -= ze._aesCrypto_forExtract.SizeOfEncryptionMetadata;
                    ze._LengthOfTrailer += 10;  // MAC
                }
                else
            #endif
                {
                    // read in the header data for "weak" encryption
                    ze._WeakEncryptionHeader = new byte[12];
                    bytesRead += ZipEntry.ReadWeakEncryptionHeader(ze._archiveStream, ze._WeakEncryptionHeader);
                    // decrease the filedata size by 12 bytes
                    ze._CompressedFileDataSize -= 12;
                }
            }

            // Remember the size of the blob for this entry.
            // We also have the starting position in the stream for this entry.
            ze._LengthOfHeader = bytesRead;
            ze._TotalEntrySize = ze._LengthOfHeader + ze._CompressedFileDataSize + ze._LengthOfTrailer;

            // We've read in the regular entry header, the extra field, and any encryption
            // header.  The pointer in the file is now at the start of the filedata, which is
            // potentially compressed and encrypted.  Just ahead in the file, there are
            // _CompressedFileDataSize bytes of data, followed by potentially a non-zero length
            // trailer, consisting of optionally, some encryption stuff (10 byte MAC for AES),
            // and the bit-3 trailer (16 or 24 bytes).

            return true;
        }
예제 #14
0
        private static void HandleUnexpectedDataDescriptor(ZipEntry entry)
        {
            Stream s = entry.ArchiveStream;

            // In some cases, the "data descriptor" is present, without a signature, even when
            // bit 3 of the BitField is NOT SET.  This is the CRC, followed
            //    by the compressed length and the uncompressed length (4 bytes for each
            //    of those three elements).  Need to check that here.
            //
            uint datum = (uint)PMDCP.Compression.Zip.SharedUtilities.ReadInt(s);
            if (datum == entry._Crc32)
            {
                int sz = PMDCP.Compression.Zip.SharedUtilities.ReadInt(s);
                if (sz == entry._CompressedSize)
                {
                    sz = PMDCP.Compression.Zip.SharedUtilities.ReadInt(s);
                    if (sz == entry._UncompressedSize)
                    {
                        // ignore everything and discard it.
                    }
                    else
                        s.Seek(-12, SeekOrigin.Current); // unread the three blocks
                }
                else
                    s.Seek(-8, SeekOrigin.Current); // unread the two blocks
            }
            else
                s.Seek(-4, SeekOrigin.Current); // unread the block
        }
예제 #15
0
        /// <summary>
        /// Reads one entry from the zip directory structure in the zip file.
        /// </summary>
        /// <param name="zf">
        /// The zipfile for which a directory entry will be read.  From this param, the
        /// method gets the ReadStream and the expected text encoding
        /// (ProvisionalAlternateEncoding) which is used if the entry is not marked
        /// UTF-8.
        /// </param>
        /// <returns>the entry read from the archive.</returns>
        internal static ZipEntry ReadDirEntry(ZipFile zf)
        {
            System.IO.Stream s = zf.ReadStream;
            System.Text.Encoding expectedEncoding = zf.ProvisionalAlternateEncoding;

            int signature = PMDCP.Compression.Zip.SharedUtilities.ReadSignature(s);
            // return null if this is not a local file header signature
            if (IsNotValidZipDirEntrySig(signature))
            {
                s.Seek(-4, System.IO.SeekOrigin.Current);

                // Getting "not a ZipDirEntry signature" here is not always wrong or an
                // error.  This can happen when walking through a zipfile.  After the
                // last ZipDirEntry, we expect to read an
                // EndOfCentralDirectorySignature.  When we get this is how we know
                // we've reached the end of the central directory.
                if (signature != ZipConstants.EndOfCentralDirectorySignature &&
                    signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature &&
                    signature != ZipConstants.ZipEntrySignature  // workitem 8299
                    )
                {
                    throw new BadReadException(String.Format("  ZipEntry::ReadDirEntry(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position));
                }
                return null;
            }

            int bytesRead = 42 + 4;
            byte[] block = new byte[42];
            int n = s.Read(block, 0, block.Length);
            if (n != block.Length) return null;

            int i = 0;
            ZipEntry zde = new ZipEntry();
            zde._Source = ZipEntrySource.ZipFile;
            zde._container = new ZipContainer(zf);

            unchecked
            {
                zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256);
                zde._VersionNeeded = (short)(block[i++] + block[i++] * 256);
                zde._BitField = (short)(block[i++] + block[i++] * 256);
                zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
                zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
                zde._LastModified = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob);
                zde._timestamp |= ZipEntryTimestamp.DOS;

                zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
                zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
            }

            // preserve
            zde._CompressionMethod_FromZipFile = zde._CompressionMethod;

            zde._filenameLength = (short)(block[i++] + block[i++] * 256);
            zde._extraFieldLength = (short)(block[i++] + block[i++] * 256);
            zde._commentLength = (short)(block[i++] + block[i++] * 256);
            zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256);

            zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256);
            zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;

            zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);

            // workitem 7801
            zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01);

            block = new byte[zde._filenameLength];
            n = s.Read(block, 0, block.Length);
            bytesRead += n;
            if ((zde._BitField & 0x0800) == 0x0800)
            {
                // UTF-8 is in use
                zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block);
            }
            else
            {
                zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
            }

            // Console.WriteLine("\nEntry : {0}", zde._LocalFileName);
            // Console.WriteLine("  V Madeby/Needed:      0x{0:X4} / 0x{1:X4}", zde._VersionMadeBy, zde._VersionNeeded);
            // Console.WriteLine("  BitField/Compression: 0x{0:X4} / 0x{1:X4}", zde._BitField, zde._CompressionMethod);
            // Console.WriteLine("  Lastmod:              {0}", zde._LastModified.ToString("u"));
            // Console.WriteLine("  CRC:                  0x{0:X8}", zde._Crc32);
            // Console.WriteLine("  Comp / Uncomp:        0x{0:X8} ({0})   0x{1:X8} ({1})", zde._CompressedSize, zde._UncompressedSize);

            //zde._FileNameInArchive = zde._LocalFileName;

            if (zde.AttributesIndicateDirectory) zde.MarkAsDirectory();  // may append a slash to filename if nec.
            // workitem 6898
            else if (zde._FileNameInArchive.EndsWith("/")) zde.MarkAsDirectory();

            zde._CompressedFileDataSize = zde._CompressedSize;
            if ((zde._BitField & 0x01) == 0x01)
            {
                zde._Encryption_FromZipFile = zde._Encryption = EncryptionAlgorithm.PkzipWeak; // this may change after processing the Extra field
                zde._sourceIsEncrypted = true;
            }

            if (zde._extraFieldLength > 0)
            {
                zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF ||
                      zde._UncompressedSize == 0xFFFFFFFF ||
                      zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF);

                // Console.WriteLine("  Input uses Z64?:      {0}", zde._InputUsesZip64);

                bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength);
                zde._CompressedFileDataSize = zde._CompressedSize;
            }

            // we've processed the extra field, so we know the encryption method is set now.
            if (zde._Encryption == EncryptionAlgorithm.PkzipWeak)
            {
                // the "encryption header" of 12 bytes precedes the file data
                zde._CompressedFileDataSize -= 12;
            }
#if AESCRYPTO
            else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 ||
                        zde.Encryption == EncryptionAlgorithm.WinZipAes256)
            {
                zde._CompressedFileDataSize = zde.CompressedSize -
                    (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10);
                zde._LengthOfTrailer = 10;
            }
#endif

            // tally the trailing descriptor
            if ((zde._BitField & 0x0008) == 0x0008)
            {
                // sig, CRC, Comp and Uncomp sizes
                if (zde._InputUsesZip64)
                    zde._LengthOfTrailer += 24;
                else
                    zde._LengthOfTrailer += 16;
            }

            if (zde._commentLength > 0)
            {
                block = new byte[zde._commentLength];
                n = s.Read(block, 0, block.Length);
                bytesRead += n;
                if ((zde._BitField & 0x0800) == 0x0800)
                {
                    // UTF-8 is in use
                    zde._Comment = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block);
                }
                else
                {
                    zde._Comment = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
                }
            }
            //zde._LengthOfDirEntry = bytesRead;
            return zde;
        }
예제 #16
0
        /// <summary>
        /// Reads one entry from the zip directory structure in the zip file.
        /// </summary>
        /// <param name="zf">
        /// The zipfile for which a directory entry will be read.  From this param, the
        /// method gets the ReadStream and the expected text encoding
        /// (ProvisionalAlternateEncoding) which is used if the entry is not marked
        /// UTF-8.
        /// </param>
        /// <returns>the entry read from the archive.</returns>
        internal static ZipEntry ReadDirEntry(ZipFile zf)
        {
            System.IO.Stream     s = zf.ReadStream;
            System.Text.Encoding expectedEncoding = zf.ProvisionalAlternateEncoding;

            int signature = PMDCP.Compression.Zip.SharedUtilities.ReadSignature(s);

            // return null if this is not a local file header signature
            if (IsNotValidZipDirEntrySig(signature))
            {
                s.Seek(-4, System.IO.SeekOrigin.Current);

                // Getting "not a ZipDirEntry signature" here is not always wrong or an
                // error.  This can happen when walking through a zipfile.  After the
                // last ZipDirEntry, we expect to read an
                // EndOfCentralDirectorySignature.  When we get this is how we know
                // we've reached the end of the central directory.
                if (signature != ZipConstants.EndOfCentralDirectorySignature &&
                    signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature &&
                    signature != ZipConstants.ZipEntrySignature  // workitem 8299
                    )
                {
                    throw new BadReadException(String.Format("  ZipEntry::ReadDirEntry(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position));
                }
                return(null);
            }

            int bytesRead = 42 + 4;

            byte[] block = new byte[42];
            int    n     = s.Read(block, 0, block.Length);

            if (n != block.Length)
            {
                return(null);
            }

            int      i   = 0;
            ZipEntry zde = new ZipEntry();

            zde._Source    = ZipEntrySource.ZipFile;
            zde._container = new ZipContainer(zf);

            unchecked
            {
                zde._VersionMadeBy     = (short)(block[i++] + block[i++] * 256);
                zde._VersionNeeded     = (short)(block[i++] + block[i++] * 256);
                zde._BitField          = (short)(block[i++] + block[i++] * 256);
                zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
                zde._TimeBlob          = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
                zde._LastModified      = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob);
                zde._timestamp        |= ZipEntryTimestamp.DOS;

                zde._Crc32            = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
                zde._CompressedSize   = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
                zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
            }

            // preserve
            zde._CompressionMethod_FromZipFile = zde._CompressionMethod;

            zde._filenameLength   = (short)(block[i++] + block[i++] * 256);
            zde._extraFieldLength = (short)(block[i++] + block[i++] * 256);
            zde._commentLength    = (short)(block[i++] + block[i++] * 256);
            zde._diskNumber       = (UInt32)(block[i++] + block[i++] * 256);

            zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256);
            zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;

            zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);

            // workitem 7801
            zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01);

            block      = new byte[zde._filenameLength];
            n          = s.Read(block, 0, block.Length);
            bytesRead += n;
            if ((zde._BitField & 0x0800) == 0x0800)
            {
                // UTF-8 is in use
                zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block);
            }
            else
            {
                zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
            }

            // Console.WriteLine("\nEntry : {0}", zde._LocalFileName);
            // Console.WriteLine("  V Madeby/Needed:      0x{0:X4} / 0x{1:X4}", zde._VersionMadeBy, zde._VersionNeeded);
            // Console.WriteLine("  BitField/Compression: 0x{0:X4} / 0x{1:X4}", zde._BitField, zde._CompressionMethod);
            // Console.WriteLine("  Lastmod:              {0}", zde._LastModified.ToString("u"));
            // Console.WriteLine("  CRC:                  0x{0:X8}", zde._Crc32);
            // Console.WriteLine("  Comp / Uncomp:        0x{0:X8} ({0})   0x{1:X8} ({1})", zde._CompressedSize, zde._UncompressedSize);

            //zde._FileNameInArchive = zde._LocalFileName;

            if (zde.AttributesIndicateDirectory)
            {
                zde.MarkAsDirectory();                                   // may append a slash to filename if nec.
            }
            // workitem 6898
            else if (zde._FileNameInArchive.EndsWith("/"))
            {
                zde.MarkAsDirectory();
            }

            zde._CompressedFileDataSize = zde._CompressedSize;
            if ((zde._BitField & 0x01) == 0x01)
            {
                zde._Encryption_FromZipFile = zde._Encryption = EncryptionAlgorithm.PkzipWeak; // this may change after processing the Extra field
                zde._sourceIsEncrypted      = true;
            }

            if (zde._extraFieldLength > 0)
            {
                zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF ||
                                       zde._UncompressedSize == 0xFFFFFFFF ||
                                       zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF);

                // Console.WriteLine("  Input uses Z64?:      {0}", zde._InputUsesZip64);

                bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength);
                zde._CompressedFileDataSize = zde._CompressedSize;
            }

            // we've processed the extra field, so we know the encryption method is set now.
            if (zde._Encryption == EncryptionAlgorithm.PkzipWeak)
            {
                // the "encryption header" of 12 bytes precedes the file data
                zde._CompressedFileDataSize -= 12;
            }
#if AESCRYPTO
            else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 ||
                     zde.Encryption == EncryptionAlgorithm.WinZipAes256)
            {
                zde._CompressedFileDataSize = zde.CompressedSize -
                                              (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10);
                zde._LengthOfTrailer = 10;
            }
#endif

            // tally the trailing descriptor
            if ((zde._BitField & 0x0008) == 0x0008)
            {
                // sig, CRC, Comp and Uncomp sizes
                if (zde._InputUsesZip64)
                {
                    zde._LengthOfTrailer += 24;
                }
                else
                {
                    zde._LengthOfTrailer += 16;
                }
            }

            if (zde._commentLength > 0)
            {
                block      = new byte[zde._commentLength];
                n          = s.Read(block, 0, block.Length);
                bytesRead += n;
                if ((zde._BitField & 0x0800) == 0x0800)
                {
                    // UTF-8 is in use
                    zde._Comment = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block);
                }
                else
                {
                    zde._Comment = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
                }
            }
            //zde._LengthOfDirEntry = bytesRead;
            return(zde);
        }
예제 #17
0
 internal bool OnZipErrorSaving(ZipEntry entry, Exception exc)
 {
     if (ZipError != null)
     {
         lock (LOCK)
         {
             var e = ZipErrorEventArgs.Saving(this.Name, entry, exc);
             ZipError(this, e);
             if (e.Cancel)
                 _saveOperationCanceled = true;
         }
     }
     return _saveOperationCanceled;
 }
예제 #18
0
 private ZipEntry _InternalAddEntry(ZipEntry ze)
 {
     // stamp all the props onto the entry
     ze._container = new ZipContainer(this);
     ze.CompressionLevel = CompressionLevel;
     ze.ExtractExistingFile = ExtractExistingFile;
     ze.ZipErrorAction = this.ZipErrorAction;
     ze.SetCompression = SetCompression;
     ze.ProvisionalAlternateEncoding = ProvisionalAlternateEncoding;
     ze.Password = _Password;
     ze.Encryption = Encryption;
     ze.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes;
     ze.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes;
     //string key = DictionaryKeyForEntry(ze);
     InternalAddEntry(ze.FileName,ze);
     AfterAddEntry(ze);
     return ze;
 }
예제 #19
0
 private void OnExtractEntry(int current, bool before, ZipEntry currentEntry, string path)
 {
     if (ExtractProgress != null)
     {
         lock (LOCK)
         {
             var e = new ExtractProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, currentEntry, path);
             ExtractProgress(this, e);
             if (e.Cancel)
                 _extractOperationCanceled = true;
         }
     }
 }
예제 #20
0
 /// <summary>
 /// Constructor for the ExtractProgressEventArgs.
 /// </summary>
 /// <param name="archiveName">the name of the zip archive.</param>
 /// <param name="before">whether this is before saving the entry, or after</param>
 /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
 /// <param name="entriesExtracted">Number of entries that have been extracted.</param>
 /// <param name="entry">The entry involved in the event.</param>
 /// <param name="extractLocation">The location to which entries are extracted.</param>
 internal ExtractProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesExtracted, ZipEntry entry, string extractLocation)
     : base(archiveName, (before) ? ZipProgressEventType.Extracting_BeforeExtractEntry : ZipProgressEventType.Extracting_AfterExtractEntry)
 {
     this.EntriesTotal = entriesTotal;
     this.CurrentEntry = entry;
     this._entriesExtracted = entriesExtracted;
     this._target = extractLocation;
 }
예제 #21
0
 private void OnSaveEntry(int current, ZipEntry entry, bool before)
 {
     if (SaveProgress != null)
     {
         lock (LOCK)
         {
             var e = new SaveProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, entry);
             SaveProgress(this, e);
             if (e.Cancel)
                 _saveOperationCanceled = true;
         }
     }
 }
예제 #22
0
 internal static ExtractProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesWritten, Int64 totalBytes)
 {
     var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_EntryBytesWritten);
     x.ArchiveName = archiveName;
     x.CurrentEntry = entry;
     x.BytesTransferred = bytesWritten;
     x.TotalBytesToTransfer = totalBytes;
     return x;
 }
예제 #23
0
 internal void AfterAddEntry(ZipEntry entry)
 {
     if (AddProgress != null)
     {
         lock (LOCK)
         {
             var e = AddProgressEventArgs.AfterEntry(ArchiveNameForEvent, entry, _entries.Count);
             AddProgress(this, e);
         }
     }
 }
예제 #24
0
 internal static ReadProgressEventArgs After(string archiveName, ZipEntry entry, int entriesTotal)
 {
     var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_AfterReadEntry);
     x.EntriesTotal = entriesTotal;
     x.CurrentEntry = entry;
     return x;
 }
예제 #25
0
 // Can be called from within ZipEntry._ExtractOne.
 internal bool OnExtractBlock(ZipEntry entry, Int64 bytesWritten, Int64 totalBytesToWrite)
 {
     if (ExtractProgress != null)
     {
         lock (LOCK)
         {
             var e = ExtractProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
                         bytesWritten, totalBytesToWrite);
             ExtractProgress(this, e);
             if (e.Cancel)
                 _extractOperationCanceled = true;
         }
     }
     return _extractOperationCanceled;
 }
예제 #26
0
 internal static SaveProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
 {
     var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_EntryBytesRead);
     x.ArchiveName = archiveName;
     x.CurrentEntry = entry;
     x.BytesTransferred = bytesXferred;
     x.TotalBytesToTransfer = totalBytes;
     return x;
 }
예제 #27
0
 internal bool OnExtractExisting(ZipEntry entry, string path)
 {
     if (ExtractProgress != null)
     {
         lock (LOCK)
         {
             var e = ExtractProgressEventArgs.ExtractExisting(ArchiveNameForEvent, entry, path);
             ExtractProgress(this, e);
             if (e.Cancel)
                 _extractOperationCanceled = true;
         }
     }
     return _extractOperationCanceled;
 }
예제 #28
0
        /// <summary>
        ///   Read the next entry from the zip file.
        /// </summary>
        ///
        /// <remarks>
        /// <para>
        ///   Call this method just before calling <see cref="Read(byte[], int, int)"/>,
        ///   to position the pointer in the zip file to the next entry that can be
        ///   read.  Subsequent calls to <c>Read()</c>, will decrypt and decompress the
        ///   data in the zip file, until <c>Read()</c> returns 0.
        /// </para>
        ///
        /// <para>
        ///   Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped
        ///   stream is moved to the next entry in the zip file.  If you call <see
        ///   cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within
        ///   the file, you will need to call <c>GetNextEntry()</c> again, to insure
        ///   that the file pointer is positioned at the beginning of a zip entry.
        /// </para>
        ///
        /// <para>
        ///   This method returns the <c>ZipEntry</c>. Using a stream approach, you will
        ///   read the raw bytes for an entry in a zip file via calls to <c>Read()</c>.
        ///   Alternatively, you can extract an entry into a file, or a stream, by
        ///   calling <see cref="ZipEntry.Extract()"/>, or one of its siblings.
        /// </para>
        ///
        /// </remarks>
        ///
        /// <returns>
        ///   The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more
        ///   entries in the zip file.
        /// </returns>
        ///
        public ZipEntry GetNextEntry()
        {
            if (_findRequired)
            {
                // find the next signature
                long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature);
                if (d == -1) return null;
                // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature
                _inputStream.Seek(-4, SeekOrigin.Current);
            }

            _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry);
            _endOfEntry = _inputStream.Position;
            _firstEntry = true;
            _needSetup = true;
            _findRequired= false;
            return _currentEntry;
        }
예제 #29
0
 internal void OnReadBytes(ZipEntry entry)
 {
     if (ReadProgress != null)
     {
         lock (LOCK)
         {
             var e = ReadProgressEventArgs.ByteUpdate(ArchiveNameForEvent,
                                 entry,
                                 ReadStream.Position,
                                 LengthOfReadStream);
             ReadProgress(this, e);
         }
     }
 }