Пример #1
0
        /// <summary>
        /// Test an archive for integrity/validity
        /// </summary>
        /// <param name="testData">Perform low level data Crc check</param>
        /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
        /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
        /// <returns>true if all tests pass, false otherwise</returns>
        /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
        public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
        {
            if (isDisposed_)
            {
                throw new ObjectDisposedException("ZipFile");
            }

            TestStatus status = new TestStatus(this);

            if (resultHandler != null)
            {
                resultHandler(status, null);
            }

            HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;

            bool testing = true;

            try
            {
                int entryIndex = 0;

                while (testing && (entryIndex < Count))
                {
                    if (resultHandler != null)
                    {
                        status.SetEntry(this[entryIndex]);
                        status.SetOperation(TestOperation.EntryHeader);
                        resultHandler(status, null);
                    }

                    try
                    {
                        TestLocalHeader(this[entryIndex], test);
                    }
                    catch (ZipException ex)
                    {
                        status.AddError();

                        if (resultHandler != null)
                        {
                            resultHandler(status,
                                string.Format("Exception during test - '{0}'", ex.Message));
                        }

                        if (strategy == TestStrategy.FindFirstError)
                        {
                            testing = false;
                        }
                    }

                    if (testing && testData && this[entryIndex].IsFile)
                    {
                        if (resultHandler != null)
                        {
                            status.SetOperation(TestOperation.EntryData);
                            resultHandler(status, null);
                        }

                        Crc32 crc = new Crc32();

                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))
                        {

                            byte[] buffer = new byte[4096];
                            long totalBytes = 0;
                            int bytesRead;
                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                crc.Update(buffer, 0, bytesRead);

                                if (resultHandler != null)
                                {
                                    totalBytes += bytesRead;
                                    status.SetBytesTested(totalBytes);
                                    resultHandler(status, null);
                                }
                            }
                        }

                        if (this[entryIndex].Crc != crc.Value)
                        {
                            status.AddError();

                            if (resultHandler != null)
                            {
                                resultHandler(status, "CRC mismatch");
                            }

                            if (strategy == TestStrategy.FindFirstError)
                            {
                                testing = false;
                            }
                        }

                        if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0)
                        {
                            ZipHelperStream helper = new ZipHelperStream(baseStream_);
                            DescriptorData data = new DescriptorData();
                            helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
                            if (this[entryIndex].Crc != data.Crc)
                            {
                                status.AddError();
                            }

                            if (this[entryIndex].CompressedSize != data.CompressedSize)
                            {
                                status.AddError();
                            }

                            if (this[entryIndex].Size != data.Size)
                            {
                                status.AddError();
                            }
                        }
                    }

                    if (resultHandler != null)
                    {
                        status.SetOperation(TestOperation.EntryComplete);
                        resultHandler(status, null);
                    }

                    entryIndex += 1;
                }

                if (resultHandler != null)
                {
                    status.SetOperation(TestOperation.MiscellaneousTests);
                    resultHandler(status, null);
                }

                // TODO: the 'Corrina Johns' test where local headers are missing from
                // the central directory.  They are therefore invisible to many archivers.
            }
            catch (Exception ex)
            {
                status.AddError();

                if (resultHandler != null)
                {
                    resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
                }
            }

            if (resultHandler != null)
            {
                status.SetOperation(TestOperation.Complete);
                status.SetEntry(null);
                resultHandler(status, null);
            }

            return (status.ErrorCount == 0);
        }
Пример #2
0
        void CopyBytes(ZipUpdate update, Stream destination, Stream source,
            long bytesToCopy, bool updateCrc)
        {
            if (destination == source)
            {
                throw new InvalidOperationException("Destination and source are the same");
            }

            // NOTE: Compressed size is updated elsewhere.
            Crc32 crc = new Crc32();
            byte[] buffer = GetBuffer();

            long targetBytes = bytesToCopy;
            long totalBytesRead = 0;

            int bytesRead;
            do
            {
                int readSize = buffer.Length;

                if (bytesToCopy < readSize)
                {
                    readSize = (int)bytesToCopy;
                }

                bytesRead = source.Read(buffer, 0, readSize);
                if (bytesRead > 0)
                {
                    if (updateCrc)
                    {
                        crc.Update(buffer, 0, bytesRead);
                    }
                    destination.Write(buffer, 0, bytesRead);
                    bytesToCopy -= bytesRead;
                    totalBytesRead += bytesRead;
                }
            }
            while ((bytesRead > 0) && (bytesToCopy > 0));

            if (totalBytesRead != targetBytes)
            {
                throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
            }

            if (updateCrc)
            {
                update.OutEntry.Crc = crc.Value;
            }
        }
