Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Shared / MS / Internal / IO / Packaging / PackagingUtilities.cs / 1 / PackagingUtilities.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // // History: // 05/13/2004: younggk Creation // //--------------------------------------------------------------------------- using System; using System.IO; using System.IO.IsolatedStorage; using MS.Internal.WindowsBase; // FriendAccessAllowed using System.Xml; // For XmlReader using System.Diagnostics; // For Debug.Assert using System.Text; // For Encoding using System.Windows; // For Exception strings - SRID using System.Security; // for SecurityCritical using System.Security.Permissions; // for permissions using Microsoft.Win32; // for Registry classes using MS.Internal; namespace MS.Internal.IO.Packaging { [FriendAccessAllowed] // Built into Base, used by Framework and Core internal static class PackagingUtilities { //----------------------------------------------------- // // Internal Fields // //----------------------------------------------------- internal static readonly string RelationshipNamespaceUri = "http://schemas.openxmlformats.org/package/2006/relationships"; internal static readonly ContentType RelationshipPartContentType = new ContentType("application/vnd.openxmlformats-package.relationships+xml"); internal const string ContainerFileExtension = "xps"; internal const string XamlFileExtension = "xaml"; //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// This method is used to determine if we support a given Encoding as per the /// OPC and XPS specs. Currently the only two encodings supported are UTF-8 and /// UTF-16 (Little Endian and Big Endian) /// /// XmlTextReader ///throws an exception if the encoding is not UTF-8 or UTF-16 internal static void PerformInitailReadAndVerifyEncoding(XmlTextReader reader) { Invariant.Assert(reader != null && reader.ReadState == ReadState.Initial); //If the first node is XmlDeclaration we check to see if the encoding attribute is present if (reader.Read() && reader.NodeType == XmlNodeType.XmlDeclaration && reader.Depth == 0) { string encoding; encoding = reader.GetAttribute(_encodingAttribute); if (encoding != null && encoding.Length > 0) { encoding = encoding.ToUpperInvariant(); //If a non-empty encoding attribute is present [for example - ] //we check to see if the value is either "utf-8" or utf-16. Only these two values are supported //Note: For Byte order markings that require additional information to be specified in //the encoding attribute in XmlDeclaration have already been ruled out by this check as we allow for //only two valid values. if (String.CompareOrdinal(encoding, _webNameUTF8) == 0 || String.CompareOrdinal(encoding, _webNameUnicode) == 0) return; else //if the encoding attribute has any other value we throw an exception throw new FileFormatException(SR.Get(SRID.EncodingNotSupported)); } } //if the XmlDeclaration is not present, or encoding attribute is not present, we //base our decision on byte order marking. reader.Encoding will take that into account //and return the correct value. //Note: For Byte order markings that require additional information to be specified in //the encoding attribute in XmlDeclaration have already been ruled out by the check above. //Note: If not encoding attribute is present or no byte order marking is present the //encoding default to UTF8 if (!(reader.Encoding is UnicodeEncoding || reader.Encoding is UTF8Encoding)) throw new FileFormatException(SR.Get(SRID.EncodingNotSupported)); } ////// VerifyStreamReadArgs /// /// stream /// buffer /// offset /// count ///Common argument verification for Stream.Read() static internal void VerifyStreamReadArgs(Stream s, byte[] buffer, int offset, int count) { if (!s.CanRead) throw new NotSupportedException(SR.Get(SRID.ReadNotSupported)); if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.OffsetNegative)); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.Get(SRID.ReadCountNegative)); } checked // catch any integer overflows { if (offset + count > buffer.Length) { throw new ArgumentException(SR.Get(SRID.ReadBufferTooSmall), "buffer"); } } } ////// VerifyStreamWriteArgs /// /// /// /// /// ///common argument verification for Stream.Write static internal void VerifyStreamWriteArgs(Stream s, byte[] buffer, int offset, int count) { if (!s.CanWrite) throw new NotSupportedException(SR.Get(SRID.WriteNotSupported)); if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.OffsetNegative)); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.Get(SRID.WriteCountNegative)); } checked { if (offset + count > buffer.Length) throw new ArgumentException(SR.Get(SRID.WriteBufferTooSmall), "buffer"); } } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// stream to read from /// buffer to read into /// offset in buffer to write to /// bytes to read ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(Stream stream, byte[] buffer, int offset, int count) { return ReliableRead(stream, buffer, offset, count, count); } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// stream to read from /// buffer to read into /// offset in buffer to write to /// count of bytes that we would like to read (max read size to try) /// minimal count of bytes that we would like to read (min read size to achieve) ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(Stream stream, byte[] buffer, int offset, int requestedCount, int requiredCount) { Invariant.Assert(stream != null); Invariant.Assert(buffer != null); Invariant.Assert(buffer.Length > 0); Invariant.Assert(offset >= 0); Invariant.Assert(requestedCount >= 0); Invariant.Assert(requiredCount >= 0); Invariant.Assert(checked(offset + requestedCount <= buffer.Length)); Invariant.Assert(requiredCount <= requestedCount); // let's read the whole block into our buffer int totalBytesRead = 0; while (totalBytesRead < requiredCount) { int bytesRead = stream.Read(buffer, offset + totalBytesRead, requestedCount - totalBytesRead); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } return totalBytesRead; } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// BinaryReader to read from /// buffer to read into /// offset in buffer to write to /// bytes to read ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(BinaryReader reader, byte[] buffer, int offset, int count) { return ReliableRead(reader, buffer, offset, count, count); } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// BinaryReader to read from /// buffer to read into /// offset in buffer to write to /// count of bytes that we would like to read (max read size to try) /// minimal count of bytes that we would like to read (min read size to achieve) ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(BinaryReader reader, byte[] buffer, int offset, int requestedCount, int requiredCount) { Invariant.Assert(reader != null); Invariant.Assert(buffer != null); Invariant.Assert(buffer.Length > 0); Invariant.Assert(offset >= 0); Invariant.Assert(requestedCount >= 0); Invariant.Assert(requiredCount >= 0); Invariant.Assert(checked(offset + requestedCount <= buffer.Length)); Invariant.Assert(requiredCount <= requestedCount); // let's read the whole block into our buffer int totalBytesRead = 0; while (totalBytesRead < requiredCount) { int bytesRead = reader.Read(buffer, offset + totalBytesRead, requestedCount - totalBytesRead); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } return totalBytesRead; } ////// CopyStream utility that is guaranteed to return the number of bytes copied (may be less then requested, /// if source stream doesn't have enough data) /// /// stream to read from /// stream to write to /// number of bytes to be copied(use Int64.MaxValue if the whole stream needs to be copied) /// number of bytes to be copied (usually it is 4K for scenarios where we expect a lot of data /// like in SparseMemoryStream case it could be larger ///bytes copied (might be less than requested if source stream is too short ///Neither source nor target stream are seeked; it is up to the caller to make sure that their positions are properly set. /// Target stream isn't truncated even if it has more data past the area that was copied. internal static long CopyStream(Stream sourceStream, Stream targetStream, long bytesToCopy, int bufferSize) { Invariant.Assert(sourceStream != null); Invariant.Assert(targetStream != null); Invariant.Assert(bytesToCopy >= 0); Invariant.Assert(bufferSize > 0); byte[] buffer = new byte[bufferSize]; // let's read the whole block into our buffer long bytesLeftToCopy = bytesToCopy; while (bytesLeftToCopy > 0) { int bytesRead = sourceStream.Read(buffer, 0, (int)Math.Min(bytesLeftToCopy, (long)bufferSize)); if (bytesRead == 0) { targetStream.Flush(); return bytesToCopy - bytesLeftToCopy; } targetStream.Write(buffer, 0, bytesRead); bytesLeftToCopy -= bytesRead; } // It must not be negative Debug.Assert(bytesLeftToCopy == 0); targetStream.Flush(); return bytesToCopy; } ////// Create a User-Domain Scoped IsolatedStorage file (or Machine-Domain scoped file if current user has no profile) /// /// returns the created file name /// number of times to retry in case of name collision (legal values between 0 and 100) ///the created stream ///retryCount was exceeded ///This function locks on IsoStoreSyncRoot and is thread-safe internal static Stream CreateUserScopedIsolatedStorageFileStreamWithRandomName(int retryCount, out String fileName) { // negative is illegal and place an upper limit of 100 if (retryCount < 0 || retryCount > 100) throw new ArgumentOutOfRangeException("retryCount"); Stream s = null; fileName = null; // GetRandomFileName returns a very random name, but collisions are still possible so we // retry if we encounter one. while (true) { try { // This function returns a highly-random name in 8.3 format. fileName = Path.GetRandomFileName(); lock (IsoStoreSyncRoot) { s = GetDefaultIsolatedStorageFile().GetStream(fileName); } // if we get to here we have a success condition so we can safely exit break; } catch (IOException) { // assume it is a name collision and ignore if we have not exhausted our retry count if (--retryCount < 0) throw; } } return s; } ////// Calculate overlap between two blocks, returning the offset and length of the overlap /// /// /// /// /// /// /// internal static void CalculateOverlap(long block1Offset, long block1Size, long block2Offset, long block2Size, out long overlapBlockOffset, out long overlapBlockSize) { checked { overlapBlockOffset = Math.Max(block1Offset, block2Offset); overlapBlockSize = Math.Min(block1Offset + block1Size, block2Offset + block2Size) - overlapBlockOffset; if (overlapBlockSize <= 0) { overlapBlockSize = 0; } } } ////// This method returns the count of xml attributes other than: /// 1. xmlns="namespace" /// 2. xmlns:someprefix="namespace" /// Reader should be positioned at the Element whose attributes /// are to be counted. /// /// ///An integer indicating the number of non-xmlns attributes internal static int GetNonXmlnsAttributeCount(XmlReader reader) { Debug.Assert(reader != null, "xmlReader should not be null"); Debug.Assert(reader.NodeType == XmlNodeType.Element, "XmlReader should be positioned at an Element"); int readerCount = 0; //If true, reader moves to the attribute //If false, there are no more attributes (or none) //and in that case the position of the reader is unchanged. //First time through, since the reader will be positioned at an Element, //MoveToNextAttribute is the same as MoveToFirstAttribute. while (reader.MoveToNextAttribute()) { if (String.CompareOrdinal(reader.Name, XmlNamespace) != 0 && String.CompareOrdinal(reader.Prefix, XmlNamespace) != 0) readerCount++; } //re-position the reader to the element reader.MoveToElement(); return readerCount; } ////// Any usage of IsolatedStorage static properties should lock on this for thread-safety /// internal static Object IsoStoreSyncRoot { get { return _isoStoreSyncObject; } } #endregion Internal Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ ////// Delete file created using CreateUserScopedIsolatedStorageFileStreamWithRandomName() /// /// ///Correctly handles temp/isostore differences private static void DeleteIsolatedStorageFile(String fileName) { lock (IsoStoreSyncRoot) { GetDefaultIsolatedStorageFile().IsoFile.DeleteFile(fileName); } } ////// Returns the IsolatedStorageFile scoped to Assembly, Domain and User /// ///Callers must lock on IsoStoreSyncRoot before calling this for thread-safety. /// For example: /// /// lock (IsoStoreSyncRoot) /// { /// // do something with the returned IsolatedStorageFile /// PackagingUtilities.DefaultIsolatedStorageFile.DeleteFile(_isolatedStorageStreamFileName); /// } /// /// private static ReliableIsolatedStorageFileFolder GetDefaultIsolatedStorageFile() { // Cache and re-use the same object for multiple requests - resurrect if disposed if (_defaultFile == null || _defaultFile.IsDisposed()) { _defaultFile = new ReliableIsolatedStorageFileFolder(); } return _defaultFile; } ////// Determine if current user has a User Profile so we can determine the appropriate /// scope to use for IsolatedStorage functionality. /// ////// Critical - Asserts read registry permission... /// - Asserts ControlPrincipal to access current user identity /// TAS - only returns a bool /// [SecurityCritical, SecurityTreatAsSafe] private static bool UserHasProfile() { // Acquire permissions to read the one key we care about from the registry // Acquite permission to query the current user identity PermissionSet permissionSet = new PermissionSet(PermissionState.None); permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlPrincipal)); permissionSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, _fullProfileListKeyName)); permissionSet.Assert(); bool userHasProfile = false; RegistryKey userProfileKey = null; try { // inspect registry and look for user profile via SID string userSid = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; userProfileKey = Registry.LocalMachine.OpenSubKey(_profileListKeyName + @"\" + userSid); userHasProfile = userProfileKey != null; } finally { if (userProfileKey != null) userProfileKey.Close(); CodeAccessPermission.RevertAssert(); } return userHasProfile; } //------------------------------------------------------ // // Private Classes // //------------------------------------------------------ ////// This class extends IsolatedStorageFileStream by adding a finalizer to ensure that /// the underlying file is deleted when the stream is closed. /// private class SafeIsolatedStorageFileStream : IsolatedStorageFileStream { //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ internal SafeIsolatedStorageFileStream( string path, FileMode mode, FileAccess access, FileShare share, ReliableIsolatedStorageFileFolder folder) : base(path, mode, access, share, folder.IsoFile) { if (path == null) throw new ArgumentNullException("path"); _path = path; _folder = folder; _folder.AddRef(); } //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // Non-standard pattern - call base.Dispose() first. // This is required because the base class is a stream and we cannot // delete the underlying file storage before it has a chance to close // and release it. base.Dispose(disposing); if (_path != null) { PackagingUtilities.DeleteIsolatedStorageFile(_path); _path = null; } //Decrement the count of files _folder.DecRef(); _folder = null; GC.SuppressFinalize(this); } _disposed = true; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private string _path; private ReliableIsolatedStorageFileFolder _folder; private bool _disposed; } ////// This class extends IsolatedStorageFileStream by adding a finalizer to ensure that /// the underlying file is deleted when the stream is closed. /// private class ReliableIsolatedStorageFileFolder : IDisposable { //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ internal IsolatedStorageFile IsoFile { get { CheckDisposed(); return _file; } } ////// Call this when a new file is created in the isoFolder /// internal void AddRef() { lock (IsoStoreSyncRoot) { CheckDisposed(); checked { ++_refCount; } } } ////// Call this when a new file is deleted from the isoFolder /// internal void DecRef() { lock (IsoStoreSyncRoot) { CheckDisposed(); checked { --_refCount; } if (_refCount <= 0) { Dispose(); } } } ////// Only used within a lock statement /// ///internal bool IsDisposed() { return _disposed; } //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ internal ReliableIsolatedStorageFileFolder() { _userHasProfile = UserHasProfile(); _file = GetCurrentStore(); } /// /// This triggers AddRef because SafeIsoStream does this in its constructor /// /// ///internal Stream GetStream(String fileName) { CheckDisposed(); // This constructor uses a scope that isolates by AppDomain and User // We cannot include Assembly scope because it prevents sharing between Base and Core dll's return new SafeIsolatedStorageFileStream( fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this); } /// /// IDisposable.Dispose() /// public void Dispose() { Dispose(true); } //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ protected virtual void Dispose(bool disposing) { try { // only lock if we are disposing if (disposing) { lock (IsoStoreSyncRoot) { if (!_disposed) { using (_file) { _file.Remove(); } _disposed = true; } _file = null; } GC.SuppressFinalize(this); } else { // We cannot rely on other managed objects in our finalizer // so we allocate a fresh object to help us delete our temp folder. using (IsolatedStorageFile file = GetCurrentStore()) { file.Remove(); } } } catch (IsolatedStorageException) { // IsolatedStorageException can be thrown if the files that are being deleted, are // currently in use. These files will not get cleaned up. } } //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ ////// Call this sparingly as it allocates resources /// ///private IsolatedStorageFile GetCurrentStore() { if (_userHasProfile) { return IsolatedStorageFile.GetUserStoreForDomain(); } else { return IsolatedStorageFile.GetMachineStoreForDomain(); } } ~ReliableIsolatedStorageFileFolder() { Dispose(false); } void CheckDisposed() { if (_disposed) throw new ObjectDisposedException("ReliableIsolatedStorageFileFolder"); } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private static IsolatedStorageFile _file; private static bool _userHasProfile; private int _refCount; // number of outstanding "streams" private bool _disposed; } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ /// /// Synchronize access to IsolatedStorage methods that can step on each-other /// ///See PS 1468964 for details. private static Object _isoStoreSyncObject = new Object(); private static ReliableIsolatedStorageFileFolder _defaultFile; private const string XmlNamespace = "xmlns"; private const string _encodingAttribute = "encoding"; private static readonly string _webNameUTF8 = Encoding.UTF8.WebName.ToUpperInvariant(); private static readonly string _webNameUnicode = Encoding.Unicode.WebName.ToUpperInvariant(); ////// ProfileListKeyName /// ////// _profileListKeyName must remain readonly for security reasons /// private const string _profileListKeyName = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"; private const string _fullProfileListKeyName = @"HKEY_LOCAL_MACHINE\" + _profileListKeyName; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // // History: // 05/13/2004: younggk Creation // //--------------------------------------------------------------------------- using System; using System.IO; using System.IO.IsolatedStorage; using MS.Internal.WindowsBase; // FriendAccessAllowed using System.Xml; // For XmlReader using System.Diagnostics; // For Debug.Assert using System.Text; // For Encoding using System.Windows; // For Exception strings - SRID using System.Security; // for SecurityCritical using System.Security.Permissions; // for permissions using Microsoft.Win32; // for Registry classes using MS.Internal; namespace MS.Internal.IO.Packaging { [FriendAccessAllowed] // Built into Base, used by Framework and Core internal static class PackagingUtilities { //----------------------------------------------------- // // Internal Fields // //----------------------------------------------------- internal static readonly string RelationshipNamespaceUri = "http://schemas.openxmlformats.org/package/2006/relationships"; internal static readonly ContentType RelationshipPartContentType = new ContentType("application/vnd.openxmlformats-package.relationships+xml"); internal const string ContainerFileExtension = "xps"; internal const string XamlFileExtension = "xaml"; //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// This method is used to determine if we support a given Encoding as per the /// OPC and XPS specs. Currently the only two encodings supported are UTF-8 and /// UTF-16 (Little Endian and Big Endian) /// /// XmlTextReader ///throws an exception if the encoding is not UTF-8 or UTF-16 internal static void PerformInitailReadAndVerifyEncoding(XmlTextReader reader) { Invariant.Assert(reader != null && reader.ReadState == ReadState.Initial); //If the first node is XmlDeclaration we check to see if the encoding attribute is present if (reader.Read() && reader.NodeType == XmlNodeType.XmlDeclaration && reader.Depth == 0) { string encoding; encoding = reader.GetAttribute(_encodingAttribute); if (encoding != null && encoding.Length > 0) { encoding = encoding.ToUpperInvariant(); //If a non-empty encoding attribute is present [for example - ] //we check to see if the value is either "utf-8" or utf-16. Only these two values are supported //Note: For Byte order markings that require additional information to be specified in //the encoding attribute in XmlDeclaration have already been ruled out by this check as we allow for //only two valid values. if (String.CompareOrdinal(encoding, _webNameUTF8) == 0 || String.CompareOrdinal(encoding, _webNameUnicode) == 0) return; else //if the encoding attribute has any other value we throw an exception throw new FileFormatException(SR.Get(SRID.EncodingNotSupported)); } } //if the XmlDeclaration is not present, or encoding attribute is not present, we //base our decision on byte order marking. reader.Encoding will take that into account //and return the correct value. //Note: For Byte order markings that require additional information to be specified in //the encoding attribute in XmlDeclaration have already been ruled out by the check above. //Note: If not encoding attribute is present or no byte order marking is present the //encoding default to UTF8 if (!(reader.Encoding is UnicodeEncoding || reader.Encoding is UTF8Encoding)) throw new FileFormatException(SR.Get(SRID.EncodingNotSupported)); } ////// VerifyStreamReadArgs /// /// stream /// buffer /// offset /// count ///Common argument verification for Stream.Read() static internal void VerifyStreamReadArgs(Stream s, byte[] buffer, int offset, int count) { if (!s.CanRead) throw new NotSupportedException(SR.Get(SRID.ReadNotSupported)); if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.OffsetNegative)); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.Get(SRID.ReadCountNegative)); } checked // catch any integer overflows { if (offset + count > buffer.Length) { throw new ArgumentException(SR.Get(SRID.ReadBufferTooSmall), "buffer"); } } } ////// VerifyStreamWriteArgs /// /// /// /// /// ///common argument verification for Stream.Write static internal void VerifyStreamWriteArgs(Stream s, byte[] buffer, int offset, int count) { if (!s.CanWrite) throw new NotSupportedException(SR.Get(SRID.WriteNotSupported)); if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.OffsetNegative)); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.Get(SRID.WriteCountNegative)); } checked { if (offset + count > buffer.Length) throw new ArgumentException(SR.Get(SRID.WriteBufferTooSmall), "buffer"); } } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// stream to read from /// buffer to read into /// offset in buffer to write to /// bytes to read ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(Stream stream, byte[] buffer, int offset, int count) { return ReliableRead(stream, buffer, offset, count, count); } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// stream to read from /// buffer to read into /// offset in buffer to write to /// count of bytes that we would like to read (max read size to try) /// minimal count of bytes that we would like to read (min read size to achieve) ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(Stream stream, byte[] buffer, int offset, int requestedCount, int requiredCount) { Invariant.Assert(stream != null); Invariant.Assert(buffer != null); Invariant.Assert(buffer.Length > 0); Invariant.Assert(offset >= 0); Invariant.Assert(requestedCount >= 0); Invariant.Assert(requiredCount >= 0); Invariant.Assert(checked(offset + requestedCount <= buffer.Length)); Invariant.Assert(requiredCount <= requestedCount); // let's read the whole block into our buffer int totalBytesRead = 0; while (totalBytesRead < requiredCount) { int bytesRead = stream.Read(buffer, offset + totalBytesRead, requestedCount - totalBytesRead); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } return totalBytesRead; } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// BinaryReader to read from /// buffer to read into /// offset in buffer to write to /// bytes to read ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(BinaryReader reader, byte[] buffer, int offset, int count) { return ReliableRead(reader, buffer, offset, count, count); } ////// Read utility that is guaranteed to return the number of bytes requested /// if they are available. /// /// BinaryReader to read from /// buffer to read into /// offset in buffer to write to /// count of bytes that we would like to read (max read size to try) /// minimal count of bytes that we would like to read (min read size to achieve) ///bytes read ///Normal Stream.Read does not guarantee how many bytes it will /// return. This one does. internal static int ReliableRead(BinaryReader reader, byte[] buffer, int offset, int requestedCount, int requiredCount) { Invariant.Assert(reader != null); Invariant.Assert(buffer != null); Invariant.Assert(buffer.Length > 0); Invariant.Assert(offset >= 0); Invariant.Assert(requestedCount >= 0); Invariant.Assert(requiredCount >= 0); Invariant.Assert(checked(offset + requestedCount <= buffer.Length)); Invariant.Assert(requiredCount <= requestedCount); // let's read the whole block into our buffer int totalBytesRead = 0; while (totalBytesRead < requiredCount) { int bytesRead = reader.Read(buffer, offset + totalBytesRead, requestedCount - totalBytesRead); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } return totalBytesRead; } ////// CopyStream utility that is guaranteed to return the number of bytes copied (may be less then requested, /// if source stream doesn't have enough data) /// /// stream to read from /// stream to write to /// number of bytes to be copied(use Int64.MaxValue if the whole stream needs to be copied) /// number of bytes to be copied (usually it is 4K for scenarios where we expect a lot of data /// like in SparseMemoryStream case it could be larger ///bytes copied (might be less than requested if source stream is too short ///Neither source nor target stream are seeked; it is up to the caller to make sure that their positions are properly set. /// Target stream isn't truncated even if it has more data past the area that was copied. internal static long CopyStream(Stream sourceStream, Stream targetStream, long bytesToCopy, int bufferSize) { Invariant.Assert(sourceStream != null); Invariant.Assert(targetStream != null); Invariant.Assert(bytesToCopy >= 0); Invariant.Assert(bufferSize > 0); byte[] buffer = new byte[bufferSize]; // let's read the whole block into our buffer long bytesLeftToCopy = bytesToCopy; while (bytesLeftToCopy > 0) { int bytesRead = sourceStream.Read(buffer, 0, (int)Math.Min(bytesLeftToCopy, (long)bufferSize)); if (bytesRead == 0) { targetStream.Flush(); return bytesToCopy - bytesLeftToCopy; } targetStream.Write(buffer, 0, bytesRead); bytesLeftToCopy -= bytesRead; } // It must not be negative Debug.Assert(bytesLeftToCopy == 0); targetStream.Flush(); return bytesToCopy; } ////// Create a User-Domain Scoped IsolatedStorage file (or Machine-Domain scoped file if current user has no profile) /// /// returns the created file name /// number of times to retry in case of name collision (legal values between 0 and 100) ///the created stream ///retryCount was exceeded ///This function locks on IsoStoreSyncRoot and is thread-safe internal static Stream CreateUserScopedIsolatedStorageFileStreamWithRandomName(int retryCount, out String fileName) { // negative is illegal and place an upper limit of 100 if (retryCount < 0 || retryCount > 100) throw new ArgumentOutOfRangeException("retryCount"); Stream s = null; fileName = null; // GetRandomFileName returns a very random name, but collisions are still possible so we // retry if we encounter one. while (true) { try { // This function returns a highly-random name in 8.3 format. fileName = Path.GetRandomFileName(); lock (IsoStoreSyncRoot) { s = GetDefaultIsolatedStorageFile().GetStream(fileName); } // if we get to here we have a success condition so we can safely exit break; } catch (IOException) { // assume it is a name collision and ignore if we have not exhausted our retry count if (--retryCount < 0) throw; } } return s; } ////// Calculate overlap between two blocks, returning the offset and length of the overlap /// /// /// /// /// /// /// internal static void CalculateOverlap(long block1Offset, long block1Size, long block2Offset, long block2Size, out long overlapBlockOffset, out long overlapBlockSize) { checked { overlapBlockOffset = Math.Max(block1Offset, block2Offset); overlapBlockSize = Math.Min(block1Offset + block1Size, block2Offset + block2Size) - overlapBlockOffset; if (overlapBlockSize <= 0) { overlapBlockSize = 0; } } } ////// This method returns the count of xml attributes other than: /// 1. xmlns="namespace" /// 2. xmlns:someprefix="namespace" /// Reader should be positioned at the Element whose attributes /// are to be counted. /// /// ///An integer indicating the number of non-xmlns attributes internal static int GetNonXmlnsAttributeCount(XmlReader reader) { Debug.Assert(reader != null, "xmlReader should not be null"); Debug.Assert(reader.NodeType == XmlNodeType.Element, "XmlReader should be positioned at an Element"); int readerCount = 0; //If true, reader moves to the attribute //If false, there are no more attributes (or none) //and in that case the position of the reader is unchanged. //First time through, since the reader will be positioned at an Element, //MoveToNextAttribute is the same as MoveToFirstAttribute. while (reader.MoveToNextAttribute()) { if (String.CompareOrdinal(reader.Name, XmlNamespace) != 0 && String.CompareOrdinal(reader.Prefix, XmlNamespace) != 0) readerCount++; } //re-position the reader to the element reader.MoveToElement(); return readerCount; } ////// Any usage of IsolatedStorage static properties should lock on this for thread-safety /// internal static Object IsoStoreSyncRoot { get { return _isoStoreSyncObject; } } #endregion Internal Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ ////// Delete file created using CreateUserScopedIsolatedStorageFileStreamWithRandomName() /// /// ///Correctly handles temp/isostore differences private static void DeleteIsolatedStorageFile(String fileName) { lock (IsoStoreSyncRoot) { GetDefaultIsolatedStorageFile().IsoFile.DeleteFile(fileName); } } ////// Returns the IsolatedStorageFile scoped to Assembly, Domain and User /// ///Callers must lock on IsoStoreSyncRoot before calling this for thread-safety. /// For example: /// /// lock (IsoStoreSyncRoot) /// { /// // do something with the returned IsolatedStorageFile /// PackagingUtilities.DefaultIsolatedStorageFile.DeleteFile(_isolatedStorageStreamFileName); /// } /// /// private static ReliableIsolatedStorageFileFolder GetDefaultIsolatedStorageFile() { // Cache and re-use the same object for multiple requests - resurrect if disposed if (_defaultFile == null || _defaultFile.IsDisposed()) { _defaultFile = new ReliableIsolatedStorageFileFolder(); } return _defaultFile; } ////// Determine if current user has a User Profile so we can determine the appropriate /// scope to use for IsolatedStorage functionality. /// ////// Critical - Asserts read registry permission... /// - Asserts ControlPrincipal to access current user identity /// TAS - only returns a bool /// [SecurityCritical, SecurityTreatAsSafe] private static bool UserHasProfile() { // Acquire permissions to read the one key we care about from the registry // Acquite permission to query the current user identity PermissionSet permissionSet = new PermissionSet(PermissionState.None); permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlPrincipal)); permissionSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, _fullProfileListKeyName)); permissionSet.Assert(); bool userHasProfile = false; RegistryKey userProfileKey = null; try { // inspect registry and look for user profile via SID string userSid = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; userProfileKey = Registry.LocalMachine.OpenSubKey(_profileListKeyName + @"\" + userSid); userHasProfile = userProfileKey != null; } finally { if (userProfileKey != null) userProfileKey.Close(); CodeAccessPermission.RevertAssert(); } return userHasProfile; } //------------------------------------------------------ // // Private Classes // //------------------------------------------------------ ////// This class extends IsolatedStorageFileStream by adding a finalizer to ensure that /// the underlying file is deleted when the stream is closed. /// private class SafeIsolatedStorageFileStream : IsolatedStorageFileStream { //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ internal SafeIsolatedStorageFileStream( string path, FileMode mode, FileAccess access, FileShare share, ReliableIsolatedStorageFileFolder folder) : base(path, mode, access, share, folder.IsoFile) { if (path == null) throw new ArgumentNullException("path"); _path = path; _folder = folder; _folder.AddRef(); } //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // Non-standard pattern - call base.Dispose() first. // This is required because the base class is a stream and we cannot // delete the underlying file storage before it has a chance to close // and release it. base.Dispose(disposing); if (_path != null) { PackagingUtilities.DeleteIsolatedStorageFile(_path); _path = null; } //Decrement the count of files _folder.DecRef(); _folder = null; GC.SuppressFinalize(this); } _disposed = true; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private string _path; private ReliableIsolatedStorageFileFolder _folder; private bool _disposed; } ////// This class extends IsolatedStorageFileStream by adding a finalizer to ensure that /// the underlying file is deleted when the stream is closed. /// private class ReliableIsolatedStorageFileFolder : IDisposable { //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ internal IsolatedStorageFile IsoFile { get { CheckDisposed(); return _file; } } ////// Call this when a new file is created in the isoFolder /// internal void AddRef() { lock (IsoStoreSyncRoot) { CheckDisposed(); checked { ++_refCount; } } } ////// Call this when a new file is deleted from the isoFolder /// internal void DecRef() { lock (IsoStoreSyncRoot) { CheckDisposed(); checked { --_refCount; } if (_refCount <= 0) { Dispose(); } } } ////// Only used within a lock statement /// ///internal bool IsDisposed() { return _disposed; } //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ internal ReliableIsolatedStorageFileFolder() { _userHasProfile = UserHasProfile(); _file = GetCurrentStore(); } /// /// This triggers AddRef because SafeIsoStream does this in its constructor /// /// ///internal Stream GetStream(String fileName) { CheckDisposed(); // This constructor uses a scope that isolates by AppDomain and User // We cannot include Assembly scope because it prevents sharing between Base and Core dll's return new SafeIsolatedStorageFileStream( fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this); } /// /// IDisposable.Dispose() /// public void Dispose() { Dispose(true); } //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ protected virtual void Dispose(bool disposing) { try { // only lock if we are disposing if (disposing) { lock (IsoStoreSyncRoot) { if (!_disposed) { using (_file) { _file.Remove(); } _disposed = true; } _file = null; } GC.SuppressFinalize(this); } else { // We cannot rely on other managed objects in our finalizer // so we allocate a fresh object to help us delete our temp folder. using (IsolatedStorageFile file = GetCurrentStore()) { file.Remove(); } } } catch (IsolatedStorageException) { // IsolatedStorageException can be thrown if the files that are being deleted, are // currently in use. These files will not get cleaned up. } } //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ ////// Call this sparingly as it allocates resources /// ///private IsolatedStorageFile GetCurrentStore() { if (_userHasProfile) { return IsolatedStorageFile.GetUserStoreForDomain(); } else { return IsolatedStorageFile.GetMachineStoreForDomain(); } } ~ReliableIsolatedStorageFileFolder() { Dispose(false); } void CheckDisposed() { if (_disposed) throw new ObjectDisposedException("ReliableIsolatedStorageFileFolder"); } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private static IsolatedStorageFile _file; private static bool _userHasProfile; private int _refCount; // number of outstanding "streams" private bool _disposed; } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ /// /// Synchronize access to IsolatedStorage methods that can step on each-other /// ///See PS 1468964 for details. private static Object _isoStoreSyncObject = new Object(); private static ReliableIsolatedStorageFileFolder _defaultFile; private const string XmlNamespace = "xmlns"; private const string _encodingAttribute = "encoding"; private static readonly string _webNameUTF8 = Encoding.UTF8.WebName.ToUpperInvariant(); private static readonly string _webNameUnicode = Encoding.Unicode.WebName.ToUpperInvariant(); ////// ProfileListKeyName /// ////// _profileListKeyName must remain readonly for security reasons /// private const string _profileListKeyName = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"; private const string _fullProfileListKeyName = @"HKEY_LOCAL_MACHINE\" + _profileListKeyName; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- __ComObject.cs
- DirectoryGroupQuery.cs
- ZeroOpNode.cs
- DateTime.cs
- BitmapEffectCollection.cs
- ModelPropertyDescriptor.cs
- InstanceData.cs
- BuildManager.cs
- ChtmlMobileTextWriter.cs
- WindowsListViewSubItem.cs
- HttpDictionary.cs
- OracleString.cs
- FastPropertyAccessor.cs
- TransactedReceiveData.cs
- Point3D.cs
- FrameAutomationPeer.cs
- MembershipSection.cs
- SafeNativeMethods.cs
- TableHeaderCell.cs
- DirtyTextRange.cs
- CodeComment.cs
- ContentElementAutomationPeer.cs
- QueryInterceptorAttribute.cs
- ListViewUpdatedEventArgs.cs
- X509Extension.cs
- TableProviderWrapper.cs
- BitmapEffectrendercontext.cs
- HttpWriter.cs
- ContractInstanceProvider.cs
- DataGridSortCommandEventArgs.cs
- TextEncodedRawTextWriter.cs
- BitmapPalettes.cs
- OuterGlowBitmapEffect.cs
- TraceUtility.cs
- DelegateTypeInfo.cs
- WindowsFormsSynchronizationContext.cs
- _ConnectStream.cs
- UIAgentAsyncEndRequest.cs
- BinaryUtilClasses.cs
- PtsPage.cs
- StylusDevice.cs
- OrderPreservingMergeHelper.cs
- HybridDictionary.cs
- BatchParser.cs
- Attributes.cs
- OfTypeExpression.cs
- WebMessageEncoderFactory.cs
- DelegateArgumentReference.cs
- TableCell.cs
- XmlLanguage.cs
- ResolveCriteriaApril2005.cs
- GradientStop.cs
- GACMembershipCondition.cs
- Normalization.cs
- DynamicRenderer.cs
- latinshape.cs
- cookiecontainer.cs
- MultiTrigger.cs
- Closure.cs
- SerializationSectionGroup.cs
- MSAANativeProvider.cs
- Command.cs
- XmlSchemaType.cs
- KeyGestureValueSerializer.cs
- RawStylusSystemGestureInputReport.cs
- MediaCommands.cs
- XsdDuration.cs
- Unit.cs
- GorillaCodec.cs
- InvokeSchedule.cs
- AutomationFocusChangedEventArgs.cs
- SoapAttributeAttribute.cs
- RightNameExpirationInfoPair.cs
- RegexEditorDialog.cs
- ProfileSettingsCollection.cs
- ControlParameter.cs
- MetadataArtifactLoaderResource.cs
- NavigationHelper.cs
- Matrix3DStack.cs
- FullTextBreakpoint.cs
- LocalizationParserHooks.cs
- AuthorizationSection.cs
- DataRowCollection.cs
- Effect.cs
- IsolatedStorageFileStream.cs
- NamespaceDecl.cs
- DesignColumn.cs
- _CacheStreams.cs
- ChannelManager.cs
- TagPrefixCollection.cs
- DataGridViewLinkCell.cs
- CFStream.cs
- MailMessageEventArgs.cs
- ContextActivityUtils.cs
- AdapterDictionary.cs
- ServiceAuthorizationElement.cs
- CodeFieldReferenceExpression.cs
- CategoryGridEntry.cs
- RetrieveVirtualItemEventArgs.cs
- SpellerHighlightLayer.cs