File: System\IO\Log\LogLogRecord.cs
Project: ndp\cdf\src\NetFx35\System.IO.Log\System.IO.Log.csproj (System.IO.Log)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.IO.Log
{
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
 
    class LogLogRecord : LogRecord
    {
        RecordStream stream;
        SequenceNumber sequenceNumber;
        SequenceNumber previous;
        SequenceNumber user;
 
        unsafe internal LogLogRecord(
            SequenceNumber sequenceNumber,
            SequenceNumber user,
            SequenceNumber previous,
            byte* data,
            long length)
        {
            this.sequenceNumber = sequenceNumber;
            this.previous = previous;
            this.user = user;
 
            if (length < LogLogRecordHeader.Size)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.LogCorrupt());
            }
 
            byte[] headerBits = new byte[LogLogRecordHeader.Size];
            Marshal.Copy(new IntPtr(data),
                         headerBits,
                         0,
                         LogLogRecordHeader.Size);
 
            LogLogRecordHeader header = new LogLogRecordHeader(headerBits);
            if (header.MajorVersion > LogLogRecordHeader.CurrentMajorVersion)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.IncompatibleVersion());
            }
 
            length -= LogLogRecordHeader.Size;
            data += LogLogRecordHeader.Size;
            if (header.Padding)
            {
                long paddingSize = LogLogRecordHeader.DecodePaddingSize(data, length);
                if ((paddingSize < 0) || (paddingSize > length))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.LogCorrupt());
                }
 
                length -= paddingSize;
                data += paddingSize;
            }
 
            this.stream = new RecordStream(
                new UnmanagedMemoryStream(data, length));
        }
 
        public override Stream Data
        {
            get
            {
                return this.stream;
            }
        }
 
        public override SequenceNumber Previous
        {
            get
            {
                return this.previous;
            }
        }
 
        public override SequenceNumber SequenceNumber
        {
            get
            {
                return this.sequenceNumber;
            }
        }
 
        public override SequenceNumber User
        {
            get
            {
                return this.user;
            }
        }
 
        public override void Dispose()
        {
            this.stream.Dispose();
        }
 
        internal void Detach()
        {
            this.stream.MakeLocalCopy();
        }
 
        class RecordStream : Stream
        {
            Stream innerStream;
            object syncRoot;
 
            internal RecordStream(Stream innerStream)
            {
                this.innerStream = innerStream;
                this.syncRoot = new object();
            }
 
            public override bool CanRead { get { return true; } }
            public override bool CanSeek { get { return true; } }
            public override bool CanWrite { get { return false; } }
 
            public override long Length
            {
                get
                {
                    lock (this.syncRoot)
                    {
                        CheckDisposed();
                        return this.innerStream.Length;
                    }
                }
            }
 
            public override long Position
            {
                get
                {
                    lock (this.syncRoot)
                    {
                        CheckDisposed();
                        return this.innerStream.Position;
                    }
                }
 
                set
                {
                    lock (this.syncRoot)
                    {
                        CheckDisposed();
                        this.innerStream.Position = value;
                    }
                }
            }
 
            public override void Flush()
            {
                lock (this.syncRoot)
                {
                    if (this.innerStream != null)
                    {
                        this.innerStream.Flush();
                    }
                }
            }
 
            public override int Read(byte[] buffer, int offset, int count)
            {
                lock (this.syncRoot)
                {
                    CheckDisposed();
                    return this.innerStream.Read(buffer, offset, count);
                }
            }
 
            public override long Seek(long offset, SeekOrigin origin)
            {
                lock (this.syncRoot)
                {
                    CheckDisposed();
                    return this.innerStream.Seek(offset, origin);
                }
            }
 
            public override void SetLength(long value)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported());
            }
 
            public override void Write(byte[] buffer, int offset, int count)
            {
                if (this.innerStream == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed());
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported());
                }
            }
 
            public override void WriteByte(byte value)
            {
                if (this.innerStream == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed());
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported());
                }
            }
 
            internal void MakeLocalCopy()
            {
                lock (this.syncRoot)
                {
                    if (this.innerStream != null)
                    {
                        long originalPosition = this.innerStream.Position;
                        try
                        {
                            try
                            {
                                byte[] newData = new byte[this.innerStream.Length];
                                this.innerStream.Position = 0;
                                this.innerStream.Read(newData, 0, newData.Length);
 
                                Stream oldStream = this.innerStream;
                                this.innerStream = new MemoryStream(newData);
                                oldStream.Close();
                            }
                            finally
                            {
                                this.innerStream.Position = originalPosition;
                            }
                        }
                        catch
                        {
                            // This outer catch block is needed to prevent an exception filter
                            // from running while we're in an inconsistent state before
                            // restoring the inner stream's original position.
                            // See http://msdn2.microsoft.com/en-US/library/8cd7yaws.aspx
                            throw;
                        }
                    }
                }
            }
 
            protected override void Dispose(bool disposing)
            {
                try
                {
                    if (disposing)
                    {
                        lock (this.syncRoot)
                        {
                            if (this.innerStream != null)
                            {
                                this.innerStream.Close();
                                this.innerStream = null;
                            }
                        }
                    }
                }
                finally
                {
                    base.Dispose(disposing);
                }
            }
 
            void CheckDisposed()
            {
                if (this.innerStream == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed());
                }
            }
        }
    }
}