예제 #1
0
        public Stream GetEntryStream(StiZipEntry entry)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException("ZipFile");
            }
            if (entry.IsCrypted)
            {
                throw new StiZipException("Encryption is not supported");
            }

            long start = LocateEntry(entry);
            CompressionMethod method = entry.CompressionMethod;
            Stream            result = new StiPartialInputStream(this, start, entry.CompressedSize);

            switch (method)
            {
            case CompressionMethod.Stored:
                break;

            case CompressionMethod.Deflated:
                byte[] buf = new byte[entry.CompressedSize];
                _baseStream.Seek(start, SeekOrigin.Begin);
                _baseStream.Read(buf, 0, buf.Length);
                MemoryStream ms = new MemoryStream(buf);
                result = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionMode.Decompress);
                break;

            default:
                throw new StiZipException("Unsupported compression method " + method);
            }

            return(result);
        }
예제 #2
0
        private long LocateEntry(StiZipEntry entry)
        {
            _baseStream.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
            if ((int)ReadLEUint() != StiZipConstants.LocalHeaderSignature)
            {
                throw new StiZipException(string.Format("Wrong local header signature @{0:X}",
                                                        offsetOfFirstEntry + entry.Offset));
            }

            short extractVersion    = (short)ReadLEUshort();
            short localFlags        = (short)ReadLEUshort();
            short compressionMethod = (short)ReadLEUshort();
            short fileTime          = (short)ReadLEUshort();
            short fileDate          = (short)ReadLEUshort();
            uint  crcValue          = ReadLEUint();
            long  compressedSize    = ReadLEUint();
            long  size             = ReadLEUint();
            int   storedNameLength = ReadLEUshort();
            int   extraDataLength  = ReadLEUshort();

            byte[] nameData = new byte[storedNameLength];
            Utils.ReadFully(_baseStream, nameData);

            byte[] extraData = new byte[extraDataLength];
            Utils.ReadFully(_baseStream, extraData);

            StiZipExtraData localExtraData = new StiZipExtraData(extraData);

            if (entry.IsFile)
            {
                if (!entry.IsCompressionMethodSupported())
                {
                    throw new StiZipException("Compression method not supported");
                }

                if ((extractVersion > StiZipConstants.VersionMadeBy) ||
                    ((extractVersion > 20) && (extractVersion < StiZipConstants.VersionZip64)) ||
                    ((localFlags &
                      (int)
                      (GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress |
                       GeneralBitFlags.HeaderMasked)) != 0))
                {
                    throw new StiZipException("The library does not support the zip version required to extract this entry");
                }
            }

            int extraLength = storedNameLength + extraDataLength;

            return(offsetOfFirstEntry + entry.Offset + StiZipConstants.LocalHeaderBaseSize + extraLength);
        }
예제 #3
0
        private void ReadEntries()
        {
            long locatedEndOfCentralDir = LocateBlockWithSignature(
                StiZipConstants.EndOfCentralDirectorySignature,
                _baseStream.Length,
                StiZipConstants.EndOfCentralRecordBaseSize,
                0xffff);

            if (locatedEndOfCentralDir < 0)
            {
                throw new StiZipException("Cannot find central directory");
            }

            ushort thisDiskNumber            = ReadLEUshort();
            ushort startCentralDirDisk       = ReadLEUshort();
            ulong  entriesForThisDisk        = ReadLEUshort();
            ulong  entriesForWholeCentralDir = ReadLEUshort();
            ulong  centralDirSize            = ReadLEUint();
            long   offsetOfCentralDir        = ReadLEUint();

            bool isZip64 = false;

            #region 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(StiZipConstants.Zip64CentralDirLocatorSignature,
                                                       locatedEndOfCentralDir, 0, 0x1000);
                if (offset < 0)
                {
                    throw new StiZipException("Cannot find Zip64 locator");
                }

                ReadLEUint();
                ulong offset64   = ReadLEUlong();
                uint  totalDisks = ReadLEUint();

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

                if (sig64 != StiZipConstants.Zip64CentralFileHeaderSignature)
                {
                    throw new StiZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
                }

                ulong recordSize       = ReadLEUlong();
                int   versionMadeBy    = ReadLEUshort();
                int   versionToExtract = ReadLEUshort();
                uint  thisDisk         = ReadLEUint();
                uint  centralDirDisk   = ReadLEUint();
                entriesForThisDisk        = ReadLEUlong();
                entriesForWholeCentralDir = ReadLEUlong();
                centralDirSize            = ReadLEUlong();
                offsetOfCentralDir        = (long)ReadLEUlong();
            }

            #endregion

            _entries = new StiZipEntry[entriesForThisDisk];

            if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)))
            {
                offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
                if (offsetOfFirstEntry <= 0)
                {
                    throw new StiZipException("Invalid embedded zip archive");
                }
            }

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

            for (ulong i = 0; i < entriesForThisDisk; i++)
            {
                if (ReadLEUint() != StiZipConstants.CentralHeaderSignature)
                {
                    throw new StiZipException("Wrong Central Directory signature");
                }

                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();
                int internalAttributes = ReadLEUshort();

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

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

                Utils.ReadFully(_baseStream, buffer, 0, nameLen);
                string name = StiZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);

                StiZipEntry entry = new StiZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
                entry.zipFile                = this;
                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 (extraLen > 0)
                {
                    byte[] extra = new byte[extraLen];
                    Utils.ReadFully(_baseStream, extra);
                    entry.ExtraData = extra;
                }

                entry.ProcessExtraData(false);

                if (commentLen > 0)
                {
                    Utils.ReadFully(_baseStream, buffer, 0, commentLen);
                    entry.Comment = StiZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
                }

                _entries[i] = entry;
            }
        }