diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/DeobfuscatingStream.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/DeobfuscatingStream.cs index 82c11c88ee9..0018d4048dd 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/DeobfuscatingStream.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/DeobfuscatingStream.cs @@ -203,7 +203,7 @@ internal DeobfuscatingStream(Stream obfuscatedStream, Uri streamUri, bool leaveO // Make sure streamUri is in the correct form; getting partUri from it will do all necessary checks for error // conditions; We also have to make sure that it has a part name - Uri partUri = PackUriHelper.GetPartUri(streamUri); + Uri partUri = System.IO.Packaging.PackUriHelper.GetPartUri(streamUri); if (partUri == null) { throw new InvalidOperationException(SR.Get(SRID.InvalidPartName)); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/IO/Packaging/PackWebRequestFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/IO/Packaging/PackWebRequestFactory.cs index cb84202eaa5..8dc9d028bb1 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/IO/Packaging/PackWebRequestFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/IO/Packaging/PackWebRequestFactory.cs @@ -74,9 +74,8 @@ WebRequest IWebRequestCreate.Create(Uri uri) #endif // only inspect cache if part name is present because cache only contains an object, not // the stream it was derived from - Uri packageUri; - Uri partUri; - MS.Internal.IO.Packaging.PackUriHelper.ValidateAndGetPackUriComponents(uri, out packageUri, out partUri); + Uri packageUri = System.IO.Packaging.PackUriHelper.GetPackageUri(uri); + Uri partUri = System.IO.Packaging.PackUriHelper.GetPartUri(uri); if (partUri != null) { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/AppModelKnownContentFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/AppModelKnownContentFactory.cs index 7161454fb33..d81ce14f2b2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/AppModelKnownContentFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/AppModelKnownContentFactory.cs @@ -25,8 +25,6 @@ using System.ComponentModel; using System.Windows.Controls; -using PackUriHelper = MS.Internal.IO.Packaging.PackUriHelper; - namespace MS.Internal.AppModel { // !!!! Note: Those methods are registered as MimeObjectFactory.StreamToObjectFactoryDelegate. The caller expects the diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs index a813ca85d47..191b943c75e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs @@ -692,11 +692,8 @@ public static StreamResourceInfo GetRemoteStream(Uri uriRemote) Uri resolvedUri = BindUriHelper.GetResolvedUri(BaseUriHelper.SiteOfOriginBaseUri, uriRemote); - // Using PackUriHelper.ValidateAndGetPackUriComponents internal method - // to get Package and Part Uri in one step - Uri packageUri; - Uri partUri; - MS.Internal.IO.Packaging.PackUriHelper.ValidateAndGetPackUriComponents(resolvedUri, out packageUri, out partUri); + Uri packageUri = PackUriHelper.GetPackageUri(resolvedUri); + Uri partUri = PackUriHelper.GetPartUri(resolvedUri); // // SiteOfOriginContainer must have been added into the package cache, the code should just @@ -2012,12 +2009,9 @@ private static PackagePart GetResourceOrContentPart(Uri uri) Uri packAppUri = BaseUriHelper.PackAppBaseUri; Uri resolvedUri = BindUriHelper.GetResolvedUri(packAppUri, uri); - // Using PackUriHelper.ValidateAndGetPackUriComponents internal method - // to get Package and Part Uri in one step - Uri packageUri; - Uri partUri; - MS.Internal.IO.Packaging.PackUriHelper.ValidateAndGetPackUriComponents(resolvedUri, out packageUri, out partUri); - + Uri packageUri = PackUriHelper.GetPackageUri(resolvedUri); + Uri partUri = PackUriHelper.GetPartUri(resolvedUri); + // // ResourceContainer must have been added into the package cache, the code should just // take use of that ResourceContainer instance, instead of creating a new instance here. diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedDocument.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedDocument.cs index 24cb576f8a6..862802861b7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedDocument.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedDocument.cs @@ -995,7 +995,7 @@ static private Uri GetStructureUriFromRelationship(Uri contentUri, string relati Uri absTargetUri = null; if (contentUri != null && relationshipName != null) { - Uri partUri = MS.Internal.IO.Packaging.PackUriHelper.GetPartUri(contentUri); + Uri partUri = PackUriHelper.GetPartUri(contentUri); if (partUri != null) { Uri packageUri = PackUriHelper.GetPackageUri(contentUri); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs index a9ba108fa97..c7c6447751a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs @@ -2023,8 +2023,14 @@ private void WriteImage(DocumentNode documentNode) // Get image type to be added to rtf content RtfImageFormat imageFormat = GetImageFormatFromImageSourceName(documentNode.FormatState.ImageSource); - // Write the shape image like as "\pngblip" or "\jpegblip" rtf control - WriteShapeImage(documentNode, imageStream, imageFormat); + // Write the shape image like as "\pngblip" or "\jpegblip" rtf control. We wrap the stream that comes + // from the package because we require the stream to be seekable. + Debug.Assert(!imageStream.CanSeek); + using (var seekableStream = new MemoryStream((int)imageStream.Length)) + { + imageStream.CopyTo(seekableStream); + WriteShapeImage(documentNode, seekableStream, imageFormat); + } #if WindowsMetaFile // This block is disabled because of performance. diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XpsS0ValidatingLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XpsS0ValidatingLoader.cs index 746f0121a22..d3c0af4ec0d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XpsS0ValidatingLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XpsS0ValidatingLoader.cs @@ -73,12 +73,9 @@ private object Load(Stream stream, Uri parentUri, ParserContext pc, ContentType XpsSchema schema = XpsSchema.GetSchema(mimeType); Uri uri = pc.BaseUri; - // Using PackUriHelper.ValidateAndGetPackUriComponents internal method - // to get Package and Part Uri in one step - Uri packageUri; - Uri partUri; - InternalPackUriHelper.ValidateAndGetPackUriComponents(uri, out packageUri, out partUri); - + Uri packageUri = PackUriHelper.GetPackageUri(uri); + Uri partUri = PackUriHelper.GetPartUri(uri); + Package package = PreloadedPackages.GetPackage(packageUri); Uri parentPackageUri = null; diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompressStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompressStream.cs deleted file mode 100644 index 3732ddad140..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompressStream.cs +++ /dev/null @@ -1,825 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// -// Description: -// Emulates a fully functional stream that persists using the Deflate compression algorithm -// -// This class provides a fully functional Stream on a restricted functionality compression -// stream (System.IO.Compression.DeflateStream). -// -// CompressStream operates in "transparent" mode (ReadThrough or WriteThrough) as long as possible for efficiency, -// reverting to full emulation mode as required to satisfy Stream requests that would violate the capabilities -// of the DeflateStream that actually does the reading or writing (decompress or compress). Emulation -// mode is implemented by class CompressEmulationStream. -// -// Note that the reason we need these modes is that DeflateStream is entirely modal in nature once -// constructed. If it is created in "compress" mode, it can only be used for compression. If it is -// opened in "decompress" mode, it can only be used for decompression. This means that Reading is only -// natively support in decompress mode, and writing is only natively supported in compress mode. -// -// Notes: -// If baseStream is non-seekable and non-readable it is not possible to enter Emulation mode. In this case -// we need to throw appropriate exception. -// -// -// - -using System; -using System.IO; -using System.IO.Compression; // for DeflateStream -using System.Diagnostics; - -using System.IO.Packaging; -using MS.Internal.IO.Zip; - -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Packaging -{ - //------------------------------------------------------ - // - // Internal Members - // - //------------------------------------------------------ - /// - /// Emulates a fully functional stream that persists using the Deflate compression algorithm - /// - /// Attempts to provide ReadThrough or WriteThrough functionality as possible. If not possible, - /// a CompressEmulationStream is created and work is delegated to that class. - internal class CompressStream : Stream - { - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - #region Stream Methods - /// - /// Return the bytes requested from the container - /// - /// destination buffer - /// offset to write into that buffer - /// how many bytes requested - /// how many bytes were written into . - /// - /// The underlying stream, expected to be a DeflateStream or a CompressEmulationStream, - /// is in charge of leaving the IO position unchanged in case of an exception. - /// - public override int Read(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); - - // no-op - if (count == 0) - return 0; - - checked // catch any integer overflows - { - switch (_mode) - { - case Mode.Start: - { - // skip to the correct logical position if necessary (DeflateStream starts at position zero) - if (_position == 0) - { - // enter ReadPassThrough mode if it is efficient - ChangeMode(Mode.ReadPassThrough); - } - else - ChangeMode(Mode.Emulation); - - break; - } - - case Mode.ReadPassThrough: // continue in ReadPassThrough mode - case Mode.Emulation: // continue to read from existing emulation stream - { - break; - } - - case Mode.WritePassThrough: // enter Emulation mode - { - // optimization - if they are trying to jump back to the start to read, simply jump to ReadPassThrough mode - if (_position == 0) - ChangeMode(Mode.ReadPassThrough); - else - ChangeMode(Mode.Emulation); - break; - } - default: Debug.Assert(false, "Illegal state for CompressStream - logic error"); break; - } - - // we might be in Start mode now if we are beyond the end of stream - just return zero - if (_current == null) - return 0; - - int bytesRead = _current.Read(buffer, offset, count); - - // optimization for ReadPassThrough mode - we actually know the length because we ran out of bytes - if (_mode == Mode.ReadPassThrough && bytesRead == 0) - { - // possible first chance to set and verify length from header against real data length - UpdateUncompressedDataLength(_position); - - // since we've exhausted the deflateStream, discard it to reduce working set - ChangeMode(Mode.Start); - } - - // Stream contract - don't update position until we are certain that no exceptions have occurred - _position += bytesRead; - - return bytesRead; - } - } - - /// - /// Write - /// - /// Note that zero length write to deflate stream actually results in a stream containing 2 bytes. This is - /// required to maintain compatibility with the standard. - public override void Write(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); - - // no-op - if (count == 0) - return; - - checked - { - switch (_mode) - { - case Mode.Start: // enter WritePassThrough mode if possible - { - // Special case: If stream has existing content, we need to go straight - // to Emulation mode otherwise we'll potentially destroy existing data. - // Don't bother entering WritePassThroughMode if position is non-zero because - // we'll just enter emulation later. - if (_position == 0 && IsDeflateStreamEmpty(_baseStream)) - ChangeMode(Mode.WritePassThrough); - else - ChangeMode(Mode.Emulation); - break; - } - case Mode.WritePassThrough: // continue in Write mode - case Mode.Emulation: // continue to read from existing emulation stream - { - break; - } - case Mode.ReadPassThrough: // enter Emulation mode - { - ChangeMode(Mode.Emulation); break; - } - default: Debug.Assert(false, "Illegal state for CompressStream - logic error"); break; - } - - _current.Write(buffer, offset, count); - - _position += count; - } - - // keep track of the current length in case someone asks for it - if (_mode == Mode.WritePassThrough) - CachedLength = _position; - - _dirtyForFlushing= true; - _dirtyForClosing= true; - } - - /// - /// Seek - /// - /// offset - /// origin - /// zero - public override long Seek(long offset, SeekOrigin origin) - { - CheckDisposed(); - - if (!CanSeek) - throw new NotSupportedException(SR.Get(SRID.SeekNotSupported)); - - checked - { - // Calculate newPos - // If origin is Begin or Current newPos can be calculated without knowing - // the stream length. If origin is End, switch to Emulation immediately. - long newPos = -1; - switch (origin) - { - case SeekOrigin.Begin: newPos = offset; break; - case SeekOrigin.Current: newPos = _position + offset; break; - case SeekOrigin.End: - ChangeMode(Mode.Emulation); // has no effect if already in Emulation mode - newPos = Length + offset; // Length is now legal to call - break; - } - - // we have a reliable newPos now - throw if its illegal - if (newPos < 0) - throw new ArgumentException(SR.Get(SRID.SeekNegative)); - - // is the new position any different than the current position? - long delta = newPos - _position; - if (delta == 0) - return _position; - - // We optimize for very restricted case - short seek forward in read-only mode. - // This prevents the expense of entering Emulation mode when a stream reader is - // skipping a few bytes while parsing binary data structures (for example). - if ((delta > 0) && (delta < _readPassThroughModeSeekThreshold) - && (_mode == Mode.ReadPassThrough)) - { - // We're able to fake the seek by reading in this one corner case. - // We cannot be in ReadPassThroughMode if currently beyond end of physical - // data so it is safe to assume that the value returned from - // this call represents real data. - long bytesNotRead = ReadPassThroughModeSeek(delta); - if (bytesNotRead > 0) - { - // Stream was exhausted - seek was beyond end of physical - // stream so we need to update our cachedLength and - // move to Start mode. - UpdateUncompressedDataLength(newPos - bytesNotRead); - ChangeMode(Mode.Start); - } - } - else - { - // Enter Emulation for efficiency - ChangeMode(Mode.Emulation); // No-op if already in Emulation - _current.Position = newPos; // Update to new value - } - - // update logical position - _position = newPos; - } - - return _position; - } - - /// - /// SetLength - /// - public override void SetLength(long newLength) - { - CheckDisposed(); - - if (!CanSeek) - throw new NotSupportedException(SR.Get(SRID.SetLengthNotSupported)); - - _lengthVerified = true; // no longer need to verify our length against our constructor value - switch (_mode) - { - case Mode.Start: - case Mode.WritePassThrough: - case Mode.ReadPassThrough: - { - // optimize for "clear the whole stream" - no need to enter emulation - if (newLength == 0) - { - ChangeMode(Mode.Start); // discard any existing deflate stream - _baseStream.SetLength(0); // clear the underlying stream - UpdateUncompressedDataLength(newLength); - } - else - ChangeMode(Mode.Emulation); - - break; - } - - case Mode.Emulation: break; - - default: Debug.Assert(false, "Illegal state for CompressStream - logic error"); break; - } - - if (_mode == Mode.Emulation) - _current.SetLength(newLength); - - // position seek pointer appropriately - if (newLength < _position) - Seek(newLength, SeekOrigin.Begin); - - // still need to mark ourselves dirty so that our caller can get the correct result - // when they query the IsDirty property - _dirtyForFlushing= true; - _dirtyForClosing= true; - } - - /// - /// Flush - /// - /// Flushes to stream (if necessary) - public override void Flush() - { - CheckDisposed(); - - // Always pass through to subordinates because they may be caching things (ignore _dirty flag here). - - // Current must be non-null if changes have been made. - if (_current != null) - { - _current.Flush(); - _dirtyForFlushing = false; // extra flushes after this will not produce more data - - // avoid clearing flag when we are empty because it would prevent generation - // of the 2-byte sequence on dispose - if ((_mode == Mode.Emulation) && (Length != 0)) - { - _dirtyForClosing = false; // if it is ReadThrough or Start (it shouldn't be dirty in the first place) - // if it is WriteThrough it is going to be dirty untill it is closed - } - } - _baseStream.Flush(); - } - #endregion Stream Methods - - #region Stream Properties - /// - /// Current logical position within the stream - /// - public override long Position - { - get - { - CheckDisposed(); - return _position; - } - set - { - CheckDisposed(); - - // convert to a Seek so we don't have to replicate the Seek logic here - Seek(checked(value - _position), SeekOrigin.Current); - } - } - - /// - /// Length - /// - public override long Length - { - get - { - CheckDisposed(); - -// if (!CanSeek) -// throw new NotSupportedException(SR.Get(SRID.LengthNotSupported)); - - switch (_mode) - { - case Mode.Start: - case Mode.WritePassThrough: - case Mode.ReadPassThrough: - { - // use cached length if possible - if (CachedLength >= 0) - return CachedLength; - else - { - // Special optimization for new/empty streams - avoid entering Emulation as long as possible. - if (_position == 0 && IsDeflateStreamEmpty(_baseStream)) - return 0; - - ChangeMode(Mode.Emulation); - } - break; - } - - case Mode.Emulation: break; - - default: Debug.Assert(false, "Illegal state for CompressStream - logic error"); break; - } - - // must be in Emulation mode to get here - // possible first chance to verify length from header against real data length - UpdateUncompressedDataLength(_current.Length); - return _current.Length; - } - } - - /// - /// Is stream readable? - /// - /// returns false when called on disposed stream - public override bool CanRead - { - get - { - // cannot read from a close stream, but don't throw if asked - return (_mode != Mode.Disposed) && _baseStream.CanRead; - } - } - - /// - /// Is stream seekable - should be handled by our owner - /// - /// returns false when called on disposed stream - public override bool CanSeek - { - get - { - // cannot seek on a close stream, but don't throw if asked - return (_mode != Mode.Disposed) && _baseStream.CanSeek; - } - } - - /// - /// Is stream writeable? - /// - /// returns false when called on disposed stream - public override bool CanWrite - { - get - { - // cannot write to a close stream, but don't throw if asked - return (_mode != Mode.Disposed) && _baseStream.CanWrite; - } - } - #endregion - - #region Internal - //------------------------------------------------------ - // - // Internal Constructors - // - //------------------------------------------------------ - /// - /// Constructor - /// - /// uncompressed length if known, or -1 if not known - /// part stream - internal CompressStream(Stream baseStream, long length) : this (baseStream, length, false) - { - } - - /// - /// Constructor - /// - /// part stream - /// new stream or not? - /// uncompressed length if known, or -1 if not known - internal CompressStream(Stream baseStream, long length, bool creating) - { - if (baseStream == null) - throw new ArgumentNullException("baseStream"); - - if (length < -1) - throw new ArgumentOutOfRangeException("length"); - - _baseStream = baseStream; - _cachedLength = length; - - Debug.Assert(_baseStream.Position == 0, - "Our logic assumes position zero and we don't seek because sometimes it's not supported"); - - // we need to be dirty if this is a new stream because an empty deflate - // stream actually causes a write (this happens only on close ); therefore - // we are dirty for close (in case of creation) and not dirty for flush - _dirtyForFlushing= false; - _dirtyForClosing= creating; - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - /// - /// IsDirty - /// - /// - internal bool IsDirty(bool closingFlag) - { - return closingFlag ? _dirtyForClosing : _dirtyForFlushing; - } - - /// - /// IsDisposed - /// - /// - internal bool IsDisposed - { - get - { - return (_mode == Mode.Disposed); - } - } - - #endregion - - #region Protected - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - /// - /// Dispose(bool) - /// - /// - /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to - /// call Dispose() instead of Close(). - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - { - if (_mode != Mode.Disposed) - { - Flush(); - - if (_current != null) - { - _current.Close(); // call Dispose() - _current = null; - } - - // Special handling for "empty" deflated streams - they actually persist - // a 2 byte sequence. - - // Three separate cases (assuming the stream is dirty): - // 1) Stream is seekable - check Length and write the 2-byte sequence - // if the stream is empty. - // 2) Stream is non-seekable and negative CachedLength - this means we were created - // (not opened) and there have been no writes so we need the 2-byte sequence. - // 3) Stream is non-seekable and zero CachedLength - this means we are - // really zero-bytes long which indicates we need the 2-byte sequence. - if (_dirtyForClosing && ((_baseStream.CanSeek && _baseStream.Length == 0) || - (_cachedLength <= 0))) - { - _baseStream.Write(_emptyDeflateStreamConstant, 0, 2); - _baseStream.Flush(); - } - - // _baseStream.Close(); // never close a stream we do not own - _baseStream = null; - - ChangeMode(Mode.Disposed); - _dirtyForClosing = false; - _dirtyForFlushing = false; - } - } - } - finally - { - base.Dispose(disposing); - } - } - #endregion - - // Changed the mode from Emulation to Start - internal void Reset() - { - CheckDisposed(); - - ChangeMode(Mode.Start); - } - - #region Private - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - /// - /// Verify Uncompressed length from data against what we were given in the constructor - /// - /// - /// verify length from header against real data length - private void UpdateUncompressedDataLength(long dataLength) - { - Debug.Assert(dataLength >= 0); - - // only compare if we have a value - if (_cachedLength >= 0) - { - if (!_lengthVerified) - { - if (_cachedLength != dataLength) - throw new FileFormatException(SR.Get(SRID.CompressLengthMismatch)); - - _lengthVerified = true; - } - } - - _cachedLength = dataLength; // always set - } - - /// - /// Helper method to reduce complexity in the public Seek method - /// - /// - /// bytes remaining - will be non-zero if stream was exhausted - /// Attempts to "seek" by reading an discarding bytes using the current - /// Decompressing DeflateStream. - /// _position is updated by our caller - this function does not change it - private long ReadPassThroughModeSeek(long bytesToSeek) - { - checked - { - Debug.Assert(bytesToSeek > 0, "Logic Error - bytesToSeek should be positive"); - - // allocate buffer just big enough for the seek, maximum of 4k - byte[] buf = new byte[Math.Min(0x1000, bytesToSeek)]; - - // read to simulate Seek - while (bytesToSeek > 0) - { - // don't exceed the buffer size - long n = Math.Min(bytesToSeek, buf.Length); - n = _current.Read(buf, 0, (int)n); - - // seek beyond end of stream is legal - if (n == 0) - { - break; // just exit - } - - bytesToSeek -= n; - } - - // return bytes not read - return bytesToSeek; - } - } - - /// - /// Call this before accepting any public API call (except some Stream calls that - /// are allowed to respond even when Closed - /// - private void CheckDisposed() - { - if (IsDisposed) - throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); - } - - /// - /// ChangeMode - /// - /// - /// Does not update Position of _current for change to ReadPassThroughMode. - private void ChangeMode(Mode newMode) - { - // ignore redundant calls (allowing these actually simplifies the logic in SetLength) - if (newMode == _mode) - return; - - // every state change requires this logic - if (_current != null) - { - _current.Close(); - _dirtyForClosing = false; - _dirtyForFlushing = false; - } - - // set the new mode - must be done before the call to Seek - _mode = newMode; - - switch (newMode) - { - case Mode.Start: - { - _current = null; - _baseStream.Position = 0; - break; - } - - case Mode.ReadPassThrough: - case Mode.WritePassThrough: - { - Debug.Assert(_baseStream.Position == 0); - - // create the appropriate DeflateStream - _current = new DeflateStream(_baseStream, - newMode == Mode.WritePassThrough ? CompressionMode.Compress : CompressionMode.Decompress, - true); - - break; - } - case Mode.Emulation: - { - // Create emulation stream. Use a MemoryStream for local caching. - // Do not change this logic for RM cases because the data is "in the clear" and must - // not be persisted in a vulnerable location. - - SparseMemoryStream memStream = new SparseMemoryStream(_lowWaterMark, _highWaterMark); - _current = new CompressEmulationStream(_baseStream, memStream, _position, new DeflateEmulationTransform()); - - // verify and set length - UpdateUncompressedDataLength(_current.Length); - break; - } - case Mode.Disposed: break; - default: - Debug.Assert(false, "Illegal state for CompressStream - logic error"); break; - } - } - - /// - /// Call this to determine if a deflate stream is empty - pass the actual compressed stream - /// - /// - /// true if empty - private static bool IsDeflateStreamEmpty(Stream s) - { - bool empty = false; - - // Special case: If stream has existing content, we need to go straight - // to Emulation mode otherwise we'll potentially destroy existing data. - // This will not be possible if the base stream is write-only and non-seekable. - // The minimal length of a persisted DeflateStream is 2 so if the length - // is 2, we can safely overwrite. We explicitly call Deflate on a stream of length - // 1 so that we can get a consistent exception because this will be an illegally - // compressed stream. - if (s.CanSeek && s.CanRead) - { - Debug.Assert(s.Position == 0); - - // read the two bytes and commpare to the known 2 bytes that represent - // and empty deflate stream - byte[] buf = new byte[2]; - int bytesRead = s.Read(buf, 0, 2); - empty = ((bytesRead == 0) || - (buf[0] == _emptyDeflateStreamConstant[0] && buf[1] == _emptyDeflateStreamConstant[1])); - - s.Position = 0; // restore position - } - else - empty = true; // if write-time-streaming we're going to destroy what's there anyway - - return empty; - } - - private long CachedLength - { - get - { - // only maintained when NOT in Emulation mode - Debug.Assert(_mode != Mode.Emulation, "Logic error: CachedLength not maintained in Emulation mode - illegal Get"); - return _cachedLength; - } - set - { - // only maintained when NOT in Emulation mode - Debug.Assert(_mode != Mode.Emulation, "Logic error: CachedLength not maintained in Emulation mode - illegal Set"); - Debug.Assert(value >= 0, "Length cannot be negative - logic error?"); - _cachedLength = value; - } - } - - //------------------------------------------------------ - // - // Private Variables - // - //------------------------------------------------------ - - // Add explicit values to these enum variables because we do some arithmetic with them and don't want to - // rely on the default behavior. - private enum Mode - { - Start = 0, // we have no outstanding memory in use - state on construction - ReadPassThrough = 1, // we are able to read from the current position - WritePassThrough = 2, // we are able to write to the current position - Emulation = 3, // we have moved all data to a memory stream and all operations are supported - Disposed = 4 // we are disposed - }; - private Mode _mode; // current stream mode - private Int64 _position; // current logical position - only copy - shared with all helpers - private Stream _baseStream; // stream we ultimately decompress from and to in the container - private Stream _current; // current stream object - - private bool _dirtyForFlushing; // are we dirty, these 2 flags are going to differ in the case of the FLushed Write Through mode - private bool _dirtyForClosing; // _dirtyForFlushing will be false (meaning that there is no data to be flushed) while - // _dirtyForClosing will be true as there might be some data that need to be added for closing - // Note: DirtyForFlushing can never be true when DirtyForClosing is false. - - private bool _lengthVerified; // true if we have successfully compared the length given in our constructor against that obtained from - // actually decompressing the data - private long _cachedLength; // cached value prevents us from entering Emulation to obtain length after ReadPassThrough reads all bytes - // -1 means not set - // this is what is persisted when a deflate stream is of length zero - private static byte[] _emptyDeflateStreamConstant = new byte[] { 0x03, 0x00 }; - - private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory - private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk - private const long _readPassThroughModeSeekThreshold = 0x40; // amount we can seek in a reasonable amount of time while decompressing - - #endregion - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackUriHelper.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackUriHelper.cs index 1600c0d4892..a838840b5fd 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackUriHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackUriHelper.cs @@ -34,31 +34,7 @@ namespace MS.Internal.IO.Packaging internal static class PackUriHelper { #region Public Methods - /// - /// This method parses the pack uri and returns the absolute - /// path of the URI. This corresponds to the part within the - /// package. This corresponds to the absolute path component in - /// the Uri. If there is no part component present, this method - /// returns a null - /// - /// Returns a relative Uri that represents the - /// part within the package. If the pack Uri points to the entire - /// package then we return a null - /// Returns a relative URI with an absolute path that points to a part within a package - /// If packUri parameter is null - /// If packUri parameter is not an absolute Uri - /// If packUri parameter does not have "pack://" scheme - /// If partUri extracted from packUri does not conform to the valid partUri syntax - public static Uri GetPartUri(Uri packUri) - { - Uri packageUri; - Uri partUri; - //Parameter Validation is done in the follwoing method - ValidateAndGetPackUriComponents(packUri, out packageUri, out partUri); - - return partUri; - } #endregion Public Methods @@ -85,31 +61,7 @@ internal static Uri PackageRootUri internal static bool IsPackUri(Uri uri) { return uri != null && - string.Compare(uri.Scheme, UriSchemePack, StringComparison.OrdinalIgnoreCase) == 0; - } - - internal static bool TryValidatePartUri(Uri partUri, out ValidatedPartUri validatedPartUri) - { - if (partUri is ValidatedPartUri) - { - validatedPartUri = (ValidatedPartUri)partUri; - return true; - } - else - { - string partUriString; - Exception exception = GetExceptionIfPartUriInvalid(partUri, out partUriString); - if (exception != null) - { - validatedPartUri = null; - return false; - } - else - { - validatedPartUri = new ValidatedPartUri(partUriString); - return true; - } - } + string.Compare(uri.Scheme, System.IO.Packaging.PackUriHelper.UriSchemePack, StringComparison.OrdinalIgnoreCase) == 0; } /// @@ -153,18 +105,7 @@ internal static string GetStringForPartUri(Uri partUri) if (!(partUri is ValidatedPartUri)) partUri = ValidatePartUri(partUri); - return ((ValidatedPartUri)partUri).PartUriString; - } - - //This method validates the packUri and returns its two components if they are valid- - //1. Package Uri - //2. Part Uri - internal static void ValidateAndGetPackUriComponents(Uri packUri, out Uri packageUri, out Uri partUri) - { - //Validate if its not null and is an absolute Uri, has pack:// Scheme. - packUri = ValidatePackUri(packUri); - packageUri = GetPackageUriComponent(packUri); - partUri = GetPartUriComponent(packUri); + return ((ValidatedPartUri)partUri).PartUriString; } #endregion Internal Methods @@ -186,7 +127,7 @@ internal static void ValidateAndGetPackUriComponents(Uri packUri, out Uri packag static PackUriHelper() { // indicate that we want "basic" parsing - if (!UriParser.IsKnownScheme(UriSchemePack)) + if (!UriParser.IsKnownScheme(System.IO.Packaging.PackUriHelper.UriSchemePack)) { try { @@ -194,7 +135,7 @@ static PackUriHelper() permobj.Assert(); //BlessedAssert: // Indicate that we want a default hierarchical parser with a registry based authority - UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority), UriSchemePack, -1); + UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority), System.IO.Packaging.PackUriHelper.UriSchemePack, -1); } finally { @@ -212,60 +153,6 @@ static PackUriHelper() //------------------------------------------------------ #region Private Methods - - /// - /// This method is used to validate the package uri - /// - /// - /// - private static Uri ValidatePackageUri(Uri packageUri) - { - if (packageUri == null) - throw new ArgumentNullException("packageUri"); - - if (!packageUri.IsAbsoluteUri) - throw new ArgumentException(SR.Get(SRID.UriShouldBeAbsolute)); - - return packageUri; - } - - //validates is a given uri has pack:// scheme - private static Uri ValidatePackUri(Uri packUri) - { - if (packUri == null) - throw new ArgumentNullException("packUri"); - - if (!packUri.IsAbsoluteUri) - throw new ArgumentException(SR.Get(SRID.UriShouldBeAbsolute)); - - if (packUri.Scheme != PackUriHelper.UriSchemePack) - throw new ArgumentException(SR.Get(SRID.UriShouldBePackScheme)); - - return packUri; -} - - /// - /// Escapes - %', '@', ',', '?' in the package URI - /// This method modifies the string in a culture safe and case safe manner. - /// - /// - /// - private static string EscapeSpecialCharacters(string path) - { - string characterString; - - // Escaping for the following - '%'; '@'; ',' and '?' - // !!Important!! - The order is important - The '%' sign should be escaped first. - // This is currently enforced by the order of characters in the _specialCharacters array - foreach (char c in _specialCharacters) - { - characterString = c.ToString(); - if (path.Contains(characterString)) - path = path.Replace(characterString, Uri.HexEscape(c)); - } - - return path; - } private static Exception GetExceptionIfPartUriInvalid(Uri partUri, out string partUriString) { @@ -327,13 +214,6 @@ private static Exception GetExceptionIfPartUriInvalid(Uri partUri, out string pa return null; } - private static void ThrowIfAbsoluteUri(Uri uri) - { - Exception exception = GetExceptionIfAbsoluteUri(uri); - if (exception != null) - throw exception; - } - private static ArgumentException GetExceptionIfAbsoluteUri(Uri uri) { if (uri.IsAbsoluteUri) @@ -342,13 +222,6 @@ private static ArgumentException GetExceptionIfAbsoluteUri(Uri uri) return null; } - private static void ThrowIfFragmentPresent(string partName) - { - Exception exception = GetExceptionIfFragmentPresent(partName); - if (exception != null) - throw exception; - } - private static ArgumentException GetExceptionIfFragmentPresent(string partName) { if (partName.Contains("#")) @@ -357,13 +230,6 @@ private static ArgumentException GetExceptionIfFragmentPresent(string partName) return null; } - private static void ThrowIfPartNameEndsWithSlash(string partName) - { - Exception exception = GetExceptionIfPartNameEndsWithSlash(partName); - if (exception != null) - throw exception; - } - private static ArgumentException GetExceptionIfPartNameEndsWithSlash(string partName) { if (partName.Length > 0) @@ -374,13 +240,6 @@ private static ArgumentException GetExceptionIfPartNameEndsWithSlash(string part return null; } - private static void ThrowIfPartNameStartsWithTwoSlashes(string partName) - { - Exception exception = GetExceptionIfPartNameStartsWithTwoSlashes(partName); - if (exception != null) - throw exception; - } - // A relative reference that begins with two slash characters is termed // a network-path reference; such references are rarely used. // However, when they are resolved they represent the authority part of the URI @@ -397,19 +256,6 @@ private static ArgumentException GetExceptionIfPartNameStartsWithTwoSlashes(stri return null; } - //Calling System.Uri.Compare method - //This method minimizes the false positives that we might get as a result - //of comparing two URIs. - //Also, we exclude the Fragment component while comparing. - private static int CompareUsingSystemUri(Uri firstUri, Uri secondUri) - { - return Uri.Compare( - firstUri, - secondUri, - UriComponents.AbsoluteUri & ~UriComponents.Fragment, - UriFormat.UriEscaped, - StringComparison.Ordinal); - } //Returns the part name in its escaped string form from an Absolute [must be pack://] or a Relative URI private static string GetStringForPartUriFromAnyUri(Uri partUri) @@ -459,39 +305,6 @@ private static bool IsPartNameEmpty(string partName) else return false; } - - //This method validates and returns the PackageUri component - private static Uri GetPackageUriComponent(Uri packUri) - { - Debug.Assert(packUri != null, "packUri parameter cannot be null"); - - //Step 1 - Get the authority part of the URI. This section represents that package URI - String hostAndPort = packUri.GetComponents(UriComponents.HostAndPort, UriFormat.UriEscaped); - - //Step 2 - Replace the ',' with '/' to reconstruct the package URI - hostAndPort = hostAndPort.Replace(',', '/'); - - //Step 3 - Unescape the special characters that we had escaped to construct the packUri - Uri packageUri = new Uri(Uri.UnescapeDataString(hostAndPort)); - - if (packageUri.Fragment != String.Empty) - throw new ArgumentException(SR.Get(SRID.InnerPackageUriHasFragment)); - - return packageUri; - } - - //This method validates and returns the PartUri component. - private static PackUriHelper.ValidatedPartUri GetPartUriComponent(Uri packUri) - { - Debug.Assert(packUri != null, "packUri parameter cannot be null"); - - string partName = GetStringForPartUriFromAnyUri(packUri); - - if (partName == String.Empty) - return null; - else - return ValidatePartUri(new Uri(partName, UriKind.Relative)); - } #endregion Private Methods @@ -509,19 +322,9 @@ private static PackUriHelper.ValidatedPartUri GetPartUriComponent(Uri packUri) //we use this dummy Uri to represent the root of the container. private static readonly Uri _packageRootUri = new Uri("/", UriKind.Relative); - // We need to perform Escaping for the following - '%'; '@'; ',' and '?' - // !!Important!! - The order is important - The '%' sign should be escaped first. - // If any more characters need to be added to the array below they should be added at the end. - private static readonly char[] _specialCharacters = { '%', '@', ',', '?' }; - //Rels segment and extension private static readonly string _relationshipPartExtensionName = ".rels"; - /// - /// pack scheme name - /// - public static readonly string UriSchemePack = "pack"; - #endregion Private Members #region Private Class @@ -602,24 +405,6 @@ internal string PartUriString } } - internal string PartUriExtension - { - get - { - if (_partUriExtension == null) - { - _partUriExtension = Path.GetExtension(_partUriString); - - //If extension is absent just return the empty string - //else remove the leading "." from the returned extension - //string - if (_partUriExtension.Length > 0) - _partUriExtension = _partUriExtension.Substring(1); - } - return _partUriExtension; - } - } - //Returns the normalized string for the part uri. internal string NormalizedPartUriString { @@ -801,7 +586,6 @@ private int Compare(ValidatedPartUri otherPartUri) private ValidatedPartUri _normalizedPartUri; private string _partUriString; private string _normalizedPartUriString; - private string _partUriExtension; private bool _isNormalized; private bool _isRelationshipPartUri; diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackagingExtensions.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackagingExtensions.cs index c57cf53116f..7dae5028b03 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackagingExtensions.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PackagingExtensions.cs @@ -27,19 +27,4 @@ internal class PackageRelationship public static Uri ContainerRelationshipPartName => System.IO.Packaging.PackUriHelper.CreatePartUri(new Uri("/_rels/.rels", UriKind.Relative)); } - internal static class ZipPackage - { - private const string ForwardSlashString = "/"; //Required for creating a part name from a zip item name - - public static string GetZipItemNameFromOpcName(string opcName) - { - System.Diagnostics.Debug.Assert(opcName != null && opcName.Length > 0); - return opcName.Substring(1); - } - - public static string GetOpcNameFromZipItemName(string zipItemName) - { - return String.Concat(ForwardSlashString, zipItemName); - } - } } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PieceNameHelper.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PieceNameHelper.cs deleted file mode 100644 index 14f7173b39d..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/PieceNameHelper.cs +++ /dev/null @@ -1,472 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// -// Description: The static class PieceNameHelper contains utilities to parse -// and create piece names in an adaptor-independent way. -// This file also contains PieceNameInfo, a structured representation -// of a piece name, and its subclass PieceInfo, which provides -// piece name and zip file info for a piece. -// - -using System; -using System.IO; -using System.IO.Packaging; // For ZipPackagePart, etc. -using System.Windows; // for ExceptionStringTable -using System.Globalization; // For CultureInfo -using System.Collections.Generic; // IEqualityComparer - -using MS.Internal; // For Invariant -using MS.Internal.IO.Zip; // For ZipFileInfo -using System.Diagnostics; // For Debug.Assert - -using ZipPackage = MS.Internal.IO.Packaging.Extensions.ZipPackage; - -namespace MS.Internal.IO.Packaging -{ - #region class PieceInfo - - /// - /// A piece descriptor, made up of a ZipFileInfo and a PieceNameInfo. - /// - /// - /// PieceNameHelper implements IComparable in such a way as to enforce - /// case-insensitive lexicographical order on <name, number, isLast> triples. - /// - internal class PieceInfo - { - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - - #region Constructors - - internal PieceInfo(ZipFileInfo zipFileInfo, PackUriHelper.ValidatedPartUri partUri, string prefixName, int pieceNumber, bool isLastPiece) - { - Debug.Assert(zipFileInfo != null); - Debug.Assert(prefixName != null && prefixName != String.Empty); - Debug.Assert(pieceNumber >= 0); - - _zipFileInfo = zipFileInfo; - - // partUri can be null to indicate that the prefixname is not a valid part name - _partUri = partUri; - _prefixName = prefixName; - _pieceNumber = pieceNumber; - _isLastPiece = isLastPiece; - - // Currently as per the book, the prefix names/ logical names should be - // compared in a case-insensitive manner. - _normalizedPieceNamePrefix = _prefixName.ToUpperInvariant(); - } - - #endregion Constructors - - //------------------------------------------------------ - // - // public methods - // - //------------------------------------------------------ - // None - //------------------------------------------------------ - // - // Internal properties - // - //------------------------------------------------------ - - #region Internal properties - - internal string NormalizedPrefixName - { - get - { - return _normalizedPieceNamePrefix; - } - } - - internal string PrefixName - { - get - { - return _prefixName; - } - } - - internal int PieceNumber - { - get - { - return _pieceNumber; - } - } - - internal bool IsLastPiece - { - get - { - return _isLastPiece; - } - } - - internal System.Uri PartUri - { - get - { - return _partUri; - } - } - - internal ZipFileInfo ZipFileInfo - { - get - { - return _zipFileInfo; - } - } - - #endregion Internal properties - - //------------------------------------------------------ - // - // Private members - // - //------------------------------------------------------ - - #region Private members - - private PackUriHelper.ValidatedPartUri _partUri; - private string _prefixName; - private int _pieceNumber; - private bool _isLastPiece; - private ZipFileInfo _zipFileInfo; - private string _normalizedPieceNamePrefix; - - #endregion Private members - } - - #endregion class PieceInfo - - #region class PieceNameHelper - - /// - /// The static class PieceNameHelper contains utilities to parse and create piece names - /// in an adaptor-independent way. - /// - internal static class PieceNameHelper - { - #region Internal Properties - - internal static PieceNameComparer PieceNameComparer - { - get - { - return _pieceNameComparer; - } - } - - #endregion Internal Properties - - #region Internal Methods - - /// - /// Build a piece name from its constituents: part name, piece number - /// and terminal status. - /// The linearized result obeys the piece name syntax: - /// piece_name = prefix_name "/" "[" 1*digit "]" [".last"] ".piece" - /// - /// A part name or the zip item name corresponding to a part name. - /// The 0-based order number of the piece. - /// Whether the piece is last in the part. - /// A Metro piece name. - /// If partName is a piece uri. - /// If pieceNumber is negative. - internal static string CreatePieceName(string partName, int pieceNumber, bool isLastPiece) - { - Invariant.Assert(pieceNumber >= 0, "Negative piece number."); - - return string.Format(CultureInfo.InvariantCulture, "{0}/[{1:D}]{2}.piece", - partName, - pieceNumber, - isLastPiece ? ".last" : ""); - } - - /// - /// Return true and create a PieceInfo if the name in the input ZipFileInfo parses - /// as a piece name. - /// - /// - /// No Uri validation is carried out at this level. All that is checked is valid piece - /// syntax. So the _prefixName returned as part of the PieceInfo will not necessarily - /// a part name. For example, it could be the name of the content type stream. - /// - internal static bool TryCreatePieceInfo(ZipFileInfo zipFileInfo, out PieceInfo pieceInfo) - { - Invariant.Assert(zipFileInfo != null); - - pieceInfo = null; - - // Try to parse as a piece name. - PieceNameInfo pieceNameConstituents; - bool result = PieceNameHelper.TryParseAsPieceName(zipFileInfo.Name, - out pieceNameConstituents); - - // Return the result and the output parameter. - if(result) - pieceInfo = new PieceInfo(zipFileInfo, - pieceNameConstituents.PartUri, - pieceNameConstituents.PrefixName, - pieceNameConstituents.PieceNumber, - pieceNameConstituents.IsLastPiece); - - return result; - } - - #endregion Internal Methods - - #region Private Methods - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - #region Scan Steps - - // The functions in this region conform to the delegate type ScanStepDelegate - // and implement the following automaton for scanning a piece name from right to left: - - // state transition new state - // ----- ---------- --------- - // FindPieceExtension ".piece" FindIsLast - // FindIsLast "].last" FindPieceNumber - // FindIsLast "]" FindPieceNumber - // FindPieceNumber "/[" 1*digit FindPartName (terminal state) - - // On entering the step, position is at the beginning of the last portion that was recognized. - // So left-to-right scanning starts at position - 1 in each step. - private delegate bool ScanStepDelegate( - string path, ref int position, ref ScanStepDelegate nextStep, ref PieceNameInfo parseResults); - - // Look for ".piece". - private static bool FindPieceExtension(string path, ref int position, ref ScanStepDelegate nextStep, - ref PieceNameInfo parseResults) - { - if (!FindString(path, ref position, ".piece")) - return false; - - nextStep = FindIsLast; - return true; - } - - // Look for "]" or "].last". - private static bool FindIsLast(string path, ref int position, ref ScanStepDelegate nextStep, - ref PieceNameInfo parseResults) - { - // Case of no ".last" member: - if (path[position - 1] == ']') - { - parseResults.IsLastPiece = false; - --position; - nextStep = FindPieceNumber; - return true; - } - - // There has to be "].last". - if (!FindString(path, ref position, "].last")) - return false; - - parseResults.IsLastPiece = true; - nextStep = FindPieceNumber; - return true; - } - - // Look for "/[" followed by decimal digits. - private static bool FindPieceNumber(string path, ref int position, ref ScanStepDelegate nextStep, - ref PieceNameInfo parseResults) - { - if (!char.IsDigit(path[position - 1])) - return false; - - int pieceNumber = 0; - int multiplier = 1; // rightmost digit is for units - --position; - do - { - pieceNumber += multiplier * (int)char.GetNumericValue(path[position]); - multiplier *= 10; - } while (char.IsDigit(path[--position])); - - // Point to the last digit found. - ++position; - - //If we have a leading 0, then its not correct piecename syntax - if (multiplier > 10 && (int)char.GetNumericValue(path[position]) == 0) - return false; - - if (!FindString(path, ref position, "/[")) - return false; - - parseResults.PieceNumber = pieceNumber; - nextStep = FindPartName; - return true; - } - - // Retrieve part name. The position points to the slash past the part name. - // So simply return the prefix up to that slash. - private static bool FindPartName(string path, ref int position, ref ScanStepDelegate nextStep, - ref PieceNameInfo parseResults) - { - parseResults.PrefixName = path.Substring(0, position); - - // Subtract the length of the part name from position. - position = 0; - - if (parseResults.PrefixName.Length == 0) - return false; - - Uri partUri = new Uri(ZipPackage.GetOpcNameFromZipItemName(parseResults.PrefixName), UriKind.Relative); - PackUriHelper.TryValidatePartUri(partUri, out parseResults.PartUri); - return true; - } - - #endregion Scan Steps - - /// - /// Attempts to parse a name as a piece name. Returns true and places the - /// output in pieceNameConstituents. Otherwise, returns false and returns - /// the default constituent values pieceName, 0, and false. - /// - /// The input string. - /// An object containing the prefix name (i.e. generally the part name), the 0-based order number of the piece, and whether the piece is last in the part. - /// True for parse success. - /// - /// Syntax of a piece name: - /// piece_name = part_name "/" "[" 1*digit "]" [".last"] ".piece" - /// - private static bool TryParseAsPieceName(string path, out PieceNameInfo parseResults) - { - parseResults = new PieceNameInfo(); // initialize to CLR default values - - // Start from the end and look for ".piece". - int position = path.Length; - ScanStepDelegate nextStep = new ScanStepDelegate(FindPieceExtension); - - // Scan backward until the whole path has been scanned. - while (position > 0) - { - if (!nextStep.Invoke(path, ref position, ref nextStep, ref parseResults)) - { - // Scan step failed. Return false. - parseResults.IsLastPiece = false; - parseResults.PieceNumber = 0; - parseResults.PrefixName = path; - parseResults.PartUri = null; - return false; - } - } - - return true; - } - - /// - /// Look for 'query' backward in 'input' starting at 'position'. - /// - private static bool FindString(string input, ref int position, string query) - { - int queryPosition = query.Length; - - //The input string should have length that is greater than or equal to the - //length of the query string. - if (position < queryPosition) - return false; - - while (--queryPosition >= 0) - { - --position; - if (Char.ToUpperInvariant(input[position]) != Char.ToUpperInvariant(query[queryPosition])) - return false; - } - return true; - } - - #endregion Private Methods - - #region Private Member Variables - - //------------------------------------------------------ - // - // Private Variables - // - //------------------------------------------------------ - - private static PieceNameComparer _pieceNameComparer = new PieceNameComparer(); - - #endregion Private Member Variables - - #region Private Struct : PieceNameInfo - - /// - /// The result of parsing a piece name as returned by the parsing methods of PieceNameHelper. - /// - /// - /// /// The first member, _prefixName, will be a part name if the input to parse begins with - /// a part name, and a zip item name if it starts with a zip item name. - /// - /// - /// In other words, all that precedes the suffixes is returned unanalyzed as an "prefix name" - /// by the parse functions of the PieceNameHelper. - /// - /// - private struct PieceNameInfo - { - internal PackUriHelper.ValidatedPartUri PartUri; - internal string PrefixName; - internal int PieceNumber; - internal bool IsLastPiece; - } - - #endregion Private Struct : PieceNameInfo - } - - #endregion class PieceNameHelper - - #region class PieceNameComparer - - internal sealed class PieceNameComparer : IComparer - { - //For comparing the piece names we consider the prefix name and piece numbers - //Pieces that are terminal and non terminal with the same number and same prefix - //number will be treated as equivalent. - //For example - /partA/[number].piece and /partA[number].last.piece will be treated - //to be equivalent, as in a well-formed package either one of them can be present, - //not both. - int IComparer.Compare(PieceInfo pieceInfoA, PieceInfo pieceInfoB) - { - //Even though most comparers allow for comparisons with null, we assert here, as - //this is an internal class and we are sure that pieceInfoA and pieceInfoB passed - //in here should be non-null, else it would be a logical error. - Invariant.Assert(pieceInfoA != null); - Invariant.Assert(pieceInfoB != null); - - int result = string.Compare( - pieceInfoA.NormalizedPrefixName, - pieceInfoB.NormalizedPrefixName, - StringComparison.Ordinal); - - if (result != 0) - return result; - - result = pieceInfoA.PieceNumber - pieceInfoB.PieceNumber; - - return result; - } - } - - #endregion class PieceNameComparer -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/streamingZipPartStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/streamingZipPartStream.cs deleted file mode 100644 index 05c755436b7..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/streamingZipPartStream.cs +++ /dev/null @@ -1,361 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// -// Description: The class StreamingZipPartStream is used to create a sequence of -// piece streams in order to implement streaming production of packages. -// - -using System; -using System.IO; -using System.IO.Packaging; // For ZipPackagePart, etc. -using MS.Internal.IO.Zip; // For ZipFileInfo. -using System.Windows; // for ExceptionStringTable - -using MS.Internal; // for Invariant -using MS.Internal.WindowsBase; - -using ZipPackage = MS.Internal.IO.Packaging.Extensions.ZipPackage; - -namespace MS.Internal.IO.Packaging -{ - /// - /// The class StreamingZipPartStream is used to create a sequence of - /// piece streams in order to implement streaming production of packages. - /// - /// - /// This class is defined for the benefit of ZipPackage, ZipPackagePart and - /// InternalRelationshipCollection. - /// Although it is quite specialized, it would hardly make sense to nest its definition in any - /// of these clases. - /// - internal class StreamingZipPartStream : Stream - { - #region Constructors - - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - - /// - /// Build a System.IO.Stream to create a multi-piece (i.e. interleaved) part. - /// Does not require a part, but a proper part name (not a piece name), and a ZipArchive. - /// - internal StreamingZipPartStream( - string partName, - ZipArchive zipArchive, - CompressionMethodEnum compressionMethod, - DeflateOptionEnum deflateOption, - FileMode mode, - FileAccess access) - { - // Right now, only production is supported in streaming mode. - if (!( (mode == FileMode.Create || mode == FileMode.CreateNew) - && access == FileAccess.Write) ) - { - throw new NotSupportedException(SR.Get(SRID.OnlyStreamingProductionIsSupported)); - } - - _partName = partName; - _archive = zipArchive; - _compressionMethod = compressionMethod; - _deflateOption = deflateOption; - _mode = mode; - _access = access; - } - - #endregion Constructors - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - - /// - /// Return the bytes requested. - /// - /// Destination buffer. - /// - /// The zero-based byte offset in buffer at which to begin storing the data read - /// from the current stream. - /// - /// How many bytes requested. - /// How many bytes were written into buffer. - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(SR.Get(SRID.OnlyWriteOperationsAreSupportedInStreamingCreation)); - } - - /// - /// Seek - /// - /// Offset in byte. - /// Offset origin (start, current, or end). - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(SR.Get(SRID.OnlyWriteOperationsAreSupportedInStreamingCreation)); - } - - /// - /// SetLength - /// - public override void SetLength(long newLength) - { - throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics, "SetLength")); - } - - /// - /// Write. Delegate to the current piece stream. - /// Lazily create the Zip item since we do not know what name to create it - /// under until a write or a close occurs. - /// - public override void Write(byte[] buffer, int offset, int count) - { - CheckClosed(); - - // We now know we're creating a non-empty piece, so it's OK to give - // it a non-terminal name. - EnsurePieceStream(false /* not last piece */); - _pieceStream.Write(buffer, offset, count); - } - - /// - /// Close the current piece stream and increment the piece number - /// to allow on-demand creation of the next piece stream in Write - /// or Close. - /// - /// Pass through the Flush calls because there is no need to - /// generate a new Piece if we are writing to a single, enormouse stream. - public override void Flush() - { - CheckClosed(); - - // _pieceStream will be null if there's been no write since the last flush. - if (_pieceStream != null) - { - // If CanWrite is false, we know that our underlying stream was closed by ZipIO layer - // as a part of its logic. Therefore, we need a new Piece. - if (_pieceStream.CanWrite) - _pieceStream.Flush(); - } - } - - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - - #region Public Properties - - /// - /// Is stream readable? - /// - /// - /// Here, the assumption, as in all capability tests, is that the status of - /// the current piece reflects the status of all pieces for the part. - /// This is justified by the fact that (i) all piece streams are opened with the same - /// parameters against the same archive and (ii) the current piece stream cannot get - /// closed unless the whole part stream is closed. - /// - public override bool CanRead - { - get - { - return false; - } - } - - /// - /// Is stream seekable? - /// - /// - /// Here, the assumption, as in all capability tests, is that the status of - /// the current piece reflects the status of all pieces for the part. - /// This is justified by the fact that (i) all piece streams are opened with the same - /// parameters against the same archive and (ii) the current piece stream cannot get - /// closed unless the whole part stream is closed. - /// - public override bool CanSeek - { - get - { - return false; - } - } - - /// - /// Is stream writable? - /// - /// - /// Here, the assumption, as in all capability tests, is that the status of - /// the current piece reflects the status of all pieces for the part. - /// This is justified by the fact that (i) all piece streams are opened with the same - /// parameters against the same archive and (ii) the current piece stream cannot get - /// closed unless the whole part stream is closed. - /// - public override bool CanWrite - { - get - { - return !_closed; - } - } - - /// - /// Logical byte position in this stream. - /// - public override long Position - { - get - { - return -1; - } - set - { - throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics, "set_Position")); - } - } - - /// - /// Length. - /// - public override long Length - { - get - { - return -1; - } - } - - #endregion Public Properties - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - - #region Protected Methods - - /// - /// Dispose(bool) - /// - /// - /// - /// An instance of streams' peculiar dispose pattern, whereby - /// the inherited abstract Stream class implements Close by calling - /// this virtual protected function. - /// In turn, each implementation is responsible for calling back - /// its base's implementation. - /// - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - { - if (!_closed) - { - // Flush pending changes into a piece, if any. - Flush(); - - // Create an empty last piece. - EnsurePieceStream(true /* last piece */); - _pieceStream.Close(); - } - } - } - finally - { - _closed = true; - base.Dispose(disposing); - } - } - - #endregion Protected Methods - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - private void EnsurePieceStream(bool isLastPiece) - { - if (_pieceStream != null) - { - // Normally, the pieces are actually closed automatically for us by the - // underlying ZipIO logic, but in the case of the last piece (when we - // are called by our own Dispose(bool) method) we must close it explicitly. - if (isLastPiece) - _pieceStream.Close(); - - // We detect that the stream has been closed by inspecting the CanWrite property - // since this is guaranteed not to throw even when the stream is disposed. - if (!_pieceStream.CanWrite) - { - // increment our piece number so we can generate the correct - // one below - checked { ++_currentPieceNumber; } - - // release it to trigger the new piece creation below - _pieceStream = null; - } - } - - if (_pieceStream == null) - { - string pieceName = PieceNameHelper.CreatePieceName( - _partName, - _currentPieceNumber, - isLastPiece); - string pieceZipName = ZipPackage.GetZipItemNameFromOpcName(pieceName); - - ZipFileInfo zipFileInfo = _archive.AddFile(pieceZipName, _compressionMethod, _deflateOption); - // We've just created the file, so the mode can only be Create, not CreateNew. - // (At least, this is part of ZipFileInfo's belief system.) - _pieceStream = zipFileInfo.GetStream(FileMode.Create, _access); - } - } - - private void CheckClosed() - { - if (_closed) - throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); - } - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - // None - - #region Private Fields - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - - private Stream _pieceStream; // write-only stream on the current piece - private string _partName; // part name used to generate correct piece names - private ZipArchive _archive; - private int _currentPieceNumber = 0; // incremented with each piece Close() cycle - private CompressionMethodEnum _compressionMethod; - private DeflateOptionEnum _deflateOption; - private FileMode _mode; - private FileAccess _access; - private bool _closed = false; - - #endregion Private Fields - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/CompressionMethodEnum.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/CompressionMethodEnum.cs deleted file mode 100644 index aa37eb19c83..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/CompressionMethodEnum.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; - -namespace MS.Internal.IO.Zip -{ - /// - /// CompressionMethodEnum is used to express a required compression on ZipArchive.AddPart calls. - /// Values in the enumeration correspond to the binary format of the ZipArchive's Compression Method field - /// - internal enum CompressionMethodEnum : ushort // takes 2 bytes in data structure - { - Stored = 0, - Deflated = 8 - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/Crc32.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/Crc32.cs deleted file mode 100644 index 3e576de3d2c..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/Crc32.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is a CRC32 calculator, originally built for ZIP IO for OPC scenarios. -// This particular piece of code generic, and doest have ane ZIP or OPC specific -// features -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; - -namespace MS.Internal.IO.Zip -{ - internal class Crc32Calculator - { - /// - /// We need to initialize table once per all intstances of this class - /// Instead of using static constructor, we are using lock to do this so that - /// we don't get into a threading issue - /// - internal Crc32Calculator() - { - lock (_globalSync) - { - if (_Crc32Table == null) - { - PrepareTable(); - } - } - } - - // Calculate CRC from the current position to the end of the stream - // CRC is calculated accumulatively on to the current residue - internal UInt32 CalculateStreamCrc(Stream stream) - { - byte[] buffer = new byte[0x1000]; - - Debug.Assert(stream != null); - - for(;;) - { - int bytesRead = stream.Read(buffer,0,buffer.Length); - if (bytesRead > 0) - { - Accumulate(buffer, 0, bytesRead); - } - else - { - break; - } - } - - return Crc; - } - - internal void Accumulate(byte[] buffer, int offset, int count) - { - Debug.Assert((offset >=0) && (count >=0) && (offset+count <= buffer.Length)); - - for(int i =offset; i> 8) & 0x00FFFFFF) - ^ - _Crc32Table[((_residue ^ buffer[i]) & 0x000000FF)]; - } - } - - internal UInt32 Crc - { - get - { - return ~_residue; - } - } - - // set the residue to the intial value so that we can recalculate CRC - internal void ClearCrc() - { - _residue = _InitialResidueValue; - } - - static private void PrepareTable() - { - _Crc32Table = new UInt32[256]; - - for(uint tablePosition=0; tablePosition < _Crc32Table.Length; tablePosition++) - { - for(byte bitPosition=0; bitPosition < 32; bitPosition++) - { - bool bitValue = false; - foreach(byte maskingBit in _maskingBitTable[bitPosition]) - { - bitValue ^= GetBit(maskingBit, tablePosition); - } - SetBit(bitPosition, ref (_Crc32Table[tablePosition]), bitValue); - } - } -} - - private static bool GetBit(byte bitOrdinal, UInt32 data) - { - Debug.Assert(bitOrdinal < 32); - - return ((data >> bitOrdinal) & 0x1) == 1; - } - - // only valid in this context (the bit in to is always 0) - private static void SetBit(byte bitOrdinal, ref UInt32 data, bool value) - { - Debug.Assert(bitOrdinal < 32); - - if (value) - { - data |= ((UInt32)0x1 << bitOrdinal); - } - } - - private const UInt32 _InitialResidueValue = 0xFFFFFFFF; - private UInt32 _residue = _InitialResidueValue; - - private static Object _globalSync = new Object(); - - // static CRC table , which is calculated in the stqatic constructor - private static UInt32[] _Crc32Table; - - // static bit mask table that is used to calculate _Crc32Table - private static byte[][] _maskingBitTable = - {new byte[] {2}, - new byte[] {0,3}, - new byte[] {0,1,4}, - new byte[] {1,2,5}, - new byte[] {0,2,3,6}, - new byte[] {1,3,4,7}, - new byte[] {4,5}, - new byte[] {0,5,6}, - new byte[] {1,6,7}, - new byte[] {7}, - new byte[] {2}, - new byte[] {3}, - new byte[] {0,4}, - new byte[] {0,1,5}, - new byte[] {1,2,6}, - new byte[] {2,3,7}, - new byte[] {0,2,3,4}, - new byte[] {0,1,3,4,5}, - new byte[] {0,1,2,4,5,6}, - new byte[] {1,2,3,5,6,7}, - new byte[] {3,4,6,7}, - new byte[] {2,4,5,7}, - new byte[] {2,3,5,6}, - new byte[] {3,4,6,7}, - new byte[] {0,2,4,5,7}, - new byte[] {0,1,2,3,5,6}, - new byte[] {0,1,2,3,4,6,7}, - new byte[] {1,3,4,5,7}, - new byte[] {0,4,5,6}, - new byte[] {0,1,5,6,7}, - new byte[] {0,1,6,7}, - new byte[] {1,7}}; - -// _Crc32Table should contain the following : -// --CRC32 Table-- -// 0000000000 - 0000000000 0x77073096 0xee0e612c 0x990951ba -// 0x00000004 - 0x076dc419 0x706af48f 0xe963a535 0x9e6495a3 -// 0x00000008 - 0x0edb8832 0x79dcb8a4 0xe0d5e91e 0x97d2d988 -// 0x0000000c - 0x09b64c2b 0x7eb17cbd 0xe7b82d07 0x90bf1d91 -// 0x00000010 - 0x1db71064 0x6ab020f2 0xf3b97148 0x84be41de -// 0x00000014 - 0x1adad47d 0x6ddde4eb 0xf4d4b551 0x83d385c7 -// 0x00000018 - 0x136c9856 0x646ba8c0 0xfd62f97a 0x8a65c9ec -// 0x0000001c - 0x14015c4f 0x63066cd9 0xfa0f3d63 0x8d080df5 -// 0x00000020 - 0x3b6e20c8 0x4c69105e 0xd56041e4 0xa2677172 -// 0x00000024 - 0x3c03e4d1 0x4b04d447 0xd20d85fd 0xa50ab56b -// 0x00000028 - 0x35b5a8fa 0x42b2986c 0xdbbbc9d6 0xacbcf940 -// 0x0000002c - 0x32d86ce3 0x45df5c75 0xdcd60dcf 0xabd13d59 -// 0x00000030 - 0x26d930ac 0x51de003a 0xc8d75180 0xbfd06116 -// 0x00000034 - 0x21b4f4b5 0x56b3c423 0xcfba9599 0xb8bda50f -// 0x00000038 - 0x2802b89e 0x5f058808 0xc60cd9b2 0xb10be924 -// 0x0000003c - 0x2f6f7c87 0x58684c11 0xc1611dab 0xb6662d3d -// 0x00000040 - 0x76dc4190 0x01db7106 0x98d220bc 0xefd5102a -// 0x00000044 - 0x71b18589 0x06b6b51f 0x9fbfe4a5 0xe8b8d433 -// 0x00000048 - 0x7807c9a2 0x0f00f934 0x9609a88e 0xe10e9818 -// 0x0000004c - 0x7f6a0dbb 0x086d3d2d 0x91646c97 0xe6635c01 -// 0x00000050 - 0x6b6b51f4 0x1c6c6162 0x856530d8 0xf262004e -// 0x00000054 - 0x6c0695ed 0x1b01a57b 0x8208f4c1 0xf50fc457 -// 0x00000058 - 0x65b0d9c6 0x12b7e950 0x8bbeb8ea 0xfcb9887c -// 0x0000005c - 0x62dd1ddf 0x15da2d49 0x8cd37cf3 0xfbd44c65 -// 0x00000060 - 0x4db26158 0x3ab551ce 0xa3bc0074 0xd4bb30e2 -// 0x00000064 - 0x4adfa541 0x3dd895d7 0xa4d1c46d 0xd3d6f4fb -// 0x00000068 - 0x4369e96a 0x346ed9fc 0xad678846 0xda60b8d0 -// 0x0000006c - 0x44042d73 0x33031de5 0xaa0a4c5f 0xdd0d7cc9 -// 0x00000070 - 0x5005713c 0x270241aa 0xbe0b1010 0xc90c2086 -// 0x00000074 - 0x5768b525 0x206f85b3 0xb966d409 0xce61e49f -// 0x00000078 - 0x5edef90e 0x29d9c998 0xb0d09822 0xc7d7a8b4 -// 0x0000007c - 0x59b33d17 0x2eb40d81 0xb7bd5c3b 0xc0ba6cad -// 0x00000080 - 0xedb88320 0x9abfb3b6 0x03b6e20c 0x74b1d29a -// 0x00000084 - 0xead54739 0x9dd277af 0x04db2615 0x73dc1683 -// 0x00000088 - 0xe3630b12 0x94643b84 0x0d6d6a3e 0x7a6a5aa8 -// 0x0000008c - 0xe40ecf0b 0x9309ff9d 0x0a00ae27 0x7d079eb1 -// 0x00000090 - 0xf00f9344 0x8708a3d2 0x1e01f268 0x6906c2fe -// 0x00000094 - 0xf762575d 0x806567cb 0x196c3671 0x6e6b06e7 -// 0x00000098 - 0xfed41b76 0x89d32be0 0x10da7a5a 0x67dd4acc -// 0x0000009c - 0xf9b9df6f 0x8ebeeff9 0x17b7be43 0x60b08ed5 -// 0x000000a0 - 0xd6d6a3e8 0xa1d1937e 0x38d8c2c4 0x4fdff252 -// 0x000000a4 - 0xd1bb67f1 0xa6bc5767 0x3fb506dd 0x48b2364b -// 0x000000a8 - 0xd80d2bda 0xaf0a1b4c 0x36034af6 0x41047a60 -// 0x000000ac - 0xdf60efc3 0xa867df55 0x316e8eef 0x4669be79 -// 0x000000b0 - 0xcb61b38c 0xbc66831a 0x256fd2a0 0x5268e236 -// 0x000000b4 - 0xcc0c7795 0xbb0b4703 0x220216b9 0x5505262f -// 0x000000b8 - 0xc5ba3bbe 0xb2bd0b28 0x2bb45a92 0x5cb36a04 -// 0x000000bc - 0xc2d7ffa7 0xb5d0cf31 0x2cd99e8b 0x5bdeae1d -// 0x000000c0 - 0x9b64c2b0 0xec63f226 0x756aa39c 0x026d930a -// 0x000000c4 - 0x9c0906a9 0xeb0e363f 0x72076785 0x05005713 -// 0x000000c8 - 0x95bf4a82 0xe2b87a14 0x7bb12bae 0x0cb61b38 -// 0x000000cc - 0x92d28e9b 0xe5d5be0d 0x7cdcefb7 0x0bdbdf21 -// 0x000000d0 - 0x86d3d2d4 0xf1d4e242 0x68ddb3f8 0x1fda836e -// 0x000000d4 - 0x81be16cd 0xf6b9265b 0x6fb077e1 0x18b74777 -// 0x000000d8 - 0x88085ae6 0xff0f6a70 0x66063bca 0x11010b5c -// 0x000000dc - 0x8f659eff 0xf862ae69 0x616bffd3 0x166ccf45 -// 0x000000e0 - 0xa00ae278 0xd70dd2ee 0x4e048354 0x3903b3c2 -// 0x000000e4 - 0xa7672661 0xd06016f7 0x4969474d 0x3e6e77db -// 0x000000e8 - 0xaed16a4a 0xd9d65adc 0x40df0b66 0x37d83bf0 -// 0x000000ec - 0xa9bcae53 0xdebb9ec5 0x47b2cf7f 0x30b5ffe9 -// 0x000000f0 - 0xbdbdf21c 0xcabac28a 0x53b39330 0x24b4a3a6 -// 0x000000f4 - 0xbad03605 0xcdd70693 0x54de5729 0x23d967bf -// 0x000000f8 - 0xb3667a2e 0xc4614ab8 0x5d681b02 0x2a6f2b94 -// 0x000000fc - 0xb40bbe37 0xc30c8ea1 0x5a05df1b 0x2d02ef8d - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/DeflateOptionEnum.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/DeflateOptionEnum.cs deleted file mode 100644 index 63738c290de..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/DeflateOptionEnum.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; - -namespace MS.Internal.IO.Zip -{ - /// - /// DeflateOptionEnum is used to express a required compression on ZipArchive.AddPart calls - /// Values in the enumeration (except None 0xFF) correspond to the binary format of the - /// ZipArchive's General Purpose Bit flags (bits 1 and 2). In order to match this value with the - /// General Purpose Bit flags, DeflateOptionEnum must be masked by the value 0x06 - /// 0xFF is a special value that is used to indicate "not applicable" for cases when data isn't deflated. - /// - internal enum DeflateOptionEnum : byte // takes 2 bits in the data structure - { - Normal = 0, //values are selected based on their position in the General purpose bit flag - Maximum = 2, // bits 1 and 2 - Fast = 4, - SuperFast = 6, - None = 0xFF - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/IZipIOBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/IZipIOBlock.cs deleted file mode 100644 index 44ffad3cbd5..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/IZipIOBlock.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; - -namespace MS.Internal.IO.Zip -{ - internal enum PreSaveNotificationScanControlInstruction : int - { - Continue = 0, // instruction to continue Pre Save Notification on the following block - Stop = 1, // instruction to stop Pre Save Notification loop - } - - /// - /// IZipIOBlock - this interface is used to enable polymorphism across all - /// supported Zip IO records. This enables ZipIOBlockManager to manipulate all blocks in a uniform way - /// - internal interface IZipIOBlock - { - /// - /// This is the current offset of the block relative to the start of the archive stream. - /// It might not necessarily correspond to the current location - /// of the block on disk. It is rather the Offset that will be used by the Save function to write data out. - /// If Block Manager needs to insert a new block it should call Move which in Turn will mark those blocks - /// dirty and will change the offset. - /// - long Offset{get;} - - /// - /// This is the current size of the block, it might not neccessarily correspond to the current size of the - /// block on disk. It is rather the Size that will be used up if Save function is called. Block Manager - /// doesn't have any direct control over this size. It is changeble only by Block Specific operations - /// (stream operations with ZipIOLocalFileBlock, add/remove files with the CentralDirectoryBlock and so on) - /// - long Size{get;} - - /// - /// This is the current state of block, if block is marked dirty it means that it was either moved from the - /// original location of load, or it was changed by the external APIs. Block Manager - /// doesn't have any direct control over this flag. It can be affected by calls to Move, - /// Save, UpdateReferences and Block Specific operations (like stream operations with ZipIOLocalFileBlock, - /// add/remove files with the CentralDirectoryBlock and so on) - /// closingFlag parameter indicates whether we querying the Dirty state for purposes of flushing or closing. - /// The only case where it makes a difference is the compressed stream. Which in the Write Through mode - /// will be Dirty for close but not Dirty for flush. - /// - bool GetDirtyFlag(bool closingFlag); - - /// - /// This function is used by the ZipIOBlockManager to adjust positions of the block in the archive, it's mostly - /// used for adding/deleting new file item blocks. Call to this function with a parameter not equal to 0 must - /// mark the block as dirty. - /// - void Move(long shiftSize); - - /// - /// This function is used by the ZipIOBlockManager to Save given block into it's current Offset position. - /// Call to this function will result in making DirtyFlag = false; - /// - void Save(); - - /// - /// This function is used by the ZipIOBlockManager to prepare block for Saving. If called on a block this function - /// is ultimately responsible for marking this block dirty for any reason including changes in other blocks. For example - /// during normal operation of the ZipIoBlock Manager EndOfCentralDirectoryBlock isn't updated with the location - /// and size of the Central Directory on every single operation that might affect it. Only just before saving - /// EndOfCentralDirectoryBlock is notified using update references call that it needs to check its' local record against - /// the position and size of the CentralDirectory. If there is a mismatch EndOfCentralDirectory will update it's local informtion - /// and mark itself dirty. - /// Similar things happen when CentralDirectoryBlock is called to UpdateReferences; it walks through all RawDataBlocks - /// and FileItemBlocks, and updates Central Directory records accordingly. - /// closingFlag parameter indicates that we should be closing streams not just flushing them. It makes a huge - /// difference for deflate scenarios where Flush is NOP and Close is actually always writing out extra data. - /// - void UpdateReferences(bool closingFlag); - - /// - /// This function is used by the ZipIOBlockManager to notify blocks that some area of the file is about to to be overwritten. - /// Depending on the caching policy of each block type (or particular block instance), it might choose to ignore this notification. - /// For Example EndOfCentralDirectoryBlock and CentralDirectoryBlocks are always fully cached (have complete snapshot of - /// the latest data in memory). Which means, that they do not care whether the area of the file where this data has originated - /// is overwritten or not. - /// In contrast RawDataBlock and LocalFileBlock by default do not cache everything in memory, so they need to implement - /// PreSaveNotification call. These types of blocks need to at least load data that they might need from disk, and make sure that the - /// area described by the parameters doesn't have any data that needs to be preserved. - /// - /// Block can also return a value indicating whether PreSaveNotification should be extended to the blocks that are positioned after - /// it in the Block List. For example, if block has completely handled PreSaveNotification in a way that it cached the whole area that - /// was in danger (of being overwritten) it means that no blocks need to worry about this anymore. After all, no 2 blocks should have - /// overlapping disk buffers. Another scenario is when a block can determine that the area in danger is positioned before the block's on-disk - /// buffers; this means that all blocks that are positioned later in the block list do not need to worry about this PreSaveNotification - /// as their buffers should be positioned even further along in the file. - /// - PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ProgressiveCrcCalculatingStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ProgressiveCrcCalculatingStream.cs deleted file mode 100644 index 65a53fe5aff..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ProgressiveCrcCalculatingStream.cs +++ /dev/null @@ -1,353 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal stream class that calcuates CRC values progressively -// if possible -// - - -using System; -using System.Diagnostics; -using System.IO; -using System.Windows; // For Exception strings - SRID - -using MS.Internal.IO.Zip; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ProgressiveCrcCalculatingStream: Stream - { - //////////////////////////////////// - // Stream section - ///////////////////////////////// - override public bool CanRead - { - get - { - return (_underlyingStream != null && _underlyingStream.CanRead); - } - } - - override public bool CanSeek - { - get - { - return (_underlyingStream != null && _underlyingStream.CanSeek); - } - } - - override public bool CanWrite - { - get - { - return (_underlyingStream != null && _underlyingStream.CanWrite); - } - } - - override public long Length - { - get - { - CheckDisposed(); - - return _underlyingStream.Length; - } - } - - override public long Position - { - get - { - CheckDisposed(); - - return _underlyingStream.Position; - } - - set - { - CheckDisposed(); - - _underlyingStream.Position = value; - } - } - - public override void SetLength(long newLength) - { - CheckDisposed(); - - if (newLength < 0) - { - throw new ArgumentOutOfRangeException("newLength"); - } - - if (newLength < _highWaterMark) - { - _highWaterMark = -1; - } - - // We don't do any check if newLength == current length here - // this normally should result in no-op, but this will complicate - // the logic due to the need of caching the underlying stream length - // Not doing this check here might result in CRC check being skipped - - _underlyingStream.SetLength(newLength); - // Setting a new length is the same as write operation - // CRC cannot be checked against the to-be-validated CRC anymore - _validateCrcWithExpectedCrc = false; - - // mark the global dirty flag - _blockManager.DirtyFlag = true; - } - - override public long Seek(long offset, SeekOrigin origin) - { - CheckDisposed(); - - return _underlyingStream.Seek(offset, origin); - } - - override public int Read(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - int readCount = 0; - - // We should calculate CRC accumulatively for the following conditions - // 1. Seek is not supported by the underlying stream: this will be the case for - // writing stream in streaming mode - // 2. This write request is consequtive to the highwater mark of the CRC calculation - // 3. This write request is at 0 offset and the CRC hasn't been calculated yet - if (!_underlyingStream.CanSeek) // Case #1 - { - readCount = _underlyingStream.Read(buffer, offset, count); - CrcCalculator.Accumulate(buffer, offset, readCount); - } - else - { - long originalPosition = _underlyingStream.Position; - - readCount = _underlyingStream.Read(buffer, offset, count); - - // This operation needs to be done after Read since read can throw an exception; in that case - // we want to preserve the original CRC - if (originalPosition == 0 && _highWaterMark == -1) - { - _highWaterMark = 0; - CrcCalculator.ClearCrc(); - } - - if (originalPosition == _highWaterMark) - { - CrcCalculator.Accumulate(buffer, offset, readCount); - _highWaterMark = _underlyingStream.Position; - } - - if (_validateCrcWithExpectedCrc && CanValidateCrcWithoutRead()) - { - if (CrcCalculator.Crc != _expectedCrc) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - } - - return readCount; - } - - override public void Write(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - // We should calculate CRC accumulatively for the following conditions - // 1. Seek is not supported by the underlying stream: this will be the case for - // writing stream in streaming mode - // 2. This write request is consequtive to the highwater mark of the CRC calculation - // 3. This write request is at 0 offset and the CRC hasn't been calculated yet - if (!_underlyingStream.CanSeek) // Case #1 - { - _underlyingStream.Write(buffer, offset, count); - CrcCalculator.Accumulate(buffer, offset, count); - } - else - { - long originalPosition = _underlyingStream.Position; - - // If we ever fail to Write below _highWaterMark, we want CRC to be recalculated in case - // if a caller decides to recover from the error - if (originalPosition < _highWaterMark) - { - _highWaterMark = -1; - } - - _underlyingStream.Write(buffer, offset, count); - - if (originalPosition == 0) - { - _highWaterMark = 0; - CrcCalculator.ClearCrc(); -} - - if (originalPosition == _highWaterMark) - { - CrcCalculator.Accumulate(buffer, offset, count); - _highWaterMark = _underlyingStream.Position; - } - } - - // CRC cannot be checked against the to-be-validated CRC anymore - _validateCrcWithExpectedCrc = false; - - // mark the global dirty flag - _blockManager.DirtyFlag = true; - } - - override public void Flush() - { - CheckDisposed(); - - _underlyingStream.Flush(); - } - - ///////////////////////////// - // Internal Constructor - ///////////////////////////// - internal ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream) : - this(blockManager, underlyingStream, 0) - { - _validateCrcWithExpectedCrc = false; - } - - internal ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream, UInt32 expectedCrc) - { - Debug.Assert(underlyingStream != null); - Debug.Assert(blockManager != null); - - _blockManager = blockManager; - _underlyingStream = underlyingStream; - _validateCrcWithExpectedCrc = true; - _expectedCrc = expectedCrc; - _highWaterMark = -1; - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - /// - /// Dispose(bool) - /// - /// - /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to - /// call Dispose() instead of Close(). - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - { - //streams wrapping this stream shouldn't pass Dipose calls through - // it is responsibility of the BlockManager or LocalFileBlock (in case of Remove) to call - // this dispose as appropriate (that is the reason why Flush isn't called here) - - // multiple calls are fine - just ignore them - // and we shouldn't be closing a stream which we do not own - _underlyingStream = null; - } - } - finally - { - base.Dispose(disposing); - } - } - - ///////////////////////////// - // Internal Methods - ///////////////////////////// - - - // !!!!!!!!!!!!!!!!IMPORTANT !!!!!!!!!!!!!!!! - // This method doesn't preserve the seek position of the underlying stream. - // It (non-preservation of the seek pointer) is mostly done for compression - // scenarios in which seeking back in the compressed streams will result in - // switching to the expensive simulation stream. This method is only called - // from scenarios during Flush Close of the package where position of the - // Compressed stream is insignificant - internal UInt32 CalculateCrc() - { - CheckDisposed(); - - if (_underlyingStream.CanSeek) - { - long originalPosition = _underlyingStream.Position; - - if (_highWaterMark == -1) - { - CrcCalculator.ClearCrc(); - _highWaterMark = 0; - } - - if (_highWaterMark < _underlyingStream.Length) - { - _underlyingStream.Position = _highWaterMark; - CrcCalculator.CalculateStreamCrc(_underlyingStream); - _highWaterMark = _underlyingStream.Length; - } - } - - return CrcCalculator.Crc; - } - - ///////////////////////////// - // Private Methods - ///////////////////////////// - - private void CheckDisposed() - { - if (_underlyingStream == null) - { - throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); - } - } - - private Crc32Calculator CrcCalculator - { - get - { - if (_crcCalculator == null) - { - _crcCalculator = new Crc32Calculator(); - } - return _crcCalculator; - } - } - - private bool CanValidateCrcWithoutRead() - { - if (_underlyingStream.CanSeek && _highWaterMark == _underlyingStream.Length) - { - return true; - } - - return false; - } - - // this is only used to switch the dirty flag in case of Write or SetLength - // no other communication is done with the BlockManager from this class - private ZipIOBlockManager _blockManager; - - private long _highWaterMark; - private Crc32Calculator _crcCalculator; - private bool _validateCrcWithExpectedCrc; - private UInt32 _expectedCrc; - - private Stream _underlyingStream; - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/WriteTimeStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/WriteTimeStream.cs deleted file mode 100644 index 1234b278c99..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/WriteTimeStream.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// -// Description: -// WriteTimeStream - wraps the ArchiveStream in Streaming generation scenarios so that we -// can determine current archive stream offset even when working on a stream that is non-seekable -// because the Position property is unusable on such streams. -// -// -// -// - -using System; -using System.IO; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class WriteTimeStream : Stream - { - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - /// - /// CanRead - never - /// - override public bool CanRead { get { return false; } } - - /// - /// CanSeek - never - /// - override public bool CanSeek{ get { return false; } } - - /// - /// CanWrite - only if we are not disposed - /// - override public bool CanWrite { get { return (_baseStream != null); } } - - /// - /// Same as Position - /// - override public long Length - { - get - { - CheckDisposed(); - return _position; - } - } - - /// - /// Get is supported even on Write-only stream - /// - override public long Position - { - get - { - CheckDisposed(); - return _position; - } - set - { - CheckDisposed(); - IllegalAccess(); // throw exception - } - } - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public override void SetLength(long newLength) - { - IllegalAccess(); // throw exception - } - - override public long Seek(long offset, SeekOrigin origin) - { - IllegalAccess(); // throw exception - return -1; // keep compiler happy - } - - override public int Read(byte[] buffer, int offset, int count) - { - IllegalAccess(); // throw exception - return -1; // keep compiler happy - } - - override public void Write(byte[] buffer, int offset, int count) - { - CheckDisposed(); - _baseStream.Write(buffer, offset, count); - checked{_position += count;} - } - - override public void Flush() - { - CheckDisposed(); - _baseStream.Flush(); - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - internal WriteTimeStream(Stream baseStream) - { - if (baseStream == null) - { - throw new ArgumentNullException("baseStream"); - } - - _baseStream = baseStream; - - // must be based on writable stream - if (!_baseStream.CanWrite) - throw new ArgumentException(SR.Get(SRID.WriteNotSupported), "baseStream"); - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - protected override void Dispose(bool disposing) - { - try - { - if (disposing && (_baseStream != null)) - { - _baseStream.Close(); - } - } - finally - { - _baseStream = null; - base.Dispose(disposing); - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private static void IllegalAccess() - { - throw new NotSupportedException(SR.Get(SRID.WriteOnlyStream)); - } - - private void CheckDisposed() - { - if (_baseStream == null) - throw new ObjectDisposedException("Stream"); - } - - // _baseStream doubles as our disposed indicator - it's null if we are disposed - private Stream _baseStream; // stream we wrap - needs to only support Write - private long _position; // current position - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipArchive.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipArchive.cs deleted file mode 100644 index f6898297423..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipArchive.cs +++ /dev/null @@ -1,700 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Globalization; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - /// - /// This is the main clas of the ZIP IO internal APIs. It has 2 stsatic constructors - /// OpenOnFile and OpenOnStream. It provides client app with ability to manipulate - /// a Zip Archive (create, open, open/add/delete file items). - /// - internal sealed class ZipArchive : IDisposable - { - //------------------------------------------------------ - // - // Public Members - // - //------------------------------------------------------ - // None - - //------------------------------------------------------ - // - // Internal Constructors - // - //------------------------------------------------------ - // None - - //------------------------------------------------------ - // - // Internal API Methods (although these methods are marked as - // Internal, they are part of the internal ZIP IO API surface - // - //------------------------------------------------------ - /// - /// Static constructor File based constructor. all parameteres are obvious. - /// This constructor wil open the file in requested mode, and it will not do any futher parsing. - /// - /// In the case of Create/CreateNew, it will also prebuild in cached in-memory - /// EndOfCentralDirectoryRecord (which is a minimal zip file requirement), so that if user - /// chooses to close right after he will get a file with just EndOfCentralDirectoryRecord. - /// - internal static ZipArchive OpenOnFile(string path, FileMode mode, FileAccess access, FileShare share, bool streaming) - { - if (mode == FileMode.OpenOrCreate || mode == FileMode.Open) - { - // for OpenOrCreate cases we need to check whether it is an exisiting file of size 0. - // Files of size 0 are onsidered invalid ZipArchives. If we skip this check here, later we wouldn't be able to distinguish - // between brand new file being created as a result of OpenOrCreate mode, or old 0 length file being open as a result of - // OpenOrCreate mode. - FileInfo fileInfo = new FileInfo(path); - - if (fileInfo.Exists && fileInfo.Length == 0 && (fileInfo.Attributes & FileAttributes.ReparsePoint) == 0) - { - throw new FileFormatException(SR.Get(SRID.ZipZeroSizeFileIsNotValidArchive)); - } - } - - ZipArchive archive = null; - FileStream archiveStream = null; - - // We would like to run initialization after openning stream in try/catch block - // so that if anything goes wrong we can close the stream (release file handler) - try - { - archiveStream = new FileStream(path, mode, access, share, 4096, streaming); - - ValidateModeAccessShareStreaming(archiveStream, mode, access, share, streaming); - - archive = new ZipArchive(archiveStream, mode, access, streaming, true); - } - catch - { - if (archive != null) - { - archive.Close(); - } - - if(archiveStream != null) - { - archiveStream.Close(); - } - - throw; - } - - return archive; - } - - /// - /// Static constructor Stream based constructor. all parameteres are obvious. - /// This constructor wil not do any futher parsing. - /// - /// In the case of Create/CreateNew, it will also prebuild in cached in-memory - /// EndOfCentralDirectoryRecord (which is a minimal zip file requirement), so that if user - /// chooses to close right after he will get a file with just EndOfCentralDirectoryRecord. - /// - internal static ZipArchive OpenOnStream(Stream stream, FileMode mode, FileAccess access, bool streaming) - { - // we can assume FileShare.None, as there is absolutely nothing we can do - // about other people working with the underlying storage - ValidateModeAccessShareStreaming(stream, mode, access, FileShare.None, streaming); - - if (stream.CanSeek) - { - bool emptyStream = (stream.Length == 0); - - switch (mode) - { - // for Open cases we need to check whether it is an existing file of size 0. - // Streams of size 0 are considered invalid ZipArchives. - case FileMode.Open: - if (emptyStream) - { - throw new FileFormatException(SR.Get(SRID.ZipZeroSizeFileIsNotValidArchive)); - } - break; - - // for Create cases, we need to check if the stream is empty or not - case FileMode.CreateNew: - if (!emptyStream) - { - throw new IOException(SR.Get(SRID.CreateNewOnNonEmptyStream)); - } - break; - case FileMode.Create: - if (!emptyStream) - { - // discard existing data - stream.SetLength(0); - } - break; - } - } - - return new ZipArchive(stream, mode, access, streaming, false); - } - - - /// - /// This method will result in a complete parsing of the EndOfCentralDirectory - /// and CentralDirectory records (if it hasn't been done yet). - /// After that (assuming no duplicates were found). It will create in appropriate - /// in memory Local FileHeaders and Central Directory Headers. - /// - internal ZipFileInfo AddFile(string zipFileName, CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption) - { - CheckDisposed(); - - if (_openAccess == FileAccess.Read) - { - throw new InvalidOperationException(SR.Get(SRID.CanNotWriteInReadOnlyMode)); - } - - // Validate parameteres - zipFileName = ZipIOBlockManager.ValidateNormalizeFileName(zipFileName); - - if ((compressionMethod != CompressionMethodEnum.Stored) && - (compressionMethod != CompressionMethodEnum.Deflated)) - { - throw new ArgumentOutOfRangeException("compressionMethod"); - } - - // non-contiguous range requires more complex test - if (deflateOption < DeflateOptionEnum.Normal || ( - deflateOption > DeflateOptionEnum.SuperFast && deflateOption != DeflateOptionEnum.None)) - { - throw new ArgumentOutOfRangeException("deflateOption"); - } - - // Check for duplicates , - if (FileExists(zipFileName)) - { - throw new System.InvalidOperationException(SR.Get(SRID.AttemptedToCreateDuplicateFileName)); - } - - // Create Local File Block through Block Manager - ZipIOLocalFileBlock fileBlock = _blockManager.CreateLocalFileBlock(zipFileName, compressionMethod, deflateOption); - - //build new ZipFileInfo and add reference to the collection, so we can keep track of the instances of the ZipFileInfo, - // that were given out and invalidate any collection that was returned on GetFiles calls - ZipFileInfo zipFileInfo = new ZipFileInfo(this, fileBlock); - ZipFileInfoDictionary.Add(zipFileInfo.Name, zipFileInfo); - - return zipFileInfo; - } - - /// - /// This method will result in a complete parsing of the EndOfCentralDirectory - /// and CentralDirectory records (if it hasn't been done yet). - /// After that (assuming the file was found). It will parse the apropriate local file block - /// header and data descriptor (if present). - /// - internal ZipFileInfo GetFile(string zipFileName) - { - CheckDisposed(); - - if (_openAccess == FileAccess.Write) - { - throw new InvalidOperationException(SR.Get(SRID.CanNotReadInWriteOnlyMode)); - } - - // Validate parameteres - zipFileName = ZipIOBlockManager.ValidateNormalizeFileName(zipFileName); - - // try to get it from the ZipFileInfo dictionary - if (ZipFileInfoDictionary.Contains(zipFileName)) - { - // this ZipFileInfo was already built through AddFile or GetFile(s) - // we have this cached - return (ZipFileInfo)(ZipFileInfoDictionary[zipFileName]); - } - else - { - // we need to check whether it is present in the central directory - if (!FileExists(zipFileName)) - { - throw new InvalidOperationException(SR.Get(SRID.FileDoesNotExists)); - } - - // Load Local File Block through Block Manager - ZipIOLocalFileBlock fileBlock = _blockManager.LoadLocalFileBlock(zipFileName); - - // build new ZipFileInfo and add reference to the collection, so we can keep track of the instances of the ZipFileInfo, - // that were given out and invalidate any collection that was returned on GetFiles calls - ZipFileInfo zipFileInfo = new ZipFileInfo(this, fileBlock); - - //this should invalidate any outstanding collections - ZipFileInfoDictionary.Add(zipFileInfo.Name, zipFileInfo); - - return zipFileInfo; - } - } - - /// - /// This method will result in a complete parsing of the EndOfCentralDirectory - /// and CentralDirectory records (if it hasn't been done yet). - /// After that it will check whether central directory contains the file. - /// It will not attempt the parsing of the local file headers / descriptors. - /// - internal bool FileExists (string zipFileName) - { - CheckDisposed(); - - // Validate parameteres - zipFileName = ZipIOBlockManager.ValidateNormalizeFileName(zipFileName); - - return _blockManager.CentralDirectoryBlock.FileExists(zipFileName); - } - - - /// - /// This method will result in a complete parsing of the EndOfCentralDirectory - /// and CentralDirectory records (if it hasn't been done yet). - /// After that it will check whether central directory contains the file. - /// If it is present it will parse local fileheader, and remove their in memory - /// representation - /// - internal void DeleteFile (string zipFileName) - { - CheckDisposed(); - - if (_openAccess == FileAccess.Read) - { - throw new InvalidOperationException(SR.Get(SRID.CanNotWriteInReadOnlyMode)); - } - - // Validate parameteres - zipFileName = ZipIOBlockManager.ValidateNormalizeFileName(zipFileName); - - if (FileExists(zipFileName)) // is it in central Directory ? - { - ZipFileInfo fileInfoToBeDeleted = GetFile(zipFileName); - - //this should invalidate any outstanding collections - // and update central directory status as appropriate - ZipFileInfoDictionary.Remove(zipFileName); - - //this should remove the local file block - // from the blockManager's collection - _blockManager.RemoveLocalFileBlock(fileInfoToBeDeleted.LocalFileBlock); - } - } - - /// - /// This method will result in a complete parsing of the EndOfCentralDirectory - /// and CentralDirectory records (if it hasn't been done yet). - /// After that it will go through allfiles in the central directory and parse their - /// local headers and desciptors one by one. - /// - internal ZipFileInfoCollection GetFiles() - { - CheckDisposed(); - - if (_openAccess == FileAccess.Write) - { - throw new InvalidOperationException(SR.Get(SRID.CanNotReadInWriteOnlyMode)); - } - - // We need to scan through the central Directory, and for each file - // call GetFile(fileName), which will result in adding missing (not loaded) - // information to the ZipFileInfoDictionary. - foreach(string fileName in _blockManager.CentralDirectoryBlock.GetFileNamesCollection()) - { - GetFile(fileName); // fileName must be validated and normalized at this - // point by the central directory parsing routine - } - return new ZipFileInfoCollection(ZipFileInfoDictionary.Values); - } - - /// - /// This method will result in a complete Flushing of any outstanding data in buffers and - /// any streams ever returned by the GetStream calls.This call results in Archive file that - /// has a completely valid state. If application were to crash right afte the Flush is complete, - /// the resulting files would be a "valid" Zip archive - /// - internal void Flush() - { - CheckDisposed(); - _blockManager.Save(false); - } - - /// - /// Results in a complete Flush of all the outstanding buffers and closing/disposing all of the objects - /// ZipFileInfo, Streams ZipArchive. - /// - internal void Close() - { - Dispose(); - } - - /// - /// Results in a complete Flush of all the outstanding buffers and closing/disposing all of the objects - /// ZipFileInfo, Streams ZipArchive. - /// - public void Dispose() - { - Dispose(true); - // GC.SuppressFinalize(this); // Because this class is sealed and there is no Finalizer, - // there is no need for this call. Leaving it in case we decide to unseal it - } - - /// - /// Throw if version needed to extract is not supported - /// - /// version to inspect - static internal void VerifyVersionNeededToExtract(UInt16 version) - { - // strictly enforce this list - switch (version) - { - case (UInt16)ZipIOVersionNeededToExtract.StoredData: break; - case (UInt16)ZipIOVersionNeededToExtract.VolumeLabel: break; - case (UInt16)ZipIOVersionNeededToExtract.DeflatedData: break; - case (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat: break; - default: - throw new NotSupportedException(SR.Get(SRID.NotSupportedVersionNeededToExtract)); - } - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - /// - /// Read only property, that returns the value of FileAccess that - /// was passed into the OpenOnFile or OpenOnStream call - /// - internal FileAccess OpenAccess - { - get - { - CheckDisposed(); - return _openAccess; - } - } - -// This functionality commented out in order to comply with FX Cop rule -// AvoidUncalledPrivateCode. However, because of a chance that this functionality -// might eventually get public exposure we would like to keep this code around -#if ZIP_IO_PUBLIC - - /// - /// Returns Comment field from the End Of Central Directory Record. - /// Therefore, call to this property might result in some parsing. - /// If the End Of Central Directory isn't parsed yet, it will be as a - /// result of querying this property. - /// - internal string Comment - { - get - { - CheckDisposed(); - return _blockManager.EndOfCentralDirectoryBlock.Comment; - } - } -#endif - - - //------------------------------------------------------ - // - // Internal NON API Methods (these methods are marked as - // Internal, and they are trully internal and not the part of the - // internal ZIP IO API surface - // - //------------------------------------------------------ - - //------------------------------------------------------ - // - // Private Constructors - // - //------------------------------------------------------ - /// - /// This private constructor isonly supposed to be called by the - /// OpenOnFile and OpenOnStream static members. - /// - /// - /// - /// - /// - /// true if this class is responsible for closing the archiveStream - private ZipArchive(Stream archiveStream, FileMode mode, FileAccess access, bool streaming, bool ownStream) - { - // as this contructor is only called from the static member - // all checks should have been done before - - _blockManager = new ZipIOBlockManager(archiveStream, streaming, ownStream); - - _openMode = mode; - _openAccess = access; - - // In case of "create" we also need to create at least an end of Central Directory Record. - // For FileMode OpenOrCreate we use stream Length to distinguish open and create scenarios. - // Implications of this decision is that existing file of size 0 opened in OpenOrCreate Mode - // will be treated as a newly/created file. - if ((_openMode == FileMode.CreateNew) || - (_openMode == FileMode.Create) || - ((_openMode == FileMode.OpenOrCreate) && archiveStream.Length == 0)) - { - _blockManager.CreateEndOfCentralDirectoryBlock(); - } - else - { - _blockManager.LoadEndOfCentralDirectoryBlock(); - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - /// - /// Dispose(bool) - /// - /// - private void Dispose(bool disposing) - { - if (disposing) - { - if (!_disposedFlag) - { - try - { - if (_blockManager != null) - { - // allow this in Debug mode to catch any place where we accidentally - // make something dirty when we are read-only -#if !DEBUG - if (_openAccess == FileAccess.ReadWrite || _openAccess == FileAccess.Write) -#endif - { - _blockManager.Save(true); - } - - ((IDisposable)_blockManager).Dispose(); - } - } - finally - { - _disposedFlag = true; - } - } - } - } - - /// - /// This is function is called by the OpenOnFile and OpenOnStream in order - /// to validate parameteresgiven to those functions. The combinations of valid - /// parameters is quite complex and not obvious, so after basic range checks, - /// it is actually using a lookup table to answer the question whether the given - /// parameter combination is valid or not. - /// - static private void ValidateModeAccessShareStreaming(Stream stream, FileMode mode, FileAccess access, FileShare share, bool streaming) - { - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - //////////// - // filter out values that are out of enum ranges first - //////////// - ValidateModeAccessShareValidEnums(mode, access, share); - - //////////// - // filter out values that are not supported regardless of other parameters - // but still validate enum members - //////////// - ValidateModeAccessShareSupportedEnums(mode, share); - - //////////// - // let's makes sure that given stream is capable of supporting required functionality - //////////// - ValidateModeAccessStreamStreamingCombinations(stream, access, streaming); - - //////////// - //let's make sure that comnbintaion of mode, access,share,,streaming - // parameters is supported - //////////// - int intMode = Convert.ToInt32(mode, CultureInfo.InvariantCulture); - int intAccess = Convert.ToInt32(access, CultureInfo.InvariantCulture); - int intShare = Convert.ToInt32(share, CultureInfo.InvariantCulture); - int intStreaming = Convert.ToInt32(streaming, CultureInfo.InvariantCulture); - for(int i=0; i<_validOpenParameters.GetLength(0); i++) - { - if ((_validOpenParameters [i,0] == intMode) && - (_validOpenParameters [i,1] == intAccess) && - (_validOpenParameters [i,2] == intShare) && - (_validOpenParameters [i,3] == intStreaming)) - { - return; - } - } - - throw new ArgumentException(SR.Get(SRID.UnsupportedCombinationOfModeAccessShareStreaming)); - } - - static private void ValidateModeAccessStreamStreamingCombinations(Stream stream, FileAccess access, bool streaming) - { - //////////// - // let's makes sure that given stream is capable of supporting required functionality - //////////// - if ((access== FileAccess.Read || access == FileAccess.ReadWrite) && !stream.CanRead) - { - throw new ArgumentException(SR.Get(SRID.CanNotReadDataFromStreamWhichDoesNotSupportReading)); - } - - // if user want to be able to write stream needs to support it - if ((access == FileAccess.Write || access == FileAccess.ReadWrite) && !stream.CanWrite) - { - throw new ArgumentException(SR.Get(SRID.CanNotWriteDataToStreamWhichDoesNotSupportWriting)); - } - - // if user works in non-streaming mode we need to Seek on underlying stream - if (! streaming && !stream.CanSeek) - { - throw new ArgumentException(SR.Get(SRID.CanNotOperateOnStreamWhichDoesNotSupportSeeking)); - } - } - - static private void ValidateModeAccessShareSupportedEnums(FileMode mode, FileShare share) - { - //////////// - // filter out values that are not supported regardless of other parameters - // but still validate enum members - //////////// - if (mode == FileMode.Append || mode == FileMode.Truncate) - { - throw new NotSupportedException(SR.Get(SRID.TruncateAppendModesNotSupported)); - } - else if (share != FileShare.Read && share != FileShare.None) - { - // later as we get to streaming other FileShare values will be supported too - throw new NotSupportedException (SR.Get(SRID.OnlyFileShareReadAndFileShareNoneSupported)); - } - } - - static private void ValidateModeAccessShareValidEnums(FileMode mode, FileAccess access, FileShare share) - { - //////////// - // filter out values that are out of enum ranges first - //////////// - if ((mode != FileMode.Append) && (mode != FileMode.Create) && (mode != FileMode.CreateNew) && (mode != FileMode.Open) - && (mode != FileMode.OpenOrCreate) && (mode != FileMode.Truncate)) - { - throw new ArgumentOutOfRangeException("mode"); - } - else if ((access != FileAccess.Read) && (access != FileAccess.ReadWrite) && (access != FileAccess.Write)) - { - throw new ArgumentOutOfRangeException("access"); - } - else if ((share != FileShare.Delete) && (share != FileShare.Inheritable) && (share != FileShare.None) && - (share != FileShare.Read) && (share != FileShare.ReadWrite) && (share != FileShare.Write)) - { - throw new ArgumentOutOfRangeException("share"); - } - } - - /// - /// Throws exception if object already Disposed/Closed. - /// - private void CheckDisposed() - { - if (_disposedFlag) - { - throw new ObjectDisposedException(null, SR.Get(SRID.ZipArchiveDisposed)); - } - } - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - /// - /// This private property is used as a mean to achieve lazy memory allocation for the - /// hashtable that maintains a cahce of the returned instrances of ZipFileInfo(s). - /// This hashtable uses file names as keys in the case insensitive and culture invariant fashion - /// - private IDictionary ZipFileInfoDictionary - { - get - { - if (_zipFileInfoDictionary == null) - { - // ordinal case sensitive comparison - _zipFileInfoDictionary = new Hashtable(_zipFileInfoDictionaryInitialSize, StringComparer.Ordinal); - } - return _zipFileInfoDictionary; - } - } - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - - // This 2 dimensional table is used by the ValidateModeAccessShareStreaming - // function as a set of valid parameter combinations - static private int[,] _validOpenParameters = new int[,] - { // FileMode // FileAccess / FileShare // streaming - {(int)FileMode.Create, (int)FileAccess.Write, (int)FileShare.None, 1}, - {(int)FileMode.Create, (int)FileAccess.Write, (int)FileShare.Read, 1}, - {(int)FileMode.Create, (int)FileAccess.ReadWrite, (int)FileShare.None, 0}, - {(int)FileMode.CreateNew, (int)FileAccess.Write, (int)FileShare.None, 1}, - {(int)FileMode.CreateNew, (int)FileAccess.Write, (int)FileShare.Read, 1}, - {(int)FileMode.CreateNew, (int)FileAccess.ReadWrite, (int)FileShare.None, 0}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.None, 1}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.None, 0}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.Read, 1}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.Read, 0}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.Write, 1}, - {(int)FileMode.Open, (int)FileAccess.Read, (int)FileShare.ReadWrite, 1}, - {(int)FileMode.Open, (int)FileAccess.ReadWrite, (int)FileShare.None, 0}, - {(int)FileMode.OpenOrCreate, (int)FileAccess.ReadWrite, (int)FileShare.None, 0} - }; - - // modes that were used for openning (OpenOnStream or OpenOnFile), - // there is no way to change these values after class is constructed - private FileMode _openMode; - private FileAccess _openAccess; - - private bool _disposedFlag; - - // reference to the ZipIOBlockManager, this reference is instantiated as - // a part of the OpenOnFile/OpenOnStream contruction - private ZipIOBlockManager _blockManager; - - // this is a Dictionary of all the ZipFileInfos that were given out. - // It uses file name as key in case insensitive and culture invariant fashion. - // all members of the class are supposed to use this field indirectly through - // ZipFileInfoDictionary property, as ZipFileInfoDictionary is respnsible - // for lazy allocation of the hashtable. - private IDictionary _zipFileInfoDictionary; - private const int _zipFileInfoDictionaryInitialSize = 50; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfo.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfo.cs deleted file mode 100644 index dc815593f07..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfo.cs +++ /dev/null @@ -1,198 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; - -namespace MS.Internal.IO.Zip -{ - internal sealed class ZipFileInfo - { - //------------------------------------------------------ - // - // Public Members - // - //------------------------------------------------------ - // None - - //------------------------------------------------------ - // - // Internal Constructors - // - //------------------------------------------------------ - // None - - //------------------------------------------------------ - // - // Internal API Methods (although these methods are marked as - // Internal they are part of the internal ZIP IO API surface - // - //------------------------------------------------------ - internal Stream GetStream(FileMode mode, FileAccess access) - { - CheckDisposed(); - return _fileBlock.GetStream(mode, access); - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - internal string Name - { - get - { - CheckDisposed(); - return _fileBlock.FileName; - } - } - - internal ZipArchive ZipArchive - { - get - { - CheckDisposed(); - return _zipArchive; - } - } - - internal CompressionMethodEnum CompressionMethod - { - get - { - CheckDisposed(); - return _fileBlock.CompressionMethod; - } - } - - internal DateTime LastModFileDateTime - { - get - { - CheckDisposed(); - return ZipIOBlockManager.FromMsDosDateTime(_fileBlock.LastModFileDateTime); - } - } - -#if false - internal bool EncryptedFlag - { - get - { - CheckDisposed(); - return _fileBlock.EncryptedFlag; - } - } -#endif - - internal DeflateOptionEnum DeflateOption - { - get - { - CheckDisposed(); - return _fileBlock.DeflateOption; - } - } -#if false - internal bool StreamingCreationFlag - { - get - { - CheckDisposed(); - return _fileBlock.StreamingCreationFlag; - } - } -#endif - // This ia Directory flag based on the informtion from the central directory - // at the moment we have only provide reliable value for the files authored in MS-DOS - // The upper byte of version made by indicating (OS) must be == 0 (MS-DOS) - // for the other cases (OSes) we will return false - internal bool FolderFlag - { - get - { - CheckDisposed(); - return _fileBlock.FolderFlag; - } - } - - // This ia Directory flag based on the informtion from the central directory - // at the moment we have only provide reliable value for the files authored in MS-DOS - // The upper byte of version made by indicating (OS) must be == 0 (MS-DOS) - // for the other cases (OSes) we will return false - internal bool VolumeLabelFlag - { - get - { - CheckDisposed(); - return _fileBlock.VolumeLabelFlag; - } - } - - //------------------------------------------------------ - // Internal NON API Constructor (this constructor is marked as internal - // and isNOT part of the ZIP IO API surface) - // It supposed to be called only by the ZipArchive class - //------------------------------------------------------ - internal ZipFileInfo(ZipArchive zipArchive, ZipIOLocalFileBlock fileBlock) - { - Debug.Assert((fileBlock != null) && (zipArchive != null)); - _fileBlock = fileBlock; - _zipArchive = zipArchive; -#if DEBUG - // validate that date time is legal - DateTime dt = LastModFileDateTime; -#endif - } - - //------------------------------------------------------ - // Internal NON API property to be used to map FileInfo back to a block that needs to be deleted - // (this prperty is marked as internal and isNOT part of the ZIP IO API surface) - // It supposed to be called only by the ZipArchive class - //------------------------------------------------------ - internal ZipIOLocalFileBlock LocalFileBlock - { - get - { - return _fileBlock; - } - } - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private void CheckDisposed() - { - _fileBlock.CheckDisposed(); - } - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - private ZipIOLocalFileBlock _fileBlock; - private ZipArchive _zipArchive; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfoCollection.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfoCollection.cs deleted file mode 100644 index d1b711b03c6..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipFileInfoCollection.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.Collections.Generic; -using System.Collections; - -namespace MS.Internal.IO.Zip -{ - /// - /// The only reason for existence of this class is to restrict operations that caller of the - /// ZipArchive.GetFiles is allowed to perform. We want to prevent any modifications to the - /// actual collection of the FileItems as it is supposed to be a read-only data structure. - /// Although this is an internal API it seems that the safeguards are warranted. - /// - internal class ZipFileInfoCollection : IEnumerable - { - //------------------------------------------------------ - // - // Internal NON API Constructor (this constructor is marked as internal - // and isNOT part of the ZIP IO API surface - // - //------------------------------------------------------ - internal ZipFileInfoCollection(ICollection zipFileInfoCollection) - { - _zipFileInfoCollection = zipFileInfoCollection; - } - - //------------------------------------------------------ - // - // Internal API Methods (although these methods are marked as - // Internal they are part of the internal ZIP IO API surface - // - //------------------------------------------------------ - IEnumerator IEnumerable.GetEnumerator() - { - return _zipFileInfoCollection.GetEnumerator(); - } - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - private ICollection _zipFileInfoCollection; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOBlockManager.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOBlockManager.cs deleted file mode 100644 index 2ee775f6e69..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOBlockManager.cs +++ /dev/null @@ -1,1258 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// -// - -using System; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Collections; -using System.Globalization; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.IO.Packaging; // for PackagingUtilities -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - /// - /// This is the main class of the actual ZIP IO implementation. It is primary responsibility - /// is to maintain the map and status of the parsed and loaded areas(blocks) of the file. - /// It is also supports manipulating this map (adding and deleting blocks) - /// - internal class ZipIOBlockManager : IDisposable, IEnumerable - { - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - IEnumerator IEnumerable.GetEnumerator() - { - CheckDisposed(); - - return _blockList.GetEnumerator(); - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - /// - /// This property returns the status of whether Central directory is loaded or not. - /// This property is rarely used, as most clients will just ask for CentralDirectoryBlock - /// and oif it isn't loaded it will be. - /// The only reason to use IsCentralDirectoryBlockLoaded property is to differentiate - /// scenarios in which some optimization is possible, if central directory isn't loaded yet. - /// - internal bool IsCentralDirectoryBlockLoaded - { - get - { - CheckDisposed(); - return (_centralDirectoryBlock != null); - } - } - - /// - /// This property returns the CentralDirectoryBlock and provides lazy load - /// fuinctionality. This isthe only way other classes can access information - /// from the Central Directory Block - /// - internal ZipIOCentralDirectoryBlock CentralDirectoryBlock - { - get - { - CheckDisposed(); - if (_centralDirectoryBlock == null) - { - // figure out if we are in ZIP64 mode or not - if (Zip64EndOfCentralDirectoryBlock.TotalNumberOfEntriesInTheCentralDirectory > 0) - { - LoadCentralDirectoryBlock(); - } - else - { - // We need to be aware of the special case of empty Zip Archive - // with a single record : End Of Central directory - //In such cases we should create new CentralDirectoryBlock - CreateCentralDirectoryBlock(); - } - } - - return _centralDirectoryBlock; - } - } - - /// - /// This property returns the Zip64EndOfCentralDirectoryBlock and provides lazy load - /// fuinctionality. This is the only way other classes can access information - /// from the Zip64EndOfCentralDirectoryBlock - /// - internal ZipIOZip64EndOfCentralDirectoryBlock Zip64EndOfCentralDirectoryBlock - { - get - { - CheckDisposed(); - - if (_zip64EndOfCentralDirectoryBlock == null) - { - CreateLoadZip64Blocks(); - } - - return _zip64EndOfCentralDirectoryBlock; - } - } - - /// - /// This property returns the Zip64EndOfCentralDirectoryLocatorBlock and provides lazy load - /// fuinctionality. This is the only way other classes can access information - /// from the Zip64EndOfCentralDirectoryLocator Block - /// - internal ZipIOZip64EndOfCentralDirectoryLocatorBlock Zip64EndOfCentralDirectoryLocatorBlock - { - get - { - CheckDisposed(); - - if (_zip64EndOfCentralDirectoryLocatorBlock == null) - { - CreateLoadZip64Blocks(); - } - - return _zip64EndOfCentralDirectoryLocatorBlock; - } - } - - /// - /// This property returns the CentralDirectoryBlock and provides lazy load - /// fuinctionality. This is the only way other classes can access information - /// from the Central Directory Block - /// - internal ZipIOEndOfCentralDirectoryBlock EndOfCentralDirectoryBlock - { - get - { - CheckDisposed(); - if (_endOfCentralDirectoryBlock == null) - { - LoadEndOfCentralDirectoryBlock(); - } - - return _endOfCentralDirectoryBlock; - } - } - - internal Stream Stream - { - get - { - CheckDisposed(); - return _archiveStream; - } - } - - internal bool Streaming - { - get - { - CheckDisposed(); - return _openStreaming; - } - } - - internal BinaryReader BinaryReader - { - get - { - CheckDisposed(); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - if (_binaryReader == null) - { - _binaryReader = new BinaryReader(Stream, Encoding); - } - return _binaryReader; - } - } - - internal BinaryWriter BinaryWriter - { - get - { - CheckDisposed(); - if (_binaryWriter == null) - { - _binaryWriter = new BinaryWriter(Stream, Encoding); - } - return _binaryWriter; - } - } - - internal Encoding Encoding - { - get - { - CheckDisposed(); - return _encoding; - } - } - - internal bool DirtyFlag - { - set - { - CheckDisposed(); - _dirtyFlag = value; - } - get - { - CheckDisposed(); - return _dirtyFlag; - } - } - - static internal int MaxFileNameSize - { - get - { - return UInt16.MaxValue; - } - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - - internal void CreateEndOfCentralDirectoryBlock() - { - CheckDisposed(); - - // Prevent accidental call if underlying stream is non-empty since - // any legal zip archive contains an EOCD block. - Debug.Assert(_openStreaming || _archiveStream.Length == 0); - - // Disallow multiple calls. - Debug.Assert(_endOfCentralDirectoryBlock == null); - - // construct Block find it and parse it - long blockOffset = 0; // this will be updated later - _endOfCentralDirectoryBlock = ZipIOEndOfCentralDirectoryBlock.CreateNew(this, blockOffset); - - // this will add a block to the tail - AppendBlock(_endOfCentralDirectoryBlock); - DirtyFlag = true; - } - - internal void LoadEndOfCentralDirectoryBlock() - { - Debug.Assert(_endOfCentralDirectoryBlock == null); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - // construct Block find it and parse it - _endOfCentralDirectoryBlock = ZipIOEndOfCentralDirectoryBlock.SeekableLoad(this); - - //ask block manager to MAP this block - MapBlock(_endOfCentralDirectoryBlock); - } - - internal ZipIOLocalFileBlock CreateLocalFileBlock(string zipFileName, CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption) - { - CheckDisposed(); - - // we are guaranteed uniqueness at this point , so let's just add a - // block at the end of the file, just before the central directory - // construct Block find it and parse it - - // STREAMING Mode: - // NOTE: _blockList is NOT in offset order except the last four blocks - // (CD, Zip64 EOCD, Zip64 EOCD Locator, and EOCD) - - ZipIOLocalFileBlock localFileBlock = ZipIOLocalFileBlock.CreateNew(this, - zipFileName, - compressionMethod, - deflateOption); - - InsertBlock(CentralDirectoryBlockIndex, localFileBlock); - - CentralDirectoryBlock.AddFileBlock(localFileBlock); - - DirtyFlag = true; - - return localFileBlock; - } - - internal ZipIOLocalFileBlock LoadLocalFileBlock(string zipFileName) - { - CheckDisposed(); - - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - Debug.Assert(CentralDirectoryBlock.FileExists(zipFileName)); // it must be in the central directory - - // construct Block find it and parse it - ZipIOLocalFileBlock localFileBlock = ZipIOLocalFileBlock.SeekableLoad(this, zipFileName); - - MapBlock(localFileBlock); - return localFileBlock; - } - - internal void RemoveLocalFileBlock(ZipIOLocalFileBlock localFileBlock) - { - CheckDisposed(); - - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - Debug.Assert(localFileBlock != null, " At this point local File block must be preloaded"); - Debug.Assert(CentralDirectoryBlock.FileExists(localFileBlock.FileName), - " At this point local File block must be mapped in central directory"); - - - // remove it from our list - _blockList.Remove(localFileBlock); - - // remove this from Central Directory - CentralDirectoryBlock.RemoveFileBlock(localFileBlock.FileName); - DirtyFlag = true; - - // at this point we can Dispose it to make sure that any calls - // to this file block through outstanding indirect references will result in object Disposed exception - localFileBlock.Dispose(); - } - - internal void MoveData(long moveBlockSourceOffset, long moveBlockTargetOffset, long moveBlockSize) - { - Debug.Assert(moveBlockSize >=0); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - if ((moveBlockSize ==0) || (moveBlockSourceOffset == moveBlockTargetOffset)) - { - //trivial empty move case - return; - } - - checked - { - byte[] tempBuffer = new byte [Math.Min(moveBlockSize,0x100000)]; // min(1mb, requested block size) - long bytesMoved = 0; - while(bytesMoved < moveBlockSize) - { - long subBlockSourceOffset; - long subBlockTargetOffset; - int subBlockSize = (int)Math.Min((long)tempBuffer.Length, moveBlockSize - bytesMoved); - - if (moveBlockSourceOffset > moveBlockTargetOffset) - { - subBlockSourceOffset = moveBlockSourceOffset + bytesMoved; - subBlockTargetOffset = moveBlockTargetOffset + bytesMoved; - } - else - { - subBlockSourceOffset = moveBlockSourceOffset + moveBlockSize - bytesMoved - subBlockSize; - subBlockTargetOffset = moveBlockTargetOffset + moveBlockSize - bytesMoved - subBlockSize; - } - - _archiveStream.Seek(subBlockSourceOffset, SeekOrigin.Begin); - int bytesRead = PackagingUtilities.ReliableRead(_archiveStream, tempBuffer, 0, subBlockSize); - - if (bytesRead != subBlockSize) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - _archiveStream.Seek(subBlockTargetOffset, SeekOrigin.Begin); - _archiveStream.Write(tempBuffer, 0, subBlockSize); - - checked{bytesMoved += subBlockSize;} - } - } - } - - /// - /// Save - stream level - /// - /// - /// closing or flushing - internal void SaveStream(ZipIOLocalFileBlock blockRequestingFlush, bool closingFlag) - { - // Prevent recursion when propagating Flush or Disposed to our minions - // because ZipIOFileItemStream.Flush calls us. - if (_propagatingFlushDisposed) - return; - else - _propagatingFlushDisposed = true; // enter first time - - try - { - // redirect depending on our mode - if (_openStreaming) - { - StreamingSaveStream(blockRequestingFlush, closingFlag); - } - else - SaveContainer(false); - } - finally - { - // all done so restore state - _propagatingFlushDisposed = false; - } - } - - /// - /// Save - container level - /// - /// true if closing, false if flushing - internal void Save(bool closingFlag) - { - CheckDisposed(); - - // Prevent recursion when propagating Flush or Disposed to our minions - // because ZipIOFileItemStream.Flush calls us. - if (_propagatingFlushDisposed) - return; - else - _propagatingFlushDisposed = true; // enter first time - - try - { - // redirect depending on our mode - if (_openStreaming) - { - StreamingSaveContainer(closingFlag); - } - else - SaveContainer(closingFlag); - } - finally - { - // all done so restore state - _propagatingFlushDisposed = false; - } - } - - /// - /// Constructor - /// - /// stream we operate on - /// - /// true if we own the stream and are expected to close it when we are disposed - internal ZipIOBlockManager(Stream archiveStream, bool streaming, bool ownStream) - { - Debug.Assert(archiveStream != null); - - _archiveStream = archiveStream; - _openStreaming = streaming; - _ownStream = ownStream; - - if (streaming) - { - // wrap the archive stream in a WriteTimeStream which keeps track of current position - _archiveStream = new WriteTimeStream(_archiveStream); - } - else if (archiveStream.Length > 0) - { - // for non-empty stream we need to map the whole stream into a raw data block - // which helps keep track of shifts and dirty areas - ZipIORawDataFileBlock rawBlock = ZipIORawDataFileBlock.Assign(this, 0, archiveStream.Length); - - _blockList.Add(rawBlock); - } - } - - internal static UInt32 ToMsDosDateTime(DateTime dateTime) - { - UInt32 result = 0; - - result |= (((UInt32)dateTime.Second) /2) & 0x1F; // seconds need to be divided by 2 - // as they stored in 5 bits - result |= (((UInt32)dateTime.Minute) & 0x3F) << 5; - result |= (((UInt32)dateTime.Hour) & 0x1F) << 11; - - result |= (((UInt32)dateTime.Day) & 0x1F) << 16; - result |= (((UInt32)dateTime.Month) & 0xF) << 21; - result |= (((UInt32)(dateTime.Year - 1980)) & 0x7F) << 25; - - return result; - } - - internal static DateTime FromMsDosDateTime(UInt32 dosDateTime) - { - int seconds = (int)((dosDateTime & 0x1F) << 1); // seconds need to be multiplied by 2 - // as they stored in 5 bits - int minutes = (int)((dosDateTime >> 5) & 0x3F); - int hours = (int)((dosDateTime >> 11) & 0x1F); - - int day = (int)((dosDateTime >> 16) & 0x1F); - int month =(int)((dosDateTime >> 21) & 0xF); - int year = (int)(1980 + ((dosDateTime >> 25) & 0x7F)); - - //this will throw if parameters are out of range - return new DateTime(year, month,day,hours,minutes,seconds); - } - - /// - /// This is standard way to normalize Zip File Item names. At this point we only - /// getting rid of the spaces. The Exists calls are responsible or making sure - /// that they check for uniqueness in a case insensitive manner. It is up to the - /// higher levels to add stricter restrictions like URI character set, and so on. - /// - static internal string ValidateNormalizeFileName(string zipFileName) - { - // Validate parameteres - if (zipFileName == null) - { - throw new ArgumentNullException("zipFileName"); - } - - if (zipFileName.Length > ZipIOBlockManager.MaxFileNameSize) - { - throw new ArgumentOutOfRangeException("zipFileName"); - } - - zipFileName = zipFileName.Trim(); - - if (zipFileName.Length < 1)//it must be at least one character - { - throw new ArgumentOutOfRangeException("zipFileName"); - } - - //Based on the Appnote : - // << The path stored should not contain a drive or device letter, or a leading slash. >> - - return zipFileName; - } - - //------------------------------------------------------ - // Internal helper CopyBytes functions for storing data into a byte[] - // it is a similar to a BinaryWriter , but not for streams but ratrher - // for byte[] - // These functiona used in the Extra field parsing, as that functionality is buit - // in terms of byte[] not streams - //------------------------------------------------------ - internal static int CopyBytes(Int16 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(Int16)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static int CopyBytes(Int32 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(Int32)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static int CopyBytes(Int64 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(Int64)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static int CopyBytes(UInt16 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(UInt16)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static int CopyBytes(UInt32 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(UInt32)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static int CopyBytes(UInt64 value, byte[] buffer, int offset) - { - Debug.Assert(checked(buffer.Length-offset) >= sizeof(UInt64)); - - byte[] tempBuffer = BitConverter.GetBytes(value); - Array.Copy(tempBuffer, 0, buffer, offset, tempBuffer.Length); - - return offset + tempBuffer.Length; - } - - internal static UInt64 ConvertToUInt64(UInt32 loverAddressValue, UInt32 higherAddressValue) - { - return checked((UInt64)loverAddressValue + (((UInt64)higherAddressValue) << 32)); - } - - internal static ZipIOVersionNeededToExtract CalcVersionNeededToExtractFromCompression - (CompressionMethodEnum compression) - { - switch (compression) - { - case CompressionMethodEnum.Stored: - return ZipIOVersionNeededToExtract.StoredData; - case CompressionMethodEnum.Deflated: - return ZipIOVersionNeededToExtract.DeflatedData; - default: - throw new NotSupportedException(); // Deflated64 this is OFF - } - } - - - /// - /// This is the common Pre Save notiofication handler for - /// RawDataFile Block and File Item Stream - /// It makes assumption that the overlap generally start coming in at the beginning of a - /// large disk image, so we should only try to cache cache overlaped data in the prefix - /// of the disk block - /// Block can also return a value indicating whether PreSaveNotification should be extended to the blocks that are positioned after - /// it in the Block List. For example, if block has completely handled PreSaveNotification in a way that it cached the whole area that - /// was in danger (of being overwritten) it means that no blocks need to worry about this anymore. After all no 2 blocks should have - /// share on disk buffers. Another scenario is when block can determine that area in danger is positioned before the block's on disk - /// buffers; this means that all blocks that are positioned later in the block list do not need to worry about this PreSaveNotification - /// as their buffers should be positioned even further alone in the file. - /// - internal static PreSaveNotificationScanControlInstruction CommonPreSaveNotificationHandler( - Stream stream, - long offset, long size, - long onDiskOffset, long onDiskSize, - ref SparseMemoryStream cachePrefixStream) - { - checked - { - Debug.Assert(size >=0); - Debug.Assert(offset >=0); - Debug.Assert(onDiskSize >=0); - Debug.Assert(onDiskOffset >=0); - - // trivial request - if (size == 0) - { - // The area being overwritten is of size 0 so there is no need to notify any blocks about this. - return PreSaveNotificationScanControlInstruction.Stop; - } - - if (cachePrefixStream != null) - { - // if we have something in cache prefix buffer we only should check whatever tail data isn't cached - checked{onDiskOffset += cachePrefixStream.Length;} - checked{onDiskSize -= cachePrefixStream.Length;} - Debug.Assert(onDiskSize >=0); - } - - if (onDiskSize == 0) - { - // the raw data block happened to be fully cached - // in this case (onDiskSize==0) can not be used as a reliable indicator of the position of the - // on disk buffer relative to the other; it is just an indicator of an empty buffer which might have a meaningless offset - // that shouldn't be driving any decisions - return PreSaveNotificationScanControlInstruction.Continue; - } - - // we need to first find out if the raw data that isn't cached yet overlaps with any disk space - // that is about to be overriden - long overlapBlockOffset; - long overlapBlockSize; - - PackagingUtilities.CalculateOverlap(onDiskOffset, onDiskSize, - offset, size , - out overlapBlockOffset, out overlapBlockSize); - if (overlapBlockSize <= 0) - { - // No overlap , we can ignore this message. - // In addition to that, if (onDiskOffset > offset) it means that, given the fact that all blocks after - // the current one will have even larger offsets, they couldn't possibly overlap with (offset ,size ) chunk . - return (onDiskOffset > offset) ? - PreSaveNotificationScanControlInstruction.Stop : - PreSaveNotificationScanControlInstruction.Continue; - } - - // at this point we have an overlap, we need to read the data that is overlapped - // and merge it with whatever we already have in cache - // let's figure out the part that isn't cached yet, and needs to be - long blockSizeToCache; - checked - { - blockSizeToCache = overlapBlockOffset + overlapBlockSize - onDiskOffset; - } - Debug.Assert(blockSizeToCache >0); // there must be a non empty block at this point that needs to be cached - - // We need to ensure that we do have a place to store this data - if (cachePrefixStream == null) - { - cachePrefixStream = new SparseMemoryStream(_lowWaterMark, _highWaterMark); - } - else - { - // if we already have some cached prefix data we have to make sure we are - // appending new data tro the tail of the already cached chunk - cachePrefixStream.Seek(0, SeekOrigin.End); - } - - stream.Seek(onDiskOffset, SeekOrigin.Begin); - long bytesCopied = PackagingUtilities.CopyStream(stream, cachePrefixStream, blockSizeToCache, 4096); - - if (bytesCopied != blockSizeToCache) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // if the contdition below is true it means that, given the fact that all blocks after - // the current one will have even larger offsets, they couldn't possibly overlap with (offset ,size ) chunk - return ((onDiskOffset + onDiskSize) >= (offset + size)) ? - PreSaveNotificationScanControlInstruction.Stop : - PreSaveNotificationScanControlInstruction.Continue; - } - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - protected void Dispose(bool disposing) - { - if (disposing) - { - // multiple calls are fine - just ignore them - if (!_disposedFlag) - { - // Prevent recursion into Save() when propagating Flush or Disposed to our minions - // because ZipIOFileItemStream.Flush calls us. - if (_propagatingFlushDisposed) - return; - else - _propagatingFlushDisposed = true; // enter first time - - try - { - try - { - if (_blockList != null) - { - foreach (IZipIOBlock block in _blockList) - { - IDisposable disposableBlock = block as IDisposable; - if (disposableBlock != null) - { - // only some Blocks are disposable, most are not - disposableBlock.Dispose(); - } - } - } - } - finally - { - // If we own the stream, we should close it. - // If not, we cannot even close the binary reader or writer as these close the - // underlying stream on us. - if (_ownStream) - { - if (_binaryReader != null) - { // this one might be null of we have been only writing - _binaryReader.Close(); - } - - if (_binaryWriter != null) - { // this one might be null of we have been only reading - _binaryWriter.Close(); - } - - if (_archiveStream != null) - { - _archiveStream.Close(); - } - } - } - } - finally - { - _blockList = null; - _encoding = null; - _endOfCentralDirectoryBlock = null; - _centralDirectoryBlock = null; - - _disposedFlag = true; - _propagatingFlushDisposed = false; // reset - } - } - } - } - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - /// - /// This property returns the index of CentralDirectoryBlock within _blockList - /// - private int CentralDirectoryBlockIndex - { - get - { - Invariant.Assert(_blockList.Count >= _requiredBlockCount); - Debug.Assert(_centralDirectoryBlock != null - && _endOfCentralDirectoryBlock != null - && _zip64EndOfCentralDirectoryBlock != null - && _zip64EndOfCentralDirectoryLocatorBlock != null); - - // We always have following blocks at the end of the block lists: - // CD, Zip64 EOCD, Zip64 EOCD Locator, and EOCD - // Thus the index of CD can be calculated from the total number of blocks - // and _requiredBlockCount which is 4 - return _blockList.Count - _requiredBlockCount; - } - } - - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - /// - /// Throwes exception if object already Disposed/Closed. - /// - private void CheckDisposed() - { - if (_disposedFlag) - { - throw new ObjectDisposedException(null, SR.Get(SRID.ZipArchiveDisposed)); - } - } - - /// - /// Save - container level - /// - /// true if closing, false if flushing - private void SaveContainer(bool closingFlag) - { - CheckDisposed(); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - - if (!closingFlag && !DirtyFlag) - { - // we are trying to save some cycles in the case of the subsequent Flush calls - // that do not close the container - // if it is being closed DirtyFlag isn't reliable as the Compressed streams carry - // some extra bytes after flushing and only write them out on closing. - return; - } - - // We need a separate cycle to update all the cross block references prior to saving blocks - // specifically the central directory needs "dirty" information from blocks in order to properly - // update it's references, otherwise (if we call UpdateReferences and Save in the same loop) - // information about block shifts will be lost by the time we ask central directory to update it's - // references - - // offset of the first block - long currentOffset = 0; // ZIP64 review type here - foreach (IZipIOBlock currentBlock in _blockList) - { - // move block so it is positioned right after the previous block - currentBlock.Move(currentOffset - currentBlock.Offset); - - // this will update references and as well as other internal structures (size) - // specifically for the FileItemBlock it will flush buffers of - // all the outstanding streams - currentBlock.UpdateReferences(closingFlag); - - //advance current stream position according to the size of the block - checked{currentOffset += currentBlock.Size;} - } - - // save dirty blocks - bool dirtyBlockFound = false; - - int blockListCount = _blockList.Count; - for (int i = 0; i < blockListCount ; i++) - { - IZipIOBlock currentBlock = (IZipIOBlock)_blockList[i]; - - if (currentBlock.GetDirtyFlag(closingFlag)) - { - dirtyBlockFound = true; - - long currentBlockOffset = currentBlock.Offset; - long currentBlockSize = currentBlock.Size; - - if (currentBlockSize > 0) - { - // before saving we need to warn all the blocks that have still some data on disk - // that might be overriden - // second loop must start at the current position of the extrrnal loop - // as all the items before have been saved - for (int j = i + 1; j < blockListCount; j++) - { - // This is an optimization which enabled us to stop going through the - // tail blocks as soon as we find a block that returns a status indicating - // that it took care of the tail of the target area or is positioned after the - // target area. - if (((IZipIOBlock)_blockList[j]).PreSaveNotification(currentBlockOffset, currentBlockSize) == - PreSaveNotificationScanControlInstruction.Stop ) - { - break; - } - } - } - - currentBlock.Save(); // Even if currentBlockSize == 0, call Save to clear DirtyFlag - } - } - - // originally we have had an assert for the case when no changes were made to the file - // but calculated size didn't match the actual stream size. - // As a result of the XPS Viewer dynamically switching streams underneath ZIP IO, we - // need to treat this case as a normal non-dirty scenario. So if nothing changed and - // nothing was written out we shouldn't even validate whether stream underneath - // was modified in any way or not (even such simple modifications as an unexpected - // Stream.Length change). If it was modified by someone we assume that the stream - // owner was aware of it's action. - if (dirtyBlockFound && (Stream.Length > currentOffset)) - { - Stream.SetLength(currentOffset); - } - - Stream.Flush(); - DirtyFlag = false; - } - - /// - /// Streaming version of Save routine - /// - /// true if closing the package - private void StreamingSaveContainer(bool closingFlag) - { - // STREAMING Mode: - // NOTE: _blockList is NOT in offset order except the last four blocks - // (CD, Zip64 EOCD, Zip64 EOCD Locator, and EOCD) - - try - { - // save dirty blocks - long currentOffset = 0; - for (int i = 0; i < _blockList.Count; i++) - { - IZipIOBlock currentBlock = (IZipIOBlock)_blockList[i]; - ZipIOLocalFileBlock localFileBlock = currentBlock as ZipIOLocalFileBlock; - - if (localFileBlock == null) - { - if (closingFlag) - { - // Move block so it is positioned right after the previous block. - // No need for nested loops like in SaveContainer because none of these - // calls can cause a block to move in the Streaming case. - currentBlock.Move(currentOffset - currentBlock.Offset); - currentBlock.UpdateReferences(closingFlag); - if (currentBlock.GetDirtyFlag(closingFlag)) - { - currentBlock.Save(); - } - } - } - else if (currentBlock.GetDirtyFlag(closingFlag)) - { - // no need to call UpdateReferences in streaming mode for regular - // local file blocks because - // we manually emit the local file header and the local file descriptor - localFileBlock.SaveStreaming(closingFlag); - } - checked{currentOffset += currentBlock.Size;} - } - - Stream.Flush(); - } - finally - { - // all done so restore state - _propagatingFlushDisposed = false; - } - } - - /// - /// Flush was called on a ZipIOFileItemStream - /// - /// block that owns the stream that Flush was called on - /// close or dispose - private void StreamingSaveStream(ZipIOLocalFileBlock blockRequestingFlush, bool closingFlag) - { - // STREAMING MODE: - // Flush will do one of two things, depending on the currently open stream: - // 1) If the currently open stream matches the one passed (or none is currently opened) - // then write will occur to the open stream. - // 2) Otherwise, the currently opened stream will be flushed and closed, and the - // given stream will become the currently opened stream - // NOTE: _blockList is NOT in offset order except the last four blocks - // (CD, Zip64 EOCD, Zip64 EOCD Locator, and EOCD) - - // different stream? - if (_streamingCurrentlyOpenStreamBlock != blockRequestingFlush) - { - // need to close the currently opened stream - // unless its our first time through - if (_streamingCurrentlyOpenStreamBlock != null) - { - _streamingCurrentlyOpenStreamBlock.SaveStreaming(true); - } - - // Now make the given stream the new "currently opened stream". - _streamingCurrentlyOpenStreamBlock = blockRequestingFlush; - } - - // this should now be flushable/closable - _streamingCurrentlyOpenStreamBlock.SaveStreaming(closingFlag); - - // if closing - discard the stream because it is now closed - if (closingFlag) - _streamingCurrentlyOpenStreamBlock = null; - } - - private void CreateCentralDirectoryBlock() - { - CheckDisposed(); - Debug.Assert(_zip64EndOfCentralDirectoryBlock != null); - - // It must not be loaded yet - Debug.Assert(!IsCentralDirectoryBlockLoaded); - - // The proper position is just before the Zip64EndOfCentralDirectoryRecord - // Zip64EndOfCentralDirectoryRecord - might be of size 0 (if file is small enough) - int blockPosition = _blockList.IndexOf(Zip64EndOfCentralDirectoryBlock); - Debug.Assert(blockPosition >= 0); - - // construct Block find it and parse it - _centralDirectoryBlock = ZipIOCentralDirectoryBlock.CreateNew(this); - - //ask block manager to insert this this block - InsertBlock(blockPosition , _centralDirectoryBlock); - } - - private void LoadCentralDirectoryBlock() - { - Debug.Assert(_centralDirectoryBlock == null); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - // construct Block find it and parse it - _centralDirectoryBlock = ZipIOCentralDirectoryBlock.SeekableLoad(this); - - //ask block manager to MAP this block - MapBlock(_centralDirectoryBlock); - } - - private void CreateLoadZip64Blocks() - { - CheckDisposed(); - - Debug.Assert ((_zip64EndOfCentralDirectoryBlock == null) && - (_zip64EndOfCentralDirectoryLocatorBlock == null)); - - // determine whether we want to create it or load it - // this check doesn't provide us with a 100% guarantee. - // After discussion we have agreed that this should be sufficient - if (!Streaming && EndOfCentralDirectoryBlock.ContainValuesHintingToPossibilityOfZip64 && - ZipIOZip64EndOfCentralDirectoryLocatorBlock.SniffTheBlockSignature(this)) - { - // attempt to sniff the header of the - LoadZip64EndOfCentralDirectoryLocatorBlock(); - LoadZip64EndOfCentralDirectoryBlock(); - } - else - { - // We delayed validation of some values in End of Central Directory that can give possible - // hints for Zip64; Since there is no Zip64 structure, we need to validate them here - _endOfCentralDirectoryBlock.ValidateZip64TriggerValues(); - - CreateZip64EndOfCentralDirectoryLocatorBlock(); - CreateZip64EndOfCentralDirectoryBlock(); - } - } - - private void CreateZip64EndOfCentralDirectoryBlock() - { - Debug.Assert(_zip64EndOfCentralDirectoryBlock == null); - - // The proper position is just before the Zip64EndOfCentralDirectoryRecordLocator - // Zip64EndOfCentralDirectoryRecord - might be of size 0 (if file is small enough) - int blockPosition = _blockList.IndexOf(Zip64EndOfCentralDirectoryLocatorBlock); - - // construct Block find it and parse it - _zip64EndOfCentralDirectoryBlock = ZipIOZip64EndOfCentralDirectoryBlock.CreateNew(this); - - //ask block manager to insert this this block - InsertBlock(blockPosition, _zip64EndOfCentralDirectoryBlock); - } - - private void LoadZip64EndOfCentralDirectoryBlock() - { - Debug.Assert(_zip64EndOfCentralDirectoryBlock == null); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - // construct Block find it and parse it - _zip64EndOfCentralDirectoryBlock = ZipIOZip64EndOfCentralDirectoryBlock.SeekableLoad(this); - - //ask block manager to insert this this block - MapBlock(_zip64EndOfCentralDirectoryBlock); - } - - private void CreateZip64EndOfCentralDirectoryLocatorBlock() - { - Debug.Assert(_zip64EndOfCentralDirectoryLocatorBlock == null); - - // The proper position is just before the EOCD - int blockPosition = _blockList.IndexOf(EndOfCentralDirectoryBlock); - - // construct Block find it and parse it - _zip64EndOfCentralDirectoryLocatorBlock = ZipIOZip64EndOfCentralDirectoryLocatorBlock.CreateNew(this); - - //ask block manager to MAP this block - InsertBlock(blockPosition, _zip64EndOfCentralDirectoryLocatorBlock); - } - - private void LoadZip64EndOfCentralDirectoryLocatorBlock() - { - Debug.Assert(_zip64EndOfCentralDirectoryLocatorBlock == null); - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - // construct Block find it and parse it - _zip64EndOfCentralDirectoryLocatorBlock = ZipIOZip64EndOfCentralDirectoryLocatorBlock.SeekableLoad(this); - - //ask block manager to MAP this block - MapBlock(_zip64EndOfCentralDirectoryLocatorBlock); - } - - private void MapBlock(IZipIOBlock block) - { - // as we map a block to existing file space it must be not dirty. - Debug.Assert(!block.GetDirtyFlag(true)); // closingFlag==true used as a more conservative option - Debug.Assert(!_openStreaming, "Not legal in Streaming mode"); - - for (int blockIndex = _blockList.Count - 1; blockIndex >= 0; --blockIndex) - { - // if we need to find a RawDataBlock that maps to the target area - ZipIORawDataFileBlock rawBlock = _blockList[blockIndex] as ZipIORawDataFileBlock; - - //check the original loaded RawBlock size / offset against the new block - if ((rawBlock != null) && rawBlock.DiskImageContains(block)) - { - ZipIORawDataFileBlock prefixBlock, suffixBlock; - - //split raw block into prefixRawBlock, SuffixRawBlock - rawBlock.SplitIntoPrefixSuffix(block, out prefixBlock, out suffixBlock); - - _blockList.RemoveAt(blockIndex); // remove the old big raw data block - - // add suffix Raw data block - if (suffixBlock != null) - { - _blockList.Insert(blockIndex, suffixBlock); - } - - // add new mapped block - _blockList.Insert(blockIndex, block); - - // add prefix Raw data block - if (prefixBlock != null) - { - _blockList.Insert(blockIndex, prefixBlock); - } - - return; - } - } - - // we couldn't find a raw data block for mapping this, we can only throw - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - private void InsertBlock(int blockPosition, IZipIOBlock block) - { - // as we are adding a new block it must be dirty unless its size is 0 - Debug.Assert(block.GetDirtyFlag(true) || // closingFlag==true used as a more conservative option - block.Size == 0); - - _blockList.Insert(blockPosition, block); - } - - private void AppendBlock(IZipIOBlock block) - { - // as we are adding a new block it must be dirty unless its size is 0 - Debug.Assert(block.GetDirtyFlag(true) || // closingFlag==true used as a more conservative option - block.Size == 0); - - // CentralDirectory persistence logic relies on the fact that we always add headers in a fashion that - // matches the order of the corresponding file items in the physical archive (currently to the end of the list). - // If this invariant is violated, the corresponding central directory persistence logic must be updated. - _blockList.Add(block); - } - - // this flag is used for Perf reasons, it doesn't carry any additional information that isn't stored somewhere - // else. In order to prevent complex dirty calculations on the sequential flush calls, we are going to keep - // this flag which will be set to true at the end of the flush (or close). This flag will be set from the ZipArchive - // and CrcCalculating entry points that can potentially make our structure dirty. - // This flag is only used for non-streaming cases. In streaming cases we do not believe there is a perf - // penalty of that nature. - private bool _dirtyFlag = false; - - private bool _disposedFlag; - private bool _propagatingFlushDisposed; // if true, we ignore calls back to Save to prevent recursion - private Stream _archiveStream; - private bool _openStreaming; - private bool _ownStream; // true if we own the archive stream - - // Streaming Mode Only: stream that is currently able to write without interfering with other streams - private ZipIOLocalFileBlock _streamingCurrentlyOpenStreamBlock; - - private BinaryReader _binaryReader; - private BinaryWriter _binaryWriter; - - private const int _initialBlockListSize = 50; - private ArrayList _blockList = new ArrayList(_initialBlockListSize); - - private ASCIIEncoding _encoding = new ASCIIEncoding(); - - ZipIOZip64EndOfCentralDirectoryBlock _zip64EndOfCentralDirectoryBlock; - ZipIOZip64EndOfCentralDirectoryLocatorBlock _zip64EndOfCentralDirectoryLocatorBlock; - ZipIOEndOfCentralDirectoryBlock _endOfCentralDirectoryBlock; - ZipIOCentralDirectoryBlock _centralDirectoryBlock; - - private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory - private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk - private const int _requiredBlockCount = 4; // We always have following blocks: CD, Zip64 EOCD, Zip64 EOCD Locator, and EOCD - // This value is used to calculate the index of CD within _blockList - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryBlock.cs deleted file mode 100644 index 291ae7d4b34..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryBlock.cs +++ /dev/null @@ -1,559 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Collections.Specialized; // OrderedDictionary -using System.Globalization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOCentralDirectoryBlock : IZipIOBlock - { - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - // standard IZipIOBlock functionality - public long Offset - { - get - { - return _offset; - } - } - - public long Size - { - get - { - long result = 0; - if (CentralDirectoryDictionary.Count > 0) - { - foreach(ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) - { - checked{result += fileHeader.Size;} - } - -// disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - if (_centralDirectoryDigitalSignature != null) - { - checked{result += _centralDirectoryDigitalSignature.Size;} - } -#endif - } - return result; - } - } - - // This property will only return reliable result if Update is called prior - public bool GetDirtyFlag(bool closingFlag) - { - return _dirtyFlag; - } - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public void Move(long shiftSize) - { - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - _dirtyFlag = true; - Debug.Assert(_offset >=0); - } - } - - public void Save() - { - if (_dirtyFlag) - { - // Central directory is an optional component of the ZIP Archive - // we need to save it if it isn't empty - if (CentralDirectoryDictionary.Count > 0) - { - BinaryWriter writer = _blockManager.BinaryWriter; - - // Emit entries in the same order as the corresponding file items as this - // improves interoperability with tools that expect this convention. - - // Streaming mode must be handled differently - if (_blockManager.Streaming) - { - // In Streaming mode we cannot rely on the order that entries were inserted via AddFiles() - // as files can be closed in different order than they are added. - - // NOTE: Neither ZipIOBlockManager._blockList nor CentralDirectoryDicstionry - // are NOT in offset order - -#if DEBUG - long lastOffset = -1; -#endif - - // collect all file headers in central directory into a local list for sorting - SortedList blockList = new SortedList(CentralDirectoryDictionary.Count); - - // We know that in Streaming mode there can be no RawDataFile blocks in - // the block list. Therefore, we can emit our headers in the order that they - // appear in the block list. - foreach (ZipIOCentralDirectoryFileHeader header in CentralDirectoryDictionary.Values) - { - blockList.Add(header.OffsetOfLocalHeader, header); - } - - // then write out the files headers for central directory in sorted order - foreach (ZipIOCentralDirectoryFileHeader header in blockList.Values) - { - header.Save(writer); -#if DEBUG - Debug.Assert(lastOffset < header.OffsetOfLocalHeader, "Sort order violated"); - lastOffset = header.OffsetOfLocalHeader; -#endif - } - } - else - { - // Non-streaming mode - CentralDirectoryDictionary has correct order. - // Assume correct location if streaming - otherwise explicitly seek. - if (_blockManager.Stream.Position != _offset) - { - // we need to seek - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - } - - // Save the headers in the order they were added as this matches the physical offsets - foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) - { - fileHeader.Save(writer); - } -} - - // disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - //central directory dig sig is optional - if (_centralDirectoryDigitalSignature != null) - { - _centralDirectoryDigitalSignature.Save(writer); - } -#endif - writer.Flush(); - } - - _dirtyFlag = false; - } - } - - public void UpdateReferences(bool closingFlag) - { - // we just need to ask Block Manager for the new Values for each header - // there are 2 distinct cases here - // 1. local file data is mapped . loaded and might have been changed in size and position - // 2. local file data is not loaded and might have been changed only in position (not in size) - - foreach(IZipIOBlock block in _blockManager) - { - ZipIOLocalFileBlock localFileBlock = block as ZipIOLocalFileBlock; - ZipIORawDataFileBlock rawDataFileBlock = block as ZipIORawDataFileBlock; - - if (localFileBlock != null) - { - // this is case 1 data is mapped and loaded, so we only need to find the matching - // Centraldirectory record and update it - Debug.Assert(CentralDirectoryDictionary.Contains(localFileBlock.FileName)); - - ZipIOCentralDirectoryFileHeader centralDirFileHeader = - (ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[localFileBlock.FileName]; - - if (centralDirFileHeader.UpdateIfNeeded(localFileBlock)) - { - //update was required let's mark ourselves as dirty - _dirtyFlag = true; - } - } - //check whether we deal with raw data block and it was moved - else if (rawDataFileBlock != null) - { - long diskImageShift = rawDataFileBlock.DiskImageShift; - if (diskImageShift != 0) - { - //this is case #2 data isn't loaded based on the shift in the RawData Block - // we need to move all overlapping central directory references - foreach (ZipIOCentralDirectoryFileHeader centralDirFileHeader in CentralDirectoryDictionary.Values) - { - // check whether central dir header points into the region of a moved RawDataBlock - if (rawDataFileBlock.DiskImageContains(centralDirFileHeader.OffsetOfLocalHeader)) - { - centralDirFileHeader.MoveReference(diskImageShift); - _dirtyFlag = true; - } - } - } - } - } - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - // we can safely ignore this notification as we do not keep any data - // after parsing on disk. Everything is in memory, it is ok to override - // original Central directory without any additional backups - - // we can also safely state that there is no need to continue the PreSafeNotification loop - // as all the blocks after the central directory (EOCD, Zip64 ....) do not have - // data that is buffered on disk - return PreSaveNotificationScanControlInstruction.Stop; - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - // although Zip 64 supports 64 bit counter for the number of - // entries in the central directory, we have chossen to not - // support those scenarios and stick wit the basic CLR type - // int Collections.Count {get;} - internal int Count - { - get - { - return CentralDirectoryDictionary.Count; - } - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - internal static ZipIOCentralDirectoryBlock SeekableLoad(ZipIOBlockManager blockManager) - { - // get proper values from zip 64 records request will be redirected to the - // regular EOCD if ZIP 64 record wasn't originated from the parsing - - ZipIOZip64EndOfCentralDirectoryBlock zip64EOCD = blockManager.Zip64EndOfCentralDirectoryBlock; - - blockManager.Stream.Seek(zip64EOCD.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); - - ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); - - block.ParseRecord(blockManager.BinaryReader, - zip64EOCD.OffsetOfStartOfCentralDirectory, - zip64EOCD.TotalNumberOfEntriesInTheCentralDirectory, - zip64EOCD.SizeOfCentralDirectory); - - return block; - } - - internal static ZipIOCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) - { - ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); - - block._offset = 0; // it just an initial value, that will be adjusted later - // it doesn't matter whether this offset overlaps anything or not - - block._dirtyFlag = true; - - // this dig sig is optional if we ever wanted to make this record, we would need to call - // ZipIOCentralDirectoryDigitalSignature.CreateNew(); - block._centralDirectoryDigitalSignature = null; - - return block; - } - - // This properrty returns current snapsot which might be out of date - // if there were changes after parsing or last UpdateReferences call - internal bool IsZip64BitRequiredForStoring - { - get - { - // These values are duplicated the EndOfCentralDirectory record - // and if any of them are to big we need to introduce - // Zip64 end of central directory record - // Zip64 end of central directory locator - return (Count >= UInt16.MaxValue) || - (Offset >= UInt32.MaxValue) || - (Size >= UInt32.MaxValue); - } - } - - internal void AddFileBlock(ZipIOLocalFileBlock fileBlock) - { - _dirtyFlag = true; - - ZipIOCentralDirectoryFileHeader fileHeader = - ZipIOCentralDirectoryFileHeader.CreateNew - (_blockManager.Encoding, fileBlock); - - CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); - } - - /// - /// - /// - /// - /// precondition: caller must ensure that fileName exists - internal void RemoveFileBlock(string fileName) - { - _dirtyFlag = true; - - CentralDirectoryDictionary.Remove(fileName); - - if (CentralDirectoryDictionary.Count == 0) - { - // in case of the the last one ,we also need to drop the signature record - _centralDirectoryDigitalSignature = null; - } - } - - internal bool FileExists(string fileName) - { - return CentralDirectoryDictionary.Contains(fileName); - } - - // this function should be used carefully as it returns reference to an object - // that is owned by CentralDirectoryBlock, and should be used by other classes only - // for querying information not for updating it. - internal ZipIOCentralDirectoryFileHeader GetCentralDirectoryFileHeader (string fileName) - { - return ((ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[fileName]); - } - - internal ICollection GetFileNamesCollection() - { - return CentralDirectoryDictionary.Keys; - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private ZipIOCentralDirectoryBlock(ZipIOBlockManager blockManager) - { - _blockManager = blockManager; - } - - /// - /// Compare FileOffsets for LocalFileHeaders - used by Sort() routine in ParseRecord - /// - private class HeaderFileOffsetComparer : IComparer - { - int IComparer.Compare(object o1, object o2) - { - ZipIOCentralDirectoryFileHeader h1 = o1 as ZipIOCentralDirectoryFileHeader; - ZipIOCentralDirectoryFileHeader h2 = o2 as ZipIOCentralDirectoryFileHeader; - Debug.Assert(h1 != null && h2 != null, "HeaderFileOffsetComparer: Comparing the wrong data types"); - - // avoid boxing - don't cast long value to (IComparable) - if (h1.OffsetOfLocalHeader > h2.OffsetOfLocalHeader) - return 1; - else if (h1.OffsetOfLocalHeader < h2.OffsetOfLocalHeader) - return -1; - else - return 0; - } - } - - private void ParseRecord (BinaryReader reader, - long centralDirectoryOffset, - int centralDirectoryCount, - long expectedCentralDirectorySize) - { - if (centralDirectoryCount > 0) - { - // collect all headers into a local array list for sorting - SortedList headerList = new SortedList(centralDirectoryCount); - ZipIOCentralDirectoryFileHeader header; - for (int i = 0; i < centralDirectoryCount; i++) - { - header = ZipIOCentralDirectoryFileHeader.ParseRecord(reader, _blockManager.Encoding); - headerList.Add(header.OffsetOfLocalHeader, header); - } - - if (reader.BaseStream.Position - centralDirectoryOffset > expectedCentralDirectorySize) - { // it looks like a corrupted file, as we have parsed more than central directory supposed to contain - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // then add to the ordered dictionary in sorted order - foreach (ZipIOCentralDirectoryFileHeader fileHeader in headerList.Values) - { - // at this point fileHeader.FileName is normalized using - // the ZipIOBlockManager.ValidateNormalizeFileName - CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); - } - - //load central directory [digital signature] - this has nothing to - // do with OPC digital signing - // this record is optional, and the function might return null - _centralDirectoryDigitalSignature = ZipIOCentralDirectoryDigitalSignature.ParseRecord(reader); - } - - _offset = centralDirectoryOffset; - _dirtyFlag = false; - - Validate(expectedCentralDirectorySize); - } - - private void Validate(long expectedCentralDirectorySize) - { - checked - { - // We only have information about the Compressed data size and the offset of the - // local headers. We do not have information about the size of the local header - // which varies depending on the file name and the extra field records size. - // (Although we do know the expected size of the file name, there is no way to - // predict the extra field size, for example it might have a padding record that we use - // optimize Disk IO for ZIP 64 scenarios). - // We are going to make sure that Blocks do not overlap each other and do not - // overlap Central Directory - - long checkedMark = 0; - - foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) - { - if ((checkedMark == 0) && (fileHeader.OffsetOfLocalHeader != 0)) - { - // first block doesn't start at 0 - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - else if (fileHeader.OffsetOfLocalHeader < checkedMark) - { - // the current block overlaps the previously analyzed block - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // we move the checked mark up by the sum of the compressed size file name size - // and the fixed minimal Local file header size - checkedMark += fileHeader.CompressedSize + - ZipIOLocalFileHeader.FixedMinimalRecordSize + - fileHeader.FileName.Length; - } - - // now we can ensure that that checked mark didn't reach over the start of the Central directory - if (_offset < checkedMark) - { - // the central directory block overlaps the last file block - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - //check the total parsed size of the central directory against value declared in EOCd or ZIP64 EOCD records - if (Size != expectedCentralDirectorySize) - { - // the central directory block overlaps the last file block - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // we should also check ofr presence of gaps between - // Central Directory - // ZIP64 EOCD - // ZIP 64 EOCD locator - // EOCD - // Zip64Eocd and Zip64EocdLocator must be either present or absent together - Debug.Assert(! (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) - ^ - (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size==0)); - - if (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) - { - // no ZIP 64 record - if (_offset + expectedCentralDirectorySize != _blockManager.EndOfCentralDirectoryBlock.Offset) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - else - { - // ZIP 64 records present - if ((_offset + expectedCentralDirectorySize - != _blockManager.Zip64EndOfCentralDirectoryBlock.Offset) || - - (_blockManager.Zip64EndOfCentralDirectoryBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryBlock.Size - != _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset) || - - (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size - != _blockManager.EndOfCentralDirectoryBlock.Offset)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - } - } - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - private IDictionary CentralDirectoryDictionary - { - get - { - if (_centralDirectoryDictionary == null) - { - // StringComparer.Ordinal guarantees ordinal, case-sensitive comparison for both cases. - - // if streaming - order is unimportant for us and we can use the cheaper Hashtable - if (_blockManager.Streaming) - { - // We take our order during Save() from the physical order of the elements of the - // block table in BlockManager. - _centralDirectoryDictionary = new Hashtable(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); - } - else - { - // This ordered dictionary serves two purposes. It allows hash-table lookup by file name - // and it also maintains the physical order of the blocks on disk. Like any OrderedDictionary, - // any of the enumerator, or integer indexer will return the items in the order that they were added. - _centralDirectoryDictionary = new OrderedDictionary(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); - } - } - return _centralDirectoryDictionary; - } - } - - //------------------------------------------------------ - // - // Private Members - // - //------------------------------------------------------ - private const int _centralDirectoryDictionaryInitialSize = 50; - - // used in Parse - private static IComparer _headerOffsetComparer = new HeaderFileOffsetComparer(); - - // This may be a HashTable (Streaming case) or an OrderedDictionary - see private property - // for explanation. - private IDictionary _centralDirectoryDictionary; - - private ZipIOCentralDirectoryDigitalSignature _centralDirectoryDigitalSignature; - - private ZipIOBlockManager _blockManager; - - private long _offset; - private bool _dirtyFlag; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryDigitalSignature.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryDigitalSignature.cs deleted file mode 100644 index 6e352f4e7be..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryDigitalSignature.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// Hisotrical Note: -// Disable creation of signatures and throw on parse if signature found: -// If we encounter archive with encrypted and /or signed data we consider those as -// �invalid OPC packages�. Even in case when client application has never requested -// read/write operations with the encrypted and/or signed area of the archive. Motivations include: -// 1. Security based -// 2. It is inappropriate to silently ignore digital signatures because this may lead to users -// assuming that the signature has been validated when in fact it has not. -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOCentralDirectoryDigitalSignature - { -#if false - internal static ZipIOCentralDirectoryDigitalSignature CreateNew() - { - ZipIOCentralDirectoryDigitalSignature record = new ZipIOCentralDirectoryDigitalSignature (); - - return record; - } -#endif - internal static ZipIOCentralDirectoryDigitalSignature ParseRecord(BinaryReader reader) - { - // this record is optional, so let's check for presence of signature rightaway - - //let's ensure we have at least enough data to cover _fixedMinimalRecordSize bytes of signature - if ((reader.BaseStream.Length - reader.BaseStream.Position) < _fixedMinimalRecordSize) - { - return null; - } - - UInt32 signatureValue = reader.ReadUInt32(); - if (signatureValue != _signatureConstant) - { - return null; - } - - //at this point we can assume that Digital Signature Record is there - // Convention is to throw - throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedSignedArchive)); - -// disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - ZipIOCentralDirectoryDigitalSignature record = new ZipIOCentralDirectoryDigitalSignature (); - - record._signature = signatureValue; - record._sizeOfData = reader.ReadUInt16(); - record._signatureData = reader.ReadBytes(record._sizeOfData ); - - record.Validate(); - - return record; -#endif - } - -// disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - internal void Save(BinaryWriter writer) - { - writer.Write(_signatureConstant); - writer.Write(_sizeOfData); - if (_sizeOfData > 0) - { - writer.Write(_signatureData , 0, _sizeOfData); - } - - writer.Flush(); - } - internal long Size - { - get - { - return _fixedMinimalRecordSize + _sizeOfData; - } - } -#endif - - private ZipIOCentralDirectoryDigitalSignature() - { - } - -// disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - private void Validate () - { - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_sizeOfData != _signatureData.Length) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } -#endif - private const long _fixedMinimalRecordSize = 6; - - private const UInt32 _signatureConstant = 0x05054b50; - -// disable creation/parsing of zip archive digital signatures -#if ArchiveSignaturesEnabled - private UInt16 _sizeOfData; - private UInt32 _signature = _signatureConstant; - private byte[] _signatureData = null; -#endif - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryFileHeader.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryFileHeader.cs deleted file mode 100644 index 1b5fa1d2b0e..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOCentralDirectoryFileHeader.cs +++ /dev/null @@ -1,532 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOCentralDirectoryFileHeader - { - internal static ZipIOCentralDirectoryFileHeader CreateNew(Encoding encoding, ZipIOLocalFileBlock fileBlock) - { - ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); - - // initialize fields that are not duplicated in the local file block(header) - header._fileCommentLength =0; - header._fileComment = null; - header._diskNumberStart = 0; - header._internalFileAttributes = 0; - header._externalFileAttributes = 0; - header._versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; - header._extraField = ZipIOExtraField.CreateNew(false /* no padding */); - - // update the rest of the fields based on the local file header - header.UpdateFromLocalFileBlock(fileBlock); - - return header; - } - - internal static ZipIOCentralDirectoryFileHeader ParseRecord(BinaryReader reader, Encoding encoding) - { - ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); - - header._signature = reader.ReadUInt32(); - header._versionMadeBy = reader.ReadUInt16(); - header._versionNeededToExtract = reader.ReadUInt16(); - header._generalPurposeBitFlag = reader.ReadUInt16(); - header._compressionMethod = reader.ReadUInt16(); - header._lastModFileDateTime = reader.ReadUInt32(); - header._crc32 = reader.ReadUInt32(); - header._compressedSize = reader.ReadUInt32(); - header._uncompressedSize = reader.ReadUInt32(); - header._fileNameLength = reader.ReadUInt16(); - header._extraFieldLength = reader.ReadUInt16(); - header._fileCommentLength = reader.ReadUInt16(); - header._diskNumberStart = reader.ReadUInt16(); - header._internalFileAttributes = reader.ReadUInt16(); - header._externalFileAttributes = reader.ReadUInt32(); - header._relativeOffsetOfLocalHeader = reader.ReadUInt32(); - - header._fileName = reader.ReadBytes(header._fileNameLength); - - // check for the ZIP 64 version and escaped values - ZipIOZip64ExtraFieldUsage zip64extraFieldUsage = ZipIOZip64ExtraFieldUsage.None; - if (header._versionNeededToExtract >= (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat) - { - if (header._compressedSize == UInt32.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize; - } - if (header._uncompressedSize == UInt32.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize; - } - if (header._relativeOffsetOfLocalHeader == UInt32.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader; - } - if (header._diskNumberStart == UInt16.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.DiskNumber; - } - } - - // if the ZIP 64 record is missing the zip64extraFieldUsage value will be ignored - header._extraField = ZipIOExtraField.ParseRecord(reader, - zip64extraFieldUsage, - header._extraFieldLength); - - header._fileComment = reader.ReadBytes(header._fileCommentLength); - - //populate frequently used field with user friendly data representations - header._stringFileName = ZipIOBlockManager.ValidateNormalizeFileName(encoding.GetString(header._fileName)); - - header.Validate(); - - return header; - } - - internal void Save(BinaryWriter writer) - { - writer.Write(_signatureConstant); - writer.Write(_versionMadeBy); - writer.Write(_versionNeededToExtract); - writer.Write(_generalPurposeBitFlag); - writer.Write(_compressionMethod); - writer.Write(_lastModFileDateTime); - writer.Write(_crc32); - writer.Write(_compressedSize); - writer.Write(_uncompressedSize); - writer.Write(_fileNameLength); - writer.Write(_extraField.Size); - writer.Write(_fileCommentLength); - writer.Write(_diskNumberStart); - writer.Write(_internalFileAttributes); - writer.Write(_externalFileAttributes); - writer.Write(_relativeOffsetOfLocalHeader); - - - Debug.Assert(_fileNameLength > 0); // we validate this for both parsing and API entry points - writer.Write(_fileName, 0, _fileNameLength); - - _extraField.Save(writer); - - if (_fileCommentLength > 0) - { - writer.Write(_fileComment , 0, _fileCommentLength); - } - } - - internal bool UpdateIfNeeded(ZipIOLocalFileBlock fileBlock) - { - if (CheckIfUpdateNeeded(fileBlock)) - { - UpdateFromLocalFileBlock(fileBlock); - return true; - } - else - { - return false; - } - } - - internal string FileName - { - get - { - return _stringFileName; - } - // set method if needed will have to update both the _stringFileName and - // _fileName - } - - internal UInt16 VersionNeededToExtract - { - get - { - return _versionNeededToExtract; - } - } - - internal UInt16 GeneralPurposeBitFlag - { - get - { - return _generalPurposeBitFlag; - } - } - - internal CompressionMethodEnum CompressionMethod - { - get - { - // cast is safe because the value is validated in Validate() - return (CompressionMethodEnum)_compressionMethod; - } - } - - internal long Size - { - get - { - return checked(_fixedMinimalRecordSize + _fileNameLength + _extraField.Size + _fileCommentLength); - } - } - - internal long OffsetOfLocalHeader - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) - { - // zip 64 extra field is there - return _extraField.OffsetOfLocalHeader; - } - else - { - // 32 bit case - return _relativeOffsetOfLocalHeader; - } - } - } - - internal long CompressedSize - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0) - { - // zip 64 extra field is there - return _extraField.CompressedSize; - } - else - { - // 32 bit case - return _compressedSize; - } - } - } - - internal long UncompressedSize - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) - { - // zip 64 extra field is there - return _extraField.UncompressedSize; - } - else - { - // 32 bit case - return _uncompressedSize; - } - } - } - - internal UInt32 Crc32 - { - get - { - return _crc32; - } - } - - internal UInt32 DiskNumberStart - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0) - { - // zip 64 extra field is there (32 bit value returned) - return _extraField.DiskNumberOfFileStart; - } - else - { - // 16 bit case - return _diskNumberStart;; - } - } - } - - internal bool FolderFlag - { - get - { - // The upper byte of version made by indicates the compatibility of the file attribute information. - // If the external file attributes are compatible with MS-DOS then this value - // will be zero. - - // lower byte of the external file attribute is the the MS-DOS directory attribute byte - // - // 0x20 5 file has been changed since last backup - // 0x10 4 entry represents a subdirectory XXXXXXXXX - // 0x08 3 entry represents a volume label - // 0x04 2 system file - // 0x02 1 hidden file - // 0x01 0 read-only - - return ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos) - && - ((_externalFileAttributes & 0x10) != 0); - } - } - - internal bool VolumeLabelFlag - { - get - { - // The upper byte of version made by indicates the compatibility of the file attribute information. - // If the external file attributes are compatible with MS-DOS then this value - // will be zero. - - // lower byte of the external file attribute is the the MS-DOS directory attribute byte - // - // 0x20 5 file has been changed since last backup - // 0x10 4 entry represents a subdirectory - // 0x08 3 entry represents a volume label XXXXXXXXX - // 0x04 2 system file - // 0x02 1 hidden file - // 0x01 0 read-only - - return ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos) - && - ((_externalFileAttributes & 0x08) != 0); - } - } - - // this function is called by the Central Dir in order to notify us that - // the appropriate file item was shifted (as detected by the shift in the Raw Data Block) - // holding given file item. - // for us it means that although all the size characteristics are preserved (local file header - // wasn't even parsed if it still in the Raw). But the offset could have changed which - // might result in Zip64 struicture. - internal void MoveReference(long shiftSize) - { - UpdateZip64Structures(CompressedSize, - UncompressedSize, - checked(OffsetOfLocalHeader +shiftSize)); - } - - // this function is sets the sizes into the either 64 or 32 bit structures based on values of the fields - // It used in 2 places by the MoveReference and by the UpdateFromLocalFileBlock - private void UpdateZip64Structures - (long compressedSize, long uncompressedSize, long offset) - { - Debug.Assert((compressedSize >= 0) && (uncompressedSize>=0) && (offset >=0)); - - // according to the appnote central directory extra field might be a mix of any values based on escaping - // we will fully (without disk number) use it every time we are building a ZIP 64 arhichive - // we also trying to stay on the safe side and treeat the boundary case of 32 escape values - // as a zip 64 scenrio - if ((compressedSize >= UInt32.MaxValue) || - (uncompressedSize >= UInt32.MaxValue) || - (offset >= UInt32.MaxValue)) - { - // Zip 64 case - _extraField.CompressedSize = compressedSize; - _extraField.UncompressedSize = uncompressedSize; - _extraField.OffsetOfLocalHeader = offset; - - //set proper escape values - _compressedSize = UInt32.MaxValue; - _uncompressedSize = UInt32.MaxValue; - _relativeOffsetOfLocalHeader = UInt32.MaxValue; - - // update version needed to extract to 4.5 - _versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat; - } - else - { - // 32 bit case - _compressedSize = checked((UInt32)compressedSize); - _uncompressedSize = checked((UInt32)uncompressedSize); - _relativeOffsetOfLocalHeader = checked((UInt32)offset); - - // reset the extra ZIP 64 field to empty - _extraField.Zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None; - - // version needed to extract needs to be recalculated from scratch based on compression - _versionNeededToExtract = (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression - ((CompressionMethodEnum)_compressionMethod); - } - } - - private void UpdateFromLocalFileBlock(ZipIOLocalFileBlock fileBlock) - { - Debug.Assert(DiskNumberStart == 0); - - _signature = _signatureConstant; - _generalPurposeBitFlag = fileBlock.GeneralPurposeBitFlag; - _compressionMethod = (UInt16)fileBlock.CompressionMethod; - _lastModFileDateTime = fileBlock.LastModFileDateTime; - _crc32 = fileBlock.Crc32; - - // file name is easy to copy - _fileNameLength = (UInt16)fileBlock.FileName.Length; // this is safe cast as file name is always validate for size - _fileName = _encoding.GetBytes(fileBlock.FileName); - _stringFileName = fileBlock.FileName; - - // this will properly update the 32 or zip 64 fields - UpdateZip64Structures(fileBlock.CompressedSize, - fileBlock.UncompressedSize, - fileBlock.Offset); - - // Previous instruction may determine that we don't really need 4.5, but we - // want to ensure that the version is identical with what is stored in the local file header. - Debug.Assert(_versionNeededToExtract <= fileBlock.VersionNeededToExtract, "Should never be making this smaller"); - - _versionNeededToExtract = fileBlock.VersionNeededToExtract; - - // These fields are intentionally ignored, as they are not present in the local header - //_fileCommentLength; - //_fileComment; - //_diskNumberStart; - //_internalFileAttributes; - //_externalFileAttributes; - } - - private bool CheckIfUpdateNeeded(ZipIOLocalFileBlock fileBlock) - { - // there is a special case for the _generalPurposeBitFlag.Bit #3 - // it could be set in the local file header indicating streaming - // creation, while it doesn't need to be set in the Central directory - // so having - // (fileBlock.GeneralPurposeBitFlag == 8 && and _generalPurposeBitFlag == 0) - // is a valid case when update is not required - - // let's compare the 3rd bit of the general purpose bit flag - bool localFileHeaderStreamingFlag = (0 != (fileBlock.GeneralPurposeBitFlag & _streamingBitMask)); - bool centralDirStreamingFlag = (0 != (_generalPurposeBitFlag & _streamingBitMask)); - - if (!localFileHeaderStreamingFlag && centralDirStreamingFlag) - { - // the mismatch if local file header in non streaming but the central directory is in streaming mode - // all the other combinations do not require an update and valid as is - // this includes scenario when local file header is in streaming and central dir is not - return true; - } - - Debug.Assert(String.CompareOrdinal(_stringFileName, fileBlock.FileName) == 0); - - return - (_signature != _signatureConstant) || - (_versionNeededToExtract != fileBlock.VersionNeededToExtract) || - (_generalPurposeBitFlag != fileBlock.GeneralPurposeBitFlag) || - (_compressionMethod != (UInt16)fileBlock.CompressionMethod) || - (_crc32 != fileBlock.Crc32) || - (CompressedSize != fileBlock.CompressedSize) || - (UncompressedSize != fileBlock.UncompressedSize) || - (OffsetOfLocalHeader != fileBlock.Offset); - - // These fields are intentionally ignored, as they are not present in the local header - //_fileCommentLength; - //_fileComment; - //_diskNumberStart; - //_internalFileAttributes; - //_externalFileAttributes; - } - - - private ZipIOCentralDirectoryFileHeader(Encoding encoding) - { - _encoding = encoding; - } - - private void Validate () - { - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (DiskNumberStart != 0) - { - throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); - } - - if (_fileNameLength != _fileName.Length) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_extraFieldLength != _extraField.Size) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); - - // if verson is below 4.5 make sure that ZIP 64 extra filed isn't present - // if it is it might be a security concern - if ((_versionNeededToExtract < (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) && - (_extraField.Zip64ExtraFieldUsage != ZipIOZip64ExtraFieldUsage.None)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_fileCommentLength != _fileComment.Length) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((_compressionMethod != (UInt16)CompressionMethodEnum.Stored) && - (_compressionMethod != (UInt16)CompressionMethodEnum.Deflated)) - { - throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); - } - } - - private Encoding _encoding; - private const int _fixedMinimalRecordSize = 46; - - private const byte _constantUpperVersionMadeByMsDos = 0x0; - - private const UInt16 _streamingBitMask = 0x08; // bit #3 - - private const UInt32 _signatureConstant = 0x02014b50; - private UInt32 _signature = _signatureConstant; - - // we expect all variables to be initialized to 0 - private UInt16 _versionMadeBy; - private UInt16 _versionNeededToExtract; - private UInt16 _generalPurposeBitFlag; - private UInt16 _compressionMethod; - private UInt32 _lastModFileDateTime; - private UInt32 _crc32; - private UInt32 _compressedSize; - private UInt32 _uncompressedSize; - private UInt16 _fileNameLength; - private UInt16 _extraFieldLength; - private UInt16 _fileCommentLength; - private UInt16 _diskNumberStart; - private UInt16 _internalFileAttributes; - private UInt32 _externalFileAttributes; - private UInt32 _relativeOffsetOfLocalHeader; - private byte[] _fileName; - private ZipIOExtraField _extraField; - private byte[] _fileComment; - - //duplicate dat for fast access - private string _stringFileName; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOEndOfCentralDirectoryBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOEndOfCentralDirectoryBlock.cs deleted file mode 100644 index 9fcb170e4fa..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOEndOfCentralDirectoryBlock.cs +++ /dev/null @@ -1,443 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.IO.Packaging; // for PackagingUtilities -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOEndOfCentralDirectoryBlock : IZipIOBlock - { - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - // standard IZipIOBlock functionality - public long Offset - { - get - { - return _offset; - } - } - - public long Size - { - get - { - return _fixedMinimalRecordSize + _zipFileCommentLength; - } - } - - public bool GetDirtyFlag(bool closingFlag) - { - return _dirtyFlag; - } - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public void Move(long shiftSize) - { - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - _dirtyFlag = true; - Debug.Assert(_offset >=0); - } - } - - public void Save() - { - if (GetDirtyFlag(true)) - { - BinaryWriter writer = _blockManager.BinaryWriter; - - // never seek in streaming mode - if (!_blockManager.Streaming && _blockManager.Stream.Position != _offset) - { - // we need to seek - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - } - - writer.Write(_signatureConstant); - writer.Write(_numberOfThisDisk); - writer.Write(_numberOfTheDiskWithTheStartOfTheCentralDirectory); - writer.Write(_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk); - writer.Write(_totalNumberOfEntriesInTheCentralDirectory); - writer.Write(_sizeOfTheCentralDirectory); - writer.Write(_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber); - writer.Write(_zipFileCommentLength); - if (_zipFileCommentLength > 0) - { - writer.Write(_zipFileComment, 0, _zipFileCommentLength); - } - writer.Flush(); - - _dirtyFlag = false; - } - } - - public void UpdateReferences(bool closingFlag) - { - // check whether Central directory is loaded and update references accordingly - // if one or more of the following conditions are true - // 1. Central Directory is dirty - // 2. Zip64 End of Central Directory is dirty - // 3. Zip64 End of Central Directory Locator is dirty - // 4. streaming mode - // if Central Directory isn't loded or none of the relevant structure is dirty, - // there is nothing to update for End Of Central directory record - if (_blockManager.IsCentralDirectoryBlockLoaded - && (_blockManager.Streaming - || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag) - || _blockManager.Zip64EndOfCentralDirectoryBlock.GetDirtyFlag(closingFlag) - || _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.GetDirtyFlag(closingFlag))) - { - // intialize them to zIP64 case, and update them if needed - UInt16 centralDirCount = UInt16.MaxValue; - UInt32 centralDirBlockSize = UInt32.MaxValue; - UInt32 centralDirOffset = UInt32.MaxValue; - UInt16 numberOfTheDiskWithTheStartOfTheCentralDirectory = 0; - UInt16 numberOfThisDisk = 0; - - - // If we don't need Zip 64 struture - if (!_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) - { - // if it isn't zip 64 let's get the data out - centralDirCount = (UInt16)_blockManager.CentralDirectoryBlock.Count; - centralDirBlockSize = (UInt32)_blockManager.CentralDirectoryBlock.Size; - centralDirOffset = (UInt32)_blockManager.CentralDirectoryBlock.Offset; - } - - // update value and mark record dirty if either it is already dirty or there is a mismatch - if ((_dirtyFlag) || - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != centralDirCount) || - (_totalNumberOfEntriesInTheCentralDirectory != centralDirCount ) || - (_sizeOfTheCentralDirectory != centralDirBlockSize) || - (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber != centralDirOffset) || - (_numberOfTheDiskWithTheStartOfTheCentralDirectory != numberOfTheDiskWithTheStartOfTheCentralDirectory) || - (_numberOfThisDisk != numberOfThisDisk)) - { - _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = centralDirCount; - _totalNumberOfEntriesInTheCentralDirectory = centralDirCount; - _sizeOfTheCentralDirectory = centralDirBlockSize; - _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = centralDirOffset; - _numberOfTheDiskWithTheStartOfTheCentralDirectory = numberOfTheDiskWithTheStartOfTheCentralDirectory; - _numberOfThisDisk = numberOfThisDisk; - - _dirtyFlag = true; - } - } - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - // we can safely ignore this notification as we do not keep any data - // after parsing on disk. Everything is in memory, it is ok to override - // original End of Central directory without any additional backups - - // we can also safely state that there is no need to continue the PreSafeNotification loop - // as there shouldn't be any blocks after the EOCD - return PreSaveNotificationScanControlInstruction.Stop; - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - internal static ZipIOEndOfCentralDirectoryBlock SeekableLoad (ZipIOBlockManager blockManager) - { - // perform custom serach for record - long blockPosition = FindPosition(blockManager.Stream); - blockManager.Stream.Seek(blockPosition, SeekOrigin.Begin); - - ZipIOEndOfCentralDirectoryBlock block = new ZipIOEndOfCentralDirectoryBlock(blockManager); - - block.ParseRecord(blockManager.BinaryReader, blockPosition); - return block; - } - - internal static ZipIOEndOfCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager, long offset) - { - ZipIOEndOfCentralDirectoryBlock block = new ZipIOEndOfCentralDirectoryBlock(blockManager); - - block._offset = offset; - block._dirtyFlag = true; - - return block; - } - - internal void ValidateZip64TriggerValues() - { - if ((_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber > _offset) - || - ((_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == _offset) && - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk > 0))) - { - // central directory must start prior to the offset of the end of central directory. - // the only exception is when size of the central directory is 0 - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((_numberOfThisDisk != 0) || - (_numberOfTheDiskWithTheStartOfTheCentralDirectory != 0) || - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != - _totalNumberOfEntriesInTheCentralDirectory)) - { - throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); - } - } - - internal uint NumberOfThisDisk - { - get - { - return _numberOfThisDisk; - } - } - - internal uint NumberOfTheDiskWithTheStartOfTheCentralDirectory - { - get - { - return _numberOfTheDiskWithTheStartOfTheCentralDirectory; - } - } - - internal uint TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk - { - get - { - return _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk ; - } - } - - internal uint TotalNumberOfEntriesInTheCentralDirectory - { - get - { - return _totalNumberOfEntriesInTheCentralDirectory; - } - } - - internal uint SizeOfTheCentralDirectory - { - get - { - return _sizeOfTheCentralDirectory; - } - } - - internal uint OffsetOfStartOfCentralDirectory - { - get - { - return _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; - } - } -#if false - internal string Comment - { - get - { - return _stringZipFileComment; - } - } -#endif - - internal bool ContainValuesHintingToPossibilityOfZip64 - { - get - { - return ((_numberOfThisDisk == UInt16.MaxValue) || - (_numberOfTheDiskWithTheStartOfTheCentralDirectory == UInt16.MaxValue) || - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk == UInt16.MaxValue) || - (_totalNumberOfEntriesInTheCentralDirectory == UInt16.MaxValue) || - (_sizeOfTheCentralDirectory == UInt32.MaxValue) || - (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == UInt32.MaxValue)); - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private ZipIOEndOfCentralDirectoryBlock(ZipIOBlockManager blockManager) - { - Debug.Assert(blockManager != null); - _blockManager= blockManager; - } - - private static long FindPosition(Stream archiveStream) - { - Debug.Assert(archiveStream.CanSeek); - byte [] buffer = new byte[_scanBlockSize + _fixedMinimalRecordSize]; - long streamLength = archiveStream.Length; - - for(long endPos = streamLength; endPos > 0; endPos -= _scanBlockSize) - { - // calculate offset position of the block to be read based on the end - // Position loop variable - long beginPos = Math.Max(0, endPos -_scanBlockSize); - - //read the block - archiveStream.Seek(beginPos, SeekOrigin.Begin); - - // the reads that we do actually overlap each other by the size == _fixedMinimalRecordSize - // this is done in order to simplify our searching logic, this way we do not need to specially - // process matches that cross buffer boundaries, as we are guaranteed that if match is present - // it falls completely inside one of the buffers, as a result of overlapping in the read requests - int bytesRead = PackagingUtilities.ReliableRead(archiveStream, buffer, 0, buffer.Length); - - // We need to pass this parameter into the function, so it knows - // the relative positon of the buffer in regard to the end of the stream; - // it needs this info in order to checke whether the candidate record - // has length of Comment field consistent with the postion of the record - long distanceFromStartOfBufferToTheEndOfStream = streamLength -beginPos; - for(int i = bytesRead - _fixedMinimalRecordSize; i>=0; i--) - { - if (IsPositionMatched(i, buffer, distanceFromStartOfBufferToTheEndOfStream)) - { - return beginPos + i; - } - } - } - - // At this point we have finished scanning the file and haven't find anything - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - - private static bool IsPositionMatched (int pos, byte[] buffer, long bufferOffsetFromEndOfStream) - { - Debug.Assert(buffer != null); - - Debug.Assert(buffer.Length >= _fixedMinimalRecordSize); // the end of central directory record must fit in there - - Debug.Assert(pos <= buffer.Length - _fixedMinimalRecordSize); // enough space to fit the record after pos - - Debug.Assert(bufferOffsetFromEndOfStream >= _fixedMinimalRecordSize); // there is no reason to start searching for the record - // after less than 22 byrtes left till the end of stream - - for(int i = 0; i<_signatureBuffer.Length; i++) - { - if (_signatureBuffer[i] != buffer[pos+i]) - { - //signature mismatch - return false; - } - } - - //we got signature matching, let's see if we can get comment length to match - // to handle little endian order of the bytes in the 16 bit length - long commentLengthFromRecord = buffer[pos + _fixedMinimalRecordSize-2] + - (buffer[pos + _fixedMinimalRecordSize-1] << 8); - - long commentLengthFromPos = bufferOffsetFromEndOfStream - pos - _fixedMinimalRecordSize; - if (commentLengthFromPos != commentLengthFromRecord) - { - return false; - } - - return true; - } - - private void ParseRecord (BinaryReader reader, long position) - { - _signature = reader.ReadUInt32(); - _numberOfThisDisk = reader.ReadUInt16(); - _numberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt16(); - _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = reader.ReadUInt16(); - _totalNumberOfEntriesInTheCentralDirectory = reader.ReadUInt16(); - _sizeOfTheCentralDirectory = reader.ReadUInt32(); - _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt32(); - _zipFileCommentLength = reader.ReadUInt16(); - _zipFileComment = reader.ReadBytes(_zipFileCommentLength); - - _stringZipFileComment = _blockManager.Encoding.GetString(_zipFileComment); - - _offset = position; - - _dirtyFlag = false; - - Validate(); - } - - // Do minimum validatation here - // The rest of validation on the fields that can indicate the possiblity of Zip64 will be validated later - // If there is the zip64 End of Central Directory, thoses values will be valided - // by ZipIO64EndOfCentralDirectoryBlock - // Otherwise it will be validated in ZipIoBlockManager when it tries load ZipIO64EndOfCentralDirectoryBlock - // In all of the supported scenarios we always try to load ZipIO64EndOfCentralDirectoryBlock immediately - // after it loads ZipIOEndOfCentralDirectoryBlock; so there is not much difference in the timing of - // the validation - private void Validate() - { - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_zipFileCommentLength != _zipFileComment.Length) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - - //------------------------------------------------------ - // - // Private Members - // - //------------------------------------------------------ - // constant that is used for locating EndOf record signature - private static byte [] _signatureBuffer = new byte[] {0x50, 0x4b, 0x05, 0x06}; - - // this blocks size is used to read data thro the tail of stream block by block - private static int _scanBlockSize = 0x01000; - - private ZipIOBlockManager _blockManager; - - private long _offset; - private bool _dirtyFlag; - - private const UInt32 _signatureConstant = 0x06054b50; - private const int _fixedMinimalRecordSize = 22; - - // data persisted on disk - private UInt32 _signature = _signatureConstant; - private UInt16 _numberOfThisDisk; - private UInt16 _numberOfTheDiskWithTheStartOfTheCentralDirectory; - private UInt16 _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk; - private UInt16 _totalNumberOfEntriesInTheCentralDirectory; - private UInt32 _sizeOfTheCentralDirectory; - private UInt32 _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; - private UInt16 _zipFileCommentLength; - private byte[] _zipFileComment; - private string _stringZipFileComment; - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraField.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraField.cs deleted file mode 100644 index ca199534b68..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraField.cs +++ /dev/null @@ -1,307 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that is used to implement parsing and -// of the extra field optionally present in the fileHeader and Central Dir -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Globalization; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOExtraField - { - internal static ZipIOExtraField CreateNew(bool createPadding) - { - // we have been asked to create a new record, current zip io implementation will add at most one Zip64 block - ZipIOExtraField extraField = new ZipIOExtraField(); - - extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); - - if (createPadding) - { - extraField._paddingElement = ZipIOExtraFieldPaddingElement.CreateNew(); - } - - return extraField; - } - - internal static ZipIOExtraField ParseRecord(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage, ushort expectedExtraFieldSize) - { - // most of the files are not ZIP 64, and instead of trying to parse it we should create new empty record - if (expectedExtraFieldSize == 0) - { - if (zip64extraFieldUsage != ZipIOZip64ExtraFieldUsage.None) - { - // in case there is an expectation by the caller for a non empty record we should throw - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // We are creating Extra Fields for the existing Local File Header, - // so no need to create a new padding field - return CreateNew(false); - } - - ZipIOExtraField extraField = new ZipIOExtraField(); - - // Parse all Extra elements from Extra Field - while (expectedExtraFieldSize > 0) - { - if (expectedExtraFieldSize < ZipIOExtraFieldElement.MinimumSize) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - ZipIOExtraFieldElement newElement = ZipIOExtraFieldElement.Parse(reader, zip64extraFieldUsage); - ZipIOExtraFieldZip64Element zip64Element = newElement as ZipIOExtraFieldZip64Element; - ZipIOExtraFieldPaddingElement paddingElement = newElement as ZipIOExtraFieldPaddingElement; - - // if we have found the Zip 64 record. let's remember it - if (zip64Element != null) - { - if (extraField._zip64Element != null) - { - // multiple ZIP 64 extra fields are not allowed - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - extraField._zip64Element = zip64Element; - } - else if (paddingElement != null) - { - if (extraField._paddingElement != null) - { - // multiple padding extra fields are not allowed - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - extraField._paddingElement = paddingElement; - } - else - { - if (extraField._extraFieldElements == null) - extraField._extraFieldElements = new ArrayList(3); // we expect to see a few records there, as it sould have been produced by other authoring systems. - - // any other instances of extra fields with the same id are allowed - extraField._extraFieldElements.Add(newElement); - } - - checked { expectedExtraFieldSize -= newElement.Size; } - } - - // if we didn't end up at the exact expected position, we are treating this as a corrupted file - if (expectedExtraFieldSize != 0) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // As we treat the ZIP 64 extra field as optional for all version >= 4.5 - // we need to explicitly consider a case when it is missing - if (extraField._zip64Element == null) - { - extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); - } - - ///////////////////////////////////////////////////////////////////// - // extraField.Validate(); - // an instance Validate function is removed to fix FxCop violation, please add it back - // if extra validation steps are required - // - // we are checking for uniqueness of the Zip 64 header ID in the Parse function. - // Although it might be a good idea to check for record id uniqueness in general, - // we are treating the rest of the field as a bag of bits, so it is probably not worth it to - // search for other duplicate ID especially as appnote considers ID duplication a possibility - // and even suggest a work around for file producers. - ///////////////////////////////////////////////////////////////////// - - return extraField; - } - - internal void Save(BinaryWriter writer) - { - // write Out the Zip 64 extra field first - if (_zip64Element.SizeField > 0) - { - _zip64Element.Save(writer); - } - - // write Out the padding field - if (_paddingElement != null) - { - _paddingElement.Save(writer); - } - - if (_extraFieldElements != null) - { - foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements) - { - extraFieldElement.Save(writer); - } - } - } - - // Add or remove padding for the given size change - internal void UpdatePadding(long size) - { - // If the local file header changed more than 100 bytes, it means - // there are some logical errors - Debug.Assert(Math.Abs(size) <= 100); - - // The header size change should be no more than what we can hold in UInt16 - if (Math.Abs(size) > UInt16.MaxValue) - return; - - // Header size increased; need to remove padding if there is an existing padding structure - if (size > 0 && _paddingElement != null) - { - // There is enough padding left over to do size adjustment - // No need to use checked{} since _paddingElement.PaddingSize >= size - if (_paddingElement.PaddingSize >= size) - _paddingElement.PaddingSize -= (UInt16) size; - // The size of the whole padding structure exactly matches the size change - else if (_paddingElement.Size == size) - { - // Then the padding structure can be completely removed - // to accommodate the size change - _paddingElement = null; - } - - return; - } - - // Header size decreased; need to add padding - if (size < 0) - { - // Padding structure is not there but, the size change is big enough for one - // to be created - if (_paddingElement == null) - { - // No need to use checked{} since size is long type - // and size < 0 - // and (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize + ZipIOExtraFieldElement.MinimumSize) - // is small number that can not cause the overflow - size += (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize - + ZipIOExtraFieldElement.MinimumSize); - - if (size >= 0) - { - _paddingElement = new ZipIOExtraFieldPaddingElement(); - // No need to use checked{} since size > 0 and less than UInt16.MaxValue - _paddingElement.PaddingSize = (UInt16) size; - } - } - else - { - // Check if we hit the max padding allowed - if ((_paddingElement.PaddingSize - size) > UInt16.MaxValue) - return; - - // No need to use checked{} since we already check the overflow - _paddingElement.PaddingSize = (UInt16) (_paddingElement.PaddingSize - size); - } - } - } - - internal UInt16 Size - { - get - { - UInt16 size = 0; - - if (_extraFieldElements != null) - { - foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements) - { - checked{size += extraFieldElement.Size;} - } - } - - checked{size += _zip64Element.Size;} - - if (_paddingElement != null) - { - checked { size += _paddingElement.Size; } - } - - return size; - } - } - - - internal ZipIOZip64ExtraFieldUsage Zip64ExtraFieldUsage - { - get - { - return _zip64Element.Zip64ExtraFieldUsage; - } - set - { - _zip64Element.Zip64ExtraFieldUsage = value; - } - } - - internal UInt32 DiskNumberOfFileStart - { - get - { - return _zip64Element.DiskNumber; - } - } - - internal long OffsetOfLocalHeader - { - get - { - return _zip64Element.OffsetOfLocalHeader; - } - set - { - _zip64Element.OffsetOfLocalHeader = value; - } - } - - internal long CompressedSize - { - get - { - return _zip64Element.CompressedSize; - } - set - { - _zip64Element.CompressedSize = value; - } - } - - internal long UncompressedSize - { - get - { - return _zip64Element.UncompressedSize; - } - set - { - _zip64Element.UncompressedSize = value; - } - } - - private ZipIOExtraField() - { - } - - private ArrayList _extraFieldElements; - private ZipIOExtraFieldZip64Element _zip64Element; - private ZipIOExtraFieldPaddingElement _paddingElement; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldElement.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldElement.cs deleted file mode 100644 index e5ed8f799de..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldElement.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that is used to implement parsing and editing of a generic extra field structure. -// It doesn't contain informaton about any specific (like Zip64) extra fields that are supported by -// this implementation. In order to isolate this from IO and streams, it deals with the data in the Byte[] form - - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Globalization; -using System.Runtime.Serialization; -using System.Windows; - -using MS.Internal.IO.Packaging; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - /// - /// This is an internal class that is used to implement parsing and editing of generic extra field structures. - /// It doesn't contain informaton about any specific (like Zip64) extra fields that are supported by - /// this implementation. In order to isolate this from IO and streams, it deals with the data in the Byte[] form - /// - internal class ZipIOExtraFieldElement - { - internal static ZipIOExtraFieldElement Parse(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage) - { - // we can safely parse the Id and Size here - // since the minimum size is checked from the caller (ZipIoExtraField) - UInt16 id = reader.ReadUInt16(); - UInt16 size = reader.ReadUInt16(); - - ZipIOExtraFieldElement newElement; - - if (id == ZipIOExtraFieldZip64Element.ConstantFieldId) // Found Zip64 Extra Field element - { - newElement = new ZipIOExtraFieldZip64Element(); - ((ZipIOExtraFieldZip64Element) newElement).Zip64ExtraFieldUsage = zip64extraFieldUsage; - } - else if (id == ZipIOExtraFieldPaddingElement.ConstantFieldId) // Found potential Padding Extra Field element - { - // Even if the id matches Padding Extra Element id, we cannot be sure if it is Microsoft defined one - // until its signature is verified - - // This extra field matches Padding Extra Element id, but it is not big enough to be ours - if (size < ZipIOExtraFieldPaddingElement.MinimumFieldDataSize) - { - // Treat it as an unknown Extra Field element - newElement = new ZipIOExtraFieldElement(id); - } - else - { - // Sniff bytes to check it it matches our Padding extra field signature - byte[] sniffedBytes = reader.ReadBytes(ZipIOExtraFieldPaddingElement.SignatureSize); - if (ZipIOExtraFieldPaddingElement.MatchesPaddingSignature(sniffedBytes)) - { - // Signature matches the Padding Extra Field signature - newElement = new ZipIOExtraFieldPaddingElement(); - } - else - { - // Signature doesn't match; treat it a an unknown Extra Field element - newElement = new ZipIOExtraFieldElement(id, sniffedBytes); - } - } - } - else - { - newElement = new ZipIOExtraFieldElement(id); - } - - // Parse the data field of the Extra Field element - newElement.ParseDataField(reader, size); - - return newElement; - } - - internal virtual void ParseDataField(BinaryReader reader, UInt16 size) - { - if (_data == null) - { - _data = reader.ReadBytes(size); - - //vaiadte that we didn't reach the end of stream too early - if (_data.Length != size) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - else // There were some data we sniffed already - { - Byte[] tempBuffer = _data; - _data = new Byte[size]; - - Array.Copy(tempBuffer, _data, _size); // _size contains the size of data in _data - - checked - { - Debug.Assert(size >= _size); - - if ((PackagingUtilities.ReliableRead(reader, _data, _size, size - _size) + _size) != size) - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - _size = size; - } - - internal virtual void Save(BinaryWriter writer) - { - Debug.Assert(_size == _data.Length); - - writer.Write(_id); - writer.Write(_size); - writer.Write(_data); - } - - // This property calculates the value of the size record whch holds the size without the Id and without the size itself. - // we are alkways guranteed that Size == SizeField + 2 * sizeof(UInt16)) - internal virtual UInt16 SizeField - { - get - { - return _size; - } - } - - // this fiels needs to be used very carefully as it retuns a writeble array - // element of which could be potentially modifyed by the caller - internal virtual byte[] DataField - { - get - { - return _data; - } - } - - // This property calculates size of the field on disk (how many bytes need to be allocated on the disk) - internal virtual UInt16 Size - { - get - { - return checked((UInt16) (_size + _minimumSize)); // the real field size has 2 UInt16 fields for Id and size - } - } - - // Minimum size of any type of Extra Field Element - // UInt16 id - // UInt16 size - internal static UInt16 MinimumSize - { - get - { - return _minimumSize; - } - } - - //------------------------------------------------------ - // - // Private Constructor - // - //------------------------------------------------------ - internal ZipIOExtraFieldElement(UInt16 id) - { - _id = id; - } - - // data: sniffied data field - private ZipIOExtraFieldElement(UInt16 id, byte[] data) - { - Debug.Assert(data != null); - - _id = id; - _data = data; - _size = checked((UInt16) data.Length); - } - - //------------------------------------------------------ - // - // Private fields - // - //------------------------------------------------------ - private UInt16 _id; - private UInt16 _size; - private byte[] _data; - - // UInt16 id: 2 - // UInt16 size: 2 - private static readonly UInt16 _minimumSize = (UInt16) (2 * sizeof(UInt16)); - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldPaddingElement.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldPaddingElement.cs deleted file mode 100644 index d5e78e67f64..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldPaddingElement.cs +++ /dev/null @@ -1,192 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that is used to implement parsing and editing of a padding extra field -// structure. This extra field is used to optimize the performance dealing with Zip64 extra field. -// When we need to create Zip64 extra field the extra padding bytes are used to create such -// structure so that the subsequent bytes don't have to be moved. - - -using System; -using System.Diagnostics; -using System.IO; -using System.Windows; - -namespace MS.Internal.IO.Zip -{ - /// - /// This class is used to represent and parse the Padding Extra Field - /// - /// The Padding Extra Field is defined as: - /// Header ID UInt16 (2 bytes) 0xA220 - /// Length of the field UInt16 (2 bytes) - /// Signature UInt16 (2 bytes) 0xA028 (for verification) - /// Padding Initial Value UInt16 (2 bytes) Padding size originally requested by the caller - /// Padding ? bytes Padding respresented by null characters - /// - internal class ZipIOExtraFieldPaddingElement : ZipIOExtraFieldElement - { - // creates a brand new empty Padding extra field element - internal static ZipIOExtraFieldPaddingElement CreateNew() - { - ZipIOExtraFieldPaddingElement newElement = new ZipIOExtraFieldPaddingElement(); - - return newElement; - } - - // parse Padding extra field element - internal override void ParseDataField(BinaryReader reader, UInt16 size) - { - // The signature is already read and validated - Debug.Assert(size >= MinimumSize); - - // It is guaranteed that there is enough bytes to read in UInt16 - // since it is already checked from ZipIOExtraFieldElement.Parse() - _initialRequestedPaddingSize = reader.ReadUInt16(); - - // need to subtract the size of the signature and size fields - // We don't need to use checked{} since size is guaranteed to be bigger than - // MinimumFieldDataSize by the called (ZipIOExtraFieldElement.Parse) - size -= _minimumFieldDataSize; - - _paddingSize = size; - - // Skip the padding - if (_paddingSize != 0) - { - reader.BaseStream.Seek(size, SeekOrigin.Current); - } - } - - internal static bool MatchesPaddingSignature(byte[] sniffiedBytes) - { - if (sniffiedBytes.Length < _signatureSize) - { - return false; - } - - Debug.Assert(sniffiedBytes.Length == _signatureSize); - - if (BitConverter.ToUInt16(sniffiedBytes, 0) != _signature) - { - return false; - } - - return true; - } - - internal override void Save(BinaryWriter writer) - { - writer.Write(_constantFieldId); - writer.Write(SizeField); - writer.Write(_signature); - writer.Write(_initialRequestedPaddingSize); - - for (int i = 0; i < _paddingSize; ++i) - { - writer.Write((byte) 0); - } - } - - // This property calculates size of the field on disk (how many bytes need to be allocated on the disk) - // id + size field + data field (SizeField) - internal override UInt16 Size - { - get - { - return checked((UInt16) (SizeField + MinimumSize)); - } - } - - // This property calculates the value of the size record whch holds the size without the Id and without the size itself. - // we are always guranteed that Size == SizeField + 2 * sizeof(UInt16)) - internal override UInt16 SizeField - { - get - { - return checked((UInt16) (_minimumFieldDataSize + _paddingSize)); - } - } - - static internal UInt16 ConstantFieldId - { - get - { - return _constantFieldId; - } - } - - static internal UInt16 MinimumFieldDataSize - { - get - { - return _minimumFieldDataSize; - } - } - - static internal UInt16 SignatureSize - { - get - { - return _signatureSize; - } - } - - internal UInt16 PaddingSize - { - get - { - return _paddingSize; - } - set - { - _paddingSize = value; - } - } - - //------------------------------------------------------ - // - // Private Constructor - // - //------------------------------------------------------ - internal ZipIOExtraFieldPaddingElement() : base(_constantFieldId) - { - _initialRequestedPaddingSize = _newInitialPaddingSize; - _paddingSize = _initialRequestedPaddingSize; - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - //------------------------------------------------------ - // - // Private fields - // - //------------------------------------------------------ - private const UInt16 _constantFieldId = 0xA220; - private const UInt16 _signature = 0xA028; - // 20 is the maximum size of Zip64 Extra Field element we can use for Local File Header - // (Id, Size, Compressed and UnCompressed Sizes; 2 + 2 + 8 + 8 = 20) - // DiskNumber and Relative Offset of Local File Header is not counted since we don't use - // it in Local File Header - private const UInt16 _newInitialPaddingSize = 20; - - // UInt16 signature - // UInt16 initial requested padding size - private static readonly UInt16 _minimumFieldDataSize = 2 * sizeof(UInt16); - private static readonly UInt16 _signatureSize = sizeof(UInt16); - - private UInt16 _paddingSize; - private UInt16 _initialRequestedPaddingSize; - } -} - - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldZip64Element.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldZip64Element.cs deleted file mode 100644 index be37b8ac579..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOExtraFieldZip64Element.cs +++ /dev/null @@ -1,338 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that helps managing/parsing the -// ZIP64 Extended Information Extra Field (0x0001): for OPC scenarios -// In order to isolate this from IO and streams, it deals with the data in the Byte[] form -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal enum ZipIOZip64ExtraFieldUsage - { - None = 0, - UncompressedSize = 1, - CompressedSize = 2, - OffsetOfLocalHeader = 4, - DiskNumber = 8, - } - - /// - /// This class is used to represent and parse the the - /// ZIP64 Extended Information Extra Field (0x0001) - /// In order to isolate this from IO and streams it deals with the data in the Byte[] form - /// - internal class ZipIOExtraFieldZip64Element : ZipIOExtraFieldElement - { - // creates brand new empty ZIP 64 extra field element - internal static ZipIOExtraFieldZip64Element CreateNew() - { - ZipIOExtraFieldZip64Element newElement = new ZipIOExtraFieldZip64Element(); - - return newElement; - } - - // extracts ZIP 64 extra field element from a given byte array - internal override void ParseDataField(BinaryReader reader, UInt16 size) - { - Debug.Assert(reader != null); - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) - { - _uncompressedSize = reader.ReadUInt64(); - - if (size < sizeof(UInt64)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - size -= sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0) - { - _compressedSize = reader.ReadUInt64(); - - if (size < sizeof(UInt64)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - size -= sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) - { - _offsetOfLocalHeader = reader.ReadUInt64(); - - if (size < sizeof(UInt64)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - size -= sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0) - { - _diskNumber = reader.ReadUInt32(); - - if (size < sizeof(UInt32)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - size -= sizeof(UInt32); - } - - // There is an extra field that is not used and must be ignored. - // The reader must also advance past the unused bytes. - if (_zip64ExtraFieldUsage == ZipIOZip64ExtraFieldUsage.None) - { - reader.BaseStream.Seek(size, SeekOrigin.Current); - _ignoredFieldSize = size; - size = 0; - } - - if (size != 0) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - Validate(); - } - - internal override void Save(BinaryWriter writer) - { - // if it is == 0 we shouldn't be persisting this - Debug.Assert(SizeField > 0); - - writer.Write(_constantFieldId); - writer.Write(SizeField); - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) - { - writer.Write(_uncompressedSize); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0) - { - writer.Write(_compressedSize); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) - { - writer.Write(_offsetOfLocalHeader); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0) - { - writer.Write(_diskNumber); - } - } - - // This property calculates size of the field on disk (how many bytes need to be allocated on the disk) - internal override UInt16 Size - { - get - { - if (SizeField == 0) // we do not need to save this, if it is empty - { - return 0; - } - else - { - return checked((UInt16)(SizeField + MinimumSize)); - } - } - } - - // This property calculates the value of the size record whch holds the size without the Id and without the size itself. - // we are always guranteed that Size == SizeField + 2 * sizeof(UInt16)) - internal override UInt16 SizeField - { - get - { - UInt16 size = 0; - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) - { - size += sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0) - { - size += sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) - { - size += sizeof(UInt64); - } - - if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0) - { - size += sizeof(UInt32); - } - - // If the file contains a blank extra field, we need to correctly indicate that - // we skipped the data in this field so that the sizes match up in the end. - if (_ignoredFieldSize.HasValue) - { - size += _ignoredFieldSize.Value; - } - - return size; - } - } - - static internal UInt16 ConstantFieldId - { - get - { - return _constantFieldId; - } - } - - internal long UncompressedSize - { - get - { - // we should never be asked to provide such value, if we do not have it - Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0); - return (long)_uncompressedSize; - } - set - { - Debug.Assert(value >= 0); - - _zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize; - _uncompressedSize = (UInt64)value; - } - } - - internal long CompressedSize - { - get - { - // we should never be asked to provide such value, if we do not have it - Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0); - return (long)_compressedSize; - } - set - { - Debug.Assert(value >= 0); - - _zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize; - _compressedSize = (UInt64)value; - } - } - - internal long OffsetOfLocalHeader - { - get - { - // we should never be asked to provide such value, if we do not have it - Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0); - return (long)_offsetOfLocalHeader; - } - set - { - Debug.Assert(value >= 0); - - _zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader; - _offsetOfLocalHeader = (UInt64)value; - } - } - - internal UInt32 DiskNumber - { - get - { - // we should never be asked to provide such value, if we do not have it - Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0); - return _diskNumber; - } - // set{} for now we do not need to support set on this property - // the only reason to set is an attempt to produce multi disk archives - } - - internal ZipIOZip64ExtraFieldUsage Zip64ExtraFieldUsage - { - get - { - return _zip64ExtraFieldUsage; - } - set - { - _zip64ExtraFieldUsage = value; - } - } - - //------------------------------------------------------ - // - // Private Constructor - // - //------------------------------------------------------ - internal ZipIOExtraFieldZip64Element() - : base(_constantFieldId) - { - _zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None; - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private void Validate() - { - // throw if we got any negative values - if ((_compressedSize >= Int64.MaxValue) || - (_uncompressedSize >= Int64.MaxValue) || - (_offsetOfLocalHeader >= Int64.MaxValue)) - { - throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge)); - } - - // throw if disk number isn't == 0 - if (_diskNumber != 0) - { - throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); - } - } - - //------------------------------------------------------ - // - // Private fields - // - //------------------------------------------------------ - private const UInt16 _constantFieldId = 0x01; - - private UInt64 _uncompressedSize; - private UInt64 _compressedSize; - private UInt64 _offsetOfLocalHeader; - private UInt32 _diskNumber; - - // Used for indicating there is an ignored extra field - private UInt16? _ignoredFieldSize; - - private ZipIOZip64ExtraFieldUsage _zip64ExtraFieldUsage; - } -} - - diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOFileItemStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOFileItemStream.cs deleted file mode 100644 index 98c11634c49..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOFileItemStream.cs +++ /dev/null @@ -1,594 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.IO.Packaging; // for PackagingUtilities -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOFileItemStream : Stream - { - //////////////////////////////////// - // Stream section - ///////////////////////////////// - override public bool CanRead - { - get - { - return (!_disposedFlag) && (_blockManager.Stream.CanRead); - } - } - - override public bool CanSeek - { - get - { - return (!_disposedFlag) && (_blockManager.Stream.CanSeek); - } - } - - override public bool CanWrite - { - get - { - return (!_disposedFlag) && (_blockManager.Stream.CanWrite); - } - } - - override public long Length - { - get - { - CheckDisposed(); - - return _currentStreamLength; - } - } - - override public long Position - { - get - { - CheckDisposed(); - return _currentStreamPosition; - } - set - { - CheckDisposed(); - Seek(value, SeekOrigin.Begin); - } - } - - public override void SetLength(long newLength) - { - CheckDisposed(); - - Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution - // that would between PreSaveNotofication call and Save SaveStreaming - - if (newLength < 0) - { - throw new ArgumentOutOfRangeException("newLength"); - } - - if (_currentStreamLength != newLength) - { - _dirtyFlag = true; - _dataChanged = true; - - if (newLength <= _persistedSize) - { - // the stream becomes smaller than our disk block, which means that - // we can drop the in-memory-sparse-suffix - if (_sparseMemoryStreamSuffix != null) - { - _sparseMemoryStreamSuffix.Close(); - _sparseMemoryStreamSuffix = null; - } - } - else - { - // we need to construct Sparse Memory stream if we do not have one yet - if (_sparseMemoryStreamSuffix == null) - { - _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); - } - - // set size on the Sparse Memory Stream - _sparseMemoryStreamSuffix.SetLength(newLength - _persistedSize); // no need for checked as it was verified above - } - - _currentStreamLength = newLength; - - // if stream was truncated to the point that our current position is beyond the end of the stream, - // we need to reset position so it is at the end of the stream - if (_currentStreamLength < _currentStreamPosition) - Seek(_currentStreamLength, SeekOrigin.Begin); - } - } - - override public long Seek(long offset, SeekOrigin origin) - { - CheckDisposed(); - - Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution - // that would between PreSaveNotofication call and Save SaveStreaming - - long newStreamPosition = _currentStreamPosition; - - if (origin ==SeekOrigin.Begin) - { - newStreamPosition = offset; - } - else if (origin == SeekOrigin.Current) - { - checked{newStreamPosition += offset;} - } - else if (origin == SeekOrigin.End) - { - checked{newStreamPosition = _currentStreamLength + offset;} - } - else - { - throw new ArgumentOutOfRangeException("origin"); - } - - if (newStreamPosition < 0) - { - throw new ArgumentException(SR.Get(SRID.SeekNegative)); - } - _currentStreamPosition = newStreamPosition; - - return _currentStreamPosition; - } - - override public int Read(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); - - Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution - // that would between PreSaveNotofication call and Save SaveStreaming - - Debug.Assert(_currentStreamPosition >= 0); - - if (count == 0) - { - return 0; - } - - if (_currentStreamLength <= _currentStreamPosition) - { - // we are past the end of the stream so let's just return 0 - return 0; - } - - int totalBytesRead; - int diskBytesRead = 0; - int diskBytesToRead = 0; - long persistedTailSize = 0; - - int memoryBytesRead = 0; - long newStreamPosition = _currentStreamPosition; - - checked - { - // Try to satisfy request with the Read from the Disk - if (newStreamPosition < _persistedSize) - { - // we have at least partial overlap between request and the data on disk - - //first let's get min between size of the stream's tail and the tail of the persisted chunk - // in some cases stream might be smaller - // e.g. _currentStreamLength < _persistedSize, if let's say stream was truncated - persistedTailSize = Math.Min(_currentStreamLength, _persistedSize) - newStreamPosition; - Debug.Assert(persistedTailSize > 0); - - // we also do not want to read more data than was requested by the user - diskBytesToRead = (int)Math.Min((long)count, persistedTailSize); // this is a safe cast as count has int type - Debug.Assert(diskBytesToRead > 0); - - // and now we can actually read it - _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); - - // we are ready for getting fewer bytes than reqested - diskBytesRead = _blockManager.Stream.Read(buffer, offset, diskBytesToRead); - - newStreamPosition += diskBytesRead; - count -= diskBytesRead; - offset +=diskBytesRead; - - if (diskBytesRead < diskBytesToRead) - { - // we didn't everything that we hae asked for. In such case we shouldn't - // try to get data from the _sparseMemoryStreamSuffix - _currentStreamPosition = newStreamPosition; - - return diskBytesRead; - } - } - - // check whether we need to get data from the memory Stream; - if ((_sparseMemoryStreamSuffix != null) && (newStreamPosition + count > _persistedSize)) - { - // we are either trying to finish the request partially satisfied by the - // on disk data or the read is entirely within the suffix - _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); - memoryBytesRead = _sparseMemoryStreamSuffix.Read(buffer, offset, count); - - newStreamPosition += memoryBytesRead; - } - - totalBytesRead = diskBytesRead + memoryBytesRead; - } - - _currentStreamPosition = newStreamPosition; - return totalBytesRead ; - } - - /// - /// Write - /// - /// - /// - /// - /// In streaming mode, write should accumulate data into the SparseMemoryStream. - override public void Write(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); - - Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution - // that would between PreSaveNotofication call and Save SaveStreaming - - Debug.Assert(_currentStreamPosition >= 0); - - if (count == 0) - { - return; - } - - int diskBytesToWrite = 0; - - _dirtyFlag = true; - _dataChanged = true; - long newStreamPosition = _currentStreamPosition; - checked - { - // Try to satisfy request with the Write to the Disk - if (newStreamPosition < _persistedSize) - { - Debug.Assert(!_blockManager.Streaming); - - // we have at least partial overlap between request and the data on disk - _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); - // Note on casting: - // It is safe to cast the result of Math.Min(count, _persistedSize - newStreamPosition)) - // from long to int since it cannot be bigger than count and count is int type - diskBytesToWrite = (int) (Math.Min(count, _persistedSize - newStreamPosition)); // this is a safe cast as count has int type - - _blockManager.Stream.Write(buffer, offset, diskBytesToWrite); - newStreamPosition += diskBytesToWrite; - count -= diskBytesToWrite; - offset += diskBytesToWrite; - } - - // check whether we need to save data to the memory Stream; - if (newStreamPosition + count > _persistedSize) - { - if (_sparseMemoryStreamSuffix == null) - { - _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); - } - - _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); - - _sparseMemoryStreamSuffix.Write(buffer, offset, count); - newStreamPosition += count; - } - - _currentStreamPosition = newStreamPosition; - _currentStreamLength = Math.Max(_currentStreamLength, _currentStreamPosition); - } - return; - } - - override public void Flush() - { - CheckDisposed(); - - // tell the BlockManager that the caller called Flush on us. Block manager will process this - // and possibly call us back on Save or SaveStreaming - _blockManager.SaveStream(_block, false); // second parameter is a closing indicator - } - - ///////////////////////////// - // Internal Constructor - ///////////////////////////// - internal ZipIOFileItemStream(ZipIOBlockManager blockManager, // blockManager is only needed - // to pass through to it Flush requests - ZipIOLocalFileBlock block, // our owning block - needed for Streaming scenarios - long persistedOffset, // to map to the stream - long persistedSize) // to map to the stream ) - { - Debug.Assert(blockManager != null); - Debug.Assert(persistedOffset >=0); - Debug.Assert(persistedSize >= 0); - Debug.Assert(block != null); - - _persistedOffset = persistedOffset; - _offset = persistedOffset; - _persistedSize = persistedSize; - - _blockManager = blockManager; - _block = block; - - _currentStreamLength = persistedSize; - } - - ///////////////////////////// - // Internal Methods for the LocalFileBlock to call in order to know Dirty status and the new size - ///////////////////////////// - internal PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - return ZipIOBlockManager.CommonPreSaveNotificationHandler( - _blockManager.Stream, - offset, - size, - _persistedOffset, - Math.Min(_persistedSize, _currentStreamLength), // in case the stream is smaller then our persisted block on - // disk, there is no need to preserve the meaningless persisted suffix - ref _cachePrefixStream); - } - - internal bool DirtyFlag - { - get - { - return _dirtyFlag; - } - } - - internal bool DataChanged - { - get - { - return _dataChanged; - } - } - - internal long Offset - { - get - { - return _offset; - } - } - - internal void Move(long shiftSize) - { - CheckDisposed(); - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - _dirtyFlag = true; - Debug.Assert(_offset >=0); - } - } - - /// - /// Streaming-specific variant of Save() - /// - /// Writes current data to the underlying stream. - /// Assumes the stream is in the correct place. - internal void SaveStreaming() - { - CheckDisposed(); - - Debug.Assert(_cachePrefixStream == null); // _cachePrefixStream must not be used in streaming cases at all - - Debug.Assert(_blockManager.Streaming); - - if (_dirtyFlag) - { - // in streaming cases all the data collected in the _sparseMemoryStreamSuffix - // and now we can save the SparseMemoryStream - if (_sparseMemoryStreamSuffix != null) - { - _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); - - // update so that subsequent MemoryStreams will know where they begin - checked{_persistedSize += _sparseMemoryStreamSuffix.Length;} - _sparseMemoryStreamSuffix.Close(); - _sparseMemoryStreamSuffix = null; - } - - _dirtyFlag = false; - _dataChanged = false; - } - } - - /// - /// Save - called by the BlockManager to cause us to Flush to the underlying stream - /// - internal void Save() - { - CheckDisposed(); - Debug.Assert(!_blockManager.Streaming); - - if(_dirtyFlag) - { - // we need to move the whole persisted block to the new position - long moveBlockSourceOffset = _persistedOffset; - - // in case the stream is smaller then our persisted block on disk there is - // no need to move meaningless persisted suffix - long moveBlockSize = Math.Min(_persistedSize, _currentStreamLength); - - long moveBlockTargetOffset = _offset; - - long newPersistedSize = 0; - - if (_cachePrefixStream != null) - { - // if we have something in cache we only should move whatever isn't cached - checked{moveBlockSourceOffset += _cachePrefixStream.Length;} - checked{moveBlockTargetOffset += _cachePrefixStream.Length;} - checked{moveBlockSize -= _cachePrefixStream.Length;} - Debug.Assert(moveBlockSize >=0); - } - - _blockManager.MoveData(moveBlockSourceOffset, moveBlockTargetOffset, moveBlockSize); - checked{newPersistedSize += moveBlockSize;} - - // only after data on disk was moved it is safe to flush the cached prefix buffer - if (_cachePrefixStream != null) - { - // we need to seek and it is safe to do as we are not in the streaming mode - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - - Debug.Assert(_cachePrefixStream.Length > 0); // should be taken care of by the constructor - // and PreSaveNotification - - _cachePrefixStream.WriteToStream(_blockManager.Stream); - checked{newPersistedSize += _cachePrefixStream.Length;} - - // we can free the memory - _cachePrefixStream.Close(); - _cachePrefixStream = null; - } - - - // and now we can save the SparseMemoryStream - if (_sparseMemoryStreamSuffix != null) - { - if (_blockManager.Stream.Position != checked (_offset + _persistedSize)) - { - // we need to seek - _blockManager.Stream.Seek(_offset + _persistedSize, SeekOrigin.Begin); - } - _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); - checked{newPersistedSize += _sparseMemoryStreamSuffix.Length;} - - _sparseMemoryStreamSuffix.Close(); - _sparseMemoryStreamSuffix = null; - } - - _blockManager.Stream.Flush(); - - // we are not shifted between on disk image and in memory image any more - _persistedOffset = _offset; - _persistedSize = newPersistedSize; - - Debug.Assert(newPersistedSize == _currentStreamLength); - - Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution - // after we are saved this field must be clear - - _dirtyFlag = false; - _dataChanged = false; - } - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - /// - /// Dispose(bool) - /// - /// - /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to - /// call Dispose() instead of Close(). - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - { - //streams wrapping this stream shouldn't pass Dispose calls through - // it is responsibility of the BlockManager or LocalFileBlock (in case of Remove) to call - // this dispose as appropriate (that is the reason why Flush isn't called here) - - // multiple calls are fine - just ignore them - if (!_disposedFlag) - { - if (_sparseMemoryStreamSuffix != null) - { - _sparseMemoryStreamSuffix.Close(); - } - - if (_cachePrefixStream != null) - { - _cachePrefixStream.Close(); - } - } - } - } - finally - { - _sparseMemoryStreamSuffix = null; - _cachePrefixStream = null; - _disposedFlag = true; - - base.Dispose(disposing); - } - } - - ///////////////////////////// - // Private Methods - ///////////////////////////// - private void CheckDisposed() - { - if (_disposedFlag) - { - throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); - } - } - - private ZipIOBlockManager _blockManager; - private ZipIOLocalFileBlock _block; // our owning block - - private long _offset; - private long _persistedOffset; - private long _persistedSize; - - private SparseMemoryStream _cachePrefixStream; - - private bool _dirtyFlag; - private bool _dataChanged; - - //support for Stream methods - private bool _disposedFlag; - - private long _currentStreamLength; - private long _currentStreamPosition; - - private SparseMemoryStream _sparseMemoryStreamSuffix; - - private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory - private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileBlock.cs deleted file mode 100644 index beb08555006..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileBlock.cs +++ /dev/null @@ -1,921 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Runtime.Serialization; -using System.Globalization; -using System.Windows; - -using MS.Internal.IO.Packaging; // For CompressStream -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOLocalFileBlock : IZipIOBlock, IDisposable - { - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - // standard IZipIOBlock functionality - public long Offset - { - get - { - CheckDisposed(); - return _offset; - } - } - - public long Size - { - get - { - CheckDisposed(); - - checked - { - long size = _localFileHeader.Size + _fileItemStream.Length; - - if (_localFileDataDescriptor != null) - { - // we only account for the data descriptor - // if it is there and data wasn't changed yet , - // because we will discard it as a part of saving - size += _localFileDataDescriptor.Size; - } - - return size; - } - } - } - - public bool GetDirtyFlag(bool closingFlag) - { - CheckDisposed(); - - bool deflateStreamDirty = false; - if (_deflateStream != null) - deflateStreamDirty = ((CompressStream) _deflateStream).IsDirty(closingFlag); - - // !!! ATTENTION !!!! - // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty". - // In the past we had Dirty flag on the ZipIoModeEnforcing stream that was always false. Enumerating - // those flags had significant perf cost (allocating all the Enumerator classes). We are removing Dirty flag - // from the ZipIoModeEnforcingStream and all the processing code associated with that. - //If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to - // reintroduce Dirty state/flag and properly account for this value in the ZipIoLocalFileBlock.DirtyFlag. - return _dirtyFlag || _fileItemStream.DirtyFlag || deflateStreamDirty; - } - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public void Move(long shiftSize) - { - CheckDisposed(); - Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); - - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - _fileItemStream.Move(shiftSize); - _dirtyFlag = true; - Debug.Assert(_offset >=0); - } - } - - /// - /// Streaming-specific variant of Save() - /// - /// - internal void SaveStreaming(bool closingFlag) - { - CheckDisposed(); - - Debug.Assert(_blockManager.Streaming, "Only legal in Streaming mode"); - - if (GetDirtyFlag(closingFlag)) - { - BinaryWriter writer = _blockManager.BinaryWriter; - - // write the local file header if not already done so - if (!_localFileHeaderSaved) - { - // our first access to the ArchiveStream - note our offset - _offset = _blockManager.Stream.Position; - _localFileHeader.Save(writer); - _localFileHeaderSaved = true; - } - - FlushExposedStreams(); - - //this will cause the actual write to disk, and it safe to do so, - // because all we're in streaming mode and there is - // no data in the way - _fileItemStream.SaveStreaming(); - - // Data Descriptor required for streaming mode - if (closingFlag) - { - // now prior to possibly closing streams we need to preserve uncompressed Size - // otherwise Length function will fail to give it to us later after closing - _localFileDataDescriptor.UncompressedSize = _crcCalculatingStream.Length; - - // calculate CRC prior to closing - _localFileDataDescriptor.Crc32 = _crcCalculatingStream.CalculateCrc(); - - // If we are closing we can do extra things , calculate CRC , close deflate stream - // it is particularly important to close the deflate stream as it might hold some extra bytes - // even after Flush() - - // close outstanding streams to signal that we need new pieces if more data comes - CloseExposedStreams(); - - // in order to get proper compressed size we have to close the deflate stream - if (_deflateStream != null) - { - _deflateStream.Close(); - _fileItemStream.SaveStreaming(); // get the extra bytes emitted by the DeflateStream - } - - _localFileDataDescriptor.CompressedSize = _fileItemStream.Length; - - _localFileDataDescriptor.Save(writer); - _dirtyFlag = false; - } - } - } - /// - /// Save() - /// - public void Save() - { - CheckDisposed(); - Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); - - // Note: This triggers a call to UpdateReferences() which will - // discard any _localFileDataDescriptor. - if (GetDirtyFlag(true)) // if we do not have closingFlag value (we should be using closingFlag=true as a more conservative approach) - { - // We need to notify the _fileItemStream that we about to save our FileHeader; - // otherwise we might be overriding some of the FileItemStream data with the - // FileHeader. Specifically we are concerned about scenario when a previous - // block become large by just a couple of bytes, so that the PreSaveNotification - // issued prior to saving the previous block didn�t trigger caching of our FileItemStream, - // but we still need to make sure that the current FileHeader will not override any data - // in our FileItemStream. - _fileItemStream.PreSaveNotification(_offset, _localFileHeader.Size); - - //position the stream - BinaryWriter writer = _blockManager.BinaryWriter; - if (_blockManager.Stream.Position != _offset) - { - // we need to seek - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - } - - _localFileHeader.Save(writer); - - //this will cause the actual write to disk, and it safe to do so, - // because all overlapping data was moved out of the way - // by the calling BlockManager - _fileItemStream.Save(); - - _dirtyFlag = false; - } - } - - - // !!! ATTENTION !!!! This function is only supposed to be called by - // Block Manager.Save which has proper protection to ensure no stack overflow will happen - // as a result of Stream.Flush calls which in turn result in BlockManager.Save calls - public void UpdateReferences(bool closingFlag) - { - Invariant.Assert(!_blockManager.Streaming); - - long uncompressedSize; - long compressedSize; - - CheckDisposed(); - - if (closingFlag) - { - CloseExposedStreams(); - } - else - { - FlushExposedStreams(); - } - - // At this point we can update Local Headers with the proper CRC Value - // We can also update other Local File Header Values (compressed/uncompressed size) - // we rely on our DirtyFlag property to properly account for all possbile modifications within streams - if (GetDirtyFlag(closingFlag)) - { - // Remember the size of the header before update - long headerSizeBeforeUpdate = _localFileHeader.Size; - - // now prior to possibly closing streams we need to preserve uncompressed Size - // otherwise Length function will fail to give it to us later after closing - uncompressedSize = _crcCalculatingStream.Length; - - // calculate CRC prior to closing - _localFileHeader.Crc32 = _crcCalculatingStream.CalculateCrc(); - - // If we are closing we can do extra things , calculate CRC , close deflate stream - // it is particularly important to close the deflate stream as it might hold some extra bytes - // even after Flush() - if (closingFlag) - { - // we have got the CRC so we can close the stream - _crcCalculatingStream.Close(); - - // in order to get proper compressed size we have to close the deflate stream - if (_deflateStream != null) - { - _deflateStream.Close(); - } - } - - if (_fileItemStream.DataChanged) - { - _localFileHeader.LastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); - } - - // get compressed size after possible closing Deflated stream - // as a result of some ineffeciencies in CRC calculation it might result in Seek in compressed stream - // and there fore switching mode and flushing extra compressed bytes - compressedSize = _fileItemStream.Length; - - // this will properly (taking into account ZIP64 scenario) update local file header - // Offset is passed in to determine whether ZIP 64 is required for small files that - // happened to be located required 32 bit offset in the archive - _localFileHeader.UpdateZip64Structures(compressedSize, uncompressedSize, Offset); - - // Add/remove padding to compensate the header size change - // NOTE: Padding needs to be updated only after updating all the header fields - // that can affect the header size - _localFileHeader.UpdatePadding(_localFileHeader.Size - headerSizeBeforeUpdate); - - // We always save File Items in Non-streaming mode unless it wasn't touched - //in which case we leave them alone - _localFileHeader.StreamingCreationFlag = false; - _localFileDataDescriptor = null; - - // in some cases UpdateZip64Structures call might result in creation/removal - // of extra field if such thing happened we need to move FileItemStream appropriatel - _fileItemStream.Move(checked(Offset + _localFileHeader.Size - _fileItemStream.Offset)); - - _dirtyFlag = true; - } -#if FALSE - // we would like to take this oppportunity and validate basic asumption - // that our GetDirtyFlag method is a reliable way to finding changes - // there is no scenario in which change will happened, affecting sizes - // and will not be registered by the GetDirtyFlag - // ??????????????????????? - else - { - // we even willing to recalculate CRC just in case for verification purposes - - UInt32 calculatedCRC32 = CalculateCrc32(); - if (!_localFileHeader.StreamingCreationFlag) - { - Debug.Assert(_localFileHeader.Crc32 == calculatedCRC32); - Debug.Assert(_localFileHeader.CompressedSize == CompressedSize); - Debug.Assert(_localFileHeader.UncompressedSize == UncompressedSize); - } - else - { - Debug.Assert(_localFileDataDescriptor.Crc32 == calculatedCRC32); - Debug.Assert(_localFileDataDescriptor.CompressedSize == CompressedSize); - Debug.Assert(_localFileDataDescriptor.UncompressedSize == UncompressedSize); - } - -/////////////////////////////////////////////////////////////////////// - - // we do not have an initialized value for the compressed size in this case - compressedSize = _fileItemStream.Length; - - Debug.Assert(CompressedSize == compressedSize); - Debug.Assert(UncompressedSize == uncompressedSize); - } -#endif - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - CheckDisposed(); - - // local file header and data descryptor are completely cached - // we only need to worry about the actual data - return _fileItemStream.PreSaveNotification(offset, size); - } - - /// - /// Dispose pattern - required implementation for classes that introduce IDisposable - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); // not strictly necessary, but if we ever have a subclass with a finalizer, this will be more efficient - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - internal static ZipIOLocalFileBlock SeekableLoad (ZipIOBlockManager blockManager, - string fileName) - { - Debug.Assert(!blockManager.Streaming); - Debug.Assert(blockManager.CentralDirectoryBlock.FileExists(fileName)); - - // Get info from the central directory - ZipIOCentralDirectoryBlock centralDir = blockManager.CentralDirectoryBlock; - ZipIOCentralDirectoryFileHeader centralDirFileHeader = centralDir.GetCentralDirectoryFileHeader(fileName); - - long localHeaderOffset = centralDirFileHeader.OffsetOfLocalHeader; - bool folderFlag = centralDirFileHeader.FolderFlag; - bool volumeLabelFlag = centralDirFileHeader.VolumeLabelFlag; - - blockManager.Stream.Seek(localHeaderOffset, SeekOrigin.Begin); - - ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, folderFlag, volumeLabelFlag); - - block.ParseRecord( - blockManager.BinaryReader, - fileName, - localHeaderOffset, - centralDir, - centralDirFileHeader); - - return block; - } - - internal static ZipIOLocalFileBlock CreateNew(ZipIOBlockManager blockManager, - string fileName, - CompressionMethodEnum compressionMethod, - DeflateOptionEnum deflateOption) - { - //this should be ensured by the higher levels - Debug.Assert(Enum.IsDefined(typeof(CompressionMethodEnum), compressionMethod)); - Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), deflateOption)); - - ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, false, false); - - block._localFileHeader = ZipIOLocalFileHeader.CreateNew - (fileName, - blockManager.Encoding, - compressionMethod, - deflateOption, blockManager.Streaming); - - // if in streaming mode - force to Zip64 mode in case the streams get large - if (blockManager.Streaming) - { - block._localFileDataDescriptor = ZipIOLocalFileDataDescriptor.CreateNew(); - } - - block._offset = 0; // intial value, that is not too important for the brand new File item - block._dirtyFlag = true; - - block._fileItemStream = new ZipIOFileItemStream(blockManager, - block, - block._offset + block._localFileHeader.Size, - 0); - - // create deflate wrapper if necessary - if (compressionMethod == CompressionMethodEnum.Deflated) - { - Debug.Assert(block._fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); - // Pass bool to indicate that this stream is "new" and must be dirty so that - // the valid empty deflate stream is emitted (2-byte sequence - see CompressStream for details). - block._deflateStream = new CompressStream(block._fileItemStream, 0, true); - - block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._deflateStream); - } - else - { - block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._fileItemStream); - } - - return block; - } - - internal Stream GetStream(FileMode mode, FileAccess access) - { - CheckDisposed(); - - // the main stream held by block Manager must be compatible with the request - CheckFileAccessParameter(_blockManager.Stream, access); - - // validate mode and Access - switch(mode) - { - case FileMode.Create: - // Check to make sure that stream isn't read only - if (!_blockManager.Stream.CanWrite) - { - throw new InvalidOperationException(SR.Get(SRID.CanNotWriteInReadOnlyMode)); - } - - if (_crcCalculatingStream != null && !_blockManager.Streaming) - { - _crcCalculatingStream.SetLength(0); - } - break; - case FileMode.Open: - break; - case FileMode.OpenOrCreate: - break; - case FileMode.CreateNew: - // because we deal with the GetStream call CreateNew is a really strange - // request, as the FileInfo is already there - throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "CreateNew")); - case FileMode.Append: - throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Append")); - case FileMode.Truncate: - throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Truncate")); - default: - throw new ArgumentOutOfRangeException("mode"); - } - - // Streaming mode: always return the same stream (if it exists already) - Stream exposedStream; - if (_blockManager.Streaming && _exposedPublicStreams != null && _exposedPublicStreams.Count > 0) - { - Debug.Assert(_exposedPublicStreams.Count == 1, "Should only be one stream returned in streaming mode"); - exposedStream = (Stream)_exposedPublicStreams[0]; - } - else - { - Debug.Assert((!_blockManager.Streaming) || (_exposedPublicStreams == null), - "Should be first and only stream returned in streaming mode"); - - exposedStream = new ZipIOModeEnforcingStream(_crcCalculatingStream, access, _blockManager, this); - - RegisterExposedStream(exposedStream); - } - - - return exposedStream; - } - - - // NOTE: This method should NOT be called anywhere else except from ZipIOModeEnforcingStream.Dispose(bool) - // This is not designed to be the part of the cyclic process of flushing - internal void DeregisterExposedStream(Stream exposedStream) - { - Debug.Assert(_exposedPublicStreams != null); - - _exposedPublicStreams.Remove(exposedStream); - } - - /// - /// Throwes exception if object already Disposed/Closed. This is the only internal - /// (and not private CheckDisposed method). It ismade internal for ZipFileInfo to call - /// - internal void CheckDisposed() - { - if (_disposedFlag) - { - throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); - } - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - internal UInt16 VersionNeededToExtract - { - get - { - CheckDisposed(); - - return _localFileHeader.VersionNeededToExtract; - } - } - - internal UInt16 GeneralPurposeBitFlag - { - get - { - CheckDisposed(); - - return _localFileHeader.GeneralPurposeBitFlag; - } - } - - internal CompressionMethodEnum CompressionMethod - { - get - { - CheckDisposed(); - - return _localFileHeader.CompressionMethod; - } - } - - internal UInt32 LastModFileDateTime - { - get - { - CheckDisposed(); - - return _localFileHeader.LastModFileDateTime; - } - } - - /// - /// Return stale CRC value stored in the header. - /// This property doesn't flush streams nor does it recalculates CRC BY DESIGN - /// all updates and revcalculations should be made as a part of the UpdateReferences function - /// which is called by the BlockManager.Save - /// - internal UInt32 Crc32 - { - get - { - CheckDisposed(); - - if (_localFileHeader.StreamingCreationFlag) - { - Invariant.Assert(_localFileDataDescriptor != null); - return _localFileDataDescriptor.Crc32; - } - else - { - return _localFileHeader.Crc32; - } - } - } - - /// - /// Return stale Compressed Size based on the local file header - /// This property doesn't flush streams, so it is possible that - /// this value will be out of date if Updatereferences isn't - /// called before getting this property - /// - internal long CompressedSize - { - get - { - CheckDisposed(); - - if (_localFileHeader.StreamingCreationFlag) - { - Invariant.Assert(_localFileDataDescriptor != null); - return _localFileDataDescriptor.CompressedSize; - } - else - { - return _localFileHeader.CompressedSize; - } - } - } - - /// - /// Return possibly stale Uncompressed Size based on the local file header - /// This property doesn't flush streams, so it is possible that - /// this value will be out of date if Updatereferences isn't - /// called before getting this property - /// - internal long UncompressedSize - { - get - { - CheckDisposed(); - - if (_localFileHeader.StreamingCreationFlag) - { - Invariant.Assert(_localFileDataDescriptor != null); - return _localFileDataDescriptor.UncompressedSize; - } - else - { - return _localFileHeader.UncompressedSize; - } - } - } - - internal DeflateOptionEnum DeflateOption - { - get - { - CheckDisposed(); - return _localFileHeader.DeflateOption; - } - } - - internal string FileName - { - get - { - CheckDisposed(); - return _localFileHeader.FileName; - } - } - - internal bool FolderFlag - { - get - { - CheckDisposed(); - return _folderFlag; - } - } - - internal bool VolumeLabelFlag - { - get - { - CheckDisposed(); - return _volumeLabelFlag; - } - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - /// - /// Dispose(bool) - /// - /// - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - // multiple calls are fine - just ignore them - if (!_disposedFlag) - { - try - { - // close all the public streams that have been exposed - CloseExposedStreams(); - - _crcCalculatingStream.Close(); - - if (_deflateStream != null) - _deflateStream.Close(); - - _fileItemStream.Close(); - } - finally - { - _disposedFlag = true; - _crcCalculatingStream = null; - _deflateStream = null; - _fileItemStream = null; - } - } - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private ZipIOLocalFileBlock(ZipIOBlockManager blockManager, - bool folderFlag, - bool volumeLabelFlag) - { - _blockManager = blockManager; - _folderFlag = folderFlag; - _volumeLabelFlag = volumeLabelFlag; - } - - private void ParseRecord (BinaryReader reader, - string fileName, - long position, - ZipIOCentralDirectoryBlock centralDir, - ZipIOCentralDirectoryFileHeader centralDirFileHeader) - { - CheckDisposed(); - Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); - - _localFileHeader = ZipIOLocalFileHeader.ParseRecord(reader, _blockManager.Encoding); - - // Let's find out whether local file descriptor is there or not - if (_localFileHeader.StreamingCreationFlag) - { - // seek forward by the uncompressed size - _blockManager.Stream.Seek(centralDirFileHeader.CompressedSize, SeekOrigin.Current); - _localFileDataDescriptor = ZipIOLocalFileDataDescriptor.ParseRecord(reader, - centralDirFileHeader.CompressedSize, - centralDirFileHeader.UncompressedSize, - centralDirFileHeader.Crc32, - _localFileHeader.VersionNeededToExtract); - } - else - { - _localFileDataDescriptor = null; - } - - _offset = position; - _dirtyFlag = false; - - checked - { - _fileItemStream = new ZipIOFileItemStream(_blockManager, - this, - position + _localFileHeader.Size, - centralDirFileHeader.CompressedSize); - } - - // init deflate stream if necessary - if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Deflated) - { - Debug.Assert(_fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); - _deflateStream = new CompressStream(_fileItemStream, centralDirFileHeader.UncompressedSize); - - _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _deflateStream, Crc32); - } - else if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Stored) - { - _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _fileItemStream, Crc32); - } - else - { - throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); - } - - Validate(fileName, centralDir, centralDirFileHeader); -} - - /// - /// Validate - /// - /// pre-trimmed and normalized filename (see ValidateNormalizeFileName) - /// central directory block - /// file header from central directory - private void Validate(string fileName, - ZipIOCentralDirectoryBlock centralDir, - ZipIOCentralDirectoryFileHeader centralDirFileHeader) - { - // check that name matches parameter in a case sensitive culture neutral way - if (0 != String.CompareOrdinal(_localFileHeader.FileName, fileName)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // compare compressed and uncompressed sizes, crc from central directory - if ((VersionNeededToExtract != centralDirFileHeader.VersionNeededToExtract) || - (GeneralPurposeBitFlag != centralDirFileHeader.GeneralPurposeBitFlag) || - (CompressedSize != centralDirFileHeader.CompressedSize) || - (UncompressedSize != centralDirFileHeader.UncompressedSize) || - (CompressionMethod != centralDirFileHeader.CompressionMethod) || - (Crc32 != centralDirFileHeader.Crc32)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // check for read into central directory (which would indicate file corruption) - if (Offset + Size > centralDir.Offset) - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - - // No CRC check here - // delay validating the actual CRC until it is possible to do so without additional read operations - // This is only for non-streaming mode (at this point we only support creation not consumption) - // This is to avoid the forced reading of entire stream just for CRC check - // CRC check is delegated to ProgressiveCrcCalculatingStream and CRC is only validated - // once calculated CRC is available. This implies that CRC check operation is not - // guaranteed to be performed - } - - static private void CheckFileAccessParameter(Stream stream, FileAccess access) - { - switch(access) - { - case FileAccess.Read: - if (!stream.CanRead) - { - throw new ArgumentException (SR.Get(SRID.CanNotReadInWriteOnlyMode)); - } - break; - case FileAccess.Write: - if (!stream.CanWrite) - { - throw new ArgumentException (SR.Get(SRID.CanNotWriteInReadOnlyMode)); - } - break; - case FileAccess.ReadWrite: - if (!stream.CanRead || !stream.CanWrite) - { - throw new ArgumentException (SR.Get(SRID.CanNotReadWriteInReadOnlyWriteOnlyMode)); - } - break; - default: - throw new ArgumentOutOfRangeException ("access"); - } - } - - private void RegisterExposedStream(Stream exposedStream) - { - if (_exposedPublicStreams == null) - { - _exposedPublicStreams = new ArrayList(_initialExposedPublicStreamsCollectionSize); - } - _exposedPublicStreams.Add(exposedStream); - } - - private void CloseExposedStreams() - { - if (_exposedPublicStreams != null) - { - for (int i = _exposedPublicStreams.Count - 1; i >= 0; i--) - { - ZipIOModeEnforcingStream exposedStream = - (ZipIOModeEnforcingStream)_exposedPublicStreams[i]; - - exposedStream.Close(); - } - } - } - - private void FlushExposedStreams() - { - // !!! ATTENTION !!!! - // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty"; - // therefore, there is no need to flush them. Enumerating and flashing those streams has some non-trivial - // perf costs. Instead, it is much cheaper to flush the CrcCalculatingStream. - // If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to flush - // all of the _exposedPublicStreams in this method. - _crcCalculatingStream.Flush(); - - - // We are going to walk through the exposed streams and if we can not find any stream that isn't Disposed yet - // we will switch deflate stream into Start Mode, by doing this we will achieve 2 goals: - // 1. Relieve Memory Pressure in the Sparse Memory Stream - // 2. Close Deflate stream in the write through mode and get the tail bytes (we can only get them if - // we close Deflate stream). This way we can make the disk layout of the File Items that are closed final. - if ((_deflateStream != null) && - (!_localFileHeader.StreamingCreationFlag)) - { - if ((_exposedPublicStreams == null) ||(_exposedPublicStreams.Count == 0)) - { - ((CompressStream)_deflateStream).Reset(); - } - } - } - - private const int _initialExposedPublicStreamsCollectionSize= 5; - - private ZipIOFileItemStream _fileItemStream; - private Stream _deflateStream; // may be null - only used if stream is Deflated - // _crcCalculatingStream is used to do optimal CRC calcuation when it is possible. - // This stream can wrap either _fileItemStream or _deflateStream - // For CRC to be calculated correctly, all regualar stream operations have to - // go through this stream. This means file item streams we hand out to a client - // need to be wrapped as ProgressiveCrcCalculatingStream. - // Any other operations specific to ZipIOFileItemStream or DeflateStream should - // be directed to those streams. - private ProgressiveCrcCalculatingStream _crcCalculatingStream; - private ArrayList _exposedPublicStreams; - - private ZipIOLocalFileHeader _localFileHeader = null; - private bool _localFileHeaderSaved; // only used in Streaming mode - private ZipIOLocalFileDataDescriptor _localFileDataDescriptor = null; - - private ZipIOBlockManager _blockManager; - - private long _offset; - - // This is a shallow dirtyFlag which doesn't account for the substructures - // (ModeEnforcing Streams, compression stream FileItem Stream ) - // GetDirtyFlag method is supposed to be used everywhere where a - // complete (deep ; non-shallow) check for "dirty" is required; - private bool _dirtyFlag; - - private bool _disposedFlag = false; - - private bool _folderFlag = false; - private bool _volumeLabelFlag = false; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileDataDescriptor.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileDataDescriptor.cs deleted file mode 100644 index a8f6c860ea0..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileDataDescriptor.cs +++ /dev/null @@ -1,249 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOLocalFileDataDescriptor - { - // used in streaming case - internal static ZipIOLocalFileDataDescriptor CreateNew() - { - ZipIOLocalFileDataDescriptor descriptor = new ZipIOLocalFileDataDescriptor(); - descriptor._size = _fixedMinimalRecordSizeWithSignatureZip64; - - return descriptor; - } - - internal static ZipIOLocalFileDataDescriptor ParseRecord(BinaryReader reader, - long compressedSizeFromCentralDir, - long uncompressedSizeFromCentralDir, - UInt32 crc32FromCentralDir, - UInt16 versionNeededToExtract) - { - ZipIOLocalFileDataDescriptor descriptor = new ZipIOLocalFileDataDescriptor(); - - // There are 4 distinct scenario we would like to support - // 1.based on the appnote it seems that the structure of this record is following: - // crc-32 4 bytes - // compressed size 4 bytes (scenario 1.a has 8 bytes) - // uncompressed size 4 bytes (scenario 1.a has 8 bytes) - // - // 2.based on files that we have been able to examine - // data descriptor signature 4 bytes (0x08074b50) - // crc-32 4 bytes - // compressed size 4 bytes (scenario 2.a has 8 bytes) - // uncompressed size 4 bytes (scenario 2.a has 8 bytes) - // - // we can safely assume that this record is not the last one in the file, so let's just - // read the max Bytes required to store the largest structure , and compare results - - // at most we are looking at 6 * 4 = 24 bytes - UInt32[] buffer = new UInt32[6]; - - // let's try to match the smallest possible structure (3 x 4) 32 bit without signature - buffer[0] = reader.ReadUInt32(); - buffer[1] = reader.ReadUInt32(); - buffer[2] = reader.ReadUInt32(); - - if (descriptor.TestMatch(_signatureConstant, - crc32FromCentralDir, - compressedSizeFromCentralDir, - uncompressedSizeFromCentralDir, - _signatureConstant, - buffer[0], - buffer[1], - buffer[2])) - { - descriptor._size = _fixedMinimalRecordSizeWithoutSignature; - return descriptor; - } - - // let's try to match the next record size (4 x 4) 32 bit with signature - buffer[3] = reader.ReadUInt32(); - if (descriptor.TestMatch(_signatureConstant, - crc32FromCentralDir, - compressedSizeFromCentralDir, - uncompressedSizeFromCentralDir, - buffer[0], - buffer[1], - buffer[2], - buffer[3])) - { - descriptor._size = _fixedMinimalRecordSizeWithSignature; - return descriptor; - } - - // At this point prior to trying to match 64 bit structures we need to make sure that version is high enough - if (versionNeededToExtract < (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - //let's try to match the 64 bit structures 64 bit without signature - buffer[4] = reader.ReadUInt32(); - if (descriptor.TestMatch(_signatureConstant, - crc32FromCentralDir, - compressedSizeFromCentralDir, - uncompressedSizeFromCentralDir, - _signatureConstant, - buffer[0], - ZipIOBlockManager.ConvertToUInt64(buffer[1], buffer[2]), - ZipIOBlockManager.ConvertToUInt64(buffer[3], buffer[4]))) - { - descriptor._size = _fixedMinimalRecordSizeWithoutSignatureZip64; - return descriptor; - } - - //let's try to match the 64 bit structures 64 bit with signature - buffer[5] = reader.ReadUInt32(); - if (descriptor.TestMatch(_signatureConstant, - crc32FromCentralDir, - compressedSizeFromCentralDir, - uncompressedSizeFromCentralDir, - buffer[0], - buffer[1], - ZipIOBlockManager.ConvertToUInt64(buffer[2], buffer[3]), - ZipIOBlockManager.ConvertToUInt64(buffer[4], buffer[5]))) - { - descriptor._size = _fixedMinimalRecordSizeWithSignatureZip64; - return descriptor; - } - - // we couldn't match anything at this point we need to fail - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - /// - /// Save - persist to given binary writer - /// - /// - internal void Save(BinaryWriter writer) - { - // we only supposed to be saving a brand new record which is created with signature in Zip64 Mode - // this only supported for streaming publishing cases. - // For editing scenarios we never save them (not even preserve them), as any editing (even trivial moving of record around) - // will result in switching File Item to a non-streaming mode without data desciptor - Invariant.Assert(_size == _fixedMinimalRecordSizeWithSignatureZip64); - - // always persist Zip64 version signature - writer.Write(_signatureConstant); // this is apparently optional, but omitting it causes wzzip to complain - writer.Write(_crc32); - writer.Write((UInt64)_compressedSize); // 8 bytes - writer.Write((UInt64)_uncompressedSize); // 8 bytes - } - - internal long Size - { - get - { - return _size; - } - } - - internal UInt32 Crc32 - { - get - { - return _crc32; - } - set - { - _crc32 = value; - } - } - - internal long CompressedSize - { - get - { - return _compressedSize; - } - set - { - Invariant.Assert((value >= 0), "CompressedSize must be non-negative"); - - _compressedSize = value; - } - } - - internal long UncompressedSize - { - get - { - return _uncompressedSize; - } - set - { - Invariant.Assert((value >= 0), "UncompressedSize must be non-negative"); - - _uncompressedSize = value; - } - } - - - private bool TestMatch(UInt32 signature, - UInt32 crc32FromCentralDir, - long compressedSizeFromCentralDir, - long uncompressedSizeFromCentralDir, - UInt32 suspectSignature, - UInt32 suspectCrc32, - UInt64 suspectCompressedSize, - UInt64 suspectUncompressedSize) - { - checked - { - // Don't compare compressedSize and uncompressedSize as long since the sniffed - // bytes might not be the actual match and can be bigger than Int64.MaxValue - // Convert them as long only if it is a match - if ((signature == suspectSignature) && - ((UInt64) compressedSizeFromCentralDir == suspectCompressedSize) && - ((UInt64) uncompressedSizeFromCentralDir == suspectUncompressedSize) && - (crc32FromCentralDir == suspectCrc32)) - { - _signature = suspectSignature; - _compressedSize = (long) suspectCompressedSize; - _uncompressedSize = (long) suspectUncompressedSize; - _crc32 = suspectCrc32; - return true; - } - else - { - return false; - } - } - } - - private const UInt32 _signatureConstant = 0x08074b50; - private const int _fixedMinimalRecordSizeWithoutSignature = 12; - private const int _fixedMinimalRecordSizeWithSignature = 16; - private const int _fixedMinimalRecordSizeWithoutSignatureZip64 = 20; - private const int _fixedMinimalRecordSizeWithSignatureZip64 = 24; - - private int _size; - - private UInt32 _signature = _signatureConstant; - private UInt32 _crc32; - private long _compressedSize = 0; - private long _uncompressedSize = 0; -} -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileHeader.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileHeader.cs deleted file mode 100644 index 45d297b7277..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOLocalFileHeader.cs +++ /dev/null @@ -1,434 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOLocalFileHeader - { - /// - /// Create a new LocalFileHeader - /// - /// - /// - /// - /// - /// true if in streaming mode - /// - internal static ZipIOLocalFileHeader CreateNew(string fileName, Encoding encoding, - CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption, bool streaming) - { - //this should be ensured by the higher levels - Debug.Assert(Enum.IsDefined(typeof(CompressionMethodEnum), compressionMethod)); - Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), deflateOption)); - - byte[] asciiName = encoding.GetBytes(fileName); - if (asciiName.Length > ZipIOBlockManager.MaxFileNameSize) - { - throw new ArgumentOutOfRangeException("fileName"); - } - - ZipIOLocalFileHeader header = new ZipIOLocalFileHeader(); - header._signature = ZipIOLocalFileHeader._signatureConstant; - header._compressionMethod = (ushort)compressionMethod; - - if (streaming) - header._versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat; - else - { - header._versionNeededToExtract = (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression( - compressionMethod); - } - - if (compressionMethod != CompressionMethodEnum.Stored) - { - Debug.Assert(deflateOption != DeflateOptionEnum.None); //this should be ensured by the higher levels - header.DeflateOption = deflateOption; - } - - if (streaming) - { - // set bit 3 - header.StreamingCreationFlag = true; - } - - header._lastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); - - header._fileNameLength = (UInt16)asciiName.Length; - - header._fileName = asciiName; - header._extraField = ZipIOExtraField.CreateNew(!streaming /* creating padding if it is not in streaming creation mode */); - header._extraFieldLength = header._extraField.Size; - - //populate frequently used field with user friendly data representations - header._stringFileName = fileName; - - return header; - } - - internal static ZipIOLocalFileHeader ParseRecord(BinaryReader reader, Encoding encoding) - { - ZipIOLocalFileHeader header = new ZipIOLocalFileHeader(); - - header._signature = reader.ReadUInt32(); - header._versionNeededToExtract = reader.ReadUInt16(); - header._generalPurposeBitFlag = reader.ReadUInt16(); - header._compressionMethod = reader.ReadUInt16(); - header._lastModFileDateTime = reader.ReadUInt32(); - header._crc32 = reader.ReadUInt32(); - header._compressedSize = reader.ReadUInt32(); - header._uncompressedSize = reader.ReadUInt32(); - header._fileNameLength = reader.ReadUInt16(); - header._extraFieldLength = reader.ReadUInt16(); - - header._fileName = reader.ReadBytes(header._fileNameLength); - - // check for the ZIP 64 version and escaped values - ZipIOZip64ExtraFieldUsage zip64extraFieldUsage = ZipIOZip64ExtraFieldUsage.None; - if (header._versionNeededToExtract >= (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat) - { - if (header._compressedSize == UInt32.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize; - } - if (header._uncompressedSize == UInt32.MaxValue) - { - zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize; - } - } - - // if the ZIP 64 record is missing from the Extra Field then the zip64extraFieldUsage - // value will be ignored and default ZipIOZip64ExtraFieldUsage.None value will be used/assumed - header._extraField = ZipIOExtraField.ParseRecord(reader, - zip64extraFieldUsage, - header._extraFieldLength); - - //populate frequently used field with user friendly data representations - header._stringFileName = ZipIOBlockManager.ValidateNormalizeFileName(encoding.GetString(header._fileName)); - - header.Validate(); - - return header; - } - - internal void Save(BinaryWriter writer) - { - writer.Write(_signatureConstant); - writer.Write(_versionNeededToExtract); - writer.Write(_generalPurposeBitFlag); - writer.Write(_compressionMethod); - writer.Write(_lastModFileDateTime); - writer.Write(_crc32); - writer.Write(_compressedSize); - writer.Write(_uncompressedSize); - writer.Write(_fileNameLength); - writer.Write(_extraField.Size); - - if (_fileNameLength > 0) - { - writer.Write(_fileName, 0, _fileNameLength); - } - - _extraField.Save(writer); - - writer.Flush(); - } - - internal UInt16 VersionNeededToExtract - { - get - { - return _versionNeededToExtract; - } - } - - internal UInt16 GeneralPurposeBitFlag - { - get - { - return _generalPurposeBitFlag; - } - } - - internal CompressionMethodEnum CompressionMethod - { - get - { - return (CompressionMethodEnum)_compressionMethod; - } - } - - internal UInt32 LastModFileDateTime - { - get - { - return _lastModFileDateTime; - } - set - { - _lastModFileDateTime = value; - } - } - - internal UInt32 Crc32 - { - get - { - return _crc32; - } - set - { - _crc32 = value; - } - } - - internal long CompressedSize - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0) - { - // zip 64 extra field is there - return _extraField.CompressedSize; - } - else - { - // 32 bit case - return _compressedSize; - } - } - } - - internal long UncompressedSize - { - get - { - if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) - { - // zip 64 extra field is there - return _extraField.UncompressedSize; - } - else - { - // 32 bit case - return _uncompressedSize; - } - } - } - - /// - /// FileName - already scrubbed via ValidateNormalizeFileName() - /// - internal string FileName - { - get - { - return _stringFileName; - } - } - - internal long Size - { - get - { - return checked(_fixedMinimalRecordSize + _fileNameLength + _extraField.Size); - } - } - - internal bool StreamingCreationFlag - { - get - { - return ((_generalPurposeBitFlag & 0x8) != 0x0); - } - set - { - if (value) - { - _generalPurposeBitFlag |= 0x8; //set bit #3 - } - else - { - _generalPurposeBitFlag &= 0xFFF7; //clear bit #3 - } - } - } - - internal DeflateOptionEnum DeflateOption - { - get - { - if (CompressionMethod == CompressionMethodEnum.Deflated) - { - return (DeflateOptionEnum)(_generalPurposeBitFlag & 0x6); - } - else - { - // defalte option is validated to be one of the 2 (deflated or stored) - return DeflateOptionEnum.None; - } - } - set - { - // this checks must be done in the levels above - Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), value)); - Debug.Assert(value != DeflateOptionEnum.None); - - // clean the value (bits 1 and 2) - _generalPurposeBitFlag &= 0xFFF9; - _generalPurposeBitFlag |= (UInt16)value; // safe cast because of the enum validation - } - } - - static internal int FixedMinimalRecordSize - { - get - { - return _fixedMinimalRecordSize; - } - } - - private bool EncryptedFlag - { - get - { - return ((_generalPurposeBitFlag & 0x1) == 0x1); - } - } - - internal void UpdateZip64Structures(long compressedSize, - long uncompressedSize, - long offset) - { - // according to the appnote local file header ZIP 64 extra field if used must contain both - // compressed and uncompressed size - // we also trying to stay on the safe side and treeat the boundary case of 32 escape values - // as a zip 64 scenario - // we will also make this ZIP64 file if it is small but positioned beyond Uint32.MaxValue offset - if ((compressedSize >= UInt32.MaxValue) || - (uncompressedSize >= UInt32.MaxValue) || - (offset >= UInt32.MaxValue)) - { - // Zip 64 case - _extraField.CompressedSize = compressedSize; - _extraField.UncompressedSize = uncompressedSize; - - //set proper escape values - _compressedSize = UInt32.MaxValue; - _uncompressedSize = UInt32.MaxValue; - - // update version needed to extract to 4.5 - _versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat; - } - else - { - // 32 bit case - _compressedSize = (UInt32)compressedSize; // checked{} isn't required because of the checks above - _uncompressedSize = (UInt32)uncompressedSize; - - // reset the extra ZIP 64 field to empty - _extraField.Zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None; - - // version needed to extract needs to be recalculated from scratch based on compression - _versionNeededToExtract = - (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression(CompressionMethod); - } - } - - internal void UpdatePadding(long headerSizeChange) - { - _extraField.UpdatePadding(headerSizeChange); - } - - private ZipIOLocalFileHeader() - { - } - - private void Validate () - { - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_fileNameLength != _fileName.Length) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); - - // encryption is not supported - if (EncryptedFlag) - throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedEncryptedArchive)); - - // if verson is below 4.5 make sure that ZIP 64 extra filed isn't present - // if it is it might be a security concern - if ((_versionNeededToExtract < (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) && - (_extraField.Zip64ExtraFieldUsage != ZipIOZip64ExtraFieldUsage.None)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // ZIP 64 validation; if extra field is present it - // must have both compressed and uncompressed size in the local file header - // according to the appnote - if ((_extraField.Zip64ExtraFieldUsage != ZipIOZip64ExtraFieldUsage.None) && - (_extraField.Zip64ExtraFieldUsage != - (ZipIOZip64ExtraFieldUsage.CompressedSize | - ZipIOZip64ExtraFieldUsage.UncompressedSize))) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_extraFieldLength != _extraField.Size) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((CompressionMethod != CompressionMethodEnum.Stored) && - (CompressionMethod != CompressionMethodEnum.Deflated)) - { - throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); - } - } - - private const int _fixedMinimalRecordSize = 30; - - private const UInt32 _signatureConstant = 0x04034b50; - private UInt32 _signature = _signatureConstant; - private UInt16 _versionNeededToExtract; - private UInt16 _generalPurposeBitFlag; - private UInt16 _compressionMethod; - private UInt32 _lastModFileDateTime; - private UInt32 _crc32; - private UInt32 _compressedSize; - private UInt32 _uncompressedSize; - private UInt16 _fileNameLength; - private UInt16 _extraFieldLength; - private byte[] _fileName; - private ZipIOExtraField _extraField; - - private string _stringFileName; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOModeEnforcingStream.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOModeEnforcingStream.cs deleted file mode 100644 index 9304631a5c9..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOModeEnforcingStream.cs +++ /dev/null @@ -1,320 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using System.Collections; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOModeEnforcingStream: Stream, IDisposable - { - // !!!!!!!!! Attention !!!!!!!!!!!! - // This stream is NOT doing any data buffering by design - // All data buffering is done underneath, by either - // FileItemStream or Compression Stream - // This assumption is used through the code of the - // FileItemBlock to calculate up to data CompressedSize UncompressedSize DirtyFlag and others - // !!!!!!!!! Attention !!!!!!!!!!!! - - //////////////////////////////////// - // Stream section - ///////////////////////////////// - override public bool CanRead - { - get - { - return (!_disposedFlag && - _baseStream.CanRead && - ((_access == FileAccess.Read) || (_access == FileAccess.ReadWrite))); - } - } - - override public bool CanSeek - { - get - { - return (!_disposedFlag) && (_baseStream.CanSeek); - } - } - - override public bool CanWrite - { - get - { - return (!_disposedFlag && - _baseStream.CanWrite && - ((_access == FileAccess.Write) || (_access == FileAccess.ReadWrite))); - } - } - - override public long Length - { - get - { - CheckDisposed(); - long result = _baseStream.Length; - - // This can definetly lead to consuming more memory Compression stream - // might sitch to Emulation mode - // disabling auto flushing functionality As a part of implementing Isolated storage fallback in the Sparse MemoryStream - //_trackingMemoryStreamFactory.ReportTransactionComplete(); - - return result; - } - } - - override public long Position - { - get - { - CheckDisposed(); - return _currentStreamPosition; - } - set - { - CheckDisposed(); - Seek(value, SeekOrigin.Begin); - } - } - - public override void SetLength(long newLength) - { - CheckDisposed(); - - if (!CanWrite) - { - throw new NotSupportedException(SR.Get(SRID.SetLengthNotSupported)); - } - - _baseStream.SetLength(newLength); - - if (newLength < _currentStreamPosition) - _currentStreamPosition = newLength; - - // This can definetly lead to consuming more memory - // disabling auto flushing functionality As a part of implementing Isolated storage fallback in the Sparse MemoryStream - //_trackingMemoryStreamFactory.ReportTransactionComplete(); - } - - override public long Seek(long offset, SeekOrigin origin) - { - CheckDisposed(); - long newStreamPosition = _currentStreamPosition; - - if (origin ==SeekOrigin.Begin) - { - newStreamPosition = offset; - } - else if (origin == SeekOrigin.Current) - { - checked{newStreamPosition += offset;} - } - else if (origin == SeekOrigin.End) - { - checked{newStreamPosition = Length + offset;} - } - else - { - throw new ArgumentOutOfRangeException("origin"); - } - - if (newStreamPosition < 0) - { - throw new ArgumentException(SR.Get(SRID.SeekNegative)); - } - _currentStreamPosition = newStreamPosition; - - return _currentStreamPosition; - } - - override public int Read(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - if (!CanRead) - { - throw new NotSupportedException(SR.Get(SRID.ReadNotSupported)); - } - - long originalStreamPosition = _currentStreamPosition; - int readResult; - - try - { - _baseStream.Seek(_currentStreamPosition, SeekOrigin.Begin); - readResult = _baseStream.Read(buffer, offset, count); - checked{_currentStreamPosition += readResult;} - } - catch - { - // when an exception is thrown, the stream position should remain unchanged - _currentStreamPosition = originalStreamPosition; - - throw; - } - - // This can definetly lead to consuming more memory (compression emulation mode) - // disabling auto flushing functionality As a part of implementing Isolated storage fallback in the Sparse MemoryStream - //_trackingMemoryStreamFactory.ReportTransactionComplete(); - - return readResult; - } - - override public void Write(byte[] buffer, int offset, int count) - { - CheckDisposed(); - - if (!CanWrite) - { - throw new NotSupportedException(SR.Get(SRID.WriteNotSupported)); - } - - if (_baseStream.CanSeek) - _baseStream.Seek(_currentStreamPosition, SeekOrigin.Begin); - // if CanSeek() is false, we are already in the correct position by default - - _baseStream.Write(buffer, offset, count); - checked{_currentStreamPosition += count;} - - // This can definetly lead to consuming more memory (compression emulation mode) - // disabling auto flushing functionality As a part of implementing Isolated storage fallback in the Sparse MemoryStream - //_trackingMemoryStreamFactory.ReportTransactionComplete(); - } - - override public void Flush() - { - CheckDisposed(); - _baseStream.Flush(); // we must be calling flush on underlying stream - // we can not do something like _blockManager.SaveStream here - // as it will make impossible to push data through the stream stack - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - internal bool Disposed - { - get - { - return _disposedFlag; - } - } - - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - /// - /// Dispose(bool) - /// - /// - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - { - // multiple calls are fine - just ignore them - if (!_disposedFlag) - { - // we do that so that the block Manager and Local File Block can make a decision whether - // there are any more open streams or not - _disposedFlag = true; - - // This will enable us to make accurate decisions in regard to the number of currently opened streams - _block.DeregisterExposedStream(this); - - // we must NOT Dispose underlying stream, as it canbe used by other opened - // ZipIOModeEnforcingStream(s) and even if there no other open - // ZipIOModeEnforcingStream(s) at the moment, Cleint app can ask for more later; - // we can only Dispose underlying stream as a part of the Container Close/Dispose calls -#if !DEBUG - // Don't call Flush() in retail builds but do in debug builds to catch any - // logic errors. - if (_access == FileAccess.ReadWrite || _access == FileAccess.Write) -#endif - { - // Tell the block manager that we want to be closed - // the second parameter is ignored in the non-streaming cases , and it will result - // in a non-streaming container level flush - _blockManager.SaveStream(_block, true); - } - } - } - } - finally - { - _baseStream = null; - base.Dispose(disposing); - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - /// - /// Constructor - streaming and non-streaming mode - /// - /// - /// - /// block manager - /// associated block - internal ZipIOModeEnforcingStream(Stream baseStream, FileAccess access, - ZipIOBlockManager blockManager, - ZipIOLocalFileBlock block) - { - Debug.Assert(baseStream != null); - - _baseStream = baseStream; - _access = access; - _blockManager = blockManager; - _block = block; - } - - private void CheckDisposed() - { - if (_disposedFlag) - { - throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); - } - } - - //------------------------------------------------------ - // - // Private Members - // - //------------------------------------------------------ - private Stream _baseStream; - private FileAccess _access; - - private bool _disposedFlag; - private long _currentStreamPosition; - - // Streaming Mode only - private ZipIOLocalFileBlock _block; // null if not in streaming mode - private ZipIOBlockManager _blockManager; // null if not in streaming mode - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIORawDataFileBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIORawDataFileBlock.cs deleted file mode 100644 index a68b2b7db6f..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIORawDataFileBlock.cs +++ /dev/null @@ -1,256 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.IO.Packaging; // for PackagingUtilities - -namespace MS.Internal.IO.Zip -{ - internal class ZipIORawDataFileBlock : IZipIOBlock - { - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - // standard IZipIOBlock functionality - public long Offset - { - get - { - return _offset; - } - } - - public long Size - { - get - { - return _size; - } - } - - public bool GetDirtyFlag(bool closingFlag) - { - return _dirtyFlag; - } - - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - public void Move(long shiftSize) - { - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - _dirtyFlag = true; - Debug.Assert(_offset >=0); - } - } - - public void Save() - { - if(GetDirtyFlag(true)) // in case we do not know whether we are closing or not we should think we are closing as a more conservative approach - { - // we need to move the whole block to the new position - long moveBlockSourceOffset = _persistedOffset; - long moveBlockSize = _size; - long moveBlockTargetOffset = _offset; - - if (_cachePrefixStream != null) - { - // if we have something in cache we only should move whatever isn't cached - checked{moveBlockSourceOffset += _cachePrefixStream.Length;} - checked{moveBlockTargetOffset += _cachePrefixStream.Length;} - checked{moveBlockSize -= _cachePrefixStream.Length;} - Debug.Assert(moveBlockSize >=0); - } - - _blockManager.MoveData(moveBlockSourceOffset, moveBlockTargetOffset, moveBlockSize); - - // only after data on disk was moved it is safe to flush the cached prefix buffer - if (_cachePrefixStream != null) - { - if (_blockManager.Stream.Position != _offset) - { - // we need to seek - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - } - - Debug.Assert(_cachePrefixStream.Length > 0); // should be taken care of by the constructor - // and PreSaveNotification - - // we do not need to flush here because Block Manager is responsible for flushing - // this in it's Save method - _cachePrefixStream.WriteToStream(_blockManager.Stream); - - // we can free the memory - _cachePrefixStream.Close(); - _cachePrefixStream = null; - } - - // we are not shifted between on disk image and in memory image any more - _persistedOffset = _offset; - - _dirtyFlag = false; - } - } - - public void UpdateReferences(bool closingFlag) - { - // this block doesn't have external references so there is nothing we need to do here - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - return ZipIOBlockManager.CommonPreSaveNotificationHandler( - _blockManager.Stream, - offset, size, - _persistedOffset, _size, - ref _cachePrefixStream); - } - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - internal long DiskImageShift - { - get - { - return _offset - _persistedOffset; - } - } - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - internal static ZipIORawDataFileBlock Assign(ZipIOBlockManager blockManager, long offset, long size) - { - if (size <= 0) - { - throw new ArgumentOutOfRangeException ("size"); - } - - if (offset < 0) - { - throw new ArgumentOutOfRangeException ("offset"); - } - - ZipIORawDataFileBlock block = new ZipIORawDataFileBlock(blockManager); - block._persistedOffset = offset; - block._offset = offset; - block._size = size; - - return block; - } - - internal bool DiskImageContains(IZipIOBlock block) - { - checked - { - Debug.Assert(block != null); - Debug.Assert(block.Offset >=0); - Debug.Assert(block.Size > 0); - - return (_persistedOffset <= block.Offset) && - (_persistedOffset + _size >= block.Offset +block.Size); - } - } - - internal bool DiskImageContains(long offset) - { - checked - { - Debug.Assert(offset >=0); - - return (_persistedOffset <= offset) && (_persistedOffset + _size > offset); - } - } - - internal void SplitIntoPrefixSuffix(IZipIOBlock block, - out ZipIORawDataFileBlock prefixBlock, out ZipIORawDataFileBlock suffixBlock) - { - // assert that current's block cache isn't loaded, if it is - // we probably missed an opportunity to used this cache in order to parse the new block - // and it might be based on the overriden data on disk - // This block can only be in cached state as a part of single BlockManager.Save execution. - // It can NOT be in cached state prior to BlockManager.Save function entry or after - // BlockManager.Save execution completed - Debug.Assert(_cachePrefixStream == null); - - // Assert that block is containe inside the current raw block - Debug.Assert(DiskImageContains(block)); - - checked - { - prefixBlock = null; - suffixBlock = null; - if (block.Offset > _persistedOffset) - { - // we have a new non empty prefix; - long newBlockOffset = _persistedOffset; - long newBlockSize = block.Offset - _persistedOffset; - - prefixBlock = Assign(_blockManager, newBlockOffset , newBlockSize); - } - - if (block.Offset + block.Size < _persistedOffset + _size) - { - // we have a new non empty suffix; - long newBlockOffset = block.Offset + block.Size; - long newBlockSize = _persistedOffset + _size - newBlockOffset; - - suffixBlock = Assign(_blockManager, newBlockOffset, newBlockSize); - } - } - } - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - private ZipIORawDataFileBlock(ZipIOBlockManager blockManager) - { - _blockManager = blockManager; - } - - //------------------------------------------------------ - // - // Private Members - // - //------------------------------------------------------ - private SparseMemoryStream _cachePrefixStream = null; - - private ZipIOBlockManager _blockManager; - - private long _persistedOffset; - - private long _offset; - private long _size; - private bool _dirtyFlag; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOVersionNeededToExtract.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOVersionNeededToExtract.cs deleted file mode 100644 index f3929516aad..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOVersionNeededToExtract.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal enumeration that maintains version needed to extract values -// for OPC scenarios -// -// -// -// - - -namespace MS.Internal.IO.Zip -{ - internal enum ZipIOVersionNeededToExtract : ushort - { - StoredData = 10, - VolumeLabel = 11, - DeflatedData = 20, - Zip64FileFormat = 45, - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryBlock.cs deleted file mode 100644 index 4183f62355c..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryBlock.cs +++ /dev/null @@ -1,436 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios (Zip 64 bit support) -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOZip64EndOfCentralDirectoryBlock : IZipIOBlock - { - // standard IZipIOBlock functionality - public long Offset - { - get - { - return _offset; - } - } - - public long Size - { - get - { - return _size; - } - } - - // This property will only return reliable result if UpdateReferences is called prior - public bool GetDirtyFlag(bool closingFlag) - { - return _dirtyFlag; - } - - public void Move(long shiftSize) - { - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - - if (_size > 0) - { - _dirtyFlag = true; - } - - Debug.Assert(_offset >=0); - } - } - - public void Save() - { - // this record is optional and shouldn't be saved if size is 0 - if (GetDirtyFlag(true) && (Size > 0)) - { - BinaryWriter writer = _blockManager.BinaryWriter; - if (_blockManager.Stream.Position != _offset) - { - // we need to seek , as current position isn't accurate - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - } - - writer.Write(_signatureConstant); - writer.Write(_sizeOfZip64EndOfCentralDirectory); - writer.Write(_versionMadeBy); - writer.Write(_versionNeededToExtract); - writer.Write(_numberOfThisDisk); - writer.Write(_numberOfTheDiskWithTheStartOfTheCentralDirectory); - writer.Write(_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk); - writer.Write(_totalNumberOfEntriesInTheCentralDirectory); - writer.Write(_sizeOfTheCentralDirectory); - writer.Write(_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber); - - if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) - { - Debug.Assert(_zip64ExtensibleDataSector != null); - Debug.Assert(_zip64ExtensibleDataSector.Length == - checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); - - writer.Write(_zip64ExtensibleDataSector, - 0, - checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); - } - - writer.Flush(); - } - - _dirtyFlag = false; - } - - public void UpdateReferences(bool closingFlag) - { - checked - { - // check whether Central directory is loaded and update references accordingly - // if one or more of the following conditions are true - // 1. Central Directory is dirty - // 2. streaming mode - // if Central Directory isn't loaded or none of the relevant structure is dirty, - // there is nothing to update for Zip64 End Of Central directory record - if (_blockManager.IsCentralDirectoryBlockLoaded - && (_blockManager.Streaming - || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag))) - { - if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) - { - UInt64 centralDirCount = (UInt64)_blockManager.CentralDirectoryBlock.Count; - UInt64 centralDirBlockSize = (UInt64)_blockManager.CentralDirectoryBlock.Size; - UInt64 centralDirOffset = (UInt64)_blockManager.CentralDirectoryBlock.Offset; - - // Here is a diagram of the record - //---------------------------------------------------------------------------------------------------------------------- - //|SignatureConst (4 bytes)|sizeOfZip64Eocd (8 bytes)|misc fixed fields (44 bytes)|Variable Size Extensible Data sector| - //A------------------------B-------------------------C----------------------------D------------------------------------E - // - // in order to calculate the actual record size we subtract _fixedMinimalValueOfSizeOfZip64EOCD (This is a chunk marked - // (C,D) in thre diagram above) from _fixedMinimalRecordSize (This is a chunk marked (A,D) in the diagram above). - // Then we add the resulting value (which would be chunked marked (A,C) to the value of sizeOfZip64Eocd field which - // contains the size of the record starting at point (C) and going to the end (E). So we get the total size as - // (A,C) + (C,E) = (A,E) - // - - long size = checked((long)( - // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD - _sizeOfZip64EndOfCentralDirectory + - // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 - _fixedMinimalRecordSize - - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains - // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 - _fixedMinimalValueOfSizeOfZip64EOCD)); - - // update value and mark record dirty if either it is already dirty or there is a mismatch - if ((_dirtyFlag) || - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != centralDirCount) || - (_totalNumberOfEntriesInTheCentralDirectory != centralDirCount ) || - (_sizeOfTheCentralDirectory != centralDirBlockSize) || - (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber != centralDirOffset) || - (_size != size)) - { - _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; - _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; - - _numberOfThisDisk = 0; - _numberOfTheDiskWithTheStartOfTheCentralDirectory = 0; - - _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = centralDirCount; - _totalNumberOfEntriesInTheCentralDirectory = centralDirCount; - _sizeOfTheCentralDirectory = centralDirBlockSize; - _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = centralDirOffset; - - _size = size; - - _dirtyFlag = true; - } - } - else - { - // we do not need zip 64 structures - if (_size != 0) - { - _dirtyFlag = true; - _size = 0; - } - } - } - } - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - // we can safely ignore this notification as we do not keep any data on disk - // after parsing on disk. Everything is in memory, it is ok to override - // original Zip64 EndOf Central Directory Block without any additional backups - - // we can also safely state that there is no need to continue the PreSafeNotification loop - // as the blocks after the Zip64 Eocd (EOCD, Zip64 locator ) do not have - // data that is buffered on disk - return PreSaveNotificationScanControlInstruction.Stop; - } - - internal static ZipIOZip64EndOfCentralDirectoryBlock SeekableLoad (ZipIOBlockManager blockManager) - { - ZipIOZip64EndOfCentralDirectoryLocatorBlock zip64endOfCentralDirectoryLocator = - blockManager.Zip64EndOfCentralDirectoryLocatorBlock; - - long zip64EndOfCentralDirectoryOffset = - zip64endOfCentralDirectoryLocator.OffsetOfZip64EndOfCentralDirectoryRecord; - - ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); - - blockManager.Stream.Seek(zip64EndOfCentralDirectoryOffset, SeekOrigin.Begin); - - block.ParseRecord(blockManager.BinaryReader, zip64EndOfCentralDirectoryOffset); - - return block; - } - - internal static ZipIOZip64EndOfCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) - { - ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); - - block._size = 0; // brand new created records are optional by definition untill UpdateReferences is called, so size must be 0 - block._offset = 0; - block._dirtyFlag = false; - - // initialize fields with ythe data from the EOCD - block.InitializeFromEndOfCentralDirectory(blockManager.EndOfCentralDirectoryBlock); - - return block; - } - - internal long OffsetOfStartOfCentralDirectory - { - get - { - return (long)_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; - } - } - - internal int TotalNumberOfEntriesInTheCentralDirectory - { - get - { - return (int)_totalNumberOfEntriesInTheCentralDirectory; // checked isn't required as we do validation during parsing - } - } - - internal long SizeOfCentralDirectory - { - get - { - return (long)_sizeOfTheCentralDirectory; - } - } - - private ZipIOZip64EndOfCentralDirectoryBlock(ZipIOBlockManager blockManager) - { - Debug.Assert(blockManager != null); - _blockManager= blockManager; - } - - private void ParseRecord (BinaryReader reader, long position) - { - _signature = reader.ReadUInt32(); - _sizeOfZip64EndOfCentralDirectory = reader.ReadUInt64(); - _versionMadeBy = reader.ReadUInt16(); - _versionNeededToExtract = reader.ReadUInt16(); - _numberOfThisDisk = reader.ReadUInt32(); - _numberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt32(); - _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = reader.ReadUInt64(); - _totalNumberOfEntriesInTheCentralDirectory = reader.ReadUInt64(); - _sizeOfTheCentralDirectory = reader.ReadUInt64(); - _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt64(); - - // pre validate before reading data based on parsed values - if ((_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) || - // we are refusing to buffer large extended areas - (_sizeOfZip64EndOfCentralDirectory > UInt16.MaxValue)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) - { - _zip64ExtensibleDataSector = reader.ReadBytes((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD)); - } - - // override some numbers bvased on the EOCD data according to the apnote - // even in presence of Zip64Eocd we still need to use the regular EOCD data - OverrideValuesBasedOnEndOfCentralDirectory(_blockManager.EndOfCentralDirectoryBlock); - - _size = checked((long)( // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD - _sizeOfZip64EndOfCentralDirectory + - // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 - _fixedMinimalRecordSize - - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains - // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 - _fixedMinimalValueOfSizeOfZip64EOCD)); - Debug.Assert(_size >= _fixedMinimalRecordSize); - - _offset = position; - _dirtyFlag = false; - - Validate(); - } - - /// - /// This function is called from the Create New routine. The purpose of this exercise , is to copy data from 32 bit EOCD into this record, - /// for scenarios when ZIP64 EOCD wasn't parsed from a file, but was just made up. - /// This is done so that Central Dir parsing code can ask the ZIP64 EOCD for this data, and regardless of whether it is real zip 64 file or - /// not a zip 64 file it will get the right CD offset , size and so on - /// - private void InitializeFromEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) - { - _numberOfThisDisk = zipIoEocd.NumberOfThisDisk; - _numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory; - _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk; - _totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory; - _sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory; - _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory; - } - - /// - /// This function is called from the Parse routine. The purpose of this exercise , is to figure out the escape - /// values in the regular 32 bit EOCD. We shouldn't be using values from the 64 bit structure if it wasn't - /// escaped in the 32 bit structure. - /// - private void OverrideValuesBasedOnEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) - { - // 16 bit numbers - if (zipIoEocd.NumberOfThisDisk < UInt16.MaxValue) - {_numberOfThisDisk = zipIoEocd.NumberOfThisDisk;} - - if (zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory < UInt16.MaxValue) - {_numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory;} - - if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk < UInt16.MaxValue) - {_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk;} - - if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory < UInt16.MaxValue) - {_totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory;} - - // 32 bit numbers - if (zipIoEocd.SizeOfTheCentralDirectory < UInt32.MaxValue) - {_sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory;} - - if (zipIoEocd.OffsetOfStartOfCentralDirectory < UInt32.MaxValue) - {_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory;} -} - - private void Validate() - { - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((_numberOfThisDisk != 0) || - (_numberOfTheDiskWithTheStartOfTheCentralDirectory != 0) || - (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != - _totalNumberOfEntriesInTheCentralDirectory)) - { - throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); - } - - // this will throw an unsupported version exception if we see a version that we do not support - ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); - - // if it is one of the supported version but it isn't a ZIP64, it is an indication of a corrupted file - if (_versionNeededToExtract != (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) - { - // if version isn't equal to the 4.5 it is a corrupted file (as we) - // as appnote explicitly states that - // When using ZIP64 extensions, the corresponding value in the - // Zip64 end of central directory record should also be set. - // This field currently supports only the value 45 to indicate - // ZIP64 extensions are present. - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk > Int32.MaxValue) || - (_totalNumberOfEntriesInTheCentralDirectory > Int32.MaxValue) || - (_sizeOfTheCentralDirectory > Int64.MaxValue) || - (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber > Int64.MaxValue)) - { - // although we are trying to support 64 bit structures - // we are limited by the CLR model for collections (down to 32 bit collection size for - // _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk ) - // and streams (down to 63 bit size) for all the outher Uint64 fields - - throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge)); - } - - ulong sizeOfZip64ExtensibleDataSector = 0; - if (_zip64ExtensibleDataSector != null) - { - sizeOfZip64ExtensibleDataSector = (ulong)_zip64ExtensibleDataSector.Length; - } - - // the subtraction below doesn't need to be checked as we have validation in the parse logic - // if (_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) { throw .. } - if (_sizeOfZip64EndOfCentralDirectory - _fixedMinimalValueOfSizeOfZip64EOCD != sizeOfZip64ExtensibleDataSector) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - //calculated record size must be larger than the min value - // it could be 0 for newly created from scratch records, but we do not pass those records through validation - // we only validate parsed data - if (_size < _fixedMinimalRecordSize) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - - - private ZipIOBlockManager _blockManager; - - private long _offset; - private long _size; - - private bool _dirtyFlag; - - private const UInt32 _signatureConstant = 0x06064b50; - private const uint _fixedMinimalRecordSize = 56; - private const uint _fixedMinimalValueOfSizeOfZip64EOCD = 44; // doesn't include the signature and the size itself - - // data persisted on disk - private UInt32 _signature = _signatureConstant; - - private UInt64 _sizeOfZip64EndOfCentralDirectory = _fixedMinimalValueOfSizeOfZip64EOCD; - private UInt16 _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; - private UInt16 _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; - private UInt32 _numberOfThisDisk; - private UInt32 _numberOfTheDiskWithTheStartOfTheCentralDirectory; - private UInt64 _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk; // all int64s declared as signed values - private UInt64 _totalNumberOfEntriesInTheCentralDirectory; // as we can not suport true unsigned 64 bit sizes - private UInt64 _sizeOfTheCentralDirectory; // as a result of limitations in Stream interface - private UInt64 _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; - private byte[] _zip64ExtensibleDataSector; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs deleted file mode 100644 index 1cbb008084c..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Zip/ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs +++ /dev/null @@ -1,279 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - - -// -// -// Description: -// This is an internal class that enables interactions with Zip archives -// for OPC scenarios (Zip 64 bit support) -// -// -// -// - -using System; -using System.IO; -using System.Diagnostics; -using System.Runtime.Serialization; -using System.Windows; -using MS.Internal.WindowsBase; - -namespace MS.Internal.IO.Zip -{ - internal class ZipIOZip64EndOfCentralDirectoryLocatorBlock : IZipIOBlock - { - // standard IZipIOBlock functionality - public long Offset - { - get - { - return _offset; - } - } - - public long Size - { - get - { - return _size; - } - } - - // This property will only return reliable result if Update is called prior - public bool GetDirtyFlag(bool closingFlag) - { - return _dirtyFlag; - } - - public void Move(long shiftSize) - { - if (shiftSize != 0) - { - checked{_offset +=shiftSize;} - - if (_size > 0) - { - _dirtyFlag = true; - } - - Debug.Assert(_offset >=0); - } - } - - public void Save() - { - if (GetDirtyFlag(true) && (Size > 0)) - { - BinaryWriter writer = _blockManager.BinaryWriter; - if (_blockManager.Stream.Position != _offset) - { - // we need to seek - _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); - - // in non seekable streams we are expected to be at the right position, no seeking required - // if this assumption is ever violated. Seek will throw on non-seekable stream, which would provide us - // with a detection mechanism for such problems - } - - writer.Write(_signatureConstant); - writer.Write(_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory); - writer.Write(_offsetOfStartOfZip64EndOfCentralDirectoryRecord); - writer.Write(_totalNumberOfDisks); - - writer.Flush(); - } - - _dirtyFlag = false; - } - - public void UpdateReferences(bool closingFlag) - { - checked - { - // check whether Central directory is loaded and update references accordingly - // if one or more of the following conditions are true - // 1. Central Directory is dirty - // 2. Zip64 End of Central Directory is dirty - // 3. streaming mode - // if Central Directory isn't loded or none of the relevant structure is dirty, - // there is nothing to update for Zip64 End Of Central directory record - if ((_blockManager.IsCentralDirectoryBlockLoaded - && (_blockManager.Streaming - || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag)) - || _blockManager.Zip64EndOfCentralDirectoryBlock.GetDirtyFlag(closingFlag))) - { - if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) - { - UInt64 offsetOfStartOfZip64EndOfCentralDirectoryRecord = - (UInt64)_blockManager.Zip64EndOfCentralDirectoryBlock.Offset; - - // update value and mark record dirty if either it is already dirty or there is a mismatch - if ((_dirtyFlag) || - (offsetOfStartOfZip64EndOfCentralDirectoryRecord != _offsetOfStartOfZip64EndOfCentralDirectoryRecord) || - (_fixedMinimalRecordSize != _size)) - { - _offsetOfStartOfZip64EndOfCentralDirectoryRecord = offsetOfStartOfZip64EndOfCentralDirectoryRecord; - _size = _fixedMinimalRecordSize; - - _dirtyFlag = true; - } - } - else - { - // we do not need zip 64 structures - if (_size != 0) - { - _size = 0; - _dirtyFlag = true; - } - } - } - } - } - - public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) - { - // we can safely ignore this notification as we do not keep any data - // after parsing on disk. Everything is in memory, it is ok to override - // original End of Central directory without any additional backups - - // we can also safely state that there is no need to continue the PreSafeNotification loop - // as the only blocks after the Zip64 EOCD (EOCD) doesn't have - // data that is buffered on disk - return PreSaveNotificationScanControlInstruction.Stop; - } - - internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock SeekableLoad (ZipIOBlockManager blockManager) - { - // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition - // in both retail and debug builds - Debug.Assert(SniffTheBlockSignature(blockManager)); - - long blockPosition = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); - - blockManager.Stream.Seek(blockPosition, SeekOrigin.Begin); - - ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); - - block.ParseRecord(blockManager.BinaryReader, blockPosition); - return block; - } - - internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock CreateNew(ZipIOBlockManager blockManager) - { - // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition - // in both retail and debug builds - Debug.Assert(!SniffTheBlockSignature(blockManager)); - - ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); - - block._offset = 0; - block._size = 0; - block._dirtyFlag = false; - - return block; - } - - internal static bool SniffTheBlockSignature(ZipIOBlockManager blockManager) - { - long suspectPos = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); - - // let's check that EndOfCentralDirectoryBlock.Offset is not too close to the start of the stream - // for the record to fit there - - // the second check isn't required, strictily speaking, as we are stepping back from the EOCD.offset - // however in some theoretical cases EOCD might not be trustable so to ensure that ReadUInt32 - // isn't going to throw we do additional check - if ((suspectPos < 0) || - (checked(suspectPos + sizeof(UInt32)) > blockManager.Stream.Length)) - { - return false; - } - - blockManager.Stream.Seek(suspectPos, SeekOrigin.Begin); - - UInt32 signature = blockManager.BinaryReader.ReadUInt32(); - return (signature == _signatureConstant); - } - - internal long OffsetOfZip64EndOfCentralDirectoryRecord - { - get - { - return (long)_offsetOfStartOfZip64EndOfCentralDirectoryRecord; - } - } - - private ZipIOZip64EndOfCentralDirectoryLocatorBlock(ZipIOBlockManager blockManager) - { - Debug.Assert(blockManager != null); - _blockManager= blockManager; - } - - private void ParseRecord (BinaryReader reader, long position) - { - _signature = reader.ReadUInt32(); - _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory = reader.ReadUInt32(); - _offsetOfStartOfZip64EndOfCentralDirectoryRecord = reader.ReadUInt64(); - _totalNumberOfDisks = reader.ReadUInt32(); - - _offset = position; - _size = _fixedMinimalRecordSize; - _dirtyFlag = false; - - Validate(); - } - - private void Validate() - { - if (_offsetOfStartOfZip64EndOfCentralDirectoryRecord > Int64.MaxValue) // C# does proper upcasting to ULONG of both operands - { - // although we are trying to support 64 bit structures - // we are limited by the CLR model for streams down to 63 - // bit size for all the Uint64 fields - - throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge)); - } - - if (_signature != _signatureConstant) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - if ((_totalNumberOfDisks != 1) || - (_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory != 0)) - { - throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); - } - - // The offset of the ZIP 64 EOCD must preceed the location of the ZIP64 EOCD locator - if ((UInt64)_offset <= _offsetOfStartOfZip64EndOfCentralDirectoryRecord) // we assume that _offset >=0 - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - - // this record is optional size must be either 0 or _fixedMinimalRecordSize - if ((_size != _fixedMinimalRecordSize) && (_size != 0)) - { - throw new FileFormatException(SR.Get(SRID.CorruptedData)); - } - } - - private ZipIOBlockManager _blockManager; - - private long _offset; - private long _size; - private bool _dirtyFlag; - - private const UInt32 _signatureConstant = 0x07064b50; - private const int _fixedMinimalRecordSize = 20; - - // data persisted on disk - private UInt32 _signature = _signatureConstant; - private UInt32 _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory; - private UInt64 _offsetOfStartOfZip64EndOfCentralDirectoryRecord; - private UInt32 _totalNumberOfDisks = 1; - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj b/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj index b35ba34cc3a..fac3b7ae23e 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj @@ -119,16 +119,13 @@ - - - @@ -328,36 +325,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Common\System\IO\Compression\DeflateZLib\ZLibNative.cs