/// <summary> /// Read the next entry from the zip file. /// </summary> /// /// <remarks> /// <para> /// Call this method just before calling <see cref="Read(byte[], int, int)"/>, /// to position the pointer in the zip file to the next entry that can be /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the /// data in the zip file, until <c>Read()</c> returns 0. /// </para> /// /// <para> /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped /// stream is moved to the next entry in the zip file. If you call <see /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within /// the file, you will need to call <c>GetNextEntry()</c> again, to insure /// that the file pointer is positioned at the beginning of a zip entry. /// </para> /// /// <para> /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>. /// Alternatively, you can extract an entry into a file, or a stream, by /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings. /// </para> /// /// </remarks> /// /// <returns> /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more /// entries in the zip file. /// </returns> /// public ZipEntry GetNextEntry() { if (_findRequired) { // find the next signature long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature); if (d == -1) { return(null); } // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature _inputStream.Seek(-4, SeekOrigin.Current); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream); } // workitem 10923 else if (_firstEntry) { // we've already read one entry. // Seek to the end of it. _inputStream.Seek(_endOfEntry, SeekOrigin.Begin); Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream); } _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry); // ReadEntry leaves the file position after all the entry // data and the optional bit-3 data descriptpr. This is // where the next entry would normally start. _endOfEntry = _inputStream.Position; _firstEntry = true; _needSetup = true; _findRequired = false; return(_currentEntry); }
private void _SetWriteStream(uint increment) { if (_innerStream != null) { _innerStream.Dispose(); if (File.Exists(CurrentName)) { File.Delete(CurrentName); } File.Move(_currentTempName, CurrentName); // Console.WriteLine("ZSS: SWS close ({0})", // Path.GetFileName(CurrentName)); } if (increment > 0) { CurrentSegment += increment; } SharedUtilities.CreateAndOpenUniqueTempFile(_baseDir, out _innerStream, out _currentTempName); // Console.WriteLine("ZSS: SWS open ({0})", // Path.GetFileName(_currentTempName)); if (CurrentSegment == 0) { _innerStream.Write(BitConverter.GetBytes(ZipConstants.SplitArchiveSignature), 0, 4); } }
/// <summary> /// Read the data from the stream into the buffer. /// </summary> /// /// <remarks> /// <para> /// The data for the zipentry will be decrypted and uncompressed, as /// necessary, before being copied into the buffer. /// </para> /// /// <para> /// You must set the <see cref="Password"/> property before calling /// <c>Read()</c> the first time for an encrypted entry. To determine if an /// entry is encrypted and requires a password, check the <see /// cref="ZipEntry.Encryption">ZipEntry.Encryption</see> property. /// </para> /// </remarks> /// /// <param name="buffer">The buffer to hold the data read from the stream.</param> /// <param name="offset">the offset within the buffer to copy the first byte read.</param> /// <param name="count">the number of bytes to read.</param> /// <returns>the number of bytes read, after decryption and decompression.</returns> public override int Read(byte[] buffer, int offset, int count) { if (_closed) { _exceptionPending = true; throw new System.InvalidOperationException("The stream has been closed."); } if (_needSetup) { SetupStream(); } if (_LeftToRead == 0) { return(0); } int len = (_LeftToRead > count) ? count : (int)_LeftToRead; int n = _crcStream.Read(buffer, offset, len); _LeftToRead -= n; if (_LeftToRead == 0) { int CrcResult = _crcStream.Crc; _currentEntry.VerifyCrcAfterExtract(CrcResult); _inputStream.Seek(_endOfEntry, SeekOrigin.Begin); // workitem 10178 SharedUtilities.Workaround_Ladybug318918(_inputStream); } return(n); }
internal static string NameInArchive(String filename, string directoryPathInArchive) { string result = null; if (directoryPathInArchive == null) { result = filename; } else { if (String.IsNullOrEmpty(directoryPathInArchive)) { result = Path.GetFileName(filename); } else { // explicitly specify a pathname for this file result = Path.Combine(directoryPathInArchive, Path.GetFileName(filename)); } } //result = Path.GetFullPath(result); result = SharedUtilities.NormalizePathForUseInZipFile(result); return(result); }
// Token: 0x06000CFF RID: 3327 RVA: 0x0004B358 File Offset: 0x00049558 internal static int ReadWithRetry(Stream s, byte[] buffer, int offset, int count, string FileName) { int result = 0; bool flag = false; int num = 0; do { try { result = s.Read(buffer, offset, count); flag = true; } catch (IOException ex) { SecurityPermission securityPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); if (!securityPermission.IsUnrestricted()) { throw; } uint num2 = SharedUtilities._HRForException(ex); if (num2 != 2147942433u) { throw new IOException(string.Format("Cannot read file {0}", FileName), ex); } num++; if (num > 10) { throw new IOException(string.Format("Cannot read file {0}, at offset 0x{1:X8} after 10 retries", FileName, offset), ex); } Thread.Sleep(250 + num * 550); } }while (!flag); return(result); }
// Token: 0x06000CF6 RID: 3318 RVA: 0x0004ADAC File Offset: 0x00048FAC internal static int ReadEntrySignature(Stream s) { int num = 0; try { num = SharedUtilities._ReadFourBytes(s, "n/a"); if (num == 134695760) { s.Seek(12L, SeekOrigin.Current); num = SharedUtilities._ReadFourBytes(s, "n/a"); if (num != 67324752) { s.Seek(8L, SeekOrigin.Current); num = SharedUtilities._ReadFourBytes(s, "n/a"); if (num != 67324752) { s.Seek(-24L, SeekOrigin.Current); num = SharedUtilities._ReadFourBytes(s, "n/a"); } } } } catch (BadReadException) { } return(num); }
// Token: 0x0600044D RID: 1101 RVA: 0x0002FC58 File Offset: 0x0002DE58 public void InitCipher(string passphrase) { byte[] array = SharedUtilities.StringToByteArray(passphrase); for (int i = 0; i < passphrase.Length; i++) { this.UpdateKeys(array[i]); } }
/// <summary> /// This method seeks in the underlying stream. /// </summary> /// /// <remarks> /// <para> /// Call this method if you want to seek around within the zip file for random access. /// </para> /// /// <para> /// Applications can intermix calls to <c>Seek()</c> with calls to <see /// cref="GetNextEntry()"/>. After a call to <c>Seek()</c>, /// <c>GetNextEntry()</c> will get the next <c>ZipEntry</c> that falls after /// the current position in the input stream. You're on your own for finding /// out just where to seek in the stream, to get to the various entries. /// </para> /// /// </remarks> /// /// <param name="offset">the offset point to seek to</param> /// <param name="origin">the reference point from which to seek</param> /// <returns>The new position</returns> public override long Seek(long offset, SeekOrigin origin) { _findRequired = true; var x = _inputStream.Seek(offset, origin); // workitem 10178 SharedUtilities.Workaround_Ladybug318918(_inputStream); return(x); }
public long TruncateBackward(uint diskNumber, long offset) { if (diskNumber >= 99) { throw new ArgumentOutOfRangeException("diskNumber"); } if (rwMode != RwMode.Write) { _exceptionPending = true; throw new ZipException("bad state."); } if (diskNumber == CurrentSegment) { return(_innerStream.Seek(offset, SeekOrigin.Begin)); } if (_innerStream != null) { _innerStream.Dispose(); if (File.Exists(_currentTempName)) { File.Delete(_currentTempName); } } for (uint num = CurrentSegment - 1; num > diskNumber; num--) { string path = _NameForSegment(num); if (File.Exists(path)) { File.Delete(path); } } CurrentSegment = diskNumber; for (int i = 0; i < 3; i++) { try { _currentTempName = SharedUtilities.InternalGetTempFileName(); File.Move(CurrentName, _currentTempName); } catch (IOException) { if (i == 2) { throw; } continue; } break; } _innerStream = new FileStream(_currentTempName, FileMode.Open); return(_innerStream.Seek(offset, SeekOrigin.Begin)); }
// Token: 0x06000342 RID: 834 RVA: 0x000181C4 File Offset: 0x000163C4 internal static int ReadSignature(Stream s) { int result = 0; try { result = SharedUtilities._ReadFourBytes(s, "n/a"); } catch (BadReadException) { } return(result); }
// Token: 0x0600033D RID: 829 RVA: 0x000180EC File Offset: 0x000162EC public static string NormalizePathForUseInZipFile(string pathName) { if (string.IsNullOrEmpty(pathName)) { return(pathName); } if (pathName.Length >= 2 && pathName[1] == ':' && pathName[2] == '\\') { pathName = pathName.Substring(3); } pathName = pathName.Replace('\\', '/'); while (pathName.StartsWith("/")) { pathName = pathName.Substring(1); } return(SharedUtilities.SimplifyFwdSlashPath(pathName)); }
// Token: 0x06000346 RID: 838 RVA: 0x00018314 File Offset: 0x00016514 internal static long FindSignature(Stream stream, int SignatureToFind) { long position = stream.Position; int num = 65536; byte[] array = new byte[] { (byte)(SignatureToFind >> 24), (byte)((SignatureToFind & 16711680) >> 16), (byte)((SignatureToFind & 65280) >> 8), (byte)(SignatureToFind & 255) }; byte[] array2 = new byte[num]; bool flag = false; do { int num2 = stream.Read(array2, 0, array2.Length); if (num2 == 0) { break; } for (int i = 0; i < num2; i++) { if (array2[i] == array[3]) { long position2 = stream.Position; stream.Seek((long)(i - num2), SeekOrigin.Current); int num3 = SharedUtilities.ReadSignature(stream); flag = (num3 == SignatureToFind); if (flag) { break; } stream.Seek(position2, SeekOrigin.Begin); } } }while (!flag); if (!flag) { stream.Seek(position, SeekOrigin.Begin); return(-1L); } return(stream.Position - position - 4L); }
public ZipEntry this[String fileName] { get { var entries = RetrievalEntries; var key = SharedUtilities.NormalizePathForUseInZipFile(fileName); if (entries.ContainsKey(key)) { return(entries[key]); } // workitem 11056 key = key.Replace("/", "\\"); if (entries.ContainsKey(key)) { return(entries[key]); } return(null); } }
// Token: 0x0600034A RID: 842 RVA: 0x000187EC File Offset: 0x000169EC public static void CreateAndOpenUniqueTempFile(string dir, out Stream fs, out string filename) { for (int i = 0; i < 3; i++) { try { filename = Path.Combine(dir, SharedUtilities.InternalGetTempFileName()); fs = new FileStream(filename, FileMode.CreateNew); return; } catch (IOException) { if (i == 2) { throw; } } } throw new IOException(); }
// Token: 0x06000689 RID: 1673 RVA: 0x0003A820 File Offset: 0x00038A20 private void _SetWriteStream(uint increment) { if (this._innerStream != null) { this._innerStream.Dispose(); if (File.Exists(this.CurrentName)) { File.Delete(this.CurrentName); } File.Move(this._currentTempName, this.CurrentName); } if (increment > 0U) { this.CurrentSegment += increment; } SharedUtilities.CreateAndOpenUniqueTempFile(this._baseDir, out this._innerStream, out this._currentTempName); if (this.CurrentSegment == 0U) { this._innerStream.Write(BitConverter.GetBytes(134695760), 0, 4); } }
/// <summary> /// Read the next entry from the zip file. /// </summary> /// /// <remarks> /// <para> /// Call this method just before calling <see cref="Read(byte[], int, int)"/>, /// to position the pointer in the zip file to the next entry that can be /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the /// data in the zip file, until <c>Read()</c> returns 0. /// </para> /// /// <para> /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped /// stream is moved to the next entry in the zip file. If you call <see /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within /// the file, you will need to call <c>GetNextEntry()</c> again, to insure /// that the file pointer is positioned at the beginning of a zip entry. /// </para> /// /// <para> /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>. /// Alternatively, you can extract an entry into a file, or a stream, by /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings. /// </para> /// /// </remarks> /// /// <returns> /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more /// entries in the zip file. /// </returns> /// public ZipEntry GetNextEntry() { if (_findRequired) { // find the next signature long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature); if (d == -1) { return(null); } // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature _inputStream.Seek(-4, SeekOrigin.Current); } _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry); _endOfEntry = _inputStream.Position; _firstEntry = true; _needSetup = true; _findRequired = false; return(_currentEntry); }
public void RemoveEntry(ZipEntry entry) { //if (!_entries.Values.Contains(entry)) // throw new ArgumentException("The entry you specified does not exist in the zip archive."); if (entry == null) { throw new ArgumentNullException("entry"); } var path = SharedUtilities.NormalizePathForUseInZipFile(entry.FileName); _entries.Remove(path); if (!AnyCaseInsensitiveMatches(path)) { _entriesInsensitive.Remove(path); } _zipEntriesAsList = null; #if NOTNEEDED if (_direntries != null) { bool FoundAndRemovedDirEntry = false; foreach (ZipDirEntry de1 in _direntries) { if (entry.FileName == de1.FileName) { _direntries.Remove(de1); FoundAndRemovedDirEntry = true; break; } } if (!FoundAndRemovedDirEntry) { throw new BadStateException("The entry to be removed was not found in the directory."); } } #endif _contentsChanged = true; }
// Token: 0x06000EE7 RID: 3815 RVA: 0x00056D58 File Offset: 0x00054F58 public ZipEntry GetNextEntry() { if (this._findRequired) { long num = SharedUtilities.FindSignature(this._inputStream, 67324752); if (num == -1L) { return(null); } this._inputStream.Seek(-4L, SeekOrigin.Current); } else if (this._firstEntry) { this._inputStream.Seek(this._endOfEntry, SeekOrigin.Begin); } this._currentEntry = ZipEntry.ReadEntry(this._container, !this._firstEntry); this._endOfEntry = this._inputStream.Position; this._firstEntry = true; this._needSetup = true; this._findRequired = false; return(this._currentEntry); }
private static ZipEntry Create(string nameInArchive, ZipEntrySource source, Object arg1, Object arg2) { if (String.IsNullOrEmpty(nameInArchive)) { throw new Ionic.Zip.ZipException("The entry name must be non-null and non-empty."); } ZipEntry entry = new ZipEntry(); // workitem 7071 // workitem 7926 - "version made by" OS should be zero for compat with WinZip entry._VersionMadeBy = (0 << 8) + 45; // indicates the attributes are FAT Attributes, and v4.5 of the spec entry._Source = source; entry._Mtime = entry._Atime = entry._Ctime = DateTime.UtcNow; if (source == ZipEntrySource.Stream) { entry._sourceStream = (arg1 as Stream); // may or may not be null } else if (source == ZipEntrySource.WriteDelegate) { entry._WriteDelegate = (arg1 as WriteDelegate); // may or may not be null } else if (source == ZipEntrySource.JitStream) { entry._OpenDelegate = (arg1 as OpenDelegate); // may or may not be null entry._CloseDelegate = (arg2 as CloseDelegate); // may or may not be null } else if (source == ZipEntrySource.ZipOutputStream) { } // workitem 9073 else if (source == ZipEntrySource.None) { // make this a valid value, for later. entry._Source = ZipEntrySource.FileSystem; } else { String filename = (arg1 as String); // must not be null if (String.IsNullOrEmpty(filename)) { throw new Ionic.Zip.ZipException("The filename must be non-null and non-empty."); } try { // The named file may or may not exist at this time. For // example, when adding a directory by name. We test existence // when necessary: when saving the ZipFile, or when getting the // attributes, and so on. // workitem 6878?? entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime(); entry._Ctime = File.GetCreationTime(filename).ToUniversalTime(); entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime(); // workitem 7071 // can only get attributes on files that exist. if (File.Exists(filename) || Directory.Exists(filename)) { entry._ExternalFileAttrs = (int)File.GetAttributes(filename); } entry._ntfsTimesAreSet = true; entry._LocalFileName = Path.GetFullPath(filename); // workitem 8813 } catch (System.IO.PathTooLongException ptle) { // workitem 14035 var msg = String.Format("The path is too long, filename={0}", filename); throw new ZipException(msg, ptle); } } entry._LastModified = entry._Mtime; entry._FileNameInArchive = SharedUtilities.NormalizePathForUseInZipFile(nameInArchive); // We don't actually slurp in the file data until the caller invokes Write on this entry. return(entry); }
private static void ReadIntoInstance(ZipFile zf) { Stream s = zf.ReadStream; try { if (!s.CanSeek) { ReadIntoInstance_Orig(zf); return; } zf.OnReadStarted(); // change for workitem 8098 //zf._originPosition = s.Position; // Try reading the central directory, rather than scanning the file. uint datum = VerifyBeginningOfZipFile(s); if (datum == ZipConstants.EndOfCentralDirectorySignature) { return; } // start at the end of the file... // seek backwards a bit, then look for the EoCD signature. int nTries = 0; bool success = false; // The size of the end-of-central-directory-footer plus 2 bytes is 18. // This implies an archive comment length of 0. We'll add a margin of // safety and start "in front" of that, when looking for the // EndOfCentralDirectorySignature long posn = s.Length - 64; long maxSeekback = Math.Max(s.Length - 0x4000, 10); do { s.Seek(posn, SeekOrigin.Begin); long bytesRead = SharedUtilities.FindSignature(s, (int)ZipConstants.EndOfCentralDirectorySignature); if (bytesRead != -1) { success = true; } else { nTries++; // Weird: with NETCF, negative offsets from SeekOrigin.End DO // NOT WORK. So rather than seek a negative offset, we seek // from SeekOrigin.Begin using a smaller number. posn -= (32 * (nTries + 1) * nTries); // increasingly larger if (posn < 0) { posn = 0; // BOF } } }while (!success && posn > maxSeekback); if (success) { // workitem 8299 zf._locEndOfCDS = s.Position - 4; byte[] block = new byte[16]; s.Read(block, 0, block.Length); zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2); if (zf._diskNumberWithCd == 0xFFFF) { throw new ZipException("Spanned archives with more than 65534 segments are not supported at this time."); } zf._diskNumberWithCd++; // I think the number in the file differs from reality by 1 int i = 12; uint offset32 = (uint)BitConverter.ToUInt32(block, i); if (offset32 == 0xFFFFFFFF) { Zip64SeekToCentralDirectory(zf); } else { // change for workitem 8098 s.Seek(offset32, SeekOrigin.Begin); } ReadCentralDirectory(zf); } else { // Could not find the central directory. // Fallback to the old method. // workitem 8098: ok //s.Seek(zf._originPosition, SeekOrigin.Begin); s.Seek(0L, SeekOrigin.Begin); ReadIntoInstance_Orig(zf); } } catch //(Exception e1) { if (zf._ReadStreamIsOurs && zf._readstream != null) { try { zf._readstream.Close(); #if !NETCF zf._readstream.Dispose(); #endif zf._readstream = null; } finally { } } throw; // new Ionic.Utils.Zip.ZipException("Exception while reading", e1); } // the instance has been read in zf._contentsChanged = false; }
/// <summary> /// Saves the Zip archive to a file, specified by the Name property of the /// <c>ZipFile</c>. /// </summary> /// /// <remarks> /// <para> /// The <c>ZipFile</c> instance is written to storage, typically a zip file /// in a filesystem, only when the caller calls <c>Save</c>. In the typical /// case, the Save operation writes the zip content to a temporary file, and /// then renames the temporary file to the desired name. If necessary, this /// method will delete a pre-existing file before the rename. /// </para> /// /// <para> /// The <see cref="ZipFile.Name"/> property is specified either explicitly, /// or implicitly using one of the parameterized ZipFile constructors. For /// COM Automation clients, the <c>Name</c> property must be set explicitly, /// because COM Automation clients cannot call parameterized constructors. /// </para> /// /// <para> /// When using a filesystem file for the Zip output, it is possible to call /// <c>Save</c> multiple times on the <c>ZipFile</c> instance. With each /// call the zip content is re-written to the same output file. /// </para> /// /// <para> /// Data for entries that have been added to the <c>ZipFile</c> instance is /// written to the output when the <c>Save</c> method is called. This means /// that the input streams for those entries must be available at the time /// the application calls <c>Save</c>. If, for example, the application /// adds entries with <c>AddEntry</c> using a dynamically-allocated /// <c>MemoryStream</c>, the memory stream must not have been disposed /// before the call to <c>Save</c>. See the <see /// cref="ZipEntry.InputStream"/> property for more discussion of the /// availability requirements of the input stream for an entry, and an /// approach for providing just-in-time stream lifecycle management. /// </para> /// /// </remarks> /// /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(String, System.IO.Stream)"/> /// /// <exception cref="Ionic.Zip.BadStateException"> /// Thrown if you haven't specified a location or stream for saving the zip, /// either in the constructor or by setting the Name property, or if you try /// to save a regular zip archive to a filename with a .exe extension. /// </exception> /// /// <exception cref="System.OverflowException"> /// Thrown if <see cref="MaxOutputSegmentSize"/> is non-zero, and the number /// of segments that would be generated for the spanned zip file during the /// save operation exceeds 99. If this happens, you need to increase the /// segment size. /// </exception> /// public void Save() { try { bool thisSaveUsedZip64 = false; _saveOperationCanceled = false; _numberOfSegmentsForMostRecentSave = 0; OnSaveStarted(); if (WriteStream == null) { throw new BadStateException("You haven't specified where to save the zip."); } if (_name != null && _name.EndsWith(".exe") && !_SavingSfx) { throw new BadStateException("You specified an EXE for a plain zip file."); } // check if modified, before saving. if (!_contentsChanged) { OnSaveCompleted(); if (Verbose) { StatusMessageTextWriter.WriteLine("No save is necessary...."); } return; } Reset(true); if (Verbose) { StatusMessageTextWriter.WriteLine("saving...."); } // validate the number of entries if (_entries.Count >= 0xFFFF && _zip64 == Zip64Option.Never) { throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance."); } // write an entry in the zip for each file int n = 0; // workitem 9831 ICollection <ZipEntry> c = (SortEntriesBeforeSaving) ? EntriesSorted : Entries; foreach (ZipEntry e in c) // _entries.Values { OnSaveEntry(n, e, true); e.Write(WriteStream); if (_saveOperationCanceled) { break; } n++; OnSaveEntry(n, e, false); if (_saveOperationCanceled) { break; } // Some entries can be skipped during the save. if (e.IncludedInMostRecentSave) { thisSaveUsedZip64 |= e.OutputUsedZip64.Value; } } if (_saveOperationCanceled) { return; } var zss = WriteStream as ZipSegmentedStream; _numberOfSegmentsForMostRecentSave = (zss != null) ? zss.CurrentSegment : 1; bool directoryNeededZip64 = ZipOutput.WriteCentralDirectoryStructure (WriteStream, c, _numberOfSegmentsForMostRecentSave, _zip64, Comment, new ZipContainer(this)); OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive); _hasBeenSaved = true; _contentsChanged = false; thisSaveUsedZip64 |= directoryNeededZip64; _OutputUsesZip64 = new Nullable <bool>(thisSaveUsedZip64); if (_fileAlreadyExists && this._readstream != null) { // This means we opened and read a zip file. // If we are now saving, we need to close the orig file, first. this._readstream.Close(); this._readstream = null; } // the archiveStream for each entry needs to be null foreach (var e in c) { var zss1 = e._archiveStream as ZipSegmentedStream; if (zss1 != null) #if NETCF { zss1.Close(); } #else { zss1.Dispose(); } #endif e._archiveStream = null; } // do the rename as necessary if (_name != null && (_temporaryFileName != null || zss != null)) { // _temporaryFileName may remain null if we are writing to a stream. // only close the stream if there is a file behind it. #if NETCF WriteStream.Close(); #else WriteStream.Dispose(); #endif if (_saveOperationCanceled) { return; } string tmpName = null; if (File.Exists(_name)) { // the steps: // // 1. Delete tmpName // 2. move existing zip to tmpName // 3. rename (File.Move) working file to name of existing zip // 4. delete tmpName // // This series of steps avoids the exception, // System.IO.IOException: // "Cannot create a file when that file already exists." // // Cannot just call File.Replace() here because // there is a possibility that the TEMP volume is different // that the volume for the final file (c:\ vs d:\). // So we need to do a Delete+Move pair. // // But, when doing the delete, Windows allows a process to // delete the file, even though it is held open by, say, a // virus scanner. It gets internally marked as "delete // pending". The file does not actually get removed from the // file system, it is still there after the File.Delete // call. // // Therefore, we need to move the existing zip, which may be // held open, to some other name. Then rename our working // file to the desired name, then delete (possibly delete // pending) the "other name". // // Ideally this would be transactional. It's possible that the // delete succeeds and the move fails. Lacking transactions, if // this kind of failure happens, we're hosed, and this logic will // throw on the next File.Move(). // //File.Delete(_name); // workitem 10447 #if NETCF || SILVERLIGHT tmpName = _name + "." + SharedUtilities.GenerateRandomStringImpl(8, 0) + ".tmp"; #else tmpName = _name + "." + Path.GetRandomFileName(); #endif if (File.Exists(tmpName)) { DeleteFileWithRetry(tmpName); } File.Move(_name, tmpName); } OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive); File.Move((zss != null) ? zss.CurrentTempName : _temporaryFileName, _name); OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive); if (tmpName != null) { try { // not critical if (File.Exists(tmpName)) { File.Delete(tmpName); } } catch { // don't care about exceptions here. } } _fileAlreadyExists = true; } _readName = _name; NotifyEntriesSaveComplete(c); OnSaveCompleted(); _JustSaved = true; } // workitem 5043 finally { CleanupAfterSaveOperation(); } return; }
public long TruncateBackward(uint diskNumber, long offset) { // Console.WriteLine("***ZSS.Trunc to disk {0}", diskNumber); // Console.WriteLine("***ZSS.Trunc: current disk {0}", CurrentSegment); if (rw != 2) { throw new ZipException("bad state."); } // Seek back in the segmented stream to a (maybe) prior segment. // Check if it is the same segment. If it is, very simple. if (diskNumber == CurrentSegment) { return(_innerStream.Seek(offset, SeekOrigin.Begin)); } // Seeking back to a prior segment. // The current segment and any intervening segments must be removed. // First, remove the current segment. if (_innerStream != null) { _innerStream.Close(); if (File.Exists(_currentTempName)) { File.Delete(_currentTempName); } } // Now, remove intervening segments. for (uint j = CurrentSegment - 1; j > diskNumber; j--) { string s = _NameForSegment(j); // Console.WriteLine("***ZSS.Trunc: removing file {0}", s); if (File.Exists(s)) { File.Delete(s); } } // now, open the desired segment. It must exist. CurrentSegment = diskNumber; // get a new temp file, try 3 times: for (int i = 0; i < 3; i++) { try { _currentTempName = SharedUtilities.InternalGetTempFileName(); File.Move(CurrentName, _currentTempName); // move the .z0x file back to a temp name } catch (IOException) { if (i == 2) { throw; } } } _innerStream = new FileStream(_currentTempName, FileMode.Open); return(_innerStream.Seek(offset, SeekOrigin.Begin)); }
// Token: 0x06000658 RID: 1624 RVA: 0x0000BD33 File Offset: 0x00009F33 public bool ContainsEntry(string name) { return(this._entriesWritten.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name))); }
/// <summary> /// Saves the Zip archive to a file, specified by the Name property of the /// <c>ZipFile</c>. /// </summary> /// /// <remarks> /// <para> /// The <c>ZipFile</c> instance is written to storage, typically a zip file /// in a filesystem, only when the caller calls <c>Save</c>. In the typical /// case, the Save operation writes the zip content to a temporary file, and /// then renames the temporary file to the desired name. If necessary, this /// method will delete a pre-existing file before the rename. /// </para> /// /// <para> /// The <see cref="ZipFile.Name"/> property is specified either explicitly, /// or implicitly using one of the parameterized ZipFile constructors. For /// COM Automation clients, the <c>Name</c> property must be set explicitly, /// because COM Automation clients cannot call parameterized constructors. /// </para> /// /// <para> /// When using a filesystem file for the Zip output, it is possible to call /// <c>Save</c> multiple times on the <c>ZipFile</c> instance. With each /// call the zip content is re-written to the same output file. /// </para> /// /// <para> /// Data for entries that have been added to the <c>ZipFile</c> instance is /// written to the output when the <c>Save</c> method is called. This means /// that the input streams for those entries must be available at the time /// the application calls <c>Save</c>. If, for example, the application /// adds entries with <c>AddEntry</c> using a dynamically-allocated /// <c>MemoryStream</c>, the memory stream must not have been disposed /// before the call to <c>Save</c>. See the <see /// cref="ZipEntry.InputStream"/> property for more discussion of the /// availability requirements of the input stream for an entry, and an /// approach for providing just-in-time stream lifecycle management. /// </para> /// /// </remarks> /// /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(String, System.IO.Stream)"/> /// /// <exception cref="Ionic.Zip.BadStateException"> /// Thrown if you haven't specified a location or stream for saving the zip, /// either in the constructor or by setting the Name property, or if you try /// to save a regular zip archive to a filename with a .exe extension. /// </exception> /// /// <exception cref="System.OverflowException"> /// Thrown if <see cref="MaxOutputSegmentSize"/> is non-zero, and the number /// of segments that would be generated for the spanned zip file during the /// save operation exceeds 99. If this happens, you need to increase the /// segment size. /// </exception> /// public void Save() { try { bool thisSaveUsedZip64 = false; _saveOperationCanceled = false; _numberOfSegmentsForMostRecentSave = 0; OnSaveStarted(); if (WriteStream == null) { throw new BadStateException("You haven't specified where to save the zip."); } if (_name != null && _name.EndsWith(".exe") && !_SavingSfx) { throw new BadStateException("You specified an EXE for a plain zip file."); } // check if modified, before saving. if (!_contentsChanged) { OnSaveCompleted(); if (Verbose) { StatusMessageTextWriter.WriteLine("No save is necessary...."); } return; } Reset(true); if (Verbose) { StatusMessageTextWriter.WriteLine("saving...."); } // validate the number of entries if (_entries.Count >= 0xFFFF && _zip64 == Zip64Option.Never) { throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance."); } // write an entry in the zip for each file int n = 0; // workitem 9831 ICollection <ZipEntry> c = (SortEntriesBeforeSaving) ? EntriesSorted : Entries; foreach (ZipEntry e in c) // _entries.Values { OnSaveEntry(n, e, true); e.Write(WriteStream); if (_saveOperationCanceled) { break; } n++; OnSaveEntry(n, e, false); if (_saveOperationCanceled) { break; } // Some entries can be skipped during the save. if (e.IncludedInMostRecentSave) { thisSaveUsedZip64 |= e.OutputUsedZip64.Value; } } if (_saveOperationCanceled) { return; } var zss = WriteStream as ZipSegmentedStream; _numberOfSegmentsForMostRecentSave = (zss != null) ? zss.CurrentSegment : 1; bool directoryNeededZip64 = ZipOutput.WriteCentralDirectoryStructure (WriteStream, c, _numberOfSegmentsForMostRecentSave, _zip64, Comment, new ZipContainer(this)); OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive); _hasBeenSaved = true; _contentsChanged = false; thisSaveUsedZip64 |= directoryNeededZip64; _OutputUsesZip64 = new Nullable <bool>(thisSaveUsedZip64); // do the rename as necessary if (_name != null && (_temporaryFileName != null || zss != null)) { // _temporaryFileName may remain null if we are writing to a stream. // only close the stream if there is a file behind it. #if NETCF WriteStream.Close(); #else WriteStream.Dispose(); #endif if (_saveOperationCanceled) { return; } if (_fileAlreadyExists && this._readstream != null) { // This means we opened and read a zip file. // If we are now saving to the same file, we need to close the // orig file, first. this._readstream.Close(); this._readstream.Dispose(); this._readstream = null; // the archiveStream for each entry needs to be null foreach (var e in c) { var zss1 = e._archiveStream as ZipSegmentedStream; if (zss1 != null) #if NETCF { zss1.Close(); } #else { zss1.Dispose(); } #endif e._archiveStream = null; } } if (_fileAlreadyExists && this._writestream != null) { this.WriteStream.Close(); } string tmpName = null; if (File.Exists(_name)) { // the steps: // // 1. Delete tmpName // 2. move existing zip to tmpName // 3. rename (File.Move) working file to name of existing zip // 4. delete tmpName // // This series of steps avoids the exception, // System.IO.IOException: // "Cannot create a file when that file already exists." // // Cannot just call File.Replace() here because // there is a possibility that the TEMP volume is different // that the volume for the final file (c:\ vs d:\). // So we need to do a Delete+Move pair. // // But, when doing the delete, Windows allows a process to // delete the file, even though it is held open by, say, a // virus scanner. It gets internally marked as "delete // pending". The file does not actually get removed from the // file system, it is still there after the File.Delete // call. // // Therefore, we need to move the existing zip, which may be // held open, to some other name. Then rename our working // file to the desired name, then delete (possibly delete // pending) the "other name". // // Ideally this would be transactional. It's possible that the // delete succeeds and the move fails. Lacking transactions, if // this kind of failure happens, we're hosed, and this logic will // throw on the next File.Move(). // //File.Delete(_name); // workitem 10447 #if NETCF || SILVERLIGHT tmpName = _name + "." + SharedUtilities.GenerateRandomStringImpl(8, 0) + ".tmp"; #else tmpName = _name + "." + Path.GetRandomFileName(); #endif if (File.Exists(tmpName)) { DeleteFileWithRetry(tmpName); } try { File.Move(_name, tmpName); } catch { if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); //Look at the comment below. Added this to force a break here instead of your catch so you don't miss the cause and waste your time like I did } throw; } //Oh boy. You've just hit an exception on that File.Move line right above this stating that the template file can't be renamed because it's open //in another process, right? //Congratulation! You've probably run into the same gibberish I ran into! //Check to make sure your file streams are closed, and ITpipes/Template Editor/Winrar/7-Zip don't have the template file open. I'm betting you won't find anything. //If you try closing Visual Studio and running the binary directly I'm betting you won't have this crash occur. Go ahead--try it. //What the hell, right? //The XAML designer process (XDesProc.exe) is configured, by default, to populate its ViewModel in the designer UI. This creates a copy of the model--which creates a second //Ionic.Zip.ZipFile object using the same template file. So when *this* ZipFile object attempts to move the existing template to replace it with an updated file //the exception is thrown. //To fix this, disable the following option in the Visual Studio toolbar above: // Tools -> Options -> XAML Designer -> "Run project code in XAML Designer (if supported)" //Once that's disabled, restart Visual Studio. Problem solved. //Hopefully these comments will prevent someone else from wasting their time obsessing over their streams and AntiVirus. - Vincent Nary } OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive); File.Move((zss != null) ? zss.CurrentTempName : _temporaryFileName, _name); OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive); if (tmpName != null) { try { // not critical if (File.Exists(tmpName)) { File.Delete(tmpName); } } catch { // don't care about exceptions here. } } _fileAlreadyExists = true; } NotifyEntriesSaveComplete(c); OnSaveCompleted(); _JustSaved = true; } // workitem 5043 finally { CleanupAfterSaveOperation(); } return; }
// Token: 0x06000340 RID: 832 RVA: 0x00018194 File Offset: 0x00016394 internal static string Utf8StringFromBuffer(byte[] buf) { return(SharedUtilities.StringFromBuffer(buf, SharedUtilities.utf8)); }
// Token: 0x0600033F RID: 831 RVA: 0x00018184 File Offset: 0x00016384 internal static byte[] StringToByteArray(string value) { return(SharedUtilities.StringToByteArray(value, SharedUtilities.ibm437)); }
// Token: 0x06000344 RID: 836 RVA: 0x00018298 File Offset: 0x00016498 internal static int ReadInt(Stream s) { return(SharedUtilities._ReadFourBytes(s, "Could not read block - no data! (position 0x{0:X8})")); }
public long TruncateBackward(uint diskNumber, long offset) { // Console.WriteLine("***ZSS.Trunc to disk {0}", diskNumber); // Console.WriteLine("***ZSS.Trunc: current disk {0}", CurrentSegment); if (diskNumber >= 99) { throw new ArgumentOutOfRangeException("diskNumber"); } if (rwMode != RwMode.Write) { _exceptionPending = true; throw new ZipException("bad state."); } // Seek back in the segmented stream to a (maybe) prior segment. // Check if it is the same segment. If it is, very simple. if (diskNumber == CurrentSegment) { var x = _innerStream.Seek(offset, SeekOrigin.Begin); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream); return(x); } // Seeking back to a prior segment. // The current segment and any intervening segments must be removed. // First, close the current segment, and then remove it. if (_innerStream != null) { #if NETCF _innerStream.Close(); #else _innerStream.Dispose(); #endif if (File.Exists(_currentTempName)) { File.Delete(_currentTempName); } } // Now, remove intervening segments. for (uint j = CurrentSegment - 1; j > diskNumber; j--) { string s = _NameForSegment(j); // Console.WriteLine("***ZSS.Trunc: removing file {0}", s); if (File.Exists(s)) { File.Delete(s); } } // now, open the desired segment. It must exist. CurrentSegment = diskNumber; // get a new temp file, try 3 times: for (int i = 0; i < 3; i++) { try { _currentTempName = SharedUtilities.InternalGetTempFileName(); // move the .z0x file back to a temp name File.Move(CurrentName, _currentTempName); break; // workitem 12403 } catch (IOException) { if (i == 2) { throw; } } } // open it _innerStream = new FileStream(_currentTempName, FileMode.Open); var r = _innerStream.Seek(offset, SeekOrigin.Begin); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream); return(r); }
private static void ReadIntoInstance(ZipFile zf) { Stream s = zf.ReadStream; try { zf._readName = zf._name; // workitem 13915 if (!s.CanSeek) { ReadIntoInstance_Orig(zf); return; } zf.OnReadStarted(); // change for workitem 8098 //zf._originPosition = s.Position; // Try reading the central directory, rather than scanning the file. uint datum = ReadFirstFourBytes(s); if (datum == ZipConstants.EndOfCentralDirectorySignature) { return; } int nTries = 0; bool success = false; long posn = s.Length - 64; long maxSeekback = Math.Max(s.Length - 0x4000, 10); do { if (posn < 0) { posn = 0; // BOF } s.Seek(posn, SeekOrigin.Begin); long bytesRead = SharedUtilities.FindSignature(s, (int)ZipConstants.EndOfCentralDirectorySignature); if (bytesRead != -1) { success = true; } else { if (posn == 0) { break; // started at the BOF and found nothing } nTries++; // Weird: with NETCF, negative offsets from SeekOrigin.End DO // NOT WORK. So rather than seek a negative offset, we seek // from SeekOrigin.Begin using a smaller number. // // We no longer target NETCF, so somebody feeling brave could // restore the (very) old code. posn -= (32 * (nTries + 1) * nTries); } }while (!success && posn > maxSeekback); if (success) { // workitem 8299 zf._locEndOfCDS = s.Position - 4; byte[] block = new byte[16]; s.Read(block, 0, block.Length); zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2); if (zf._diskNumberWithCd == 0xFFFF) { throw new ZipException("Spanned archives with more than 65534 segments are not supported at this time."); } zf._diskNumberWithCd++; // I think the number in the file differs from reality by 1 int i = 12; uint offset32 = (uint)BitConverter.ToUInt32(block, i); if (offset32 == 0xFFFFFFFF) { Zip64SeekToCentralDirectory(zf); } else { zf._OffsetOfCentralDirectory = offset32; // change for workitem 8098 s.Seek(offset32, SeekOrigin.Begin); } ReadCentralDirectory(zf); } else { // Could not find the central directory. // Fallback to the old method. // workitem 8098: ok //s.Seek(zf._originPosition, SeekOrigin.Begin); s.Seek(0L, SeekOrigin.Begin); ReadIntoInstance_Orig(zf); } } catch (Exception ex1) { if (zf._ReadStreamIsOurs && zf._readstream != null) { try { zf._readstream.Dispose(); zf._readstream = null; } finally { } } throw new ZipException("Cannot read that as a ZipFile", ex1); } // the instance has been read in zf._contentsChanged = false; }