/// <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> /// 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); }