Collects general purpose utility methods.
        /// <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);
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        // 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);
        }
Пример #6
0
        // 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);
        }
Пример #7
0
 // 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]);
     }
 }
Пример #8
0
        /// <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);
        }
Пример #9
0
 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));
 }
Пример #10
0
        // 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);
        }
Пример #11
0
 // 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));
 }
Пример #12
0
        // 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);
        }
Пример #13
0
 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);
     }
 }
Пример #14
0
 // 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();
 }
Пример #15
0
 // 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);
     }
 }
Пример #16
0
        /// <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);
        }
Пример #17
0
        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;
        }
Пример #18
0
 // 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);
 }
Пример #19
0
        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);
        }
Пример #20
0
        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;
        }
Пример #21
0
        /// <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;
        }
Пример #22
0
        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));
        }
Пример #23
0
 // Token: 0x06000658 RID: 1624 RVA: 0x0000BD33 File Offset: 0x00009F33
 public bool ContainsEntry(string name)
 {
     return(this._entriesWritten.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name)));
 }
Пример #24
0
        /// <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;
        }
Пример #25
0
 // Token: 0x06000340 RID: 832 RVA: 0x00018194 File Offset: 0x00016394
 internal static string Utf8StringFromBuffer(byte[] buf)
 {
     return(SharedUtilities.StringFromBuffer(buf, SharedUtilities.utf8));
 }
Пример #26
0
 // Token: 0x0600033F RID: 831 RVA: 0x00018184 File Offset: 0x00016384
 internal static byte[] StringToByteArray(string value)
 {
     return(SharedUtilities.StringToByteArray(value, SharedUtilities.ibm437));
 }
Пример #27
0
 // 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})"));
 }
Пример #28
0
        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;
        }