Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / MS / Internal / IO / Packaging / CompoundFile / VersionedStreamOwner.cs / 1 / VersionedStreamOwner.cs
//------------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description:
// This class provides file versioning support for streams provided by
// IDataTransform implementations and any client code that needs
// to store a FormatVersion at the beginning of a stream.
//
// History:
// 02/21/2006: BruceMac: Initial implementation.
//
//-----------------------------------------------------------------------------
using System;
using System.IO; // for Stream
using System.Windows; // ExceptionStringTable
using System.Globalization; // for CultureInfo
using System.Diagnostics; // for Debug.Assert
namespace MS.Internal.IO.Packaging.CompoundFile
{
///
/// Specialized stream that owns the FormatVersion
///
/// Dispose() functionality is handled by our subclass VersionedStream
internal class VersionedStreamOwner : VersionedStream
{
#region Stream Methods
///
/// Return the bytes requested from the container
///
public override int Read(byte[] buffer, int offset, int count)
{
// throw if version missing
ReadAttempt(true);
return BaseStream.Read(buffer, offset, count);
}
///
/// Write
///
public override void Write(byte[] buffer, int offset, int count)
{
WriteAttempt();
BaseStream.Write(buffer, offset, count);
}
///
/// ReadByte
///
public override int ReadByte()
{
ReadAttempt(true);
return BaseStream.ReadByte();
}
///
/// WriteByte
///
public override void WriteByte(byte b)
{
WriteAttempt();
BaseStream.WriteByte(b);
}
///
/// Seek
///
/// offset
/// origin
/// zero
public override long Seek(long offset, SeekOrigin origin)
{
ReadAttempt();
long temp = -1;
switch (origin)
{
// seek beyond the FormatVersion
case SeekOrigin.Begin:
temp = offset;
break;
case SeekOrigin.Current:
checked { temp = Position + offset; }
break;
case SeekOrigin.End:
checked { temp = Length + offset; }
break;
}
if (temp < 0)
throw new ArgumentException(SR.Get(SRID.SeekNegative));
checked { BaseStream.Position = temp + _dataOffset; }
return temp;
}
///
/// SetLength
///
public override void SetLength(long newLength)
{
if (newLength < 0)
throw new ArgumentOutOfRangeException("newLength");
WriteAttempt();
checked { BaseStream.SetLength(newLength + _dataOffset); }
}
///
/// Flush
///
public override void Flush()
{
CheckDisposed();
BaseStream.Flush();
}
#endregion Stream Methods
//-----------------------------------------------------
//
// Public Properties
//
//-----------------------------------------------------
#region Stream Properties
///
/// Current logical position within the stream
///
public override long Position
{
get
{
ReadAttempt(); // ensure _dataOffset is valid
return checked(BaseStream.Position - _dataOffset);
}
set
{
// share Seek logic and validation
Seek(value, SeekOrigin.Begin);
}
}
///
/// Length
///
public override long Length
{
get
{
ReadAttempt(); // ensure _dataOffset is valid
long temp = checked(BaseStream.Length - _dataOffset);
Invariant.Assert(temp >= 0); // catch any math errors
return temp;
}
}
///
/// Is stream readable?
///
/// returns false when called on disposed stream
public override bool CanRead
{
get
{
return (BaseStream != null) && BaseStream.CanRead && IsReadable;
}
}
///
/// Is stream seekable - should be handled by our owner
///
/// returns false when called on disposed stream
public override bool CanSeek
{
get
{
return (BaseStream != null) && BaseStream.CanSeek && IsReadable;
}
}
///
/// Is stream writeable?
///
/// returns false when called on disposed stream
public override bool CanWrite
{
get
{
return (BaseStream != null) && BaseStream.CanWrite && IsUpdatable;
}
}
#endregion
///
/// Constructor to use for the "versioned stream" - the one that actually houses the
/// persisted FormatVersion.
///
///
///
internal VersionedStreamOwner(Stream baseStream, FormatVersion codeVersion)
: base(baseStream)
{
_codeVersion = codeVersion;
}
internal bool IsUpdatable
{
get
{
CheckDisposed();
// first try to read the format version
EnsureParsed();
// We can write if either:
// 1. FileVersion doesn't exist - this is normal for a new, empty stream
// 2. It does exist and the FormatVersion indicates that we can update it
return (_fileVersion == null) ||
_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion);
}
}
internal bool IsReadable
{
get
{
CheckDisposed();
// first try to read the format version
EnsureParsed();
// We can read if either:
// 1. FileVersion doesn't exist - normal for a new, empty stream
// 1. FileVersion exists and indicates that we can read it
return (_fileVersion == null) ||
_fileVersion.IsReadableBy(_codeVersion.ReaderVersion);
}
}
///
/// Callback for when a stream is written to
///
/// Can modify the FormatVersion stream pointer.
internal void WriteAttempt()
{
CheckDisposed(); // central location
if (!_writeOccurred)
{
// first try to read the format version
EnsureParsed();
if (_fileVersion == null)
{
// stream is empty so write our version
PersistVersion(_codeVersion);
}
else
{
// file version found - ensure we are able to update it
if (!_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion))
{
throw new FileFormatException(
SR.Get(
SRID.UpdaterVersionError,
_fileVersion.UpdaterVersion,
_codeVersion
)
);
}
// if our version is different than previous
// updater then "update" the updater
if (_codeVersion.UpdaterVersion != _fileVersion.UpdaterVersion)
{
_fileVersion.UpdaterVersion = _codeVersion.UpdaterVersion;
PersistVersion(_fileVersion);
}
}
_writeOccurred = true;
}
}
internal void ReadAttempt()
{
ReadAttempt(false);
}
///
/// Callback for when a Stream is read from
///
/// Can modify the FormatVersion stream pointer.
/// caller requires an existing FormatVersion
internal void ReadAttempt(bool throwIfEmpty)
{
CheckDisposed(); // central location
// only do this once
if (!_readOccurred)
{
// read
EnsureParsed();
// first usage?
if (throwIfEmpty || BaseStream.Length > 0)
{
if (_fileVersion == null)
throw new FileFormatException(SR.Get(SRID.VersionStreamMissing));
// compare versions
// verify we can read this version
if (!_fileVersion.IsReadableBy(_codeVersion.ReaderVersion))
{
throw new FileFormatException(
SR.Get(
SRID.ReaderVersionError,
_fileVersion.ReaderVersion,
_codeVersion
)
);
}
}
_readOccurred = true;
}
}
//------------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
///
/// Ensure that the version is persisted
///
/// Leaves stream at position just after the FormatVersion.
/// Destructive. This is called automatically from WriteAttempt but callers
/// can call directly if they have changed the stream contents to a format
/// that is no longer compatible with the persisted FormatVersion. If
/// this is not called directly, and a FormatVersion was found in the file
/// then only the Updater field is modified.
///
private void PersistVersion(FormatVersion version)
{
if (!BaseStream.CanWrite)
throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));
// normalize and save
long tempPos = checked(BaseStream.Position - _dataOffset);
BaseStream.Seek(0, SeekOrigin.Begin);
// update _dataOffset
long offset = version.SaveToStream(BaseStream);
_fileVersion = version; // we know what it is - no need to deserialize
// existing value - ensure we didn't change sizes as this could lead to
// data corruption
if ((_dataOffset != 0) && (offset != _dataOffset))
throw new FileFormatException(SR.Get(SRID.VersionUpdateFailure));
// at this point we know the offset
_dataOffset = offset;
// restore and shift
checked { BaseStream.Position = tempPos + _dataOffset; }
}
///
/// Load and compare feature identifier
///
/// There is no need for this method to maintain any previous Seek pointer.
/// This method only modifies the stream position when called for the first time with a non-empty
/// stream. It is always called from Seek() and set_Position, which subsequently modify the stream
/// pointer as appropriate after the call.
private void EnsureParsed()
{
// empty stream cannot have a version in it
if ((_fileVersion == null) && (BaseStream.Length > 0))
{
Debug.Assert(_dataOffset == 0);
// if no version was found and we cannot read from it, then the format is invalid
if (!BaseStream.CanRead)
throw new NotSupportedException(SR.Get(SRID.ReadNotSupported));
//
// The physical stream begins with a header that identifies the transform to
// which the stream belongs. The "logical" stream object handed to us by the
// compound file begins -after- this stream header, so when we seek to the
// "beginning" of this stream, we are actually seeking to the location after
// the stream header, where the instance data starts.
//
BaseStream.Seek(0, SeekOrigin.Begin);
//
// The instance data starts with format version information for this transform.
//
_fileVersion = FormatVersion.LoadFromStream(BaseStream);
//
// Ensure that the feature name is as expected.
//
// NOTE: We preserve case, but do case-insensitive comparison.
if (String.CompareOrdinal(
_fileVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture),
_codeVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture)) != 0)
{
throw new FileFormatException(
SR.Get(
SRID.InvalidTransformFeatureName,
_fileVersion.FeatureIdentifier,
_codeVersion.FeatureIdentifier
)
);
}
_dataOffset = BaseStream.Position;
}
}
//------------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
private bool _writeOccurred; // did one of our streams get written to?
private bool _readOccurred; // did one of our streams get read from?
private FormatVersion _codeVersion; // code version
private FormatVersion _fileVersion; // current file version (null if not read or created yet)
private long _dataOffset = 0; // where FormatVersion ends and data begins
}
}
// 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:
// This class provides file versioning support for streams provided by
// IDataTransform implementations and any client code that needs
// to store a FormatVersion at the beginning of a stream.
//
// History:
// 02/21/2006: BruceMac: Initial implementation.
//
//-----------------------------------------------------------------------------
using System;
using System.IO; // for Stream
using System.Windows; // ExceptionStringTable
using System.Globalization; // for CultureInfo
using System.Diagnostics; // for Debug.Assert
namespace MS.Internal.IO.Packaging.CompoundFile
{
///
/// Specialized stream that owns the FormatVersion
///
/// Dispose() functionality is handled by our subclass VersionedStream
internal class VersionedStreamOwner : VersionedStream
{
#region Stream Methods
///
/// Return the bytes requested from the container
///
public override int Read(byte[] buffer, int offset, int count)
{
// throw if version missing
ReadAttempt(true);
return BaseStream.Read(buffer, offset, count);
}
///
/// Write
///
public override void Write(byte[] buffer, int offset, int count)
{
WriteAttempt();
BaseStream.Write(buffer, offset, count);
}
///
/// ReadByte
///
public override int ReadByte()
{
ReadAttempt(true);
return BaseStream.ReadByte();
}
///
/// WriteByte
///
public override void WriteByte(byte b)
{
WriteAttempt();
BaseStream.WriteByte(b);
}
///
/// Seek
///
/// offset
/// origin
/// zero
public override long Seek(long offset, SeekOrigin origin)
{
ReadAttempt();
long temp = -1;
switch (origin)
{
// seek beyond the FormatVersion
case SeekOrigin.Begin:
temp = offset;
break;
case SeekOrigin.Current:
checked { temp = Position + offset; }
break;
case SeekOrigin.End:
checked { temp = Length + offset; }
break;
}
if (temp < 0)
throw new ArgumentException(SR.Get(SRID.SeekNegative));
checked { BaseStream.Position = temp + _dataOffset; }
return temp;
}
///
/// SetLength
///
public override void SetLength(long newLength)
{
if (newLength < 0)
throw new ArgumentOutOfRangeException("newLength");
WriteAttempt();
checked { BaseStream.SetLength(newLength + _dataOffset); }
}
///
/// Flush
///
public override void Flush()
{
CheckDisposed();
BaseStream.Flush();
}
#endregion Stream Methods
//-----------------------------------------------------
//
// Public Properties
//
//-----------------------------------------------------
#region Stream Properties
///
/// Current logical position within the stream
///
public override long Position
{
get
{
ReadAttempt(); // ensure _dataOffset is valid
return checked(BaseStream.Position - _dataOffset);
}
set
{
// share Seek logic and validation
Seek(value, SeekOrigin.Begin);
}
}
///
/// Length
///
public override long Length
{
get
{
ReadAttempt(); // ensure _dataOffset is valid
long temp = checked(BaseStream.Length - _dataOffset);
Invariant.Assert(temp >= 0); // catch any math errors
return temp;
}
}
///
/// Is stream readable?
///
/// returns false when called on disposed stream
public override bool CanRead
{
get
{
return (BaseStream != null) && BaseStream.CanRead && IsReadable;
}
}
///
/// Is stream seekable - should be handled by our owner
///
/// returns false when called on disposed stream
public override bool CanSeek
{
get
{
return (BaseStream != null) && BaseStream.CanSeek && IsReadable;
}
}
///
/// Is stream writeable?
///
/// returns false when called on disposed stream
public override bool CanWrite
{
get
{
return (BaseStream != null) && BaseStream.CanWrite && IsUpdatable;
}
}
#endregion
///
/// Constructor to use for the "versioned stream" - the one that actually houses the
/// persisted FormatVersion.
///
///
///
internal VersionedStreamOwner(Stream baseStream, FormatVersion codeVersion)
: base(baseStream)
{
_codeVersion = codeVersion;
}
internal bool IsUpdatable
{
get
{
CheckDisposed();
// first try to read the format version
EnsureParsed();
// We can write if either:
// 1. FileVersion doesn't exist - this is normal for a new, empty stream
// 2. It does exist and the FormatVersion indicates that we can update it
return (_fileVersion == null) ||
_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion);
}
}
internal bool IsReadable
{
get
{
CheckDisposed();
// first try to read the format version
EnsureParsed();
// We can read if either:
// 1. FileVersion doesn't exist - normal for a new, empty stream
// 1. FileVersion exists and indicates that we can read it
return (_fileVersion == null) ||
_fileVersion.IsReadableBy(_codeVersion.ReaderVersion);
}
}
///
/// Callback for when a stream is written to
///
/// Can modify the FormatVersion stream pointer.
internal void WriteAttempt()
{
CheckDisposed(); // central location
if (!_writeOccurred)
{
// first try to read the format version
EnsureParsed();
if (_fileVersion == null)
{
// stream is empty so write our version
PersistVersion(_codeVersion);
}
else
{
// file version found - ensure we are able to update it
if (!_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion))
{
throw new FileFormatException(
SR.Get(
SRID.UpdaterVersionError,
_fileVersion.UpdaterVersion,
_codeVersion
)
);
}
// if our version is different than previous
// updater then "update" the updater
if (_codeVersion.UpdaterVersion != _fileVersion.UpdaterVersion)
{
_fileVersion.UpdaterVersion = _codeVersion.UpdaterVersion;
PersistVersion(_fileVersion);
}
}
_writeOccurred = true;
}
}
internal void ReadAttempt()
{
ReadAttempt(false);
}
///
/// Callback for when a Stream is read from
///
/// Can modify the FormatVersion stream pointer.
/// caller requires an existing FormatVersion
internal void ReadAttempt(bool throwIfEmpty)
{
CheckDisposed(); // central location
// only do this once
if (!_readOccurred)
{
// read
EnsureParsed();
// first usage?
if (throwIfEmpty || BaseStream.Length > 0)
{
if (_fileVersion == null)
throw new FileFormatException(SR.Get(SRID.VersionStreamMissing));
// compare versions
// verify we can read this version
if (!_fileVersion.IsReadableBy(_codeVersion.ReaderVersion))
{
throw new FileFormatException(
SR.Get(
SRID.ReaderVersionError,
_fileVersion.ReaderVersion,
_codeVersion
)
);
}
}
_readOccurred = true;
}
}
//------------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
///
/// Ensure that the version is persisted
///
/// Leaves stream at position just after the FormatVersion.
/// Destructive. This is called automatically from WriteAttempt but callers
/// can call directly if they have changed the stream contents to a format
/// that is no longer compatible with the persisted FormatVersion. If
/// this is not called directly, and a FormatVersion was found in the file
/// then only the Updater field is modified.
///
private void PersistVersion(FormatVersion version)
{
if (!BaseStream.CanWrite)
throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));
// normalize and save
long tempPos = checked(BaseStream.Position - _dataOffset);
BaseStream.Seek(0, SeekOrigin.Begin);
// update _dataOffset
long offset = version.SaveToStream(BaseStream);
_fileVersion = version; // we know what it is - no need to deserialize
// existing value - ensure we didn't change sizes as this could lead to
// data corruption
if ((_dataOffset != 0) && (offset != _dataOffset))
throw new FileFormatException(SR.Get(SRID.VersionUpdateFailure));
// at this point we know the offset
_dataOffset = offset;
// restore and shift
checked { BaseStream.Position = tempPos + _dataOffset; }
}
///
/// Load and compare feature identifier
///
/// There is no need for this method to maintain any previous Seek pointer.
/// This method only modifies the stream position when called for the first time with a non-empty
/// stream. It is always called from Seek() and set_Position, which subsequently modify the stream
/// pointer as appropriate after the call.
private void EnsureParsed()
{
// empty stream cannot have a version in it
if ((_fileVersion == null) && (BaseStream.Length > 0))
{
Debug.Assert(_dataOffset == 0);
// if no version was found and we cannot read from it, then the format is invalid
if (!BaseStream.CanRead)
throw new NotSupportedException(SR.Get(SRID.ReadNotSupported));
//
// The physical stream begins with a header that identifies the transform to
// which the stream belongs. The "logical" stream object handed to us by the
// compound file begins -after- this stream header, so when we seek to the
// "beginning" of this stream, we are actually seeking to the location after
// the stream header, where the instance data starts.
//
BaseStream.Seek(0, SeekOrigin.Begin);
//
// The instance data starts with format version information for this transform.
//
_fileVersion = FormatVersion.LoadFromStream(BaseStream);
//
// Ensure that the feature name is as expected.
//
// NOTE: We preserve case, but do case-insensitive comparison.
if (String.CompareOrdinal(
_fileVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture),
_codeVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture)) != 0)
{
throw new FileFormatException(
SR.Get(
SRID.InvalidTransformFeatureName,
_fileVersion.FeatureIdentifier,
_codeVersion.FeatureIdentifier
)
);
}
_dataOffset = BaseStream.Position;
}
}
//------------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
private bool _writeOccurred; // did one of our streams get written to?
private bool _readOccurred; // did one of our streams get read from?
private FormatVersion _codeVersion; // code version
private FormatVersion _fileVersion; // current file version (null if not read or created yet)
private long _dataOffset = 0; // where FormatVersion ends and data begins
}
}
// 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
- ChildrenQuery.cs
- TemplateInstanceAttribute.cs
- EmptyReadOnlyDictionaryInternal.cs
- DataTableExtensions.cs
- ProfileSettings.cs
- ReflectPropertyDescriptor.cs
- SoapIgnoreAttribute.cs
- DataGridViewComboBoxEditingControl.cs
- MemberBinding.cs
- FormClosedEvent.cs
- CaretElement.cs
- ParseElement.cs
- TraceSwitch.cs
- XmlReaderSettings.cs
- KoreanCalendar.cs
- EasingKeyFrames.cs
- ListChunk.cs
- DataSourceXmlClassAttribute.cs
- StaticFileHandler.cs
- CustomCredentialPolicy.cs
- DateTimeFormatInfo.cs
- TypeSystemProvider.cs
- RsaSecurityTokenAuthenticator.cs
- SecurityDocument.cs
- TreeNodeBinding.cs
- WebPartZoneBase.cs
- InvalidCastException.cs
- EntitySqlQueryCacheEntry.cs
- HttpClientCertificate.cs
- ProfileSection.cs
- CodeObject.cs
- __ConsoleStream.cs
- CompilationRelaxations.cs
- IdentityReference.cs
- Visual3DCollection.cs
- IdnMapping.cs
- DesignerWithHeader.cs
- KnownTypesHelper.cs
- Rfc2898DeriveBytes.cs
- DrawingAttributesDefaultValueFactory.cs
- Predicate.cs
- SqlMethodAttribute.cs
- Error.cs
- HttpCookieCollection.cs
- GridSplitter.cs
- QueryAccessibilityHelpEvent.cs
- SqlProvider.cs
- ManipulationInertiaStartingEventArgs.cs
- Trace.cs
- StrokeNodeOperations2.cs
- HtmlGenericControl.cs
- DeflateInput.cs
- BooleanExpr.cs
- PropertyItemInternal.cs
- XmlElementAttributes.cs
- AutomationPropertyInfo.cs
- FileSystemEventArgs.cs
- ExpressionBinding.cs
- CharacterMetrics.cs
- AssemblyResourceLoader.cs
- DCSafeHandle.cs
- ResourceWriter.cs
- CachedTypeface.cs
- MSAAWinEventWrap.cs
- MsmqActivation.cs
- SecurityPolicySection.cs
- PublisherMembershipCondition.cs
- IIS7WorkerRequest.cs
- XPathDocumentBuilder.cs
- MaskedTextBoxTextEditorDropDown.cs
- MetadataUtilsSmi.cs
- TimeoutValidationAttribute.cs
- SafeFileHandle.cs
- HybridDictionary.cs
- IdentitySection.cs
- FormViewActionList.cs
- TreePrinter.cs
- SoapExtensionReflector.cs
- ExtensionWindowHeader.cs
- TimeoutHelper.cs
- TextOnlyOutput.cs
- InstancePersistenceContext.cs
- WebBrowsableAttribute.cs
- LinkLabelLinkClickedEvent.cs
- LabelLiteral.cs
- SkipQueryOptionExpression.cs
- Menu.cs
- OuterGlowBitmapEffect.cs
- GlobalProxySelection.cs
- DiagnosticsConfiguration.cs
- EventLogHandle.cs
- CommandLineParser.cs
- TextOutput.cs
- SQLCharsStorage.cs
- CodeGenerationManager.cs
- ArrayConverter.cs
- GridEntry.cs
- NameValuePermission.cs
- OleDbDataReader.cs
- CLSCompliantAttribute.cs