Esempio n. 1
0
        /// <summary>
        /// Open a new file as an archive
        /// </summary>
        /// <param name="filename">Name of the new file to open</param>
        /// <param name="timestamp">Timestamp the file should have</param>
        /// <param name="readHeaders">True if file headers should be read, false otherwise</param>
        /// <returns>Status of the underlying stream</returns>
        public ZipReturn Open(string filename, long timestamp, bool readHeaders)
        {
            // If a stream already exists, close it
            Close();

            // Now, reset the archive information
            _zipStatus      = ZipStatus.None;
            _zip64          = false;
            _centerDirStart = 0;
            _centerDirSize  = 0;
            _zipFileInfo    = null;

            // Then, attempt to open the file and get information from it
            try
            {
                // If the input file doesn't exist, close the stream and return
                if (!File.Exists(filename))
                {
                    Close();
                    return(ZipReturn.ZipErrorFileNotFound);
                }

                // Get the fileinfo object
                _zipFileInfo = new FileInfo(filename);

                // If the timestamps don't match, close the stream and return
                if (_zipFileInfo.LastWriteTime.Ticks != timestamp)
                {
                    Close();
                    return(ZipReturn.ZipErrorTimeStamp);
                }

                // Now try to open the file for reading
                _zipstream = Utilities.TryOpenRead(filename);
                int read = _zipstream.Read(new byte[1], 0, 1);
                if (read != 1)
                {
                    Close();
                    return(ZipReturn.ZipErrorOpeningFile);
                }
                _zipstream.Position = 0;
            }
            catch (PathTooLongException)
            {
                Close();
                return(ZipReturn.ZipFileNameToLong);
            }
            catch (IOException)
            {
                Close();
                return(ZipReturn.ZipErrorOpeningFile);
            }

            // If we succeeded, set the flag for read
            _zipOpen = ZipOpenType.OpenRead;

            // If we're not reading the headers, return
            if (!readHeaders)
            {
                return(ZipReturn.ZipGood);
            }

            //Otherwise, we want to get all of the archive information
            try
            {
                // First, try to get the end of the central directory
                ZipReturn zr = FindEndOfCentralDirSignature();
                if (zr != ZipReturn.ZipGood)
                {
                    Close();
                    return(zr);
                }

                // Now read the end of the central directory
                long eocd = _zipstream.Position;
                zr = ReadEndOfCentralDir();
                if (zr != ZipReturn.ZipGood)
                {
                    Close();
                    return(zr);
                }

                // If we have any indicators of Zip64, check for the Zip64 EOCD
                if (_centerDirStart == 0xffffffff || _centerDirSize == 0xffffffff || _entriesCount == 0xffff)
                {
                    _zip64 = true;

                    // Check for the Zip64 EOCD locator
                    _zipstream.Position = eocd - 20;
                    zr = ReadZip64EndOfCentralDirectoryLocator();
                    if (zr != ZipReturn.ZipGood)
                    {
                        Close();
                        return(zr);
                    }

                    // If it was found, read the Zip64 EOCD
                    _zipstream.Position = (long)_endOfCenterDir64;
                    zr = ReadZip64EndOfCentralDir();
                    if (zr != ZipReturn.ZipGood)
                    {
                        Close();
                        return(zr);
                    }
                }

                // Now that we have the rest of the information, check for TorrentZip
                bool torrentZip = false;
                if (_fileComment.Length == 22)
                {
                    if (Encoding.ASCII.GetString(_fileComment).Substring(0, 14) == "TORRENTZIPPED-")
                    {
                        // First get to the right part of the stream
                        OptimizedCRC ocrc   = new OptimizedCRC();
                        byte[]       buffer = new byte[_centerDirSize];
                        _zipstream.Position = (long)_centerDirStart;

                        // Then read in the central directory and hash
                        BinaryReader br = new BinaryReader(_zipstream);
                        buffer = br.ReadBytes((int)_centerDirSize);
                        ocrc.Update(buffer, 0, (int)_centerDirSize);
                        string calculatedCrc = ocrc.Value.ToString("X8");

                        // If the hashes match, then we have a torrentzip file
                        string extractedCrc = Encoding.ASCII.GetString(_fileComment).Substring(14, 8);
                        if (String.Equals(calculatedCrc, extractedCrc, StringComparison.Ordinal))
                        {
                            torrentZip = true;
                        }
                    }
                }

                // With potential torrentzip out of the way, read the central directory
                _zipstream.Position = (long)_centerDirStart;

                // Remove any entries already listed in the archive
                _entries.Clear();
                _entries.Capacity = (int)_entriesCount;

                // Now populate the entries from the central directory
                for (int i = 0; i < _entriesCount; i++)
                {
                    ZipFileEntry zfe = new ZipFileEntry(_zipstream);
                    zr = zfe.ReadCentralDirectory();

                    // If we get any errors, close and return
                    if (zr != ZipReturn.ZipGood)
                    {
                        Close();
                        return(zr);
                    }

                    // If we have a Zip64 entry, make sure the archive is
                    _zip64 |= zfe.Zip64;

                    // Now add the entry to the archive
                    _entries.Add(zfe);
                }

                // Now that the entries are populated, verify against the actual headers
                for (int i = 0; i < _entriesCount; i++)
                {
                    zr = _entries[i].ReadHeader();

                    // If we get any errors, close and return
                    if (zr != ZipReturn.ZipGood)
                    {
                        Close();
                        return(zr);
                    }

                    // If we have a torrentzipped entry, make sure the archive is
                    torrentZip &= _entries[i].TorrentZip;
                }

                // If we have a torrentzipped file, check the file order
                if (torrentZip)
                {
                    for (int i = 0; i < _entriesCount - 1; i++)
                    {
                        if (TorrentZipStringCompare(_entries[i].FileName, _entries[i + 1].FileName) < 0)
                        {
                            continue;
                        }
                        torrentZip = false;
                        break;
                    }
                }

                // Now check for torrentzipped directories if we still have a torrentZip file
                if (torrentZip)
                {
                    for (int i = 0; i < _entriesCount - 1; i++)
                    {
                        // See if we found a directory
                        string filename0 = _entries[i].FileName;
                        if (filename0.Substring(filename0.Length - 1, 1) != "/")
                        {
                            continue;
                        }

                        // See if the next file is in that directory
                        string filename1 = _entries[i + 1].FileName;
                        if (filename1.Length <= filename0.Length)
                        {
                            continue;
                        }
                        if (TorrentZipStringCompare(filename0, filename1.Substring(0, filename0.Length)) == 0)
                        {
                            continue;
                        }

                        // If we found a file in the directory, then we don't need the directory entry
                        torrentZip = false;
                        break;
                    }
                }

                // If we still have torrentzip, say the archive is too
                if (torrentZip)
                {
                    _zipStatus |= ZipStatus.TorrentZip;
                }

                return(ZipReturn.ZipGood);
            }
            catch
            {
                Close();
                return(ZipReturn.ZipErrorReadingFile);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Close the file that the stream refers to
        /// </summary>
        public void Close()
        {
            // If the stream is already closed, then just return
            if (_zipOpen == ZipOpenType.Closed)
            {
                return;
            }

            // If the stream is opened for read, close it
            if (_zipOpen == ZipOpenType.OpenRead)
            {
                Dispose();
                _zipOpen = ZipOpenType.Closed;
                return;
            }

            // Now, the only other choice is open for writing so we check everything is correct
            _zip64 = false;
            bool torrentZip = true;

            // Check the central directory
            _centerDirStart = (ulong)_zipstream.Position;
            if (_centerDirStart >= 0xffffffff)
            {
                _zip64 = true;
            }

            // Now loop through and add all of the central directory entries
            foreach (ZipFileEntry zfe in _entries)
            {
                zfe.WriteCentralDirectory(_zipstream);
                _zip64     |= zfe.Zip64;
                torrentZip &= zfe.TorrentZip;
            }

            _centerDirSize = (ulong)_zipstream.Position - _centerDirStart;

            // Then get the central directory hash
            OptimizedCRC ocrc = new OptimizedCRC();

            byte[] buffer          = new byte[_centerDirSize];
            long   currentPosition = _zipstream.Position;

            _zipstream.Position = (long)_centerDirStart;

            // Then read in the central directory and hash
            BinaryReader br = new BinaryReader(_zipstream);

            buffer = br.ReadBytes((int)_centerDirSize);
            ocrc.Update(buffer, 0, (int)_centerDirSize);
            string calculatedCrc = ocrc.Value.ToString("X8");

            // Finally get back to the original position
            _zipstream.Position = currentPosition;

            // Now set more of the information
            _fileComment = (torrentZip ? Encoding.ASCII.GetBytes(("TORRENTZIPPED-" + calculatedCrc).ToCharArray()) : new byte[0]);
            _zipStatus   = (torrentZip ? ZipStatus.TorrentZip : ZipStatus.None);

            // If we have a Zip64 archive, write the correct information
            if (_zip64)
            {
                _endOfCenterDir64 = (ulong)_zipstream.Position;
                WriteZip64EndOfCentralDir();
                WriteZip64EndOfCentralDirectoryLocator();
            }

            // Now write out the end of the central directory
            WriteEndOfCentralDir();

            // Finally, close and dispose of the stream
            _zipstream.SetLength(_zipstream.Position);
            _zipstream.Flush();
            _zipstream.Close();
            _zipstream.Dispose();

            // Get the new file information
            _zipFileInfo = new FileInfo(_zipFileInfo.FullName);

            // And set the stream to closed
            _zipOpen = ZipOpenType.Closed;
        }
        /// <summary>
        /// Get the data from the current file, if not already checked
        /// </summary>
        public void Check()
        {
            // If the file has been tested or has an error, return
            if (_fileStatus != ZipReturn.ZipUntested)
            {
                return;
            }

            try
            {
                Stream stream = null;
                _zipstream.Seek((long)_dataLocation, SeekOrigin.Begin);

                switch (_compressionMethod)
                {
                case CompressionMethod.Deflated:
                    stream = new DeflateStream(_zipstream, CompressionMode.Decompress, true);
                    break;

                case CompressionMethod.Stored:
                    stream = _zipstream;
                    break;
                }

                if (stream == null)
                {
                    _fileStatus = ZipReturn.ZipErrorGettingDataStream;
                    return;
                }

                // Create the hashers
                uint         tempCrc;
                OptimizedCRC crc  = new OptimizedCRC();
                MD5          md5  = System.Security.Cryptography.MD5.Create();
                SHA1         sha1 = System.Security.Cryptography.SHA1.Create();

                // Now get the hash of the stream
                BinaryReader fs = new BinaryReader(stream);

                byte[] buffer = new byte[1024];
                int    read;
                while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    crc.Update(buffer, 0, read);
                    md5.TransformBlock(buffer, 0, read, buffer, 0);
                    sha1.TransformBlock(buffer, 0, read, buffer, 0);
                }

                crc.Update(buffer, 0, 0);
                md5.TransformFinalBlock(buffer, 0, 0);
                sha1.TransformFinalBlock(buffer, 0, 0);

                tempCrc = crc.UnsignedValue;
                _md5    = md5.Hash;
                _sha1   = sha1.Hash;

                // Dispose of the hashers
                crc.Dispose();
                md5.Dispose();
                sha1.Dispose();

                if (_compressionMethod == CompressionMethod.Deflated)
                {
                    stream.Close();
                    stream.Dispose();
                }

                _fileStatus = (_crc == tempCrc ? ZipReturn.ZipGood : ZipReturn.ZipCRCDecodeError);
            }
            catch
            {
                _fileStatus = ZipReturn.ZipDecodeError;
            }
        }