Пример #1
0
        public ZipEntry GetNextEntry()
        {
            if (crc == null) {
                throw new InvalidOperationException("Closed.");
            }

            if (entry != null) {
                CloseEntry();
            }

            int header = inputBuffer.ReadLeInt();

            if (header == ZipConstants.CentralHeaderSignature ||
                header == ZipConstants.EndOfCentralDirectorySignature ||
                header == ZipConstants.CentralHeaderDigitalSignature ||
                header == ZipConstants.ArchiveExtraDataSignature ||
                header == ZipConstants.Zip64CentralFileHeaderSignature) {
                Close();
                return null;
            }

            if ( (header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature) ) {
                header = inputBuffer.ReadLeInt();
            }

            short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();

            flags          = inputBuffer.ReadLeShort();
            method         = inputBuffer.ReadLeShort();
            uint dostime   = (uint)inputBuffer.ReadLeInt();
            int crc2       = inputBuffer.ReadLeInt();
            csize          = inputBuffer.ReadLeInt();
            size           = inputBuffer.ReadLeInt();
            int nameLen    = inputBuffer.ReadLeShort();
            int extraLen   = inputBuffer.ReadLeShort();

            bool isCrypted = (flags & 1) == 1;

            byte[] buffer = new byte[nameLen];
            inputBuffer.ReadRawBuffer(buffer);

            string name = ZipConstants.ConvertToStringExt(flags, buffer);

            entry = new ZipEntry(name, versionRequiredToExtract);
            entry.Flags = flags;

            entry.CompressionMethod = (CompressionMethod)method;

            if ((flags & 8) == 0) {
                entry.Crc  = crc2 & 0xFFFFFFFFL;
                entry.Size = size & 0xFFFFFFFFL;
                entry.CompressedSize = csize & 0xFFFFFFFFL;

                entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);

            } else {

                if (crc2 != 0) {
                    entry.Crc = crc2 & 0xFFFFFFFFL;
                }

                if (size != 0) {
                    entry.Size = size & 0xFFFFFFFFL;
                }

                if (csize != 0) {
                    entry.CompressedSize = csize & 0xFFFFFFFFL;
                }

                entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
            }

            entry.DosTime = dostime;

            if (extraLen > 0) {
                byte[] extra = new byte[extraLen];
                inputBuffer.ReadRawBuffer(extra);
                entry.ExtraData = extra;
            }

            entry.ProcessExtraData(true);
            if ( entry.CompressedSize >= 0 ) {
                csize = entry.CompressedSize;
            }

            if ( entry.Size >= 0 ) {
                size = entry.Size;
            }

            if (entry.IsCompressionMethodSupported()) {
                internalReader = new ReadDataHandler(InitialRead);
            } else {
                internalReader = new ReadDataHandler(ReadingNotSupported);
            }

            return entry;
        }