Пример #3
0
        void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sourcePosition)
        {
            long bytesToCopy = update.Entry.CompressedSize;

            // NOTE: Compressed size is updated elsewhere.
            Crc32 crc = new Crc32();
            byte[] buffer = GetBuffer();

            long targetBytes = bytesToCopy;
            long totalBytesRead = 0;

            int bytesRead;
            do
            {
                int readSize = buffer.Length;

                if (bytesToCopy < readSize)
                {
                    readSize = (int)bytesToCopy;
                }

                stream.Position = sourcePosition;
                bytesRead = stream.Read(buffer, 0, readSize);
                if (bytesRead > 0)
                {
                    if (updateCrc)
                    {
                        crc.Update(buffer, 0, bytesRead);
                    }
                    stream.Position = destinationPosition;
                    stream.Write(buffer, 0, bytesRead);

                    destinationPosition += bytesRead;
                    sourcePosition += bytesRead;
                    bytesToCopy -= bytesRead;
                    totalBytesRead += bytesRead;
                }
            }
            while ((bytesRead > 0) && (bytesToCopy > 0));

            if (totalBytesRead != targetBytes)
            {
                throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
            }

            if (updateCrc)
            {
                update.OutEntry.Crc = crc.Value;
            }
        }
        bool ReadHeader()
        {
            // Initialize CRC for this block
            crc = new Crc32();

            // Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF,
            // which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves.
            if (inputBuffer.Available <= 0)
            {
                inputBuffer.Fill();
                if (inputBuffer.Available <= 0)
                {
                    // No header, EOF.
                    return false;
                }
            }

            // 1. Check the two magic bytes
            Crc32 headCRC = new Crc32();
            int magic = inputBuffer.ReadLeByte();

            if (magic < 0)
            {
                throw new EndOfStreamException("EOS reading GZIP header");
            }

            headCRC.Update(magic);
            if (magic != (GZipConstants.GZIP_MAGIC >> 8))
            {
                throw new GZipException("Error GZIP header, first magic byte doesn't match");
            }

            //magic = baseInputStream.ReadByte();
            magic = inputBuffer.ReadLeByte();

            if (magic < 0)
            {
                throw new EndOfStreamException("EOS reading GZIP header");
            }

            if (magic != (GZipConstants.GZIP_MAGIC & 0xFF))
            {
                throw new GZipException("Error GZIP header,  second magic byte doesn't match");
            }

            headCRC.Update(magic);

            // 2. Check the compression type (must be 8)
            int compressionType = inputBuffer.ReadLeByte();

            if (compressionType < 0)
            {
                throw new EndOfStreamException("EOS reading GZIP header");
            }

            if (compressionType != 8)
            {
                throw new GZipException("Error GZIP header, data not in deflate format");
            }
            headCRC.Update(compressionType);

            // 3. Check the flags
            int flags = inputBuffer.ReadLeByte();
            if (flags < 0)
            {
                throw new EndOfStreamException("EOS reading GZIP header");
            }
            headCRC.Update(flags);

            /*    This flag byte is divided into individual bits as follows:

            bit 0   FTEXT
            bit 1   FHCRC
            bit 2   FEXTRA
            bit 3   FNAME
            bit 4   FCOMMENT
            bit 5   reserved
            bit 6   reserved
            bit 7   reserved
            */

            // 3.1 Check the reserved bits are zero

            if ((flags & 0xE0) != 0)
            {
                throw new GZipException("Reserved flag bits in GZIP header != 0");
            }

            // 4.-6. Skip the modification time, extra flags, and OS type
            for (int i = 0; i < 6; i++)
            {
                int readByte = inputBuffer.ReadLeByte();
                if (readByte < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }
                headCRC.Update(readByte);
            }

            // 7. Read extra field
            if ((flags & GZipConstants.FEXTRA) != 0)
            {
                // Skip subfield id
                for (int i = 0; i < 2; i++)
                {
                    int readByte = inputBuffer.ReadLeByte();
                    if (readByte < 0)
                    {
                        throw new EndOfStreamException("EOS reading GZIP header");
                    }
                    headCRC.Update(readByte);
                }

                if (inputBuffer.ReadLeByte() < 0 || inputBuffer.ReadLeByte() < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }

                int len1, len2;
                len1 = inputBuffer.ReadLeByte();
                len2 = inputBuffer.ReadLeByte();
                if ((len1 < 0) || (len2 < 0))
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }
                headCRC.Update(len1);
                headCRC.Update(len2);

                int extraLen = (len1 << 8) | len2;
                for (int i = 0; i < extraLen; i++)
                {
                    int readByte = inputBuffer.ReadLeByte();
                    if (readByte < 0)
                    {
                        throw new EndOfStreamException("EOS reading GZIP header");
                    }
                    headCRC.Update(readByte);
                }
            }

            // 8. Read file name
            if ((flags & GZipConstants.FNAME) != 0)
            {
                int readByte;
                while ((readByte = inputBuffer.ReadLeByte()) > 0)
                {
                    headCRC.Update(readByte);
                }

                if (readByte < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }
                headCRC.Update(readByte);
            }

            // 9. Read comment
            if ((flags & GZipConstants.FCOMMENT) != 0)
            {
                int readByte;
                while ((readByte = inputBuffer.ReadLeByte()) > 0)
                {
                    headCRC.Update(readByte);
                }

                if (readByte < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }

                headCRC.Update(readByte);
            }

            // 10. Read header CRC
            if ((flags & GZipConstants.FHCRC) != 0)
            {
                int tempByte;
                int crcval = inputBuffer.ReadLeByte();
                if (crcval < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }

                tempByte = inputBuffer.ReadLeByte();
                if (tempByte < 0)
                {
                    throw new EndOfStreamException("EOS reading GZIP header");
                }

                crcval = (crcval << 8) | tempByte;
                if (crcval != ((int)headCRC.Value & 0xffff))
                {
                    throw new GZipException("Header CRC value mismatch");
                }
            }

            readGZIPHeader = true;
            return true;
        }