ZipArchiveFile represents one archive file in the ZipArchive. It is analogous to the System.IO.DiffFile object for normal files.
 /// <summary>
 /// Gets an archiveFile by name. 'archivePath' is the full path name of
 /// the archiveFile in the archive. It returns null if the name does not
 /// exist.
 /// </summary>
 /// <param name="archivePath">The archive path.</param>
 public ZipArchiveFile this[string archivePath]
 {
     get
     {
         ZipArchiveFile ret = null;
         _entries.TryGetValue(archivePath, out ret);
         return(ret);
     }
 }
        /// <summary>
        /// Overwrites the archive textStream 'archivePath' with the text in
        /// 'data'.
        /// </summary>
        /// <param name="archivePath">The filename.</param>
        /// <param name="data">The string data to write.</param>
        public void WriteAllText(string archivePath, string data)
        {
            ZipArchiveFile newEntry;

            if (!_entries.TryGetValue(archivePath, out newEntry))
            {
                newEntry = new ZipArchiveFile(this, archivePath);
            }
            newEntry.WriteAllText(data);
        }
        /// <summary>
        /// Opens a textStream in the archive for writing as a text textStream.
        /// </summary>
        /// <param name="archivePath">The filename.</param>
        /// <returns>Returns the resulting TextWriter.</returns>
        public TextWriter CreateText(string archivePath)
        {
            ZipArchiveFile newEntry;

            if (!_entries.TryGetValue(archivePath, out newEntry))
            {
                newEntry = new ZipArchiveFile(this, archivePath);
            }
            return(newEntry.CreateText());
        }
        /// <summary>
        /// Copies 'sourceFilePath from the textStream system to the archive as
        /// 'targetArchivePath'. Will overwrite any existing textStream.
        /// </summary>
        /// <param name="sourceFilePath">The source filename.</param>
        /// <param name="targetArchivePath">The target path.</param>
        public void CopyFromFile(string sourceFilePath, string targetArchivePath)
        {
            using (Stream inFile = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            {
                using (Stream outFile = Create(targetArchivePath))
                {
                    ZipArchiveFile.CopyStream(inFile, outFile);
                }
            }

            this[targetArchivePath].LastWriteTime = File.GetLastWriteTime(sourceFilePath);
        }
 /// <summary>
 /// Read from the archive stream.
 /// </summary>
 /// <param name="archiveStream">The archive stream.</param>
 private void Read(Stream archiveStream)
 {
     // Original IronPython source noted a to-do for seekable streams,
     // to seek to the end of the stream, and use the archive directory
     // there to avoid reading most of the file.
     for (;;)
     {
         ZipArchiveFile entry = ZipArchiveFile.Read(this);
         if (entry == null)
         {
             break;
         }
     }
 }
 /// <summary>
 /// Overwrites the archive textStream 'archivePath' with the text in
 /// 'data'.
 /// </summary>
 /// <param name="archivePath">The filename.</param>
 /// <param name="data">The string data to write.</param>
 public void WriteAllText(string archivePath, string data)
 {
     ZipArchiveFile newEntry;
     if (!_entries.TryGetValue(archivePath, out newEntry))
     {
         newEntry = new ZipArchiveFile(this, archivePath);
     }
     newEntry.WriteAllText(data);
 }
 /// <summary>
 /// Opens a textStream in the archive for writing as a text textStream.
 /// </summary>
 /// <param name="archivePath">The filename.</param>
 /// <returns>Returns the resulting TextWriter.</returns>
 public TextWriter CreateText(string archivePath)
 {
     ZipArchiveFile newEntry;
     if (!_entries.TryGetValue(archivePath, out newEntry))
     {
         newEntry = new ZipArchiveFile(this, archivePath);
     }
     return newEntry.CreateText();
 }
        /// <summary>
        /// Reads a single archiveFile from a Zip Archive. Should only be used
        /// by ZipArchive.
        /// </summary>
        /// <param name="archive">The Zip archive object.</param>
        /// <returns>A ZipArchiveFile representing the archiveFile read from the
        /// archive.</returns>
        internal static ZipArchiveFile Read(ZipArchive archive)
        {
            Stream reader = archive.FromStream;
            ByteBuffer header = new ByteBuffer(30);
            int count = header.ReadContentsFrom(reader);
            if (count == 0)
            {
                return null;
            }

            // Local file header:
            //
            // local file header signature     4 bytes  (0x04034b50)
            // version needed to extract       2 bytes
            // general purpose bit flag        2 bytes
            // compression method              2 bytes
            // last mod file time              2 bytes
            // last mod file date              2 bytes
            // crc-32                          4 bytes
            // compressed size                 4 bytes
            // uncompressed size               4 bytes
            // file name length                2 bytes
            // extra field length              2 bytes
            //
            // file name (variable size)
            // extra field (variable size)

            uint fileSignature = header.ReadUInt32();
            if (fileSignature != SignatureFileEntry)
            {
                if (fileSignature != SignatureArchiveDirectory)
                {
                    throw new InvalidOperationException("Bad ZipFile Header");
                }
                return null;
            }

            ushort versionNeededToExtract = header.ReadUInt16();
            if (versionNeededToExtract > MaximumVersionExtractable)
            {
                throw new NotSupportedException("Zip file requires unsupported features");
            }

            header.SkipBytes(2); // general purpose bit flag

            ZipArchiveFile newEntry = new ZipArchiveFile(archive, null);

            newEntry._compressionMethod = (CompressionMethod)header.ReadUInt16();
            newEntry._lastWriteTime = DosTimeToDateTime(header.ReadUInt32());
            newEntry._crc32 = header.ReadUInt32();
            newEntry._compressedLength = checked((int)header.ReadUInt32());
            newEntry._length = header.ReadUInt32();
            int fileNameLength = checked((int)header.ReadUInt16());

            byte[] fileNameBuffer = new byte[fileNameLength];
            int fileNameCount = reader.Read(fileNameBuffer, 0, fileNameLength);
            newEntry._name = Encoding.UTF8.GetString(fileNameBuffer).Replace('/', Path.DirectorySeparatorChar);
            archive.Entries[newEntry._name] = newEntry;

            if (count != header.Length || fileNameCount != fileNameLength || fileNameLength == 0 || newEntry.LastWriteTime.Ticks == 0)
            {
                throw new InvalidOperationException("Bad Zip File Header");
            }

            if (newEntry.Name.IndexOfAny(invalidPathChars) >= 0)
            {
                throw new InvalidOperationException("Invalid File Name");
            }

            if (newEntry._compressionMethod != CompressionMethod.None && newEntry._compressionMethod != CompressionMethod.Deflate)
            {
                throw new NotSupportedException("Unsupported compression mode " + newEntry._compressionMethod);
            }

            if (archive.IsReadOnly && reader.CanSeek)
            {
                // Optimization: we can defer reading in the data in the common
                // case of a read-only archive by simply remembering where the
                // data is and fetching it on demand.  This is nice because we
                // only hold on to memory of data we are actually operating on,
                // instead of the whole archive.
                // 
                // Because uncompresseData is null, we know that we fetch it
                // from the archive 'fromStream'.
                newEntry._positionOfCompressedDataInArchive = archive.FromStream.Position;
                reader.Seek(newEntry._compressedLength, SeekOrigin.Current);
            }
            else
            {
                // We may be updating the archive in place, so we need to copy
                // the data out.
                newEntry._compressedData = new byte[newEntry._compressedLength];
                reader.Read(newEntry._compressedData, 0, (int)newEntry._compressedLength);
            }

#if DEBUG
            newEntry.Validate();
#endif

            return newEntry;
        }
        /// <summary>
        /// Reads a single archiveFile from a Zip Archive. Should only be used
        /// by ZipArchive.
        /// </summary>
        /// <param name="archive">The Zip archive object.</param>
        /// <returns>A ZipArchiveFile representing the archiveFile read from the
        /// archive.</returns>
        internal static ZipArchiveFile Read(ZipArchive archive)
        {
            Stream     reader = archive.FromStream;
            ByteBuffer header = new ByteBuffer(30);
            int        count  = header.ReadContentsFrom(reader);

            if (count == 0)
            {
                return(null);
            }

            // Local file header:
            //
            // local file header signature     4 bytes  (0x04034b50)
            // version needed to extract       2 bytes
            // general purpose bit flag        2 bytes
            // compression method              2 bytes
            // last mod file time              2 bytes
            // last mod file date              2 bytes
            // crc-32                          4 bytes
            // compressed size                 4 bytes
            // uncompressed size               4 bytes
            // file name length                2 bytes
            // extra field length              2 bytes
            //
            // file name (variable size)
            // extra field (variable size)

            uint fileSignature = header.ReadUInt32();

            if (fileSignature != SignatureFileEntry)
            {
                if (fileSignature != SignatureArchiveDirectory)
                {
                    throw new InvalidOperationException("Bad ZipFile Header");
                }
                return(null);
            }

            ushort versionNeededToExtract = header.ReadUInt16();

            if (versionNeededToExtract > MaximumVersionExtractable)
            {
                throw new NotSupportedException("Zip file requires unsupported features");
            }

            header.SkipBytes(2); // general purpose bit flag

            ZipArchiveFile newEntry = new ZipArchiveFile(archive, null);

            newEntry._compressionMethod = (CompressionMethod)header.ReadUInt16();
            newEntry._lastWriteTime     = DosTimeToDateTime(header.ReadUInt32());
            newEntry._crc32             = header.ReadUInt32();
            newEntry._compressedLength  = checked ((int)header.ReadUInt32());
            newEntry._length            = header.ReadUInt32();
            int fileNameLength = checked ((int)header.ReadUInt16());

            byte[] fileNameBuffer = new byte[fileNameLength];
            int    fileNameCount  = reader.Read(fileNameBuffer, 0, fileNameLength);

            newEntry._name = Encoding.UTF8.GetString(fileNameBuffer).Replace('/', Path.DirectorySeparatorChar);
            archive.Entries[newEntry._name] = newEntry;

            if (count != header.Length || fileNameCount != fileNameLength || fileNameLength == 0 || newEntry.LastWriteTime.Ticks == 0)
            {
                throw new InvalidOperationException("Bad Zip File Header");
            }

            if (newEntry.Name.IndexOfAny(invalidPathChars) >= 0)
            {
                throw new InvalidOperationException("Invalid File Name");
            }

            if (newEntry._compressionMethod != CompressionMethod.None && newEntry._compressionMethod != CompressionMethod.Deflate)
            {
                throw new NotSupportedException("Unsupported compression mode " + newEntry._compressionMethod);
            }

            if (archive.IsReadOnly && reader.CanSeek)
            {
                // Optimization: we can defer reading in the data in the common
                // case of a read-only archive by simply remembering where the
                // data is and fetching it on demand.  This is nice because we
                // only hold on to memory of data we are actually operating on,
                // instead of the whole archive.
                //
                // Because uncompresseData is null, we know that we fetch it
                // from the archive 'fromStream'.
                newEntry._positionOfCompressedDataInArchive = archive.FromStream.Position;
                reader.Seek(newEntry._compressedLength, SeekOrigin.Current);
            }
            else
            {
                // We may be updating the archive in place, so we need to copy
                // the data out.
                newEntry._compressedData = new byte[newEntry._compressedLength];
                reader.Read(newEntry._compressedData, 0, (int)newEntry._compressedLength);
            }

#if DEBUG
            newEntry.Validate();
#endif

            return(newEntry);
        }