Пример #2
0
        /// <summary>
        /// Search for and read the central directory of a zip file filling the entries array.
        /// </summary>
        /// <exception cref="System.IO.IOException">
        /// An i/o error occurs.
        /// </exception>
        /// <exception cref="Mikolaytis.Unzip.Zip.ZipException">
        /// The central directory is malformed or cannot be found
        /// </exception>
        void ReadEntries()
        {
            // Search for the End Of Central Directory.  When a zip comment is
            // present the directory will start earlier
            //
            // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
            // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
            // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
            // this could be invalid.
            // Could also speed this up by reading memory in larger blocks.

            long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
                baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);

            // Read end of central directory record
            ushort thisDiskNumber           = ReadLEUshort();
            ushort startCentralDirDisk      = ReadLEUshort();
            ulong entriesForThisDisk        = ReadLEUshort();
            ulong entriesForWholeCentralDir = ReadLEUshort();
            ulong centralDirSize            = ReadLEUint();
            long offsetOfCentralDir         = ReadLEUint();
            uint commentSize                = ReadLEUshort();

            if ( commentSize > 0 ) {
                byte[] comment = new byte[commentSize];

                StreamUtils.ReadFully(baseStream_, comment);
                comment_ = ZipConstants.ConvertToString(comment);
            }
            else {
                comment_ = string.Empty;
            }

            bool isZip64 = false;

            // Check if zip64 header information is required.
            if ( (thisDiskNumber == 0xffff) ||
                (startCentralDirDisk == 0xffff) ||
                (entriesForThisDisk == 0xffff) ||
                (entriesForWholeCentralDir == 0xffff) ||
                (centralDirSize == 0xffffffff) ||
                (offsetOfCentralDir == 0xffffffff) ) {
                isZip64 = true;

                long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 0x1000);

                // number of the disk with the start of the zip64 end of central directory 4 bytes
                // relative offset of the zip64 end of central directory record 8 bytes
                // total number of disks 4 bytes
                ReadLEUint(); // startDisk64 is not currently used
                ulong offset64 = ReadLEUlong();
                uint totalDisks = ReadLEUint();

                baseStream_.Position = (long)offset64;
                long sig64 = ReadLEUint();

                // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
                ulong recordSize = ReadLEUlong();
                int versionMadeBy = ReadLEUshort();
                int versionToExtract = ReadLEUshort();
                uint thisDisk = ReadLEUint();
                uint centralDirDisk = ReadLEUint();
                entriesForThisDisk = ReadLEUlong();
                entriesForWholeCentralDir = ReadLEUlong();
                centralDirSize = ReadLEUlong();
                offsetOfCentralDir = (long)ReadLEUlong();

                // NOTE: zip64 extensible data sector (variable size) is ignored.
            }

            entries_ = new ZipEntry[entriesForThisDisk];

            // SFX/embedded support, find the offset of the first entry vis the start of the stream
            // This applies to Zip files that are appended to the end of an SFX stub.
            // Or are appended as a resource to an executable.
            // Zip files created by some archivers have the offsets altered to reflect the true offsets
            // and so dont require any adjustment here...
            // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
            if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {
                offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
            }

            baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);

            for (ulong i = 0; i < entriesForThisDisk; i++) {

                int versionMadeBy      = ReadLEUshort();
                int versionToExtract   = ReadLEUshort();
                int bitFlags           = ReadLEUshort();
                int method             = ReadLEUshort();
                uint dostime           = ReadLEUint();
                uint crc               = ReadLEUint();
                long csize             = (long)ReadLEUint();
                long size              = (long)ReadLEUint();
                int nameLen            = ReadLEUshort();
                int extraLen           = ReadLEUshort();
                int commentLen         = ReadLEUshort();

                int diskStartNo        = ReadLEUshort();  // Not currently used
                int internalAttributes = ReadLEUshort();  // Not currently used

                uint externalAttributes = ReadLEUint();
                long offset             = ReadLEUint();

                byte[] buffer = new byte[Math.Max(nameLen, commentLen)];

                StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
                string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);

                ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
                entry.Crc = crc & 0xffffffffL;
                entry.Size = size & 0xffffffffL;
                entry.CompressedSize = csize & 0xffffffffL;
                entry.Flags = bitFlags;
                entry.DosTime = (uint)dostime;
                entry.ZipFileIndex = (long)i;
                entry.Offset = offset;
                entry.ExternalFileAttributes = (int)externalAttributes;

                if ((bitFlags & 8) == 0) {
                    entry.CryptoCheckValue = (byte)(crc >> 24);
                }
                else {
                    entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
                }

                if (extraLen > 0) {
                    byte[] extra = new byte[extraLen];
                    StreamUtils.ReadFully(baseStream_, extra);
                    entry.ExtraData = extra;
                }

                entry.ProcessExtraData(false);

                if (commentLen > 0) {
                    StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
                    entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
                }

                entries_[i] = entry;
            }
        }