InkSerializer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / Ink / InkSerializedFormat / InkSerializer.cs / 1305600 / InkSerializer.cs

                            //#define OLD_ISF 
//------------------------------------------------------------------------
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//  
//-----------------------------------------------------------------------
 
using MS.Utility; 
using System;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging; 
using System.IO;
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Security.Permissions;
using System.Runtime.Serialization; 
using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using System.Windows.Ink; 
using MS.Internal.IO.Packaging;
 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
 
namespace MS.Internal.Ink.InkSerializedFormat
{
    internal class StrokeCollectionSerializer
    { 
        #region Constants (Static Fields)
        internal static readonly double AvalonToHimetricMultiplier = 2540F / 96.0F; 
        internal static readonly double HimetricToAvalonMultiplier = 96.0F / 2540.0F; 
        internal static readonly TransformDescriptor IdentityTransformDescriptor;
 
        static StrokeCollectionSerializer()
        {
            TransformDescriptor transformDescriptor = new TransformDescriptor();
            transformDescriptor.Transform[0] = 1.0f; 
            transformDescriptor.Tag = KnownTagCache.KnownTagIndex.TransformIsotropicScale;
            transformDescriptor.Size = 1; 
            StrokeCollectionSerializer.IdentityTransformDescriptor = transformDescriptor; 
        }
        #endregion 

        #region Constructors

        // disable default constructor 
        private StrokeCollectionSerializer() { }
 
        ///  
        /// Initialize the Ink serializer
        ///  
        /// Pointer to the core stroke collection - avoids recreation of collections
        internal StrokeCollectionSerializer(StrokeCollection coreStrokes)
        {
            _coreStrokes = coreStrokes; 
        }
 
        #endregion 

        #region Public Fields 

        internal PersistenceFormat CurrentPersistenceFormat = PersistenceFormat.InkSerializedFormat;
        internal CompressionMode CurrentCompressionMode = CompressionMode.Compressed;
        internal System.Collections.Generic.List StrokeIds = null; 
        #endregion
 
        #region Decoding 

        #region Public Methods 


        /// 
        /// Loads a Ink object from a spcified byte array in the form of Ink Serialzied Format 
        /// This method checks for the 'base64:' prefix in the byte[] because that is how V1
        /// saved ISF 
        ///  
        /// 
        internal void DecodeISF(Stream inkData) 
        {
            try
            {
                // First examine the input data header 
                bool isBase64;
                bool isGif; 
                uint cbData; 

                ExamineStreamHeader(inkData, out isBase64, out isGif, out cbData); 
                if (isBase64)
                {
                    //
                    // this is a funky tablet v1 based byte[] that is base64 encoded... 
                    // each 4 bytes in this array corresponds to 3 bytes of ISF data.
                    // EXCEPT the first 7 bytes which are saved with the value 
                    // 'base64:' and must not be base64 decoded. 
                    // and the last null terminator (if present)
                    // 
                    //  The following code does two things:
                    //  1) Convert each byte to a char so it can be base64 decoded
                    //  2) Strips out the first 7 resulting characters
                    // 
                    int isfBase64PrefixLength = Base64HeaderBytes.Length;
                    // the previous call to ExamineStreamHeader guarantees that inkData.Length > isfBase64PrefixLength 
                    System.Diagnostics.Debug.Assert(inkData.Length > isfBase64PrefixLength); 

                    inkData.Position = (long)isfBase64PrefixLength; 
                    List charData = new List((int)inkData.Length);
                    int intByte = inkData.ReadByte();
                    while (intByte != -1)
                    { 
                        byte b = (byte)intByte;
                        charData.Add((char)b); 
                        intByte = inkData.ReadByte(); 
                    }
 
                    if (0 == (byte)(charData[charData.Count - 1]))
                    {
                        //strip the null terminator
                        charData.RemoveAt(charData.Count - 1); 
                    }
 
                    char[] chars = charData.ToArray(); 
                    byte[] isfData = Convert.FromBase64CharArray(chars, 0, chars.Length);
                    MemoryStream ms = new MemoryStream(isfData); 
                    if (IsGIFData(ms))
                    {
                        DecodeRawISF(ReadGifData(ms));
                    } 
                    else
                    { 
                        DecodeRawISF(ms); 
                    }
                } 
                else if (true == isGif)
                {
                    DecodeRawISF(ReadGifData(inkData));
                } 
                else
                { 
                    DecodeRawISF(inkData); 
                }
            } 
#if DEBUG
            catch (ArgumentException ex)
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            } 
            catch (InvalidOperationException ex) 
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            }
            catch (IndexOutOfRangeException ex)
            { 
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex); 
            } 
            catch (NullReferenceException ex)
            { 
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            }
            catch (EndOfStreamException ex) 
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex); 
            }
            catch (OverflowException ex) 
            {
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            } 
#else
            catch (ArgumentException) 
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            } 
            catch (InvalidOperationException)
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            } 
            catch (IndexOutOfRangeException)
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor() 
            }
            catch (NullReferenceException) 
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            }
            catch (EndOfStreamException) 
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor() 
            } 
            catch (OverflowException)
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            }
#endif
        } 

        #endregion 
 
        #region Private Methods
 
        /// 
        /// Loads the strokeIds from the stream, we need to do this to decrement the count of bytes
        /// 
        internal uint LoadStrokeIds(Stream isfStream, uint cbSize) 
        {
            if (0 == cbSize) 
                return 0; 

            uint cb; 
            uint cbTotal = cbSize;

            // First decode the no of ids
            uint count; 

            cb = SerializationHelper.Decode(isfStream, out count); 
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "isfStream");
 
            cbTotal -= cb;
            if (0 == count)
                return (cbSize - cbTotal);
 
            cb = cbTotal;
 
            byte[] inputdata = new byte[cb]; 

            // read the stream 
            uint bytesRead = StrokeCollectionSerializer.ReliableRead(isfStream, inputdata, cb);
            if (cb != bytesRead)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "isfStream"); 
            }
            cbTotal -= cb; 
 
            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "isfStream"); 

            return cbSize;
        }
 

        private bool IsGIFData(Stream inkdata) 
        { 
            Debug.Assert(inkdata != null);
            long currentPosition = inkdata.Position; 
            try
            {
                return ((byte)inkdata.ReadByte() == 'G' &&
                        (byte)inkdata.ReadByte() == 'I' && 
                        (byte)inkdata.ReadByte() == 'F');
            } 
            finally 
            {
                //reset position 
                inkdata.Position = currentPosition;
            }
        }
 
        private Stream ReadGifData(Stream inkdata)
        { 
            // Read the GIF header ... 
            System.Drawing.Bitmap img = new System.Drawing.Bitmap(inkdata);
            // Read the comment as that is where the ISF is stored... 
            // for reference the tag is PropertyTagExifUserComment [0x9286] or 37510 (int)
            System.Drawing.Imaging.PropertyItem piComment = img.GetPropertyItem(37510);
            return new MemoryStream(piComment.Value);
        } 

        private void ExamineStreamHeader(Stream inkdata, out bool fBase64, out bool fGif, out uint cbData) 
        { 
            fGif = false;
            cbData = 0; 
            fBase64 = false;

            if (inkdata.Length >= 7)
            { 
                fBase64 = IsBase64Data(inkdata);
            } 
 
            // Check for RAW gif
 	        if (!fBase64 && inkdata.Length >= 3) 
	        {
                fGif = IsGIFData(inkdata);
	        }
		 
            return;
        } 
 
        private static readonly byte[] Base64HeaderBytes
                                            = new byte[]{(byte)'b', 
                                                        (byte)'a',
                                                        (byte)'s',
                                                        (byte)'e',
                                                        (byte)'6', 
                                                        (byte)'4',
                                                        (byte)':'}; 
 
#if OLD_ISF
        ///  
        /// Takes an ISF byte[] and populates the StrokeCollection
        ///  attached to this StrokeCollectionSerializer.
        /// 
        /// a byte[] of the raw isf to decode 
        /// 
        ///     Critical - Calls critical methods in Compressor 
        ///     TreatAsSafe - inkdata is a disconnected copy from the one passed in 
        ///         underlying unmanaged code has been security reviewed and fuzzed
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
#else
        /// 
        /// Takes an ISF Stream and populates the StrokeCollection 
        ///  attached to this StrokeCollectionSerializer.
        ///  
        /// a Stream the raw isf to decode 
#endif
        private void DecodeRawISF(Stream inputStream) 
        {
            Debug.Assert(inputStream != null);

            KnownTagCache.KnownTagIndex isfTag; 
            uint remainingBytesInStream;
            uint bytesDecodedInCurrentTag = 0; 
            bool strokeDescriptorBlockDecoded = false; 
            bool drawingAttributesBlockDecoded = false;
            bool metricBlockDecoded = false; 
            bool transformDecoded = false;
            uint strokeDescriptorTableIndex = 0;
            uint oldStrokeDescriptorTableIndex = 0xFFFFFFFF;
            uint drawingAttributesTableIndex = 0; 
            uint oldDrawingAttributesTableIndex = 0xFFFFFFFF;
            uint metricDescriptorTableIndex = 0; 
            uint oldMetricDescriptorTableIndex = 0xFFFFFFFF; 
            uint transformTableIndex = 0;
            uint oldTransformTableIndex = 0xFFFFFFFF; 
            GuidList guidList = new GuidList();
            int strokeIndex = 0;

            StylusPointDescription currentStylusPointDescription = null; 
            Matrix currentTabletToInkTransform = Matrix.Identity;
 
            _strokeDescriptorTable = new System.Collections.Generic.List(); 
            _drawingAttributesTable = new System.Collections.Generic.List();
            _transformTable = new System.Collections.Generic.List(); 
            _metricTable = new System.Collections.Generic.List();

            // First make sure this ink is empty
            if (0 != _coreStrokes.Count || _coreStrokes.ExtendedProperties.Count != 0) 
            {
                throw new InvalidOperationException(ISFDebugMessage("ISF decoder cannot operate on non-empty ink container")); 
            } 
#if OLD_ISF
            // 
            // store a compressor reference at this scope, if it is needed (if there is a compresson header) and
            // therefore instanced during this routine, we will dispose of it
            // in the finally block
            // 
            Compressor compressor = null;
 
            try 
            {
#endif 

            // First read the isfTag
            uint uiTag;
            uint localBytesDecoded = SerializationHelper.Decode(inputStream, out uiTag); 
            if (0x00 != uiTag)
                throw new ArgumentException(SR.Get(SRID.InvalidStream)); 
 
            // Now read the size of the stream
            localBytesDecoded = SerializationHelper.Decode(inputStream, out remainingBytesInStream); 
            ISFDebugTrace("Decoded Stream Size in Bytes: " + remainingBytesInStream.ToString());
            if (0 == remainingBytesInStream)
                return;
 
            while (0 < remainingBytesInStream)
            { 
                bytesDecodedInCurrentTag = 0; 

                // First read the isfTag 
                localBytesDecoded = SerializationHelper.Decode(inputStream, out uiTag);
                isfTag = (KnownTagCache.KnownTagIndex)uiTag;
                if (remainingBytesInStream >= localBytesDecoded)
                    remainingBytesInStream -= localBytesDecoded; 
                else
                { 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                }
 
                ISFDebugTrace("Decoding Tag: " + ((KnownTagCache.KnownTagIndex)isfTag).ToString());
                switch (isfTag)
                {
                    case KnownTagCache.KnownTagIndex.GuidTable: 
                    case KnownTagCache.KnownTagIndex.DrawingAttributesTable:
                    case KnownTagCache.KnownTagIndex.DrawingAttributesBlock: 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorTable: 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorBlock:
                    case KnownTagCache.KnownTagIndex.MetricTable: 
                    case KnownTagCache.KnownTagIndex.MetricBlock:
                    case KnownTagCache.KnownTagIndex.TransformTable:
                    case KnownTagCache.KnownTagIndex.ExtendedTransformTable:
                    case KnownTagCache.KnownTagIndex.Stroke: 
                    case KnownTagCache.KnownTagIndex.CompressionHeader:
                    case KnownTagCache.KnownTagIndex.PersistenceFormat: 
                    case KnownTagCache.KnownTagIndex.HimetricSize: 
                    case KnownTagCache.KnownTagIndex.StrokeIds:
                        { 
                            localBytesDecoded = SerializationHelper.Decode(inputStream, out bytesDecodedInCurrentTag);
                            if (remainingBytesInStream < (localBytesDecoded + bytesDecodedInCurrentTag))
                            {
                                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inputStream"); 
                            }
 
                            remainingBytesInStream -= localBytesDecoded; 

                            // Based on the isfTag figure out what information we're loading 
                            switch (isfTag)
                            {
                                case KnownTagCache.KnownTagIndex.GuidTable:
                                    { 
                                        // Load guid Table
                                        localBytesDecoded = guidList.Load(inputStream, bytesDecodedInCurrentTag); 
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.DrawingAttributesTable:
                                    {
                                        // Load drawing attributes table
                                        localBytesDecoded = LoadDrawAttrsTable(inputStream, guidList, bytesDecodedInCurrentTag); 
                                        drawingAttributesBlockDecoded = true;
                                        break; 
                                    } 

                                case KnownTagCache.KnownTagIndex.DrawingAttributesBlock: 
                                    {
                                        //initialize to V1 defaults, we do it this way as opposed
                                        //to dr.DrawingFlags = 0 because this was a perf hot spot
                                        //and instancing the epc first mitigates it 
                                        ExtendedPropertyCollection epc = new ExtendedPropertyCollection();
                                        epc.Add(KnownIds.DrawingFlags, DrawingFlags.Polyline); 
                                        DrawingAttributes dr = new DrawingAttributes(epc); 
                                        localBytesDecoded = DrawingAttributeSerializer.DecodeAsISF(inputStream, guidList, bytesDecodedInCurrentTag, dr);
 
                                        _drawingAttributesTable.Add(dr);
                                        drawingAttributesBlockDecoded = true;
                                        break;
                                    } 

                                case KnownTagCache.KnownTagIndex.StrokeDescriptorTable: 
                                    { 
                                        // Load stroke descriptor table
                                        localBytesDecoded = DecodeStrokeDescriptorTable(inputStream, bytesDecodedInCurrentTag); 
                                        strokeDescriptorBlockDecoded = true;
                                        break;
                                    }
 
                                case KnownTagCache.KnownTagIndex.StrokeDescriptorBlock:
                                    { 
                                        // Load a single stroke descriptor 
                                        localBytesDecoded = DecodeStrokeDescriptorBlock(inputStream, bytesDecodedInCurrentTag);
                                        strokeDescriptorBlockDecoded = true; 
                                        break;
                                    }

                                case KnownTagCache.KnownTagIndex.MetricTable: 
                                    {
                                        // Load Metric Table 
                                        localBytesDecoded = DecodeMetricTable(inputStream, bytesDecodedInCurrentTag); 
                                        metricBlockDecoded = true;
                                        break; 
                                    }

                                case KnownTagCache.KnownTagIndex.MetricBlock:
                                    { 
                                        // Load a single Metric Block
                                        MetricBlock blk; 
 
                                        localBytesDecoded = DecodeMetricBlock(inputStream, bytesDecodedInCurrentTag, out blk);
                                        _metricTable.Clear(); 
                                        _metricTable.Add(blk);
                                        metricBlockDecoded = true;
                                        break;
                                    } 

                                case KnownTagCache.KnownTagIndex.TransformTable: 
                                    { 
                                        // Load Transform Table
                                        localBytesDecoded = DecodeTransformTable(inputStream, bytesDecodedInCurrentTag, false); 
                                        transformDecoded = true;
                                        break;
                                    }
 
                                case KnownTagCache.KnownTagIndex.ExtendedTransformTable:
                                    { 
                                        // non-double transform table should have already been loaded 
                                        if (!transformDecoded)
                                        { 
                                            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                                        }

                                        // Load double-sized Transform Table 
                                        localBytesDecoded = DecodeTransformTable(inputStream, bytesDecodedInCurrentTag, true);
                                        break; 
                                    } 

                                case KnownTagCache.KnownTagIndex.PersistenceFormat: 
                                    {
                                        uint fmt;

                                        localBytesDecoded = SerializationHelper.Decode(inputStream, out fmt); 
                                        // Set the appropriate persistence information
                                        if (0 == fmt) 
                                        { 
                                            CurrentPersistenceFormat = PersistenceFormat.InkSerializedFormat;
                                        } 
                                        else if (0x00000001 == fmt)
                                        {
                                            CurrentPersistenceFormat = PersistenceFormat.Gif;
                                        } 

 
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.HimetricSize:
                                    {
                                        // Loads the Hi Metric Size for Fortified GIFs
                                        int sz; 

                                        localBytesDecoded = SerializationHelper.SignDecode(inputStream, out sz); 
                                        if (localBytesDecoded > remainingBytesInStream) 
                                            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                        _himetricSize.X = (double)sz;
                                        localBytesDecoded += SerializationHelper.SignDecode(inputStream, out sz);

                                        _himetricSize.Y = (double)sz; 
                                        break;
                                    } 
 
                                case KnownTagCache.KnownTagIndex.CompressionHeader:
                                    { 
#if OLD_ISF
                                        byte[] data = new byte[bytesDecodedInCurrentTag];

                                        // read the header from the stream 
                                        uint bytesRead = StrokeCollectionSerializer.ReliableRead(inputStream, data, bytesDecodedInCurrentTag);
                                        if (bytesDecodedInCurrentTag != bytesRead) 
                                        { 
                                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "isfStream");
                                        } 

                                        uint size = bytesDecodedInCurrentTag;
                                        compressor = new Compressor(data, ref size);
                                        // in case the actual number of bytes read by the compressor 
                                        //      is less than the encoder had expected (e.g. compression
                                        //      header was encoded as 10 bytes, but only 7 bytes were read) 
                                        //      then we don't want to adjust the stream position because 
                                        //      there are likely other following tags that are encoded
                                        //      after the compression tag. This should never happen, 
                                        //      so just fail if the compressor is broken or the ISF is
                                        //      corrupted.
                                        if (size != bytesDecodedInCurrentTag)
                                        { 
                                            throw new InvalidOperationException(ISFDebugMessage("Compressor intialization reported inconsistent size"));
                                        } 
#else 
                                        //just advance the inputstream position, we don't need
                                        //no compression header in the new isf decoding 
                                        inputStream.Seek(bytesDecodedInCurrentTag, SeekOrigin.Current);
#endif
                                        localBytesDecoded = bytesDecodedInCurrentTag;
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.StrokeIds: 
                                    {
                                        localBytesDecoded = LoadStrokeIds(inputStream, bytesDecodedInCurrentTag); 
                                        break;
                                    }

                                case KnownTagCache.KnownTagIndex.Stroke: 
                                    {
                                        ISFDebugTrace("   Decoding Stroke Id#(" + (strokeIndex + 1).ToString() + ")"); 
 
                                        StrokeDescriptor strokeDescriptor = null;
 
                                        // Load the stroke descriptor based on the index from the list of unique
                                        // stroke descriptors
                                        if (strokeDescriptorBlockDecoded)
                                        { 
                                            if (oldStrokeDescriptorTableIndex != strokeDescriptorTableIndex)
                                            { 
                                                if (_strokeDescriptorTable.Count <= strokeDescriptorTableIndex) 
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                                            } 

                                            strokeDescriptor = _strokeDescriptorTable[(int)strokeDescriptorTableIndex];
                                        }
 
                                        // use new transform if the last transform is uninit'd or has changed
                                        if (oldTransformTableIndex != transformTableIndex) 
                                        { 
                                            // if transform was specified in the ISF stream
                                            if (transformDecoded) 
                                            {
                                                if (_transformTable.Count <= transformTableIndex)
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                                // Load the transform descriptor based on the index from the list of unique
                                                // transforn descriptors 
                                                currentTabletToInkTransform = LoadTransform(_transformTable[(int)transformTableIndex]); 
                                            }
 
                                            oldTransformTableIndex = transformTableIndex; // cache the transform by remembering the index

                                            // since ISF is stored in HIMETRIC, and we want to expose packet data
                                            //      as Avalon units, we'll update the convert the transform before loading the stroke 
                                            currentTabletToInkTransform.Scale(StrokeCollectionSerializer.HimetricToAvalonMultiplier, StrokeCollectionSerializer.HimetricToAvalonMultiplier);
                                        } 
 
                                        MetricBlock metricBlock = null;
 
                                        // Load the metric block based on the index from the list of unique metric blocks
                                        if (metricBlockDecoded)
                                        {
                                            if (oldMetricDescriptorTableIndex != metricDescriptorTableIndex) 
                                            {
                                                if (_metricTable.Count <= metricDescriptorTableIndex) 
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                                            }
 
                                            metricBlock = _metricTable[(int)metricDescriptorTableIndex];
                                        }

                                        DrawingAttributes activeDrawingAttributes = null; 

                                        // Load the drawing attributes based on the index from the list of unique drawing attributes 
                                        if (drawingAttributesBlockDecoded) 
                                        {
                                            if (oldDrawingAttributesTableIndex != drawingAttributesTableIndex) 
                                            {
                                                if (_drawingAttributesTable.Count <= drawingAttributesTableIndex)
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                                oldDrawingAttributesTableIndex = drawingAttributesTableIndex;
                                            } 
                                            DrawingAttributes currDA = (DrawingAttributes)_drawingAttributesTable[(int)drawingAttributesTableIndex]; 
                                            //we always clone so we don't get strokes that share DAs, which can lead
                                            //to all sorts of unpredictable behavior (ex: see Windows OS Bugs 1450047) 
                                            activeDrawingAttributes = currDA.Clone();
                                        }

                                        // if we didn't find an existing da to use, instance a new one 
                                        if (activeDrawingAttributes == null)
                                        { 
                                            activeDrawingAttributes = new DrawingAttributes(); 
                                        }
 
                                        // Now create the StylusPacketDescription from the stroke descriptor and metric block
                                        if (oldMetricDescriptorTableIndex != metricDescriptorTableIndex || oldStrokeDescriptorTableIndex != strokeDescriptorTableIndex)
                                        {
                                            currentStylusPointDescription = BuildStylusPointDescription(strokeDescriptor, metricBlock, guidList); 
                                            oldStrokeDescriptorTableIndex = strokeDescriptorTableIndex;
                                            oldMetricDescriptorTableIndex = metricDescriptorTableIndex; 
                                        } 

                                        // Load the stroke 
                                        Stroke localStroke;
#if OLD_ISF
                                        localBytesDecoded = StrokeSerializer.DecodeStroke(inputStream, bytesDecodedInCurrentTag, guidList, strokeDescriptor, currentStylusPointDescription, activeDrawingAttributes, currentTabletToInkTransform, compressor, out localStroke);
#else 
                                        localBytesDecoded = StrokeSerializer.DecodeStroke(inputStream, bytesDecodedInCurrentTag, guidList, strokeDescriptor, currentStylusPointDescription, activeDrawingAttributes, currentTabletToInkTransform, out localStroke);
#endif 
 
                                        if (localStroke != null)
                                        { 
                                            _coreStrokes.AddWithoutEvent(localStroke);
                                            strokeIndex++;
                                        }
                                        break; 
                                    }
 
                                default: 
                                    {
                                        throw new InvalidOperationException(ISFDebugMessage("Invalid ISF tag logic")); 
                                    }
                            }

                            // if this isfTag's decoded size != expected size, then error out 
                            if (localBytesDecoded != bytesDecodedInCurrentTag)
                            { 
                                throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                            }
 
                            break;
                        }

                    case KnownTagCache.KnownTagIndex.Transform: 
                    case KnownTagCache.KnownTagIndex.TransformIsotropicScale:
                    case KnownTagCache.KnownTagIndex.TransformAnisotropicScale: 
                    case KnownTagCache.KnownTagIndex.TransformRotate: 
                    case KnownTagCache.KnownTagIndex.TransformTranslate:
                    case KnownTagCache.KnownTagIndex.TransformScaleAndTranslate: 
                        {
                            // Load a single Transform Block
                            TransformDescriptor xform;
 
                            bytesDecodedInCurrentTag = DecodeTransformBlock(inputStream, isfTag, remainingBytesInStream, false, out xform);
                            transformDecoded = true; 
                            _transformTable.Clear(); 
                            _transformTable.Add(xform);
                            break; 
                        }

                    case KnownTagCache.KnownTagIndex.TransformTableIndex:
                        { 
                            // Load the Index into the Transform Table which will be used by the stroke following this till
                            // a next different Index is found 
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out transformTableIndex); 
                            break;
                        } 

                    case KnownTagCache.KnownTagIndex.MetricTableIndex:
                        {
                            // Load the Index into the Metric Table which will be used by the stroke following this till 
                            // a next different Index is found
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out metricDescriptorTableIndex); 
                            break; 
                        }
 
                    case KnownTagCache.KnownTagIndex.DrawingAttributesTableIndex:
                        {
                            // Load the Index into the Drawing Attributes Table which will be used by the stroke following this till
                            // a next different Index is found 
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out drawingAttributesTableIndex);
                            break; 
                        } 

                    case KnownTagCache.KnownTagIndex.InkSpaceRectangle: 
                        {
                            // Loads the Ink Space Rectangle information
                            bytesDecodedInCurrentTag = DecodeInkSpaceRectangle(inputStream, remainingBytesInStream);
                            break; 
                        }
 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorTableIndex: 
                        {
                            // Load the Index into the Stroke Descriptor Table which will be used by the stroke following this till 
                            // a next different Index is found
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out strokeDescriptorTableIndex);
                            break;
                        } 

                    default: 
                        { 
                            if ((uint)isfTag >= KnownIdCache.CustomGuidBaseIndex || ((uint)isfTag >= KnownTagCache.KnownTagCount && ((uint)isfTag < (KnownTagCache.KnownTagCount + KnownIdCache.OriginalISFIdTable.Length))))
                            { 
                                ISFDebugTrace("  CUSTOM_GUID=" + guidList.FindGuid(isfTag).ToString());

                                // Loads any custom property data
                                bytesDecodedInCurrentTag = remainingBytesInStream; 

                                Guid guid = guidList.FindGuid(isfTag); 
                                if (guid == Guid.Empty) 
                                {
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Global Custom Attribute tag embedded in ISF stream does not match guid table"), "inkdata"); 
                                }


                                object data; 

                                // load the custom property data from the stream (and decode the type) 
                                localBytesDecoded = ExtendedPropertySerializer.DecodeAsISF(inputStream, bytesDecodedInCurrentTag, guidList, isfTag, ref guid, out data); 
                                if (localBytesDecoded > bytesDecodedInCurrentTag)
                                { 
                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inkdata");
                                }

 
                                // add the guid/data pair into the property collection (don't redecode the type)
                                _coreStrokes.ExtendedProperties[guid] = data; 
                            } 
                            else
                            { 
                                // Skip objects that this library doesn't know about
                                // First read the size associated with this unknown isfTag
                                localBytesDecoded = SerializationHelper.Decode(inputStream, out bytesDecodedInCurrentTag);
                                if (remainingBytesInStream < (localBytesDecoded + bytesDecodedInCurrentTag)) 
                                {
                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                                } 
                                else
                                { 
                                    inputStream.Seek(bytesDecodedInCurrentTag + localBytesDecoded, SeekOrigin.Current);
                                }
                            }
 
                            bytesDecodedInCurrentTag = localBytesDecoded;
                            break; 
                        } 
                }
                ISFDebugTrace("    Size = " + bytesDecodedInCurrentTag.ToString()); 
                if (bytesDecodedInCurrentTag > remainingBytesInStream)
                {
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                } 

                // update remaining ISF buffer length with decoded so far 
                remainingBytesInStream -= bytesDecodedInCurrentTag; 
            }
#if OLD_ISF 
        }
        finally
        {
            if (null != compressor) 
            {
                compressor.Dispose(); 
                compressor = null; 
            }
        } 
#endif
        if (0 != remainingBytesInStream)
            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inkdata");
    } 
#if OLD_ISF
    ///  
    /// Loads a DrawingAttributes Table from the stream and adds individual drawing attributes to the drawattr 
    /// list passed
    ///  
    /// 
    /// 
    ///     Critical - Calls the DrawingAttributeSerializer.DecodeAsISF critical method
    ///  
    [SecurityCritical]
#else 
    ///  
    /// Loads a DrawingAttributes Table from the stream and adds individual drawing attributes to the drawattr
    /// list passed 
    /// 
#endif
    private uint LoadDrawAttrsTable(Stream strm, GuidList guidList, uint cbSize)
    { 
        _drawingAttributesTable.Clear();
 
        // First, allocate a temporary buffer and read the stream into it. 
        // These will be compressed DRAW_ATTR structures.
        uint cbTotal = cbSize; 

        // OK, now we count the number of DRAW_ATTRS compressed into this block
        uint cbDA = 0;
 
        while (cbTotal > 0)
        { 
            // First read the size of the first drawing attributes block 
            uint cb = SerializationHelper.Decode(strm, out cbDA);
 
            if (cbSize < cb)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            cbTotal -= cb;
            if (cbTotal < cbDA) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 

            // Create a new drawing attribute
            DrawingAttributes attributes = new DrawingAttributes();
            // pull off our defaults onthe drawing attribute as we need to 
            //  respect what the ISF has.
            attributes.DrawingFlags = 0; 
            cb = DrawingAttributeSerializer.DecodeAsISF(strm, guidList, cbDA, attributes); 

            // Load the stream into this attribute 
            if (cbSize < cbDA)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            cbTotal -= cbDA;
 
            // Add this attribute to the global list 
            _drawingAttributesTable.Add(attributes);
        } 

        if (0 != cbTotal)
            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

        return cbSize; 
    } 

    ///  
    /// Reads and Decodes a stroke descriptor information from the stream. For details on how it is stored
    /// please refer the spec
    /// 
    ///  
    /// 
    ///  
    ///  
    private uint DecodeStrokeDescriptor(Stream strm, uint cbSize, out StrokeDescriptor descr)
    { 
        descr = new StrokeDescriptor();
        if (0 == cbSize)
            return 0;
 
        uint cb;
        uint cbBlock = cbSize; 
 
        while (cbBlock > 0)
        { 
            // first read the tag
            KnownTagCache.KnownTagIndex tag;
            uint uiTag;
 
            cb = SerializationHelper.Decode(strm, out uiTag);
            tag = (KnownTagCache.KnownTagIndex)uiTag; 
            if (cb > cbBlock) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbBlock -= cb;
            descr.Template.Add(tag);

            // If this is TAG_BUTTONS 
            if (KnownTagCache.KnownTagIndex.Buttons == tag && cbBlock > 0)
            { 
                uint cbButton; 

                // Read the no. of buttons first 
                cb = SerializationHelper.Decode(strm, out cbButton);
                if (cb > cbBlock)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
                cbBlock -= cb;
                descr.Template.Add((KnownTagCache.KnownTagIndex)cbButton); 
                while (cbBlock > 0 && cbButton > 0) 
                {
                    uint dw; 

                    cb = SerializationHelper.Decode(strm, out dw);
                    if (cb > cbBlock)
                        throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

                    cbBlock -= cb; 
                    cbButton--; 
                    descr.Template.Add((KnownTagCache.KnownTagIndex)dw);
                } 
            }
            else if (KnownTagCache.KnownTagIndex.StrokePropertyList == tag && cbBlock > 0)
            {
                // Usually stroke property comes last in the template. Hence everything below this is 
                // are Tags for strokes extended properties
                while (cbBlock > 0) 
                { 
                    uint dw;
 
                    cb = SerializationHelper.Decode(strm, out dw);
                    if (cb > cbBlock)
                        throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
                    cbBlock -= cb;
                    descr.Template.Add((KnownTagCache.KnownTagIndex)dw); 
                } 
            }
            } 

            if (0 != cbBlock)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            return cbSize;
        } 
 

        ///  
        /// Reads and Decodes a stroke descriptor information from the stream. For details on how it is stored
        /// please refer the spec
        /// 
        ///  
        /// 
        ///  
        private uint DecodeStrokeDescriptorBlock(Stream strm, uint cbSize) 
        {
            _strokeDescriptorTable.Clear(); 
            if (0 == cbSize)
                return 0;

            StrokeDescriptor descr; 
            uint cbRead = DecodeStrokeDescriptor(strm, cbSize, out descr);
 
            if (cbRead != cbSize) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            _strokeDescriptorTable.Add(descr);
            return cbRead;
        }
 

        ///  
        /// Reads and Decodes a number of stroke descriptor information from the stream. For details on how they are stored 
        /// please refer the spec
        ///  
        /// 
        /// 
        /// 
        private uint DecodeStrokeDescriptorTable(Stream strm, uint cbSize) 
        {
            _strokeDescriptorTable.Clear(); 
            if (0 == cbSize) 
                return 0;
 
            uint cb;                // Tracks the total no of bytes read from the stream
            uint cbTotal = cbSize;  // Tracks how many more bytes can be read from the stream for the table. Limited by cbSize

            while (cbTotal > 0) 
            {
                // First decode the size of the next block 
                uint cbBlock; 

                cb = SerializationHelper.Decode(strm, out cbBlock); 
                if (cb > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
                cbTotal -= cb;
                if (cbBlock > cbTotal) 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 

                StrokeDescriptor descr;

                cb = DecodeStrokeDescriptor(strm, cbBlock, out descr); 
                if (cb != cbBlock)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 

                cbTotal -= cb; 

                // Add this stroke descriptor to the list of global stroke descriptors
                _strokeDescriptorTable.Add(descr);
            } 

            if (0 != cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
            return cbSize;
        }

 
        /// 
        /// Decodes metric table from the stream. For information on how they are stored in the stream, please refer to the spec. 
        ///  
        /// 
        ///  
        /// 
        private uint DecodeMetricTable(Stream strm, uint cbSize)
        {
            _metricTable.Clear(); 
            if (cbSize == 0)
                return 0; 
 
            uint cb;
            uint cbTotal = cbSize; 

            // This data is a list of Metric block. Each block starts with size of the block. After that it contains an
            // array of Metric Entries. Each metric enty comprises of size of the entry, tag for the property and the metric
            // properties. 
            while (cbTotal > 0)
            { 
                // First read the size of the metric block 
                uint dw;
 
                cb = SerializationHelper.Decode(strm, out dw);
                if (cb + dw > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                cbTotal -= cb; 
 
                MetricBlock newblock;
 
                cb = DecodeMetricBlock(strm, dw, out newblock);
                if (cb != dw)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                cbTotal -= cb; 
                _metricTable.Add(newblock); 
            }
 
            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            return cbSize;
        } 
 

        ///  
        /// Decodes a Metric Block from the stream. For information on how they are stored in the stream, please refer to the spec.
        /// 
        /// 
        ///  
        /// 
        ///  
        private uint DecodeMetricBlock(Stream strm, uint cbSize, out MetricBlock block) 
        {
            // allocate the block 
            block = new MetricBlock();
            if (cbSize == 0)
                return 0;
 
            uint cb;
            uint cbTotal = cbSize; 
            uint size; 

            while (cbTotal > 0) 
            {
                // First decode the tag for this entry
                uint dw;
 
                cb = SerializationHelper.Decode(strm, out dw);
                if (cb > cbTotal) 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
                cbTotal -= cb;

                // Next read the size of the metric data
                cb = SerializationHelper.Decode(strm, out size); 
                if (cb + size > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 

                cbTotal -= cb; 

                // now create new metric entry
                MetricEntry entry = new MetricEntry();
 
                entry.Tag = (KnownTagCache.KnownTagIndex)dw;
 
                byte[] data = new byte[size]; 

                uint bytesRead = StrokeCollectionSerializer.ReliableRead(strm, data, size); 
                cbTotal -= bytesRead;

                if ( bytesRead != size )
                { 
                    // Make sure the bytes read are expected. If not, we should bail out.
                    // An exception will be thrown. 
                    break; 
                }
 
                entry.Data = data;
                block.AddMetricEntry(entry);

            } 

            if (0 != cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
            return cbSize;
        }

 
        /// 
        /// Reads and Decodes a Table of Transform Descriptors from the stream. For information on how they are stored 
        /// in the stream, please refer to the spec. 
        /// 
        ///  
        /// 
        /// 
        /// 
        private uint DecodeTransformTable(Stream strm, uint cbSize, bool useDoubles) 
        {
            // only clear the transform table if not using doubles 
            //      (e.g. first pass through transform table) 
            if (!useDoubles)
            { 
                _transformTable.Clear();
            }

            if (0 == cbSize) 
                return 0;
 
            uint cb; 
            uint cbTotal = cbSize;
            int tableIndex = 0; 

            while (cbTotal > 0)
            {
                KnownTagCache.KnownTagIndex tag; 
                uint uiTag;
                cb = SerializationHelper.Decode(strm, out uiTag); 
                tag = (KnownTagCache.KnownTagIndex)uiTag; 
                if (cb > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

                cbTotal -= cb;

                TransformDescriptor xform; 

                cb = DecodeTransformBlock(strm, tag, cbTotal, useDoubles, out xform); 
                cbTotal -= cb; 
                if (useDoubles)
                { 
                    _transformTable[tableIndex] = xform;
                }
                else
                { 
                    _transformTable.Add(xform);
                } 
 
                tableIndex++;
            } 

            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            return cbSize;
        } 
 
        /// 
        /// ReliableRead 
        /// 
        /// 
        /// 
        ///  
        /// 
        internal static uint ReliableRead(Stream stream, byte[] buffer, uint requestedCount) 
        { 
            if (stream == null ||
                buffer == null || 
                requestedCount > buffer.Length)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid argument passed to ReliableRead"));
            } 

            // let's read the whole block into our buffer 
            uint totalBytesRead = 0; 
            while (totalBytesRead < requestedCount)
            { 
                int bytesRead = stream.Read(buffer,
                                (int)totalBytesRead,
                                (int)(requestedCount - totalBytesRead));
                if (bytesRead == 0) 
                {
                    break; 
                } 
                totalBytesRead += (uint)bytesRead;
            } 
            return totalBytesRead;
        }

 
        /// 
        /// Reads and Decodes a Transfrom Descriptor Block from the stream. For information on how it is stored in the stream, 
        /// please refer to the spec. 
        /// 
        ///  
        /// 
        /// 
        /// 
        ///  
        /// 
        private uint DecodeTransformBlock(Stream strm, KnownTagCache.KnownTagIndex tag, uint cbSize, bool useDoubles, out TransformDescriptor xform) 
        { 
            xform = new TransformDescriptor();
            xform.Tag = tag; 

            uint cbRead = 0;
            uint cbTotal = cbSize;
 
            if (0 == cbSize)
                return 0; 
 
            // samgeo - Presharp issue
            // Presharp gives a warning when local IDisposable variables are not closed 
            // in this case, we can't call Dispose since it will also close the underlying stream
            // which still needs to be read from
#pragma warning disable 1634, 1691
#pragma warning disable 6518 
            BinaryReader bw = new BinaryReader(strm);
 
            if (KnownTagCache.KnownTagIndex.TransformRotate == tag) 
            {
                uint angle; 

                cbRead = SerializationHelper.Decode(strm, out angle);
                if (cbRead > cbSize)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
                xform.Transform[0] = (double)angle; 
                xform.Size = 1;
            } 
            else
            {
                if (tag == KnownTagCache.KnownTagIndex.TransformIsotropicScale)
                { 
                    xform.Size = 1;
                } 
                else if (tag == KnownTagCache.KnownTagIndex.TransformAnisotropicScale || tag == KnownTagCache.KnownTagIndex.TransformTranslate) 
                {
                    xform.Size = 2; 
                }
                else if (tag == KnownTagCache.KnownTagIndex.TransformScaleAndTranslate)
                {
                    xform.Size = 4; 
                }
                else 
                { 
                    xform.Size = 6;
                } 

                if (useDoubles)
                {
                    cbRead = xform.Size * Native.SizeOfDouble; 
                }
                else 
                { 
                    cbRead = xform.Size * Native.SizeOfFloat;
                } 

                if (cbRead > cbSize)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                for (int i = 0; i < xform.Size; i++) 
                { 
                    if (useDoubles)
                    { 
                        xform.Transform[i] = bw.ReadDouble();
                    }
                    else
                    { 
                        xform.Transform[i] = (double)bw.ReadSingle();
                    } 
                } 
            }
 
            return cbRead;
#pragma warning restore 6518
#pragma warning restore 1634, 1691
        } 

        ///  
        /// Decodes Ink Space Rectangle information from the stream 
        /// 
        ///  
        /// 
        /// 
        private uint DecodeInkSpaceRectangle(Stream strm, uint cbSize)
        { 
            uint cb, cbRead = 0;
            uint cbTotal = cbSize; 
            int data; 

            //Left 
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbTotal -= cb;
            cbRead += cb; 
            _inkSpaceRectangle.X = data; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            //Top
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbTotal -= cb; 
            cbRead += cb;
            _inkSpaceRectangle.Y = data; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

            //Right 
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            cbTotal -= cb; 
            cbRead += cb;
            _inkSpaceRectangle.Width = data - _inkSpaceRectangle.Left;
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            //Bottom 
            cb = SerializationHelper.SignDecode(strm, out data); 
            if (cb > cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            cbTotal -= cb;
            cbRead += cb;
            _inkSpaceRectangle.Height = data - _inkSpaceRectangle.Top; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 
            return cbRead;
        } 


        /// 
        /// Creates a Matrix Information structure based on the transform descriptor 
        /// 
        ///  
        ///  
        private Matrix LoadTransform(TransformDescriptor tdrd)
        { 
            double M00 = 0.0f, M01 = 0.0f, M10 = 0.0f, M11 = 0.0f, M20 = 0.0f, M21 = 0.0f;

            if (KnownTagCache.KnownTagIndex.TransformIsotropicScale == tdrd.Tag)
            { 
                M00 = M11 = tdrd.Transform[0];
            } 
            else if (KnownTagCache.KnownTagIndex.TransformRotate == tdrd.Tag) 
            {
                double dAngle = (tdrd.Transform[0] / 100) * (Math.PI / 180); 

                M00 = M11 = Math.Cos(dAngle);
                M01 = Math.Sin(dAngle);
                if (M01 == 0.0f && M11 == 1.0f) 
                {
                    //special case for 0 degree rotate transforms 
                    //this is identity 
                    M10 = 0.0f;
                } 
                else
                {
                    M10 = -M11;
                } 
            }
            else if (KnownTagCache.KnownTagIndex.TransformAnisotropicScale == tdrd.Tag) 
            { 
                M00 = tdrd.Transform[0];
                M11 = tdrd.Transform[1]; 
            }
            else if (KnownTagCache.KnownTagIndex.TransformTranslate == tdrd.Tag)
            {
                M20 = tdrd.Transform[0]; 
                M21 = tdrd.Transform[1];
            } 
            else if (KnownTagCache.KnownTagIndex.TransformScaleAndTranslate == tdrd.Tag) 
            {
                M00 = tdrd.Transform[0]; 
                M11 = tdrd.Transform[1];
                M20 = tdrd.Transform[2];
                M21 = tdrd.Transform[3];
            } 
            else    // TAG_TRANSFORM
            { 
                M00 = tdrd.Transform[0]; 
                M01 = tdrd.Transform[1];
                M10 = tdrd.Transform[2]; 
                M11 = tdrd.Transform[3];
                M20 = tdrd.Transform[4];
                M21 = tdrd.Transform[5];
            } 

            return new Matrix(M00, M01, M10, M11, M20, M21); 
        } 

 
        /// 
        /// Sets the Property Metrics for a property based on Tag and metric descriptor block
        /// 
        ///  
        /// 
        ///  
        ///  
        private StylusPointPropertyInfo GetStylusPointPropertyInfo(Guid guid, KnownTagCache.KnownTagIndex tag, MetricBlock block)
        { 
            int dw = 0;
            bool fSetDefault = false;
            uint cbEntry;
            // StylusPointPropertyInfo values that we need to read in. 
            int minimum = 0;
            int maximum = 0; 
            StylusPointPropertyUnit unit = StylusPointPropertyUnit.None; 
            float resolution = 1.0f;
 
            // To begin with initialize the property metrics with respective default valuses
            // first check if this property belongs to optional list
            for (dw = 0; dw < 11; dw++)
            { 
                if (MetricEntry.MetricEntry_Optional[dw].Tag == tag)
                { 
                    minimum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Minimum; 
                    maximum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Maximum;
                    resolution = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Resolution; 
                    unit = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Unit;
                    fSetDefault = true;
                    break;
                } 
            }
 
            if (false == fSetDefault) 
            {
                // We will come here if the property is not found in the Optional List 
                // All other cases, we will have only default values
                minimum = Int32.MinValue;
                maximum = Int32.MaxValue;
                unit = StylusPointPropertyUnit.None; 
                resolution = 1.0f;
                fSetDefault = true; 
            } 

            // Now see if there is a valid MetricBlock. If there is one, update the PROPERTY_METRICS with 
            // values from this Block
            if (null != block)
            {
                MetricEntry entry = block.GetMetricEntryList(); 

                while (null != entry) 
                { 
                    if (entry.Tag == tag)
                    { 
                        cbEntry = 0;

                        int range;
 
                        using (MemoryStream strm = new MemoryStream(entry.Data))
                        { 
                            // Decoded the Logical Min 
                            cbEntry += SerializationHelper.SignDecode(strm, out range);
                            if (cbEntry >= entry.Size) 
                            {
                                break; // return false;
                            }
 
                            minimum = range;
 
                            // Logical Max 
                            cbEntry += SerializationHelper.SignDecode(strm, out range);
                            if (cbEntry >= entry.Size) 
                            {
                                break; // return false;
                            }
 
                            maximum = range;
 
                            uint cb; 

                            // Units 
                            cbEntry += SerializationHelper.Decode(strm, out cb);
                            unit = (StylusPointPropertyUnit)cb;
                            if (cbEntry >= entry.Size)
                            { 
                                break; // return false;
                            } 
 
                            using (BinaryReader br = new BinaryReader(strm))
                            { 
                                resolution = br.ReadSingle();
                                cbEntry += Native.SizeOfFloat;
                            }
                        } 

                        break; 
                    } 

                    entry = entry.Next; 
                }
            }

            // return a new StylusPointPropertyInfo 
            return new StylusPointPropertyInfo( new StylusPointProperty(guid, StylusPointPropertyIds.IsKnownButton(guid)),
                                                minimum, 
                                                maximum, 
                                                unit,
                                                resolution); 
        }


        ///  
        /// Builds StylusPointDescription based on StrokeDescriptor and Metric Descriptor Block. Sometime Metric Descriptor block may contain
        /// metric information for properties which are not part of the stroke descriptor. They are simply ignored. 
        ///  
        /// 
        ///  
        /// 
        /// 
        private StylusPointDescription BuildStylusPointDescription(StrokeDescriptor strd, MetricBlock block, GuidList guidList)
        { 
            int cTags = 0;
            int packetPropertyCount = 0; 
            uint buttonCount = 0; 
            Guid[] buttonguids = null;
            System.Collections.Generic.List tags = null; 

            // if strd is null, it means there is only default descriptor with X & Y
            if (null != strd)
            { 
                tags = new System.Collections.Generic.List();
                while (cTags < strd.Template.Count) 
                { 
                    KnownTagCache.KnownTagIndex tag = (KnownTagCache.KnownTagIndex)strd.Template[cTags];
 
                    if (KnownTagCache.KnownTagIndex.Buttons == tag)
                    {
                        cTags++;
 
                        // The next item in the array is no of buttongs.
                        buttonCount = (uint)strd.Template[cTags]; 
                        cTags++; 

                        // Currently we skip the the no of buttons as buttons is not implimented yet 
                        buttonguids = new Guid[buttonCount];
                        for (uint u = 0; u < buttonCount; u++)
                        {
                            Guid guid = guidList.FindGuid(strd.Template[cTags]); 
                            if (guid == Guid.Empty)
                            { 
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Button guid tag embedded in ISF stream does not match guid table"),"strd"); 
                            }
 
                            buttonguids[(int)u] = guid;
                            cTags++;
                        }
                    } 
                    else if (KnownTagCache.KnownTagIndex.StrokePropertyList == tag)
                    { 
                        break; // since no more Packet properties can be stored 
                    }
                    else 
                    {
                        if (KnownTagCache.KnownTagIndex.NoX == tag ||
                            KnownTagCache.KnownTagIndex.NoY == tag)
                        { 
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF with NoX or NoY specified"), "strd");
                        } 
 
                        tags.Add(strd.Template[cTags]);
                        packetPropertyCount++; 
                        cTags++;
                    }
                }
            } 

 
            List stylusPointPropertyInfos = new List(); 
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.X, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.X), block));
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.Y, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.Y), block)); 
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.NormalPressure, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.NormalPressure), block));

            int pressureIndex = -1;
            if (tags != null) 
            {
                for (int i = 0; i < tags.Count; i++) 
                { 
                    Guid guid = guidList.FindGuid(tags[i]);
                    if (guid == Guid.Empty) 
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packet Description Property tag embedded in ISF stream does not match guid table"), "strd");
                    }
                    if (pressureIndex == -1 && guid == StylusPointPropertyIds.NormalPressure) 
                    {
                        pressureIndex = i + 2; //x,y have already been accounted for 
                        continue; //we've already added pressure (above) 
                    }
 
                    stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(guid, tags[i], block));
                }

                if (null != buttonguids) 
                {
                    // 
                    // add the buttons to the end of the description if they exist 
                    //
                    for (int i = 0; i < buttonguids.Length; i++) 
                    {
                        StylusPointProperty buttonProperty = new StylusPointProperty(buttonguids[i], true);
                        StylusPointPropertyInfo buttonInfo = new StylusPointPropertyInfo(buttonProperty);
                        stylusPointPropertyInfos.Add(buttonInfo); 
                    }
                } 
            } 

            return new StylusPointDescription(stylusPointPropertyInfos, pressureIndex); 
        }
        #endregion

        #endregion // Decoding 

        #region Encoding 
 
        #region Public Methods
#if OLD_ISF 
        /// 
        /// This functions Saves the Ink as Ink Serialized Format based on the Compression code
        /// 
        /// A byte[] with the encoded ISF 
        /// 
        ///     Critical - Calls critical methods: 
        ///             StrokeCollectionSerializer.SaveStrokeIds 
        ///             ExtendedPropertySerializer.EncodeAsISF
        ///             StrokeCollectionSerializer.StoreStrokeData 
        ///
        ///
        ///     TreatAsSafe - We're saving a StrokeCollection and we control and verify
        ///             all of the data the StrokeCollection directly and indirectly contains 
        ///
        ///             This codepath calls into unmanaged code in Compressor.CompressPacketData 
        ///             and Compressor.CompressPropertyData.  The underlying unmanaged code has been 
        ///              security reviewed and fuzzed
        /// 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
#else
        ///  
        /// This functions Saves the Ink as Ink Serialized Format based on the Compression code
        ///  
        /// A byte[] with the encoded ISF 
#endif
        internal void EncodeISF(Stream outputStream) 
        {
            _strokeLookupTable =
                new System.Collections.Generic.Dictionary(_coreStrokes.Count);
 
            // Next go through all the strokes
            for (int i = 0; i < _coreStrokes.Count; i++) 
            { 
                _strokeLookupTable.Add(_coreStrokes[i], new StrokeLookupEntry());
            } 

            // Initialize all Arraylists
            _strokeDescriptorTable = new List(_coreStrokes.Count);
            _drawingAttributesTable = new List(); 
            _metricTable = new List();
            _transformTable = new List(); 
 
            using (MemoryStream localStream = new MemoryStream(_coreStrokes.Count * 125)) //reasonable default
            { 
                GuidList guidList = BuildGuidList();
                uint cumulativeEncodedSize = 0;
                uint localEncodedSize = 0;
 
                byte xpData = (CurrentCompressionMode == CompressionMode.NoCompression) ? AlgoModule.NoCompression : AlgoModule.DefaultCompression;
                foreach (Stroke s in _coreStrokes) 
                { 
                    _strokeLookupTable[s].CompressionData = xpData;
 
                    //
                    // we need to get this data up front so that we can
                    // know if pressure was used (and thus if we need to add Pressure
                    // to the ISF packet description 
                    //
                    int[][] isfReadyData; 
                    bool shouldStorePressure; 
                    s.StylusPoints.ToISFReadyArrays(out isfReadyData, out shouldStorePressure);
                    _strokeLookupTable[s].ISFReadyStrokeData = isfReadyData; 
                    //
                    // this is our flag that ToISFReadyArrays sets if pressure was all default
                    //
                    _strokeLookupTable[s].StorePressure = shouldStorePressure; 
                }
 
 
                // Store Ink space rectangle information if necessary and anything other than default
                if (_inkSpaceRectangle != new Rect()) 
                {
                    localEncodedSize = cumulativeEncodedSize;

                    Rect inkSpaceRectangle = _inkSpaceRectangle; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.InkSpaceRectangle);
 
                    int i = (int)inkSpaceRectangle.Left; 

                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
                    i = (int)inkSpaceRectangle.Top;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i);
                    i = (int)inkSpaceRectangle.Right;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
                    i = (int)inkSpaceRectangle.Bottom;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
 
                    // validate that the expected inkspace rectangle block in ISF was the actual size encoded
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoded InkSpaceRectangle: size=" + localEncodedSize);

                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 
 
                // First prepare the compressor. Currently Compression is not supported.
                // Next write the persistence format information if anything other than ISF 
                // Currently only ISF is implemented
                if (PersistenceFormat.InkSerializedFormat != CurrentPersistenceFormat)
                {
                    localEncodedSize = cumulativeEncodedSize; 

                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.PersistenceFormat); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)SerializationHelper.VarSize((uint)CurrentPersistenceFormat)); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)CurrentPersistenceFormat);
 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoded PersistenceFormat: size=" + localEncodedSize);
 
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                } 

                // Store any size information if necessary such as GIF image size 
                // NTRAID#T2-00000-2004/03/15-[....]: WORK: Not Yet Implemented

                // Now store the Custom Guids
                localEncodedSize = cumulativeEncodedSize; 
                cumulativeEncodedSize += guidList.Save(localStream);
                localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                if (localEncodedSize != 0) 
                    ISFDebugTrace("Encoded Custom Guid Table: size=" + localEncodedSize);
 
                if (cumulativeEncodedSize != localStream.Length)
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));

                // Now build the tables 
                BuildTables(guidList);
 
                // first write the drawing attributes 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeDrawingAttrsTable(localStream, guidList); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded DrawingAttributesTable: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Next write the stroke descriptor table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializePacketDescrTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Packet Description: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Write the metric table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeMetricTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Metric Table: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Write the transform table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeTransformTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Transform Table: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Save global ink properties 
                if (_coreStrokes.ExtendedProperties.Count > 0)
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += ExtendedPropertySerializer.EncodeAsISF(_coreStrokes.ExtendedProperties, localStream, guidList, GetCompressionAlgorithm(), true);
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("Encoded Global Ink Attributes Table: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // Save stroke ids
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SaveStrokeIds(_coreStrokes, localStream, false);
                localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Stroke Id List: size=" + localEncodedSize); 
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                StoreStrokeData(localStream, guidList, ref cumulativeEncodedSize, ref localEncodedSize);

                ISFDebugTrace("Embedded ISF Stream size=" + cumulativeEncodedSize);
 
                // Now that all data has been written we need to prepend the stream
                long preEncodingPosition = outputStream.Position; 
                uint cbFinal = SerializationHelper.Encode(outputStream, (uint)0x00); 

                cbFinal += SerializationHelper.Encode(outputStream, cumulativeEncodedSize); 

                //we have to use localStream to encode ISF because we have to place a variable byte 'size of isf' at the
                //beginning of the stream
                outputStream.Write(localStream.GetBuffer(), 0, (int)cumulativeEncodedSize); 
                cbFinal += cumulativeEncodedSize;
 
                ISFDebugTrace("Final ISF Stream size=" + cbFinal); 

                if (cbFinal != outputStream.Position - preEncodingPosition) 
                {
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                }
            } 
        }
 
#if OLD_ISF 
        /// 
        /// Encodes all of the strokes in a strokecollection to ISF 
        /// 
        /// 
        ///     Critical - Calls the critical method StrokeSerializer.EncodeStroke
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        /// 
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF 
        ///
        ///  
        [SecurityCritical]
#else
        /// 
        /// Encodes all of the strokes in a strokecollection to ISF 
        /// 
#endif 
        private void StoreStrokeData(Stream localStream, GuidList guidList, ref uint cumulativeEncodedSize, ref uint localEncodedSize) 
        {
            // Now we will save the stroke data 
            uint currentDrawingAttributesTableIndex = 0;
            uint currentStrokeDescriptorTableIndex = 0;
            uint uCurrMetricDescriptorTableIndex = 0;
            uint currentTransformTableIndex = 0; 

            int[] strokeIds = StrokeIdGenerator.GetStrokeIds(_coreStrokes); 
            for (int i = 0; i < _coreStrokes.Count; i++) 
            {
                Stroke s = _coreStrokes[i]; 
                uint cbStroke = 0;

                ISFDebugTrace("Encoding Stroke Id#" + strokeIds[i]);
 
                // if the drawing attribute index is different from the current one, write it
                if (currentDrawingAttributesTableIndex != _strokeLookupTable[s].DrawingAttributesTableIndex) 
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesTableIndex); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].DrawingAttributesTableIndex);
                    currentDrawingAttributesTableIndex = _strokeLookupTable[s].DrawingAttributesTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("    Encoded DrawingAttribute Table Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // if the stroke descriptor index is different from the current one, write it
                if (currentStrokeDescriptorTableIndex != _strokeLookupTable[s].StrokeDescriptorTableIndex)
                {
                    localEncodedSize = cumulativeEncodedSize; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorTableIndex);
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].StrokeDescriptorTableIndex); 
                    currentStrokeDescriptorTableIndex = _strokeLookupTable[s].StrokeDescriptorTableIndex; 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("    Encoded Stroke Descriptor Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 

                // if the metric table index is different from the current one, write it 
                if (uCurrMetricDescriptorTableIndex != _strokeLookupTable[s].MetricDescriptorTableIndex) 
                {
                    localEncodedSize = cumulativeEncodedSize; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.MetricTableIndex);
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].MetricDescriptorTableIndex);
                    uCurrMetricDescriptorTableIndex = _strokeLookupTable[s].MetricDescriptorTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("    Encoded Metric Index: size=" + localEncodedSize); 
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 

                // if the Transform index is different from the current one, write it
                if (currentTransformTableIndex != _strokeLookupTable[s].TransformTableIndex)
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.TransformTableIndex); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].TransformTableIndex); 
                    currentTransformTableIndex = _strokeLookupTable[s].TransformTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("    Encoded Transform Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // now create a separate Memory Stream object which will be used for storing the saved stroke data temporarily 
                using (MemoryStream tempstrm = new MemoryStream(s.StylusPoints.Count * 5)) //good approximation based on profiling isf files
                { 
                    localEncodedSize = cumulativeEncodedSize;
#if OLD_ISF
                    // Now save the stroke in the temp stream
                    cbStroke = StrokeSerializer.EncodeStroke(s, tempstrm, null/*we never use CompressionMode.Max)*/, GetCompressionAlgorithm(), guidList, _strokeLookupTable[s]); 
#else
                    cbStroke = StrokeSerializer.EncodeStroke(s, tempstrm, GetCompressionAlgorithm(), guidList, _strokeLookupTable[s]); 
#endif 

                    if (cbStroke != tempstrm.Length) 
                    {
                        throw new InvalidOperationException(ISFDebugMessage("Encoded stroke size != reported size"));
                    }
 
                    // Now write the tag KnownTagCache.KnownTagIndex.Stroke
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.Stroke); 
                    ISFDebugTrace("Stroke size=" + tempstrm.Length); 

                    // Now write the size of the stroke 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, cbStroke);

                    // Finally write the stroke data
                    localStream.Write(tempstrm.GetBuffer(), 0, (int)cbStroke); 
                    cumulativeEncodedSize += cbStroke;
 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoding Stroke Id#" + strokeIds[i] + " size=" + localEncodedSize); 
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                }
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
            } 
        } 
#if OLD_ISF
        ///  
        /// Saves the stroke Ids in the stream.
        /// 
        /// 
        ///  
        /// save ids even if they are contiguous
        ///  
        ///  
        ///     Critical - Calls the critical method Compressor.CompressPacketData
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        ///
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF
        /// 
        /// 
        [SecurityCritical] 
#else 
        /// 
        /// Saves the stroke Ids in the stream. 
        /// 
        /// 
        /// 
        /// save ids even if they are contiguous 
#endif
        internal static uint SaveStrokeIds(StrokeCollection strokes, Stream strm, bool forceSave) 
        { 
            if (0 == strokes.Count)
                return 0; 

            // Define an ArrayList to store the stroke ids
            int[] strkIds = StrokeIdGenerator.GetStrokeIds(strokes);
 
            // First enumerate all strokes to collect the ids and also check if the follow the default sequence.
            // If they do we don't save the stroke ids 
            bool fDefIds = true; 

            if (!forceSave) 
            {
                // since the stroke allocation algorithm is i++, we check if any
                //  values are not equal to the sequential and consecutive list
                for (int i = 0; i < strkIds.Length; i++) 
                {
                    if (strkIds[i] != (i + 1)) 
                    { 
                            // if non-sequential or non-consecutive, then persist the ids
                        fDefIds = false; 
                        break;
                    }
                }
                // no need to store them if all of them follow the default sequence 
                if (fDefIds) return 0;
            } 
 
            // The format is as follows
            //     
            // Encode size of stroke count
            // First write the KnownTagCache.KnownTagIndex.StrokeIds
            uint cbWrote = SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeIds);
 
            ISFDebugTrace("Saved KnownTagCache.KnownTagIndex.StrokeIds size=" + cbWrote.ToString());
 
            // First findout the no of bytes required to huffman compress these ids 
            byte algorithm = AlgoModule.DefaultCompression;
#if OLD_ISF 
            byte[] data = Compressor.CompressPacketData(null, strkIds, ref algorithm);
#else
            byte[] data = Compressor.CompressPacketData(strkIds, ref algorithm);
#endif 

 
            if (data != null) 
            {
                // First write the encoded size of the buffer 
                cbWrote += SerializationHelper.Encode(strm, (uint)(data.Length + SerializationHelper.VarSize((uint)strokes.Count)));

                // Write the count of ids
                cbWrote += SerializationHelper.Encode(strm, (uint)strokes.Count); 
                strm.Write(data, 0, (int)data.Length);
                cbWrote += (uint)data.Length; 
            } 
            // If compression fails for some reason, write the uncompressed data
            else 
            {
                byte bCompAlgo = AlgoModule.NoCompression;

                // Find out the size of the data + size of the id count 
                uint cbStrokeId = (uint)(strokes.Count * Native.SizeOfInt + 1 + SerializationHelper.VarSize((uint)strokes.Count)); // 1 is for the compression header
 
                cbWrote += SerializationHelper.Encode(strm, cbStrokeId); 
                cbWrote += SerializationHelper.Encode(strm, (uint)strokes.Count);
                strm.WriteByte(bCompAlgo); 
                cbWrote++;

                // Now write all the ids in the stream
                // samgeo - Presharp issue 
                // Presharp gives a warning when local IDisposable variables are not closed
                // in this case, we can't call Dispose since it will also close the underlying stream 
                // which still needs to be written to 
#pragma warning disable 1634, 1691
#pragma warning disable 6518 
                BinaryWriter bw = new BinaryWriter(strm);

                for (int i = 0; i < strkIds.Length; i++)
                { 
                    bw.Write(strkIds[i]);
                    cbWrote += Native.SizeOfInt; 
                } 
#pragma warning restore 6518
#pragma warning restore 1634, 1691 
            }

            return cbWrote;
        } 

 
        #endregion 

        #region Private Methods 

        /// 
        /// Simple helper method to examine the first 7 members (if they exist)
        /// of the byte[] and see if they have the ascii characters 'base64:' in them. 
        /// 
        ///  
        ///  
        private bool IsBase64Data(Stream data)
        { 
            Debug.Assert(data != null);
            long currentPosition = data.Position;
            try
            { 
                byte[] isfBase64PrefixBytes = Base64HeaderBytes;
                if (data.Length < isfBase64PrefixBytes.Length) 
                { 
                    return false;
                } 

                for (int x = 0; x < isfBase64PrefixBytes.Length; x++)
                {
                    if ((byte)data.ReadByte() != isfBase64PrefixBytes[x]) 
                    {
                        return false; 
                    } 
                }
                return true; 
            }
            finally
            {
                //reset position 
                data.Position = currentPosition;
            } 
        } 

        ///  
        /// Builds the GuidList based on ExtendedPropeties and StrokeCollection
        /// 
        /// 
        private GuidList BuildGuidList() 
        {
            GuidList guidList = new GuidList(); 
            int i = 0; 

            // First go through the list of ink properties 
            ExtendedPropertyCollection attributes = _coreStrokes.ExtendedProperties;
            for (i = 0; i < attributes.Count; i++)
            {
                guidList.Add(attributes[i].Id); 
            }
 
            // Next go through all the strokes 
            for (int j = 0; j < _coreStrokes.Count; j++)
            { 
                BuildStrokeGuidList(_coreStrokes[j], guidList);
            }

            return guidList; 
        }
        ///  
        /// Builds the list of Custom Guids that were used by this particular stroke, either in the packet layout 
        /// or in the drawing attributes, or in the buttons or in Extended properties or in the point properties
        /// and updates the guidlist with that information 
        /// 
        /// 
        /// 
        private void BuildStrokeGuidList(Stroke stroke, GuidList guidList) 
        {
            int i = 0; 
 
            // First drawing attributes
            //      Ignore the default Guids/attributes in the DrawingAttributes 
            int count;
            Guid[] guids = ExtendedPropertySerializer.GetUnknownGuids(stroke.DrawingAttributes.ExtendedProperties, out count);

            for (i = 0; i < count; i++) 
            {
                guidList.Add(guids[i]); 
            } 

            Guid[] descriptionGuids = stroke.StylusPoints.Description.GetStylusPointPropertyIds(); 
            for (i = 0; i < descriptionGuids.Length; i++)
            {
                guidList.Add(descriptionGuids[i]);
            } 

            if (stroke.ExtendedProperties.Count > 0) 
            { 
                // Add the ExtendedProperty guids in the list
                for (i = 0; i < stroke.ExtendedProperties.Count; i++) 
                {
                    guidList.Add(stroke.ExtendedProperties[i].Id);
                }
            } 
        }
 
 
        private byte GetCompressionAlgorithm()
        { 
            if (CompressionMode.Compressed == CurrentCompressionMode)
            {
                return AlgoModule.DefaultCompression;
            } 
            return AlgoModule.NoCompression;
        } 
 

        ///  
        /// This function serializes Stroke Descriptor Table in the stream. For information on how they are serialized, please refer to the spec.
        ///
        /// 
        ///  
        /// 
        private uint SerializePacketDescrTable(Stream strm) 
        { 
            if (_strokeDescriptorTable.Count == 0)
                return 0; 

            int count = 0;
            uint cbData = 0;
 
            // First add the appropriate header information
            if (_strokeDescriptorTable.Count == 1) 
            { 
                StrokeDescriptor tmp = _strokeDescriptorTable[0];
 
                // If there is no tag, that means default template and only one entry in the list. Return from here
                if (tmp.Template.Count == 0)
                    return 0;
                else 
                {
                    // Write it out directly 
                    // First the tag 
                    cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorBlock);
 
                    // Now encode the descriptor itself
                    cbData += EncodeStrokeDescriptor(strm, tmp);
                }
            } 
            else
            { 
                uint cbTotal = 0; 

                // First calculate the total encoded size of the all the Templates 
                for (count = 0; count < _strokeDescriptorTable.Count; count++)
                {
                    cbTotal += SerializationHelper.VarSize((_strokeDescriptorTable[count]).Size) + (_strokeDescriptorTable[count]).Size;
                } 

                // Now write the Tag 
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorTable); 
                cbData += SerializationHelper.Encode(strm, cbTotal);
 
                // Now write the encoded templates
                for (count = 0; count < _strokeDescriptorTable.Count; count++)
                {
                    cbData += EncodeStrokeDescriptor(strm, _strokeDescriptorTable[count]); 
                }
            } 
 
            return cbData;
        } 


        /// 
        /// This function serializes Metric Descriptor Table in the stream. For information on how they are serialized, please refer to the spec. 
        /// 
        ///  
        ///  
        private uint SerializeMetricTable(Stream strm)
        { 
            uint cSize = 0;
            MetricBlock block;

            if (0 == _metricTable.Count) 
                return 0;
 
            for (int i = 0; i < _metricTable.Count; i++) 
                cSize += _metricTable[i].Size;
 
            uint cbData = 0;

            // if total size of the blocks is 1, then there is nothing to write
            //  the reason that the size of the blocks is 1 instead of 0 is because 
            //  MetricBlock.Size returns the size of the block plus the byte encoded
            //  size value itself. If the MetricBlock size value is 0, then byte 
            //  encoded size value is 0, which has a byte size of 1. 
            if (1 == cSize)
            { 
                return 0;
            }
            else if (1 == _metricTable.Count)
            { 
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.MetricBlock);
            } 
            else 
            {
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.MetricTable); 
                cbData += SerializationHelper.Encode(strm, cSize);
            }

            for (int i = 0; i < _metricTable.Count; i++) 
            {
                block = _metricTable[i]; 
                cbData += block.Pack(strm); 
            }
 
            return cbData;
        }

 
        /// 
        /// Multibyte Encodes a Stroke Descroptor 
        ///  
        /// 
        ///  
        /// 
        private uint EncodeStrokeDescriptor(Stream strm, StrokeDescriptor strd)
        {
            uint cbData = 0; 

            // First encode the size of the descriptor 
            cbData += SerializationHelper.Encode(strm, strd.Size); 
            for (int count = 0; count < strd.Template.Count; count++)
            { 
                // Now encode all members of the descriptor
                cbData += SerializationHelper.Encode(strm, (uint)strd.Template[count]);
            }
 
            return cbData;
        } 
 

        ///  
        /// This function serializes Transform Descriptor Table in the stream. For information on how they are serialized, please refer to the spec.
        /// 
        /// 
        ///  
        private uint SerializeTransformTable(Stream strm)
        { 
            // If there is only one entry in the TransformDescriptor table 
            //      and it is the default descriptor, skip serialization of transforms
            if (_transformTable.Count == 1 && _transformTable[0].Size == 0) 
            {
                return 0;
            }
 
            uint floatTotal = 0;
            uint doubleTotal = 0; 
 
            // First count the size of all transforms (handling both float && double versions)
            for (int i = 0; i < _transformTable.Count; i++) 
            {
                TransformDescriptor xform = _transformTable[i];
                uint cbLocal = SerializationHelper.VarSize((uint)xform.Tag);
 
                floatTotal += cbLocal;
                doubleTotal += cbLocal; 
                if (KnownTagCache.KnownTagIndex.TransformRotate == xform.Tag) 
                {
                    cbLocal = SerializationHelper.VarSize((uint)(xform.Transform[0] + 0.5f)); 
                    floatTotal += cbLocal;
                    doubleTotal += cbLocal;
                }
                else 
                {
                    cbLocal = xform.Size * Native.SizeOfFloat; 
                    floatTotal += cbLocal; 
                    doubleTotal += cbLocal * 2;
                } 
            }

            uint cbTotal = 0;
 
            // If there is only one entry in the TransformDescriptor table
            if (_transformTable.Count == 1) 
            { 
                TransformDescriptor xform = _transformTable[0];
 
                cbTotal = EncodeTransformDescriptor(strm, xform, false);
            }
            else
            { 
                // Now first write the block descriptor and then write all transforms
                cbTotal += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.TransformTable); 
                cbTotal += SerializationHelper.Encode(strm, floatTotal); 
                for (int i = 0; i < _transformTable.Count; i++)
                { 
                    cbTotal += EncodeTransformDescriptor(strm, _transformTable[i], false);
                }
            }
            // now write the Extended Transform table (using doubles instead of floats) 
            { // note that we do not distinguish between 1 and > 1 transforms for compression
                // Now first write the block descriptor and then write all transforms 
                cbTotal += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.ExtendedTransformTable); 
                cbTotal += SerializationHelper.Encode(strm, doubleTotal);
                for (int i = 0; i < _transformTable.Count; i++) 
                {
                    cbTotal += EncodeTransformDescriptor(strm, _transformTable[i], true);
                }
            } 
            return cbTotal;
        } 
 

        ///  
        /// Multibyte Encode if necessary a Transform Descriptor into the stream
        /// 
        /// 
        ///  
        /// 
        ///  
        private uint EncodeTransformDescriptor(Stream strm, TransformDescriptor xform, bool useDoubles) 
        {
            uint cbData = 0; 

            // First encode the tag
            cbData = SerializationHelper.Encode(strm, (uint)xform.Tag);
 
            // Encode specially if transform denotes rotation
            if (KnownTagCache.KnownTagIndex.TransformRotate == xform.Tag) 
            { 
                uint angle = (uint)(xform.Transform[0] + 0.5f);
 
                cbData += SerializationHelper.Encode(strm, angle);
            }
            else
            { 
                // samgeo - Presharp issue
                // Presharp gives a warning when local IDisposable variables are not closed 
                // in this case, we can't call Dispose since it will also close the underlying stream 
                // which still needs to be written to
#pragma warning disable 1634, 1691 
#pragma warning disable 6518
                BinaryWriter bw = new BinaryWriter(strm);

                for (int i = 0; i < xform.Size; i++) 
                {
                    // note that the binary writer changes serialization 
                    //      lengths depending on the Write parameter cast 
                    if (useDoubles)
                    { 
                        bw.Write(xform.Transform[i]);
                        cbData += Native.SizeOfDouble;
                    }
                    else 
                    {
                        bw.Write((float)xform.Transform[i]); 
                        cbData += Native.SizeOfFloat; 
                    }
                } 
#pragma warning restore 6518
#pragma warning restore 1634, 1691
            }
 
            return cbData;
        } 
 
#if OLD_ISF
        ///  
        /// This function serializes Drawing Attributes Table in the stream. For information on how they are serialized, please refer to the spec.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///     Critical - Calls the critical method 
        ///         DrawingAttributeSerializer.EncodeAsISF
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        ///
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF
        /// 
        /// 
        [SecurityCritical] 
#else 
        /// 
        /// This function serializes Drawing Attributes Table in the stream. For information on how they are serialized, please refer to the spec. 
        /// 
        /// 
        /// 
#endif 
        private uint SerializeDrawingAttrsTable(Stream stream, GuidList guidList)
        { 
            uint totalSizeOfSerializedBytes = 0; 
            uint sizeOfHeaderInBytes = 0;
 
            if (1 == _drawingAttributesTable.Count)
            {
                //we always serialize a single DA, even if it has default values so we will write width back to the stream
                DrawingAttributes drawingAttributes = _drawingAttributesTable[0]; 

                // There is single drawing attribute. Save it along with the size 
                totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesBlock); 

                // Get the size of the saved bytes 
                using (MemoryStream drawingAttributeStream = new MemoryStream(16)) //reasonable default based onn profiling
                {
                    sizeOfHeaderInBytes = DrawingAttributeSerializer.EncodeAsISF(drawingAttributes, drawingAttributeStream, guidList, 0, true);
 
                    // Write the size first
                    totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizeOfHeaderInBytes); 
 
                    // write the data
                    uint bytesWritten = Convert.ToUInt32(drawingAttributeStream.Position); 
                    totalSizeOfSerializedBytes += bytesWritten;
                    Debug.Assert(sizeOfHeaderInBytes == bytesWritten);

                    stream.Write(   drawingAttributeStream.GetBuffer(), //returns a direct ref, no copied 
                                    0,
                                    Convert.ToInt32(bytesWritten)); 
 
                    drawingAttributeStream.Dispose();
                } 
            }
            else
            {
                // Temporarily declare an array to hold the size of the saved drawing attributes 
                uint[] sizes = new uint[_drawingAttributesTable.Count];
                MemoryStream[] drawingAttributeStreams = new MemoryStream[_drawingAttributesTable.Count]; 
 
                // First calculate the size of each attribute
                for (int i = 0; i < _drawingAttributesTable.Count; i++) 
                {
                    DrawingAttributes drawingAttributes = _drawingAttributesTable[i];
                    drawingAttributeStreams[i] = new MemoryStream(16); //reasonable default based on profiling
 
                    sizes[i] = DrawingAttributeSerializer.EncodeAsISF(drawingAttributes, drawingAttributeStreams[i], guidList, 0, true);
                    sizeOfHeaderInBytes += SerializationHelper.VarSize(sizes[i]) + sizes[i]; 
                } 

                // Now write the KnownTagCache.KnownTagIndex.DrawingAttributesTable first, then sizeOfHeaderInBytes and then individual Drawing Attributes 
                totalSizeOfSerializedBytes = SerializationHelper.Encode(stream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesTable);

                totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizeOfHeaderInBytes);
                for (int i = 0; i < _drawingAttributesTable.Count; i++) 
                {
                    DrawingAttributes drawingAttributes = _drawingAttributesTable[i]; 
 
                    // write the size of the block
                    totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizes[i]); 

                    // write the saved data
                    uint bytesWritten = Convert.ToUInt32(drawingAttributeStreams[i].Position);
                    totalSizeOfSerializedBytes += bytesWritten; 
                    Debug.Assert(sizes[i] == bytesWritten);
 
                    stream.Write(   drawingAttributeStreams[i].GetBuffer(), //returns a direct ref, no copies 
                                    0,
                                    Convert.ToInt32(bytesWritten)); 

                    drawingAttributeStreams[i].Dispose();
                }
            } 

            return totalSizeOfSerializedBytes; 
        } 

        ///  
        /// This function builds list of all unique Tables, ie Stroke Descriptor Table, Metric Descriptor Table, Transform Descriptor Table
        /// and Drawing Attributes Table based on all the strokes. Each entry in the Table is unique with respect to the table.
        /// 
        ///  
        private void BuildTables(GuidList guidList)
        { 
            _transformTable.Clear(); 
            _strokeDescriptorTable.Clear();
            _metricTable.Clear(); 
            _drawingAttributesTable.Clear();

            int count = 0;
 
            for (count = 0; count < _coreStrokes.Count; count++)
            { 
                Stroke stroke = _coreStrokes[count]; 

                // First get the updated descriptor from the stroke 
                StrokeDescriptor strokeDescriptor;
                MetricBlock metricBlock;
                StrokeSerializer.BuildStrokeDescriptor(stroke, guidList, _strokeLookupTable[stroke], out strokeDescriptor, out metricBlock);
                bool fMatch = false; 

                // Compare this with all the global stroke descriptor for a match 
                for (int descriptorIndex = 0; descriptorIndex < _strokeDescriptorTable.Count; descriptorIndex++) 
                {
                    if (strokeDescriptor.IsEqual(_strokeDescriptorTable[descriptorIndex])) 
                    {
                        fMatch = true;
                        _strokeLookupTable[stroke].StrokeDescriptorTableIndex = (uint)descriptorIndex;
                        break; 
                    }
                } 
                if (false == fMatch) 
                {
                    _strokeDescriptorTable.Add(strokeDescriptor); 
                    _strokeLookupTable[stroke].StrokeDescriptorTableIndex = (uint)_strokeDescriptorTable.Count - 1;
                }

                // If there is at least one entry in the metric block, check if the current Block is equvalent to 
                // any of the existing one.
                fMatch = false; 
                for (int tmp = 0; tmp < _metricTable.Count; tmp++) 
                {
                    MetricBlock block = _metricTable[tmp]; 
                    SetType type = SetType.SubSet;

                    if (block.CompareMetricBlock(metricBlock, ref type))
                    { 
                        // This entry exists in the list. If it is a subset of the element, do nothing.
                        // Otherwise, replace the entry with this one 
                        if (type == SetType.SuperSet) 
                        {
                            _metricTable[tmp] = metricBlock; 
                        }

                        fMatch = true;
                        _strokeLookupTable[stroke].MetricDescriptorTableIndex = (uint)tmp; 
                        break;
                    } 
                } 

                if (false == fMatch) 
                {
                    _metricTable.Add(metricBlock);
                    _strokeLookupTable[stroke].MetricDescriptorTableIndex = (uint)(_metricTable.Count - 1);
                } 

                // Now build the Transform Table 
                fMatch = false; 

                // 
                // always identity
                //
                TransformDescriptor xform = StrokeCollectionSerializer.IdentityTransformDescriptor;
 
                // First check to see if this matches with any existing Transform Blocks
                for (int i = 0; i < _transformTable.Count; i++) 
                { 
                    if (true == xform.Compare(_transformTable[i]))
                    { 
                        fMatch = true;
                        _strokeLookupTable[stroke].TransformTableIndex = (uint)i;
                        break;
                    } 
                }
 
                if (false == fMatch) 
                {
                    _transformTable.Add(xform); 
                    _strokeLookupTable[stroke].TransformTableIndex = (uint)(_transformTable.Count - 1);
                }

                // Now build the drawing attributes table 
                fMatch = false;
 
                DrawingAttributes drattrs = _coreStrokes[count].DrawingAttributes; 

                // First check to see if this matches with any existing transform blocks 
                for (int i = 0; i < _drawingAttributesTable.Count; i++)
                {
                    if (true == drattrs.Equals(_drawingAttributesTable[i]))
                    { 
                        fMatch = true;
                        _strokeLookupTable[stroke].DrawingAttributesTableIndex = (uint)i; 
                        break; 
                    }
                } 

                if (false == fMatch)
                {
                    _drawingAttributesTable.Add(drattrs); 
                    _strokeLookupTable[stroke].DrawingAttributesTableIndex = (uint)_drawingAttributesTable.Count - 1;
                } 
            } 
        }
 
        #endregion // Private Methods

        internal class StrokeLookupEntry
        { 
            internal uint MetricDescriptorTableIndex = 0;
            internal uint StrokeDescriptorTableIndex = 0; 
            internal uint TransformTableIndex = 0; 
            internal uint DrawingAttributesTableIndex = 0;
 
            // Compression algorithm data
            internal byte CompressionData = 0;

            internal int[][] ISFReadyStrokeData = null; 
            internal bool StorePressure = false;
        } 
 
        #endregion // Encoding
 
        #region Debugging Methods

        [System.Diagnostics.Conditional("DEBUG_ISF")]
        static void ISFDebugTrace(string message) 
        {
            System.Diagnostics.Debug.WriteLine(message); 
        } 
        #endregion
 
        // [System.Diagnostics.Conditional("DEBUG_ISF")]
        internal static string ISFDebugMessage(string debugMessage)
        {
#if DEBUG 
            return debugMessage;
#else 
            return SR.Get(SRID.IsfOperationFailed); 
#endif
        } 

        #region Private Fields

        StrokeCollection _coreStrokes; 
        private System.Collections.Generic.List _strokeDescriptorTable = null;
        private System.Collections.Generic.List _transformTable = null; 
        private System.Collections.Generic.List _drawingAttributesTable = null; 
        private System.Collections.Generic.List _metricTable = null;
        private Vector _himetricSize = new Vector(0.0f, 0.0f); 


            // The ink space rectangle (e.g. bounding box for GIF) is stored
            //      with the serialization info so that load/save roundtrip the 
            //      rectangle
        private Rect _inkSpaceRectangle = new Rect(); 
 
        System.Collections.Generic.Dictionary _strokeLookupTable = null;
 
        #endregion
    }

    ///  
    /// Simple static method for generating StrokeIds
    ///  
    internal static class StrokeIdGenerator 
    {
        ///  
        /// Generates backwards compatible StrokeID's for the strokes
        /// 
        /// strokes
        ///  
        internal static int[] GetStrokeIds(StrokeCollection strokes)
        { 
            System.Diagnostics.Debug.Assert(strokes != null); 

            int[] strokeIds = new int[strokes.Count]; 
            for (int x = 0; x < strokeIds.Length; x++)
            {
                //stroke ID's are 1 based (1,2,3...)
                strokeIds[x] = x + 1; 
            }
            return strokeIds; 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//#define OLD_ISF 
//------------------------------------------------------------------------
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//  
//-----------------------------------------------------------------------
 
using MS.Utility; 
using System;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging; 
using System.IO;
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Security.Permissions;
using System.Runtime.Serialization; 
using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using System.Windows.Ink; 
using MS.Internal.IO.Packaging;
 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
 
namespace MS.Internal.Ink.InkSerializedFormat
{
    internal class StrokeCollectionSerializer
    { 
        #region Constants (Static Fields)
        internal static readonly double AvalonToHimetricMultiplier = 2540F / 96.0F; 
        internal static readonly double HimetricToAvalonMultiplier = 96.0F / 2540.0F; 
        internal static readonly TransformDescriptor IdentityTransformDescriptor;
 
        static StrokeCollectionSerializer()
        {
            TransformDescriptor transformDescriptor = new TransformDescriptor();
            transformDescriptor.Transform[0] = 1.0f; 
            transformDescriptor.Tag = KnownTagCache.KnownTagIndex.TransformIsotropicScale;
            transformDescriptor.Size = 1; 
            StrokeCollectionSerializer.IdentityTransformDescriptor = transformDescriptor; 
        }
        #endregion 

        #region Constructors

        // disable default constructor 
        private StrokeCollectionSerializer() { }
 
        ///  
        /// Initialize the Ink serializer
        ///  
        /// Pointer to the core stroke collection - avoids recreation of collections
        internal StrokeCollectionSerializer(StrokeCollection coreStrokes)
        {
            _coreStrokes = coreStrokes; 
        }
 
        #endregion 

        #region Public Fields 

        internal PersistenceFormat CurrentPersistenceFormat = PersistenceFormat.InkSerializedFormat;
        internal CompressionMode CurrentCompressionMode = CompressionMode.Compressed;
        internal System.Collections.Generic.List StrokeIds = null; 
        #endregion
 
        #region Decoding 

        #region Public Methods 


        /// 
        /// Loads a Ink object from a spcified byte array in the form of Ink Serialzied Format 
        /// This method checks for the 'base64:' prefix in the byte[] because that is how V1
        /// saved ISF 
        ///  
        /// 
        internal void DecodeISF(Stream inkData) 
        {
            try
            {
                // First examine the input data header 
                bool isBase64;
                bool isGif; 
                uint cbData; 

                ExamineStreamHeader(inkData, out isBase64, out isGif, out cbData); 
                if (isBase64)
                {
                    //
                    // this is a funky tablet v1 based byte[] that is base64 encoded... 
                    // each 4 bytes in this array corresponds to 3 bytes of ISF data.
                    // EXCEPT the first 7 bytes which are saved with the value 
                    // 'base64:' and must not be base64 decoded. 
                    // and the last null terminator (if present)
                    // 
                    //  The following code does two things:
                    //  1) Convert each byte to a char so it can be base64 decoded
                    //  2) Strips out the first 7 resulting characters
                    // 
                    int isfBase64PrefixLength = Base64HeaderBytes.Length;
                    // the previous call to ExamineStreamHeader guarantees that inkData.Length > isfBase64PrefixLength 
                    System.Diagnostics.Debug.Assert(inkData.Length > isfBase64PrefixLength); 

                    inkData.Position = (long)isfBase64PrefixLength; 
                    List charData = new List((int)inkData.Length);
                    int intByte = inkData.ReadByte();
                    while (intByte != -1)
                    { 
                        byte b = (byte)intByte;
                        charData.Add((char)b); 
                        intByte = inkData.ReadByte(); 
                    }
 
                    if (0 == (byte)(charData[charData.Count - 1]))
                    {
                        //strip the null terminator
                        charData.RemoveAt(charData.Count - 1); 
                    }
 
                    char[] chars = charData.ToArray(); 
                    byte[] isfData = Convert.FromBase64CharArray(chars, 0, chars.Length);
                    MemoryStream ms = new MemoryStream(isfData); 
                    if (IsGIFData(ms))
                    {
                        DecodeRawISF(ReadGifData(ms));
                    } 
                    else
                    { 
                        DecodeRawISF(ms); 
                    }
                } 
                else if (true == isGif)
                {
                    DecodeRawISF(ReadGifData(inkData));
                } 
                else
                { 
                    DecodeRawISF(inkData); 
                }
            } 
#if DEBUG
            catch (ArgumentException ex)
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            } 
            catch (InvalidOperationException ex) 
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            }
            catch (IndexOutOfRangeException ex)
            { 
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex); 
            } 
            catch (NullReferenceException ex)
            { 
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            }
            catch (EndOfStreamException ex) 
            {
                //only include an inner exception in debug builds 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex); 
            }
            catch (OverflowException ex) 
            {
                //only include an inner exception in debug builds
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), ex);
            } 
#else
            catch (ArgumentException) 
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            } 
            catch (InvalidOperationException)
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            } 
            catch (IndexOutOfRangeException)
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor() 
            }
            catch (NullReferenceException) 
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            }
            catch (EndOfStreamException) 
            {
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor() 
            } 
            catch (OverflowException)
            { 
                throw new ArgumentException(SR.Get(SRID.IsfOperationFailed), "stream");//stream comes from StrokeCollection.ctor()
            }
#endif
        } 

        #endregion 
 
        #region Private Methods
 
        /// 
        /// Loads the strokeIds from the stream, we need to do this to decrement the count of bytes
        /// 
        internal uint LoadStrokeIds(Stream isfStream, uint cbSize) 
        {
            if (0 == cbSize) 
                return 0; 

            uint cb; 
            uint cbTotal = cbSize;

            // First decode the no of ids
            uint count; 

            cb = SerializationHelper.Decode(isfStream, out count); 
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "isfStream");
 
            cbTotal -= cb;
            if (0 == count)
                return (cbSize - cbTotal);
 
            cb = cbTotal;
 
            byte[] inputdata = new byte[cb]; 

            // read the stream 
            uint bytesRead = StrokeCollectionSerializer.ReliableRead(isfStream, inputdata, cb);
            if (cb != bytesRead)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "isfStream"); 
            }
            cbTotal -= cb; 
 
            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "isfStream"); 

            return cbSize;
        }
 

        private bool IsGIFData(Stream inkdata) 
        { 
            Debug.Assert(inkdata != null);
            long currentPosition = inkdata.Position; 
            try
            {
                return ((byte)inkdata.ReadByte() == 'G' &&
                        (byte)inkdata.ReadByte() == 'I' && 
                        (byte)inkdata.ReadByte() == 'F');
            } 
            finally 
            {
                //reset position 
                inkdata.Position = currentPosition;
            }
        }
 
        private Stream ReadGifData(Stream inkdata)
        { 
            // Read the GIF header ... 
            System.Drawing.Bitmap img = new System.Drawing.Bitmap(inkdata);
            // Read the comment as that is where the ISF is stored... 
            // for reference the tag is PropertyTagExifUserComment [0x9286] or 37510 (int)
            System.Drawing.Imaging.PropertyItem piComment = img.GetPropertyItem(37510);
            return new MemoryStream(piComment.Value);
        } 

        private void ExamineStreamHeader(Stream inkdata, out bool fBase64, out bool fGif, out uint cbData) 
        { 
            fGif = false;
            cbData = 0; 
            fBase64 = false;

            if (inkdata.Length >= 7)
            { 
                fBase64 = IsBase64Data(inkdata);
            } 
 
            // Check for RAW gif
 	        if (!fBase64 && inkdata.Length >= 3) 
	        {
                fGif = IsGIFData(inkdata);
	        }
		 
            return;
        } 
 
        private static readonly byte[] Base64HeaderBytes
                                            = new byte[]{(byte)'b', 
                                                        (byte)'a',
                                                        (byte)'s',
                                                        (byte)'e',
                                                        (byte)'6', 
                                                        (byte)'4',
                                                        (byte)':'}; 
 
#if OLD_ISF
        ///  
        /// Takes an ISF byte[] and populates the StrokeCollection
        ///  attached to this StrokeCollectionSerializer.
        /// 
        /// a byte[] of the raw isf to decode 
        /// 
        ///     Critical - Calls critical methods in Compressor 
        ///     TreatAsSafe - inkdata is a disconnected copy from the one passed in 
        ///         underlying unmanaged code has been security reviewed and fuzzed
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
#else
        /// 
        /// Takes an ISF Stream and populates the StrokeCollection 
        ///  attached to this StrokeCollectionSerializer.
        ///  
        /// a Stream the raw isf to decode 
#endif
        private void DecodeRawISF(Stream inputStream) 
        {
            Debug.Assert(inputStream != null);

            KnownTagCache.KnownTagIndex isfTag; 
            uint remainingBytesInStream;
            uint bytesDecodedInCurrentTag = 0; 
            bool strokeDescriptorBlockDecoded = false; 
            bool drawingAttributesBlockDecoded = false;
            bool metricBlockDecoded = false; 
            bool transformDecoded = false;
            uint strokeDescriptorTableIndex = 0;
            uint oldStrokeDescriptorTableIndex = 0xFFFFFFFF;
            uint drawingAttributesTableIndex = 0; 
            uint oldDrawingAttributesTableIndex = 0xFFFFFFFF;
            uint metricDescriptorTableIndex = 0; 
            uint oldMetricDescriptorTableIndex = 0xFFFFFFFF; 
            uint transformTableIndex = 0;
            uint oldTransformTableIndex = 0xFFFFFFFF; 
            GuidList guidList = new GuidList();
            int strokeIndex = 0;

            StylusPointDescription currentStylusPointDescription = null; 
            Matrix currentTabletToInkTransform = Matrix.Identity;
 
            _strokeDescriptorTable = new System.Collections.Generic.List(); 
            _drawingAttributesTable = new System.Collections.Generic.List();
            _transformTable = new System.Collections.Generic.List(); 
            _metricTable = new System.Collections.Generic.List();

            // First make sure this ink is empty
            if (0 != _coreStrokes.Count || _coreStrokes.ExtendedProperties.Count != 0) 
            {
                throw new InvalidOperationException(ISFDebugMessage("ISF decoder cannot operate on non-empty ink container")); 
            } 
#if OLD_ISF
            // 
            // store a compressor reference at this scope, if it is needed (if there is a compresson header) and
            // therefore instanced during this routine, we will dispose of it
            // in the finally block
            // 
            Compressor compressor = null;
 
            try 
            {
#endif 

            // First read the isfTag
            uint uiTag;
            uint localBytesDecoded = SerializationHelper.Decode(inputStream, out uiTag); 
            if (0x00 != uiTag)
                throw new ArgumentException(SR.Get(SRID.InvalidStream)); 
 
            // Now read the size of the stream
            localBytesDecoded = SerializationHelper.Decode(inputStream, out remainingBytesInStream); 
            ISFDebugTrace("Decoded Stream Size in Bytes: " + remainingBytesInStream.ToString());
            if (0 == remainingBytesInStream)
                return;
 
            while (0 < remainingBytesInStream)
            { 
                bytesDecodedInCurrentTag = 0; 

                // First read the isfTag 
                localBytesDecoded = SerializationHelper.Decode(inputStream, out uiTag);
                isfTag = (KnownTagCache.KnownTagIndex)uiTag;
                if (remainingBytesInStream >= localBytesDecoded)
                    remainingBytesInStream -= localBytesDecoded; 
                else
                { 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                }
 
                ISFDebugTrace("Decoding Tag: " + ((KnownTagCache.KnownTagIndex)isfTag).ToString());
                switch (isfTag)
                {
                    case KnownTagCache.KnownTagIndex.GuidTable: 
                    case KnownTagCache.KnownTagIndex.DrawingAttributesTable:
                    case KnownTagCache.KnownTagIndex.DrawingAttributesBlock: 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorTable: 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorBlock:
                    case KnownTagCache.KnownTagIndex.MetricTable: 
                    case KnownTagCache.KnownTagIndex.MetricBlock:
                    case KnownTagCache.KnownTagIndex.TransformTable:
                    case KnownTagCache.KnownTagIndex.ExtendedTransformTable:
                    case KnownTagCache.KnownTagIndex.Stroke: 
                    case KnownTagCache.KnownTagIndex.CompressionHeader:
                    case KnownTagCache.KnownTagIndex.PersistenceFormat: 
                    case KnownTagCache.KnownTagIndex.HimetricSize: 
                    case KnownTagCache.KnownTagIndex.StrokeIds:
                        { 
                            localBytesDecoded = SerializationHelper.Decode(inputStream, out bytesDecodedInCurrentTag);
                            if (remainingBytesInStream < (localBytesDecoded + bytesDecodedInCurrentTag))
                            {
                                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inputStream"); 
                            }
 
                            remainingBytesInStream -= localBytesDecoded; 

                            // Based on the isfTag figure out what information we're loading 
                            switch (isfTag)
                            {
                                case KnownTagCache.KnownTagIndex.GuidTable:
                                    { 
                                        // Load guid Table
                                        localBytesDecoded = guidList.Load(inputStream, bytesDecodedInCurrentTag); 
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.DrawingAttributesTable:
                                    {
                                        // Load drawing attributes table
                                        localBytesDecoded = LoadDrawAttrsTable(inputStream, guidList, bytesDecodedInCurrentTag); 
                                        drawingAttributesBlockDecoded = true;
                                        break; 
                                    } 

                                case KnownTagCache.KnownTagIndex.DrawingAttributesBlock: 
                                    {
                                        //initialize to V1 defaults, we do it this way as opposed
                                        //to dr.DrawingFlags = 0 because this was a perf hot spot
                                        //and instancing the epc first mitigates it 
                                        ExtendedPropertyCollection epc = new ExtendedPropertyCollection();
                                        epc.Add(KnownIds.DrawingFlags, DrawingFlags.Polyline); 
                                        DrawingAttributes dr = new DrawingAttributes(epc); 
                                        localBytesDecoded = DrawingAttributeSerializer.DecodeAsISF(inputStream, guidList, bytesDecodedInCurrentTag, dr);
 
                                        _drawingAttributesTable.Add(dr);
                                        drawingAttributesBlockDecoded = true;
                                        break;
                                    } 

                                case KnownTagCache.KnownTagIndex.StrokeDescriptorTable: 
                                    { 
                                        // Load stroke descriptor table
                                        localBytesDecoded = DecodeStrokeDescriptorTable(inputStream, bytesDecodedInCurrentTag); 
                                        strokeDescriptorBlockDecoded = true;
                                        break;
                                    }
 
                                case KnownTagCache.KnownTagIndex.StrokeDescriptorBlock:
                                    { 
                                        // Load a single stroke descriptor 
                                        localBytesDecoded = DecodeStrokeDescriptorBlock(inputStream, bytesDecodedInCurrentTag);
                                        strokeDescriptorBlockDecoded = true; 
                                        break;
                                    }

                                case KnownTagCache.KnownTagIndex.MetricTable: 
                                    {
                                        // Load Metric Table 
                                        localBytesDecoded = DecodeMetricTable(inputStream, bytesDecodedInCurrentTag); 
                                        metricBlockDecoded = true;
                                        break; 
                                    }

                                case KnownTagCache.KnownTagIndex.MetricBlock:
                                    { 
                                        // Load a single Metric Block
                                        MetricBlock blk; 
 
                                        localBytesDecoded = DecodeMetricBlock(inputStream, bytesDecodedInCurrentTag, out blk);
                                        _metricTable.Clear(); 
                                        _metricTable.Add(blk);
                                        metricBlockDecoded = true;
                                        break;
                                    } 

                                case KnownTagCache.KnownTagIndex.TransformTable: 
                                    { 
                                        // Load Transform Table
                                        localBytesDecoded = DecodeTransformTable(inputStream, bytesDecodedInCurrentTag, false); 
                                        transformDecoded = true;
                                        break;
                                    }
 
                                case KnownTagCache.KnownTagIndex.ExtendedTransformTable:
                                    { 
                                        // non-double transform table should have already been loaded 
                                        if (!transformDecoded)
                                        { 
                                            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                                        }

                                        // Load double-sized Transform Table 
                                        localBytesDecoded = DecodeTransformTable(inputStream, bytesDecodedInCurrentTag, true);
                                        break; 
                                    } 

                                case KnownTagCache.KnownTagIndex.PersistenceFormat: 
                                    {
                                        uint fmt;

                                        localBytesDecoded = SerializationHelper.Decode(inputStream, out fmt); 
                                        // Set the appropriate persistence information
                                        if (0 == fmt) 
                                        { 
                                            CurrentPersistenceFormat = PersistenceFormat.InkSerializedFormat;
                                        } 
                                        else if (0x00000001 == fmt)
                                        {
                                            CurrentPersistenceFormat = PersistenceFormat.Gif;
                                        } 

 
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.HimetricSize:
                                    {
                                        // Loads the Hi Metric Size for Fortified GIFs
                                        int sz; 

                                        localBytesDecoded = SerializationHelper.SignDecode(inputStream, out sz); 
                                        if (localBytesDecoded > remainingBytesInStream) 
                                            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                        _himetricSize.X = (double)sz;
                                        localBytesDecoded += SerializationHelper.SignDecode(inputStream, out sz);

                                        _himetricSize.Y = (double)sz; 
                                        break;
                                    } 
 
                                case KnownTagCache.KnownTagIndex.CompressionHeader:
                                    { 
#if OLD_ISF
                                        byte[] data = new byte[bytesDecodedInCurrentTag];

                                        // read the header from the stream 
                                        uint bytesRead = StrokeCollectionSerializer.ReliableRead(inputStream, data, bytesDecodedInCurrentTag);
                                        if (bytesDecodedInCurrentTag != bytesRead) 
                                        { 
                                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "isfStream");
                                        } 

                                        uint size = bytesDecodedInCurrentTag;
                                        compressor = new Compressor(data, ref size);
                                        // in case the actual number of bytes read by the compressor 
                                        //      is less than the encoder had expected (e.g. compression
                                        //      header was encoded as 10 bytes, but only 7 bytes were read) 
                                        //      then we don't want to adjust the stream position because 
                                        //      there are likely other following tags that are encoded
                                        //      after the compression tag. This should never happen, 
                                        //      so just fail if the compressor is broken or the ISF is
                                        //      corrupted.
                                        if (size != bytesDecodedInCurrentTag)
                                        { 
                                            throw new InvalidOperationException(ISFDebugMessage("Compressor intialization reported inconsistent size"));
                                        } 
#else 
                                        //just advance the inputstream position, we don't need
                                        //no compression header in the new isf decoding 
                                        inputStream.Seek(bytesDecodedInCurrentTag, SeekOrigin.Current);
#endif
                                        localBytesDecoded = bytesDecodedInCurrentTag;
                                        break; 
                                    }
 
                                case KnownTagCache.KnownTagIndex.StrokeIds: 
                                    {
                                        localBytesDecoded = LoadStrokeIds(inputStream, bytesDecodedInCurrentTag); 
                                        break;
                                    }

                                case KnownTagCache.KnownTagIndex.Stroke: 
                                    {
                                        ISFDebugTrace("   Decoding Stroke Id#(" + (strokeIndex + 1).ToString() + ")"); 
 
                                        StrokeDescriptor strokeDescriptor = null;
 
                                        // Load the stroke descriptor based on the index from the list of unique
                                        // stroke descriptors
                                        if (strokeDescriptorBlockDecoded)
                                        { 
                                            if (oldStrokeDescriptorTableIndex != strokeDescriptorTableIndex)
                                            { 
                                                if (_strokeDescriptorTable.Count <= strokeDescriptorTableIndex) 
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                                            } 

                                            strokeDescriptor = _strokeDescriptorTable[(int)strokeDescriptorTableIndex];
                                        }
 
                                        // use new transform if the last transform is uninit'd or has changed
                                        if (oldTransformTableIndex != transformTableIndex) 
                                        { 
                                            // if transform was specified in the ISF stream
                                            if (transformDecoded) 
                                            {
                                                if (_transformTable.Count <= transformTableIndex)
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                                // Load the transform descriptor based on the index from the list of unique
                                                // transforn descriptors 
                                                currentTabletToInkTransform = LoadTransform(_transformTable[(int)transformTableIndex]); 
                                            }
 
                                            oldTransformTableIndex = transformTableIndex; // cache the transform by remembering the index

                                            // since ISF is stored in HIMETRIC, and we want to expose packet data
                                            //      as Avalon units, we'll update the convert the transform before loading the stroke 
                                            currentTabletToInkTransform.Scale(StrokeCollectionSerializer.HimetricToAvalonMultiplier, StrokeCollectionSerializer.HimetricToAvalonMultiplier);
                                        } 
 
                                        MetricBlock metricBlock = null;
 
                                        // Load the metric block based on the index from the list of unique metric blocks
                                        if (metricBlockDecoded)
                                        {
                                            if (oldMetricDescriptorTableIndex != metricDescriptorTableIndex) 
                                            {
                                                if (_metricTable.Count <= metricDescriptorTableIndex) 
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                                            }
 
                                            metricBlock = _metricTable[(int)metricDescriptorTableIndex];
                                        }

                                        DrawingAttributes activeDrawingAttributes = null; 

                                        // Load the drawing attributes based on the index from the list of unique drawing attributes 
                                        if (drawingAttributesBlockDecoded) 
                                        {
                                            if (oldDrawingAttributesTableIndex != drawingAttributesTableIndex) 
                                            {
                                                if (_drawingAttributesTable.Count <= drawingAttributesTableIndex)
                                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
 
                                                oldDrawingAttributesTableIndex = drawingAttributesTableIndex;
                                            } 
                                            DrawingAttributes currDA = (DrawingAttributes)_drawingAttributesTable[(int)drawingAttributesTableIndex]; 
                                            //we always clone so we don't get strokes that share DAs, which can lead
                                            //to all sorts of unpredictable behavior (ex: see Windows OS Bugs 1450047) 
                                            activeDrawingAttributes = currDA.Clone();
                                        }

                                        // if we didn't find an existing da to use, instance a new one 
                                        if (activeDrawingAttributes == null)
                                        { 
                                            activeDrawingAttributes = new DrawingAttributes(); 
                                        }
 
                                        // Now create the StylusPacketDescription from the stroke descriptor and metric block
                                        if (oldMetricDescriptorTableIndex != metricDescriptorTableIndex || oldStrokeDescriptorTableIndex != strokeDescriptorTableIndex)
                                        {
                                            currentStylusPointDescription = BuildStylusPointDescription(strokeDescriptor, metricBlock, guidList); 
                                            oldStrokeDescriptorTableIndex = strokeDescriptorTableIndex;
                                            oldMetricDescriptorTableIndex = metricDescriptorTableIndex; 
                                        } 

                                        // Load the stroke 
                                        Stroke localStroke;
#if OLD_ISF
                                        localBytesDecoded = StrokeSerializer.DecodeStroke(inputStream, bytesDecodedInCurrentTag, guidList, strokeDescriptor, currentStylusPointDescription, activeDrawingAttributes, currentTabletToInkTransform, compressor, out localStroke);
#else 
                                        localBytesDecoded = StrokeSerializer.DecodeStroke(inputStream, bytesDecodedInCurrentTag, guidList, strokeDescriptor, currentStylusPointDescription, activeDrawingAttributes, currentTabletToInkTransform, out localStroke);
#endif 
 
                                        if (localStroke != null)
                                        { 
                                            _coreStrokes.AddWithoutEvent(localStroke);
                                            strokeIndex++;
                                        }
                                        break; 
                                    }
 
                                default: 
                                    {
                                        throw new InvalidOperationException(ISFDebugMessage("Invalid ISF tag logic")); 
                                    }
                            }

                            // if this isfTag's decoded size != expected size, then error out 
                            if (localBytesDecoded != bytesDecodedInCurrentTag)
                            { 
                                throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                            }
 
                            break;
                        }

                    case KnownTagCache.KnownTagIndex.Transform: 
                    case KnownTagCache.KnownTagIndex.TransformIsotropicScale:
                    case KnownTagCache.KnownTagIndex.TransformAnisotropicScale: 
                    case KnownTagCache.KnownTagIndex.TransformRotate: 
                    case KnownTagCache.KnownTagIndex.TransformTranslate:
                    case KnownTagCache.KnownTagIndex.TransformScaleAndTranslate: 
                        {
                            // Load a single Transform Block
                            TransformDescriptor xform;
 
                            bytesDecodedInCurrentTag = DecodeTransformBlock(inputStream, isfTag, remainingBytesInStream, false, out xform);
                            transformDecoded = true; 
                            _transformTable.Clear(); 
                            _transformTable.Add(xform);
                            break; 
                        }

                    case KnownTagCache.KnownTagIndex.TransformTableIndex:
                        { 
                            // Load the Index into the Transform Table which will be used by the stroke following this till
                            // a next different Index is found 
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out transformTableIndex); 
                            break;
                        } 

                    case KnownTagCache.KnownTagIndex.MetricTableIndex:
                        {
                            // Load the Index into the Metric Table which will be used by the stroke following this till 
                            // a next different Index is found
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out metricDescriptorTableIndex); 
                            break; 
                        }
 
                    case KnownTagCache.KnownTagIndex.DrawingAttributesTableIndex:
                        {
                            // Load the Index into the Drawing Attributes Table which will be used by the stroke following this till
                            // a next different Index is found 
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out drawingAttributesTableIndex);
                            break; 
                        } 

                    case KnownTagCache.KnownTagIndex.InkSpaceRectangle: 
                        {
                            // Loads the Ink Space Rectangle information
                            bytesDecodedInCurrentTag = DecodeInkSpaceRectangle(inputStream, remainingBytesInStream);
                            break; 
                        }
 
                    case KnownTagCache.KnownTagIndex.StrokeDescriptorTableIndex: 
                        {
                            // Load the Index into the Stroke Descriptor Table which will be used by the stroke following this till 
                            // a next different Index is found
                            bytesDecodedInCurrentTag = SerializationHelper.Decode(inputStream, out strokeDescriptorTableIndex);
                            break;
                        } 

                    default: 
                        { 
                            if ((uint)isfTag >= KnownIdCache.CustomGuidBaseIndex || ((uint)isfTag >= KnownTagCache.KnownTagCount && ((uint)isfTag < (KnownTagCache.KnownTagCount + KnownIdCache.OriginalISFIdTable.Length))))
                            { 
                                ISFDebugTrace("  CUSTOM_GUID=" + guidList.FindGuid(isfTag).ToString());

                                // Loads any custom property data
                                bytesDecodedInCurrentTag = remainingBytesInStream; 

                                Guid guid = guidList.FindGuid(isfTag); 
                                if (guid == Guid.Empty) 
                                {
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Global Custom Attribute tag embedded in ISF stream does not match guid table"), "inkdata"); 
                                }


                                object data; 

                                // load the custom property data from the stream (and decode the type) 
                                localBytesDecoded = ExtendedPropertySerializer.DecodeAsISF(inputStream, bytesDecodedInCurrentTag, guidList, isfTag, ref guid, out data); 
                                if (localBytesDecoded > bytesDecodedInCurrentTag)
                                { 
                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inkdata");
                                }

 
                                // add the guid/data pair into the property collection (don't redecode the type)
                                _coreStrokes.ExtendedProperties[guid] = data; 
                            } 
                            else
                            { 
                                // Skip objects that this library doesn't know about
                                // First read the size associated with this unknown isfTag
                                localBytesDecoded = SerializationHelper.Decode(inputStream, out bytesDecodedInCurrentTag);
                                if (remainingBytesInStream < (localBytesDecoded + bytesDecodedInCurrentTag)) 
                                {
                                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data")); 
                                } 
                                else
                                { 
                                    inputStream.Seek(bytesDecodedInCurrentTag + localBytesDecoded, SeekOrigin.Current);
                                }
                            }
 
                            bytesDecodedInCurrentTag = localBytesDecoded;
                            break; 
                        } 
                }
                ISFDebugTrace("    Size = " + bytesDecodedInCurrentTag.ToString()); 
                if (bytesDecodedInCurrentTag > remainingBytesInStream)
                {
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"));
                } 

                // update remaining ISF buffer length with decoded so far 
                remainingBytesInStream -= bytesDecodedInCurrentTag; 
            }
#if OLD_ISF 
        }
        finally
        {
            if (null != compressor) 
            {
                compressor.Dispose(); 
                compressor = null; 
            }
        } 
#endif
        if (0 != remainingBytesInStream)
            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"), "inkdata");
    } 
#if OLD_ISF
    ///  
    /// Loads a DrawingAttributes Table from the stream and adds individual drawing attributes to the drawattr 
    /// list passed
    ///  
    /// 
    /// 
    ///     Critical - Calls the DrawingAttributeSerializer.DecodeAsISF critical method
    ///  
    [SecurityCritical]
#else 
    ///  
    /// Loads a DrawingAttributes Table from the stream and adds individual drawing attributes to the drawattr
    /// list passed 
    /// 
#endif
    private uint LoadDrawAttrsTable(Stream strm, GuidList guidList, uint cbSize)
    { 
        _drawingAttributesTable.Clear();
 
        // First, allocate a temporary buffer and read the stream into it. 
        // These will be compressed DRAW_ATTR structures.
        uint cbTotal = cbSize; 

        // OK, now we count the number of DRAW_ATTRS compressed into this block
        uint cbDA = 0;
 
        while (cbTotal > 0)
        { 
            // First read the size of the first drawing attributes block 
            uint cb = SerializationHelper.Decode(strm, out cbDA);
 
            if (cbSize < cb)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            cbTotal -= cb;
            if (cbTotal < cbDA) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 

            // Create a new drawing attribute
            DrawingAttributes attributes = new DrawingAttributes();
            // pull off our defaults onthe drawing attribute as we need to 
            //  respect what the ISF has.
            attributes.DrawingFlags = 0; 
            cb = DrawingAttributeSerializer.DecodeAsISF(strm, guidList, cbDA, attributes); 

            // Load the stream into this attribute 
            if (cbSize < cbDA)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            cbTotal -= cbDA;
 
            // Add this attribute to the global list 
            _drawingAttributesTable.Add(attributes);
        } 

        if (0 != cbTotal)
            throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

        return cbSize; 
    } 

    ///  
    /// Reads and Decodes a stroke descriptor information from the stream. For details on how it is stored
    /// please refer the spec
    /// 
    ///  
    /// 
    ///  
    ///  
    private uint DecodeStrokeDescriptor(Stream strm, uint cbSize, out StrokeDescriptor descr)
    { 
        descr = new StrokeDescriptor();
        if (0 == cbSize)
            return 0;
 
        uint cb;
        uint cbBlock = cbSize; 
 
        while (cbBlock > 0)
        { 
            // first read the tag
            KnownTagCache.KnownTagIndex tag;
            uint uiTag;
 
            cb = SerializationHelper.Decode(strm, out uiTag);
            tag = (KnownTagCache.KnownTagIndex)uiTag; 
            if (cb > cbBlock) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbBlock -= cb;
            descr.Template.Add(tag);

            // If this is TAG_BUTTONS 
            if (KnownTagCache.KnownTagIndex.Buttons == tag && cbBlock > 0)
            { 
                uint cbButton; 

                // Read the no. of buttons first 
                cb = SerializationHelper.Decode(strm, out cbButton);
                if (cb > cbBlock)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
                cbBlock -= cb;
                descr.Template.Add((KnownTagCache.KnownTagIndex)cbButton); 
                while (cbBlock > 0 && cbButton > 0) 
                {
                    uint dw; 

                    cb = SerializationHelper.Decode(strm, out dw);
                    if (cb > cbBlock)
                        throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

                    cbBlock -= cb; 
                    cbButton--; 
                    descr.Template.Add((KnownTagCache.KnownTagIndex)dw);
                } 
            }
            else if (KnownTagCache.KnownTagIndex.StrokePropertyList == tag && cbBlock > 0)
            {
                // Usually stroke property comes last in the template. Hence everything below this is 
                // are Tags for strokes extended properties
                while (cbBlock > 0) 
                { 
                    uint dw;
 
                    cb = SerializationHelper.Decode(strm, out dw);
                    if (cb > cbBlock)
                        throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
                    cbBlock -= cb;
                    descr.Template.Add((KnownTagCache.KnownTagIndex)dw); 
                } 
            }
            } 

            if (0 != cbBlock)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            return cbSize;
        } 
 

        ///  
        /// Reads and Decodes a stroke descriptor information from the stream. For details on how it is stored
        /// please refer the spec
        /// 
        ///  
        /// 
        ///  
        private uint DecodeStrokeDescriptorBlock(Stream strm, uint cbSize) 
        {
            _strokeDescriptorTable.Clear(); 
            if (0 == cbSize)
                return 0;

            StrokeDescriptor descr; 
            uint cbRead = DecodeStrokeDescriptor(strm, cbSize, out descr);
 
            if (cbRead != cbSize) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            _strokeDescriptorTable.Add(descr);
            return cbRead;
        }
 

        ///  
        /// Reads and Decodes a number of stroke descriptor information from the stream. For details on how they are stored 
        /// please refer the spec
        ///  
        /// 
        /// 
        /// 
        private uint DecodeStrokeDescriptorTable(Stream strm, uint cbSize) 
        {
            _strokeDescriptorTable.Clear(); 
            if (0 == cbSize) 
                return 0;
 
            uint cb;                // Tracks the total no of bytes read from the stream
            uint cbTotal = cbSize;  // Tracks how many more bytes can be read from the stream for the table. Limited by cbSize

            while (cbTotal > 0) 
            {
                // First decode the size of the next block 
                uint cbBlock; 

                cb = SerializationHelper.Decode(strm, out cbBlock); 
                if (cb > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
                cbTotal -= cb;
                if (cbBlock > cbTotal) 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 

                StrokeDescriptor descr;

                cb = DecodeStrokeDescriptor(strm, cbBlock, out descr); 
                if (cb != cbBlock)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 

                cbTotal -= cb; 

                // Add this stroke descriptor to the list of global stroke descriptors
                _strokeDescriptorTable.Add(descr);
            } 

            if (0 != cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
            return cbSize;
        }

 
        /// 
        /// Decodes metric table from the stream. For information on how they are stored in the stream, please refer to the spec. 
        ///  
        /// 
        ///  
        /// 
        private uint DecodeMetricTable(Stream strm, uint cbSize)
        {
            _metricTable.Clear(); 
            if (cbSize == 0)
                return 0; 
 
            uint cb;
            uint cbTotal = cbSize; 

            // This data is a list of Metric block. Each block starts with size of the block. After that it contains an
            // array of Metric Entries. Each metric enty comprises of size of the entry, tag for the property and the metric
            // properties. 
            while (cbTotal > 0)
            { 
                // First read the size of the metric block 
                uint dw;
 
                cb = SerializationHelper.Decode(strm, out dw);
                if (cb + dw > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                cbTotal -= cb; 
 
                MetricBlock newblock;
 
                cb = DecodeMetricBlock(strm, dw, out newblock);
                if (cb != dw)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                cbTotal -= cb; 
                _metricTable.Add(newblock); 
            }
 
            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

 
            return cbSize;
        } 
 

        ///  
        /// Decodes a Metric Block from the stream. For information on how they are stored in the stream, please refer to the spec.
        /// 
        /// 
        ///  
        /// 
        ///  
        private uint DecodeMetricBlock(Stream strm, uint cbSize, out MetricBlock block) 
        {
            // allocate the block 
            block = new MetricBlock();
            if (cbSize == 0)
                return 0;
 
            uint cb;
            uint cbTotal = cbSize; 
            uint size; 

            while (cbTotal > 0) 
            {
                // First decode the tag for this entry
                uint dw;
 
                cb = SerializationHelper.Decode(strm, out dw);
                if (cb > cbTotal) 
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
                cbTotal -= cb;

                // Next read the size of the metric data
                cb = SerializationHelper.Decode(strm, out size); 
                if (cb + size > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 

                cbTotal -= cb; 

                // now create new metric entry
                MetricEntry entry = new MetricEntry();
 
                entry.Tag = (KnownTagCache.KnownTagIndex)dw;
 
                byte[] data = new byte[size]; 

                uint bytesRead = StrokeCollectionSerializer.ReliableRead(strm, data, size); 
                cbTotal -= bytesRead;

                if ( bytesRead != size )
                { 
                    // Make sure the bytes read are expected. If not, we should bail out.
                    // An exception will be thrown. 
                    break; 
                }
 
                entry.Data = data;
                block.AddMetricEntry(entry);

            } 

            if (0 != cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
            return cbSize;
        }

 
        /// 
        /// Reads and Decodes a Table of Transform Descriptors from the stream. For information on how they are stored 
        /// in the stream, please refer to the spec. 
        /// 
        ///  
        /// 
        /// 
        /// 
        private uint DecodeTransformTable(Stream strm, uint cbSize, bool useDoubles) 
        {
            // only clear the transform table if not using doubles 
            //      (e.g. first pass through transform table) 
            if (!useDoubles)
            { 
                _transformTable.Clear();
            }

            if (0 == cbSize) 
                return 0;
 
            uint cb; 
            uint cbTotal = cbSize;
            int tableIndex = 0; 

            while (cbTotal > 0)
            {
                KnownTagCache.KnownTagIndex tag; 
                uint uiTag;
                cb = SerializationHelper.Decode(strm, out uiTag); 
                tag = (KnownTagCache.KnownTagIndex)uiTag; 
                if (cb > cbTotal)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

                cbTotal -= cb;

                TransformDescriptor xform; 

                cb = DecodeTransformBlock(strm, tag, cbTotal, useDoubles, out xform); 
                cbTotal -= cb; 
                if (useDoubles)
                { 
                    _transformTable[tableIndex] = xform;
                }
                else
                { 
                    _transformTable.Add(xform);
                } 
 
                tableIndex++;
            } 

            if (0 != cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            return cbSize;
        } 
 
        /// 
        /// ReliableRead 
        /// 
        /// 
        /// 
        ///  
        /// 
        internal static uint ReliableRead(Stream stream, byte[] buffer, uint requestedCount) 
        { 
            if (stream == null ||
                buffer == null || 
                requestedCount > buffer.Length)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid argument passed to ReliableRead"));
            } 

            // let's read the whole block into our buffer 
            uint totalBytesRead = 0; 
            while (totalBytesRead < requestedCount)
            { 
                int bytesRead = stream.Read(buffer,
                                (int)totalBytesRead,
                                (int)(requestedCount - totalBytesRead));
                if (bytesRead == 0) 
                {
                    break; 
                } 
                totalBytesRead += (uint)bytesRead;
            } 
            return totalBytesRead;
        }

 
        /// 
        /// Reads and Decodes a Transfrom Descriptor Block from the stream. For information on how it is stored in the stream, 
        /// please refer to the spec. 
        /// 
        ///  
        /// 
        /// 
        /// 
        ///  
        /// 
        private uint DecodeTransformBlock(Stream strm, KnownTagCache.KnownTagIndex tag, uint cbSize, bool useDoubles, out TransformDescriptor xform) 
        { 
            xform = new TransformDescriptor();
            xform.Tag = tag; 

            uint cbRead = 0;
            uint cbTotal = cbSize;
 
            if (0 == cbSize)
                return 0; 
 
            // samgeo - Presharp issue
            // Presharp gives a warning when local IDisposable variables are not closed 
            // in this case, we can't call Dispose since it will also close the underlying stream
            // which still needs to be read from
#pragma warning disable 1634, 1691
#pragma warning disable 6518 
            BinaryReader bw = new BinaryReader(strm);
 
            if (KnownTagCache.KnownTagIndex.TransformRotate == tag) 
            {
                uint angle; 

                cbRead = SerializationHelper.Decode(strm, out angle);
                if (cbRead > cbSize)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

 
                xform.Transform[0] = (double)angle; 
                xform.Size = 1;
            } 
            else
            {
                if (tag == KnownTagCache.KnownTagIndex.TransformIsotropicScale)
                { 
                    xform.Size = 1;
                } 
                else if (tag == KnownTagCache.KnownTagIndex.TransformAnisotropicScale || tag == KnownTagCache.KnownTagIndex.TransformTranslate) 
                {
                    xform.Size = 2; 
                }
                else if (tag == KnownTagCache.KnownTagIndex.TransformScaleAndTranslate)
                {
                    xform.Size = 4; 
                }
                else 
                { 
                    xform.Size = 6;
                } 

                if (useDoubles)
                {
                    cbRead = xform.Size * Native.SizeOfDouble; 
                }
                else 
                { 
                    cbRead = xform.Size * Native.SizeOfFloat;
                } 

                if (cbRead > cbSize)
                    throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 

                for (int i = 0; i < xform.Size; i++) 
                { 
                    if (useDoubles)
                    { 
                        xform.Transform[i] = bw.ReadDouble();
                    }
                    else
                    { 
                        xform.Transform[i] = (double)bw.ReadSingle();
                    } 
                } 
            }
 
            return cbRead;
#pragma warning restore 6518
#pragma warning restore 1634, 1691
        } 

        ///  
        /// Decodes Ink Space Rectangle information from the stream 
        /// 
        ///  
        /// 
        /// 
        private uint DecodeInkSpaceRectangle(Stream strm, uint cbSize)
        { 
            uint cb, cbRead = 0;
            uint cbTotal = cbSize; 
            int data; 

            //Left 
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbTotal -= cb;
            cbRead += cb; 
            _inkSpaceRectangle.X = data; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            //Top
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");
 
            cbTotal -= cb; 
            cbRead += cb;
            _inkSpaceRectangle.Y = data; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm");

            //Right 
            cb = SerializationHelper.SignDecode(strm, out data);
            if (cb > cbTotal) 
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            cbTotal -= cb; 
            cbRead += cb;
            _inkSpaceRectangle.Width = data - _inkSpaceRectangle.Left;
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            //Bottom 
            cb = SerializationHelper.SignDecode(strm, out data); 
            if (cb > cbTotal)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 

            cbTotal -= cb;
            cbRead += cb;
            _inkSpaceRectangle.Height = data - _inkSpaceRectangle.Top; 
            if (cbRead > cbSize)
                throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); 
 
            return cbRead;
        } 


        /// 
        /// Creates a Matrix Information structure based on the transform descriptor 
        /// 
        ///  
        ///  
        private Matrix LoadTransform(TransformDescriptor tdrd)
        { 
            double M00 = 0.0f, M01 = 0.0f, M10 = 0.0f, M11 = 0.0f, M20 = 0.0f, M21 = 0.0f;

            if (KnownTagCache.KnownTagIndex.TransformIsotropicScale == tdrd.Tag)
            { 
                M00 = M11 = tdrd.Transform[0];
            } 
            else if (KnownTagCache.KnownTagIndex.TransformRotate == tdrd.Tag) 
            {
                double dAngle = (tdrd.Transform[0] / 100) * (Math.PI / 180); 

                M00 = M11 = Math.Cos(dAngle);
                M01 = Math.Sin(dAngle);
                if (M01 == 0.0f && M11 == 1.0f) 
                {
                    //special case for 0 degree rotate transforms 
                    //this is identity 
                    M10 = 0.0f;
                } 
                else
                {
                    M10 = -M11;
                } 
            }
            else if (KnownTagCache.KnownTagIndex.TransformAnisotropicScale == tdrd.Tag) 
            { 
                M00 = tdrd.Transform[0];
                M11 = tdrd.Transform[1]; 
            }
            else if (KnownTagCache.KnownTagIndex.TransformTranslate == tdrd.Tag)
            {
                M20 = tdrd.Transform[0]; 
                M21 = tdrd.Transform[1];
            } 
            else if (KnownTagCache.KnownTagIndex.TransformScaleAndTranslate == tdrd.Tag) 
            {
                M00 = tdrd.Transform[0]; 
                M11 = tdrd.Transform[1];
                M20 = tdrd.Transform[2];
                M21 = tdrd.Transform[3];
            } 
            else    // TAG_TRANSFORM
            { 
                M00 = tdrd.Transform[0]; 
                M01 = tdrd.Transform[1];
                M10 = tdrd.Transform[2]; 
                M11 = tdrd.Transform[3];
                M20 = tdrd.Transform[4];
                M21 = tdrd.Transform[5];
            } 

            return new Matrix(M00, M01, M10, M11, M20, M21); 
        } 

 
        /// 
        /// Sets the Property Metrics for a property based on Tag and metric descriptor block
        /// 
        ///  
        /// 
        ///  
        ///  
        private StylusPointPropertyInfo GetStylusPointPropertyInfo(Guid guid, KnownTagCache.KnownTagIndex tag, MetricBlock block)
        { 
            int dw = 0;
            bool fSetDefault = false;
            uint cbEntry;
            // StylusPointPropertyInfo values that we need to read in. 
            int minimum = 0;
            int maximum = 0; 
            StylusPointPropertyUnit unit = StylusPointPropertyUnit.None; 
            float resolution = 1.0f;
 
            // To begin with initialize the property metrics with respective default valuses
            // first check if this property belongs to optional list
            for (dw = 0; dw < 11; dw++)
            { 
                if (MetricEntry.MetricEntry_Optional[dw].Tag == tag)
                { 
                    minimum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Minimum; 
                    maximum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Maximum;
                    resolution = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Resolution; 
                    unit = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Unit;
                    fSetDefault = true;
                    break;
                } 
            }
 
            if (false == fSetDefault) 
            {
                // We will come here if the property is not found in the Optional List 
                // All other cases, we will have only default values
                minimum = Int32.MinValue;
                maximum = Int32.MaxValue;
                unit = StylusPointPropertyUnit.None; 
                resolution = 1.0f;
                fSetDefault = true; 
            } 

            // Now see if there is a valid MetricBlock. If there is one, update the PROPERTY_METRICS with 
            // values from this Block
            if (null != block)
            {
                MetricEntry entry = block.GetMetricEntryList(); 

                while (null != entry) 
                { 
                    if (entry.Tag == tag)
                    { 
                        cbEntry = 0;

                        int range;
 
                        using (MemoryStream strm = new MemoryStream(entry.Data))
                        { 
                            // Decoded the Logical Min 
                            cbEntry += SerializationHelper.SignDecode(strm, out range);
                            if (cbEntry >= entry.Size) 
                            {
                                break; // return false;
                            }
 
                            minimum = range;
 
                            // Logical Max 
                            cbEntry += SerializationHelper.SignDecode(strm, out range);
                            if (cbEntry >= entry.Size) 
                            {
                                break; // return false;
                            }
 
                            maximum = range;
 
                            uint cb; 

                            // Units 
                            cbEntry += SerializationHelper.Decode(strm, out cb);
                            unit = (StylusPointPropertyUnit)cb;
                            if (cbEntry >= entry.Size)
                            { 
                                break; // return false;
                            } 
 
                            using (BinaryReader br = new BinaryReader(strm))
                            { 
                                resolution = br.ReadSingle();
                                cbEntry += Native.SizeOfFloat;
                            }
                        } 

                        break; 
                    } 

                    entry = entry.Next; 
                }
            }

            // return a new StylusPointPropertyInfo 
            return new StylusPointPropertyInfo( new StylusPointProperty(guid, StylusPointPropertyIds.IsKnownButton(guid)),
                                                minimum, 
                                                maximum, 
                                                unit,
                                                resolution); 
        }


        ///  
        /// Builds StylusPointDescription based on StrokeDescriptor and Metric Descriptor Block. Sometime Metric Descriptor block may contain
        /// metric information for properties which are not part of the stroke descriptor. They are simply ignored. 
        ///  
        /// 
        ///  
        /// 
        /// 
        private StylusPointDescription BuildStylusPointDescription(StrokeDescriptor strd, MetricBlock block, GuidList guidList)
        { 
            int cTags = 0;
            int packetPropertyCount = 0; 
            uint buttonCount = 0; 
            Guid[] buttonguids = null;
            System.Collections.Generic.List tags = null; 

            // if strd is null, it means there is only default descriptor with X & Y
            if (null != strd)
            { 
                tags = new System.Collections.Generic.List();
                while (cTags < strd.Template.Count) 
                { 
                    KnownTagCache.KnownTagIndex tag = (KnownTagCache.KnownTagIndex)strd.Template[cTags];
 
                    if (KnownTagCache.KnownTagIndex.Buttons == tag)
                    {
                        cTags++;
 
                        // The next item in the array is no of buttongs.
                        buttonCount = (uint)strd.Template[cTags]; 
                        cTags++; 

                        // Currently we skip the the no of buttons as buttons is not implimented yet 
                        buttonguids = new Guid[buttonCount];
                        for (uint u = 0; u < buttonCount; u++)
                        {
                            Guid guid = guidList.FindGuid(strd.Template[cTags]); 
                            if (guid == Guid.Empty)
                            { 
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Button guid tag embedded in ISF stream does not match guid table"),"strd"); 
                            }
 
                            buttonguids[(int)u] = guid;
                            cTags++;
                        }
                    } 
                    else if (KnownTagCache.KnownTagIndex.StrokePropertyList == tag)
                    { 
                        break; // since no more Packet properties can be stored 
                    }
                    else 
                    {
                        if (KnownTagCache.KnownTagIndex.NoX == tag ||
                            KnownTagCache.KnownTagIndex.NoY == tag)
                        { 
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF with NoX or NoY specified"), "strd");
                        } 
 
                        tags.Add(strd.Template[cTags]);
                        packetPropertyCount++; 
                        cTags++;
                    }
                }
            } 

 
            List stylusPointPropertyInfos = new List(); 
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.X, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.X), block));
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.Y, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.Y), block)); 
            stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(KnownIds.NormalPressure, (KnownTagCache.KnownTagIndex)((uint)KnownIdCache.KnownGuidBaseIndex + (uint)KnownIdCache.OriginalISFIdIndex.NormalPressure), block));

            int pressureIndex = -1;
            if (tags != null) 
            {
                for (int i = 0; i < tags.Count; i++) 
                { 
                    Guid guid = guidList.FindGuid(tags[i]);
                    if (guid == Guid.Empty) 
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packet Description Property tag embedded in ISF stream does not match guid table"), "strd");
                    }
                    if (pressureIndex == -1 && guid == StylusPointPropertyIds.NormalPressure) 
                    {
                        pressureIndex = i + 2; //x,y have already been accounted for 
                        continue; //we've already added pressure (above) 
                    }
 
                    stylusPointPropertyInfos.Add(GetStylusPointPropertyInfo(guid, tags[i], block));
                }

                if (null != buttonguids) 
                {
                    // 
                    // add the buttons to the end of the description if they exist 
                    //
                    for (int i = 0; i < buttonguids.Length; i++) 
                    {
                        StylusPointProperty buttonProperty = new StylusPointProperty(buttonguids[i], true);
                        StylusPointPropertyInfo buttonInfo = new StylusPointPropertyInfo(buttonProperty);
                        stylusPointPropertyInfos.Add(buttonInfo); 
                    }
                } 
            } 

            return new StylusPointDescription(stylusPointPropertyInfos, pressureIndex); 
        }
        #endregion

        #endregion // Decoding 

        #region Encoding 
 
        #region Public Methods
#if OLD_ISF 
        /// 
        /// This functions Saves the Ink as Ink Serialized Format based on the Compression code
        /// 
        /// A byte[] with the encoded ISF 
        /// 
        ///     Critical - Calls critical methods: 
        ///             StrokeCollectionSerializer.SaveStrokeIds 
        ///             ExtendedPropertySerializer.EncodeAsISF
        ///             StrokeCollectionSerializer.StoreStrokeData 
        ///
        ///
        ///     TreatAsSafe - We're saving a StrokeCollection and we control and verify
        ///             all of the data the StrokeCollection directly and indirectly contains 
        ///
        ///             This codepath calls into unmanaged code in Compressor.CompressPacketData 
        ///             and Compressor.CompressPropertyData.  The underlying unmanaged code has been 
        ///              security reviewed and fuzzed
        /// 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
#else
        ///  
        /// This functions Saves the Ink as Ink Serialized Format based on the Compression code
        ///  
        /// A byte[] with the encoded ISF 
#endif
        internal void EncodeISF(Stream outputStream) 
        {
            _strokeLookupTable =
                new System.Collections.Generic.Dictionary(_coreStrokes.Count);
 
            // Next go through all the strokes
            for (int i = 0; i < _coreStrokes.Count; i++) 
            { 
                _strokeLookupTable.Add(_coreStrokes[i], new StrokeLookupEntry());
            } 

            // Initialize all Arraylists
            _strokeDescriptorTable = new List(_coreStrokes.Count);
            _drawingAttributesTable = new List(); 
            _metricTable = new List();
            _transformTable = new List(); 
 
            using (MemoryStream localStream = new MemoryStream(_coreStrokes.Count * 125)) //reasonable default
            { 
                GuidList guidList = BuildGuidList();
                uint cumulativeEncodedSize = 0;
                uint localEncodedSize = 0;
 
                byte xpData = (CurrentCompressionMode == CompressionMode.NoCompression) ? AlgoModule.NoCompression : AlgoModule.DefaultCompression;
                foreach (Stroke s in _coreStrokes) 
                { 
                    _strokeLookupTable[s].CompressionData = xpData;
 
                    //
                    // we need to get this data up front so that we can
                    // know if pressure was used (and thus if we need to add Pressure
                    // to the ISF packet description 
                    //
                    int[][] isfReadyData; 
                    bool shouldStorePressure; 
                    s.StylusPoints.ToISFReadyArrays(out isfReadyData, out shouldStorePressure);
                    _strokeLookupTable[s].ISFReadyStrokeData = isfReadyData; 
                    //
                    // this is our flag that ToISFReadyArrays sets if pressure was all default
                    //
                    _strokeLookupTable[s].StorePressure = shouldStorePressure; 
                }
 
 
                // Store Ink space rectangle information if necessary and anything other than default
                if (_inkSpaceRectangle != new Rect()) 
                {
                    localEncodedSize = cumulativeEncodedSize;

                    Rect inkSpaceRectangle = _inkSpaceRectangle; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.InkSpaceRectangle);
 
                    int i = (int)inkSpaceRectangle.Left; 

                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
                    i = (int)inkSpaceRectangle.Top;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i);
                    i = (int)inkSpaceRectangle.Right;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
                    i = (int)inkSpaceRectangle.Bottom;
                    cumulativeEncodedSize += SerializationHelper.SignEncode(localStream, i); 
 
                    // validate that the expected inkspace rectangle block in ISF was the actual size encoded
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoded InkSpaceRectangle: size=" + localEncodedSize);

                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 
 
                // First prepare the compressor. Currently Compression is not supported.
                // Next write the persistence format information if anything other than ISF 
                // Currently only ISF is implemented
                if (PersistenceFormat.InkSerializedFormat != CurrentPersistenceFormat)
                {
                    localEncodedSize = cumulativeEncodedSize; 

                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.PersistenceFormat); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)SerializationHelper.VarSize((uint)CurrentPersistenceFormat)); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)CurrentPersistenceFormat);
 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoded PersistenceFormat: size=" + localEncodedSize);
 
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                } 

                // Store any size information if necessary such as GIF image size 
                // NTRAID#T2-00000-2004/03/15-[....]: WORK: Not Yet Implemented

                // Now store the Custom Guids
                localEncodedSize = cumulativeEncodedSize; 
                cumulativeEncodedSize += guidList.Save(localStream);
                localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                if (localEncodedSize != 0) 
                    ISFDebugTrace("Encoded Custom Guid Table: size=" + localEncodedSize);
 
                if (cumulativeEncodedSize != localStream.Length)
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));

                // Now build the tables 
                BuildTables(guidList);
 
                // first write the drawing attributes 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeDrawingAttrsTable(localStream, guidList); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded DrawingAttributesTable: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Next write the stroke descriptor table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializePacketDescrTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Packet Description: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Write the metric table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeMetricTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Metric Table: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Write the transform table 
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SerializeTransformTable(localStream); 
                localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Transform Table: size=" + localEncodedSize);
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                // Save global ink properties 
                if (_coreStrokes.ExtendedProperties.Count > 0)
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += ExtendedPropertySerializer.EncodeAsISF(_coreStrokes.ExtendedProperties, localStream, guidList, GetCompressionAlgorithm(), true);
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("Encoded Global Ink Attributes Table: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // Save stroke ids
                localEncodedSize = cumulativeEncodedSize;
                cumulativeEncodedSize += SaveStrokeIds(_coreStrokes, localStream, false);
                localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                if (localEncodedSize != 0)
                    ISFDebugTrace("Encoded Stroke Id List: size=" + localEncodedSize); 
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
 
                StoreStrokeData(localStream, guidList, ref cumulativeEncodedSize, ref localEncodedSize);

                ISFDebugTrace("Embedded ISF Stream size=" + cumulativeEncodedSize);
 
                // Now that all data has been written we need to prepend the stream
                long preEncodingPosition = outputStream.Position; 
                uint cbFinal = SerializationHelper.Encode(outputStream, (uint)0x00); 

                cbFinal += SerializationHelper.Encode(outputStream, cumulativeEncodedSize); 

                //we have to use localStream to encode ISF because we have to place a variable byte 'size of isf' at the
                //beginning of the stream
                outputStream.Write(localStream.GetBuffer(), 0, (int)cumulativeEncodedSize); 
                cbFinal += cumulativeEncodedSize;
 
                ISFDebugTrace("Final ISF Stream size=" + cbFinal); 

                if (cbFinal != outputStream.Position - preEncodingPosition) 
                {
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                }
            } 
        }
 
#if OLD_ISF 
        /// 
        /// Encodes all of the strokes in a strokecollection to ISF 
        /// 
        /// 
        ///     Critical - Calls the critical method StrokeSerializer.EncodeStroke
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        /// 
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF 
        ///
        ///  
        [SecurityCritical]
#else
        /// 
        /// Encodes all of the strokes in a strokecollection to ISF 
        /// 
#endif 
        private void StoreStrokeData(Stream localStream, GuidList guidList, ref uint cumulativeEncodedSize, ref uint localEncodedSize) 
        {
            // Now we will save the stroke data 
            uint currentDrawingAttributesTableIndex = 0;
            uint currentStrokeDescriptorTableIndex = 0;
            uint uCurrMetricDescriptorTableIndex = 0;
            uint currentTransformTableIndex = 0; 

            int[] strokeIds = StrokeIdGenerator.GetStrokeIds(_coreStrokes); 
            for (int i = 0; i < _coreStrokes.Count; i++) 
            {
                Stroke s = _coreStrokes[i]; 
                uint cbStroke = 0;

                ISFDebugTrace("Encoding Stroke Id#" + strokeIds[i]);
 
                // if the drawing attribute index is different from the current one, write it
                if (currentDrawingAttributesTableIndex != _strokeLookupTable[s].DrawingAttributesTableIndex) 
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesTableIndex); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].DrawingAttributesTableIndex);
                    currentDrawingAttributesTableIndex = _strokeLookupTable[s].DrawingAttributesTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("    Encoded DrawingAttribute Table Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // if the stroke descriptor index is different from the current one, write it
                if (currentStrokeDescriptorTableIndex != _strokeLookupTable[s].StrokeDescriptorTableIndex)
                {
                    localEncodedSize = cumulativeEncodedSize; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorTableIndex);
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].StrokeDescriptorTableIndex); 
                    currentStrokeDescriptorTableIndex = _strokeLookupTable[s].StrokeDescriptorTableIndex; 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize;
                    if (localEncodedSize != 0) 
                        ISFDebugTrace("    Encoded Stroke Descriptor Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 

                // if the metric table index is different from the current one, write it 
                if (uCurrMetricDescriptorTableIndex != _strokeLookupTable[s].MetricDescriptorTableIndex) 
                {
                    localEncodedSize = cumulativeEncodedSize; 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.MetricTableIndex);
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].MetricDescriptorTableIndex);
                    uCurrMetricDescriptorTableIndex = _strokeLookupTable[s].MetricDescriptorTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("    Encoded Metric Index: size=" + localEncodedSize); 
                    if (cumulativeEncodedSize != localStream.Length) 
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                } 

                // if the Transform index is different from the current one, write it
                if (currentTransformTableIndex != _strokeLookupTable[s].TransformTableIndex)
                { 
                    localEncodedSize = cumulativeEncodedSize;
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.TransformTableIndex); 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, _strokeLookupTable[s].TransformTableIndex); 
                    currentTransformTableIndex = _strokeLookupTable[s].TransformTableIndex;
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("    Encoded Transform Index: size=" + localEncodedSize);
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size")); 
                }
 
                // now create a separate Memory Stream object which will be used for storing the saved stroke data temporarily 
                using (MemoryStream tempstrm = new MemoryStream(s.StylusPoints.Count * 5)) //good approximation based on profiling isf files
                { 
                    localEncodedSize = cumulativeEncodedSize;
#if OLD_ISF
                    // Now save the stroke in the temp stream
                    cbStroke = StrokeSerializer.EncodeStroke(s, tempstrm, null/*we never use CompressionMode.Max)*/, GetCompressionAlgorithm(), guidList, _strokeLookupTable[s]); 
#else
                    cbStroke = StrokeSerializer.EncodeStroke(s, tempstrm, GetCompressionAlgorithm(), guidList, _strokeLookupTable[s]); 
#endif 

                    if (cbStroke != tempstrm.Length) 
                    {
                        throw new InvalidOperationException(ISFDebugMessage("Encoded stroke size != reported size"));
                    }
 
                    // Now write the tag KnownTagCache.KnownTagIndex.Stroke
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, (uint)KnownTagCache.KnownTagIndex.Stroke); 
                    ISFDebugTrace("Stroke size=" + tempstrm.Length); 

                    // Now write the size of the stroke 
                    cumulativeEncodedSize += SerializationHelper.Encode(localStream, cbStroke);

                    // Finally write the stroke data
                    localStream.Write(tempstrm.GetBuffer(), 0, (int)cbStroke); 
                    cumulativeEncodedSize += cbStroke;
 
                    localEncodedSize = cumulativeEncodedSize - localEncodedSize; 
                    if (localEncodedSize != 0)
                        ISFDebugTrace("Encoding Stroke Id#" + strokeIds[i] + " size=" + localEncodedSize); 
                    if (cumulativeEncodedSize != localStream.Length)
                        throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
                }
                if (cumulativeEncodedSize != localStream.Length) 
                    throw new InvalidOperationException(ISFDebugMessage("Calculated ISF stream size != actual stream size"));
            } 
        } 
#if OLD_ISF
        ///  
        /// Saves the stroke Ids in the stream.
        /// 
        /// 
        ///  
        /// save ids even if they are contiguous
        ///  
        ///  
        ///     Critical - Calls the critical method Compressor.CompressPacketData
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        ///
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF
        /// 
        /// 
        [SecurityCritical] 
#else 
        /// 
        /// Saves the stroke Ids in the stream. 
        /// 
        /// 
        /// 
        /// save ids even if they are contiguous 
#endif
        internal static uint SaveStrokeIds(StrokeCollection strokes, Stream strm, bool forceSave) 
        { 
            if (0 == strokes.Count)
                return 0; 

            // Define an ArrayList to store the stroke ids
            int[] strkIds = StrokeIdGenerator.GetStrokeIds(strokes);
 
            // First enumerate all strokes to collect the ids and also check if the follow the default sequence.
            // If they do we don't save the stroke ids 
            bool fDefIds = true; 

            if (!forceSave) 
            {
                // since the stroke allocation algorithm is i++, we check if any
                //  values are not equal to the sequential and consecutive list
                for (int i = 0; i < strkIds.Length; i++) 
                {
                    if (strkIds[i] != (i + 1)) 
                    { 
                            // if non-sequential or non-consecutive, then persist the ids
                        fDefIds = false; 
                        break;
                    }
                }
                // no need to store them if all of them follow the default sequence 
                if (fDefIds) return 0;
            } 
 
            // The format is as follows
            //     
            // Encode size of stroke count
            // First write the KnownTagCache.KnownTagIndex.StrokeIds
            uint cbWrote = SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeIds);
 
            ISFDebugTrace("Saved KnownTagCache.KnownTagIndex.StrokeIds size=" + cbWrote.ToString());
 
            // First findout the no of bytes required to huffman compress these ids 
            byte algorithm = AlgoModule.DefaultCompression;
#if OLD_ISF 
            byte[] data = Compressor.CompressPacketData(null, strkIds, ref algorithm);
#else
            byte[] data = Compressor.CompressPacketData(strkIds, ref algorithm);
#endif 

 
            if (data != null) 
            {
                // First write the encoded size of the buffer 
                cbWrote += SerializationHelper.Encode(strm, (uint)(data.Length + SerializationHelper.VarSize((uint)strokes.Count)));

                // Write the count of ids
                cbWrote += SerializationHelper.Encode(strm, (uint)strokes.Count); 
                strm.Write(data, 0, (int)data.Length);
                cbWrote += (uint)data.Length; 
            } 
            // If compression fails for some reason, write the uncompressed data
            else 
            {
                byte bCompAlgo = AlgoModule.NoCompression;

                // Find out the size of the data + size of the id count 
                uint cbStrokeId = (uint)(strokes.Count * Native.SizeOfInt + 1 + SerializationHelper.VarSize((uint)strokes.Count)); // 1 is for the compression header
 
                cbWrote += SerializationHelper.Encode(strm, cbStrokeId); 
                cbWrote += SerializationHelper.Encode(strm, (uint)strokes.Count);
                strm.WriteByte(bCompAlgo); 
                cbWrote++;

                // Now write all the ids in the stream
                // samgeo - Presharp issue 
                // Presharp gives a warning when local IDisposable variables are not closed
                // in this case, we can't call Dispose since it will also close the underlying stream 
                // which still needs to be written to 
#pragma warning disable 1634, 1691
#pragma warning disable 6518 
                BinaryWriter bw = new BinaryWriter(strm);

                for (int i = 0; i < strkIds.Length; i++)
                { 
                    bw.Write(strkIds[i]);
                    cbWrote += Native.SizeOfInt; 
                } 
#pragma warning restore 6518
#pragma warning restore 1634, 1691 
            }

            return cbWrote;
        } 

 
        #endregion 

        #region Private Methods 

        /// 
        /// Simple helper method to examine the first 7 members (if they exist)
        /// of the byte[] and see if they have the ascii characters 'base64:' in them. 
        /// 
        ///  
        ///  
        private bool IsBase64Data(Stream data)
        { 
            Debug.Assert(data != null);
            long currentPosition = data.Position;
            try
            { 
                byte[] isfBase64PrefixBytes = Base64HeaderBytes;
                if (data.Length < isfBase64PrefixBytes.Length) 
                { 
                    return false;
                } 

                for (int x = 0; x < isfBase64PrefixBytes.Length; x++)
                {
                    if ((byte)data.ReadByte() != isfBase64PrefixBytes[x]) 
                    {
                        return false; 
                    } 
                }
                return true; 
            }
            finally
            {
                //reset position 
                data.Position = currentPosition;
            } 
        } 

        ///  
        /// Builds the GuidList based on ExtendedPropeties and StrokeCollection
        /// 
        /// 
        private GuidList BuildGuidList() 
        {
            GuidList guidList = new GuidList(); 
            int i = 0; 

            // First go through the list of ink properties 
            ExtendedPropertyCollection attributes = _coreStrokes.ExtendedProperties;
            for (i = 0; i < attributes.Count; i++)
            {
                guidList.Add(attributes[i].Id); 
            }
 
            // Next go through all the strokes 
            for (int j = 0; j < _coreStrokes.Count; j++)
            { 
                BuildStrokeGuidList(_coreStrokes[j], guidList);
            }

            return guidList; 
        }
        ///  
        /// Builds the list of Custom Guids that were used by this particular stroke, either in the packet layout 
        /// or in the drawing attributes, or in the buttons or in Extended properties or in the point properties
        /// and updates the guidlist with that information 
        /// 
        /// 
        /// 
        private void BuildStrokeGuidList(Stroke stroke, GuidList guidList) 
        {
            int i = 0; 
 
            // First drawing attributes
            //      Ignore the default Guids/attributes in the DrawingAttributes 
            int count;
            Guid[] guids = ExtendedPropertySerializer.GetUnknownGuids(stroke.DrawingAttributes.ExtendedProperties, out count);

            for (i = 0; i < count; i++) 
            {
                guidList.Add(guids[i]); 
            } 

            Guid[] descriptionGuids = stroke.StylusPoints.Description.GetStylusPointPropertyIds(); 
            for (i = 0; i < descriptionGuids.Length; i++)
            {
                guidList.Add(descriptionGuids[i]);
            } 

            if (stroke.ExtendedProperties.Count > 0) 
            { 
                // Add the ExtendedProperty guids in the list
                for (i = 0; i < stroke.ExtendedProperties.Count; i++) 
                {
                    guidList.Add(stroke.ExtendedProperties[i].Id);
                }
            } 
        }
 
 
        private byte GetCompressionAlgorithm()
        { 
            if (CompressionMode.Compressed == CurrentCompressionMode)
            {
                return AlgoModule.DefaultCompression;
            } 
            return AlgoModule.NoCompression;
        } 
 

        ///  
        /// This function serializes Stroke Descriptor Table in the stream. For information on how they are serialized, please refer to the spec.
        ///
        /// 
        ///  
        /// 
        private uint SerializePacketDescrTable(Stream strm) 
        { 
            if (_strokeDescriptorTable.Count == 0)
                return 0; 

            int count = 0;
            uint cbData = 0;
 
            // First add the appropriate header information
            if (_strokeDescriptorTable.Count == 1) 
            { 
                StrokeDescriptor tmp = _strokeDescriptorTable[0];
 
                // If there is no tag, that means default template and only one entry in the list. Return from here
                if (tmp.Template.Count == 0)
                    return 0;
                else 
                {
                    // Write it out directly 
                    // First the tag 
                    cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorBlock);
 
                    // Now encode the descriptor itself
                    cbData += EncodeStrokeDescriptor(strm, tmp);
                }
            } 
            else
            { 
                uint cbTotal = 0; 

                // First calculate the total encoded size of the all the Templates 
                for (count = 0; count < _strokeDescriptorTable.Count; count++)
                {
                    cbTotal += SerializationHelper.VarSize((_strokeDescriptorTable[count]).Size) + (_strokeDescriptorTable[count]).Size;
                } 

                // Now write the Tag 
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.StrokeDescriptorTable); 
                cbData += SerializationHelper.Encode(strm, cbTotal);
 
                // Now write the encoded templates
                for (count = 0; count < _strokeDescriptorTable.Count; count++)
                {
                    cbData += EncodeStrokeDescriptor(strm, _strokeDescriptorTable[count]); 
                }
            } 
 
            return cbData;
        } 


        /// 
        /// This function serializes Metric Descriptor Table in the stream. For information on how they are serialized, please refer to the spec. 
        /// 
        ///  
        ///  
        private uint SerializeMetricTable(Stream strm)
        { 
            uint cSize = 0;
            MetricBlock block;

            if (0 == _metricTable.Count) 
                return 0;
 
            for (int i = 0; i < _metricTable.Count; i++) 
                cSize += _metricTable[i].Size;
 
            uint cbData = 0;

            // if total size of the blocks is 1, then there is nothing to write
            //  the reason that the size of the blocks is 1 instead of 0 is because 
            //  MetricBlock.Size returns the size of the block plus the byte encoded
            //  size value itself. If the MetricBlock size value is 0, then byte 
            //  encoded size value is 0, which has a byte size of 1. 
            if (1 == cSize)
            { 
                return 0;
            }
            else if (1 == _metricTable.Count)
            { 
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.MetricBlock);
            } 
            else 
            {
                cbData += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.MetricTable); 
                cbData += SerializationHelper.Encode(strm, cSize);
            }

            for (int i = 0; i < _metricTable.Count; i++) 
            {
                block = _metricTable[i]; 
                cbData += block.Pack(strm); 
            }
 
            return cbData;
        }

 
        /// 
        /// Multibyte Encodes a Stroke Descroptor 
        ///  
        /// 
        ///  
        /// 
        private uint EncodeStrokeDescriptor(Stream strm, StrokeDescriptor strd)
        {
            uint cbData = 0; 

            // First encode the size of the descriptor 
            cbData += SerializationHelper.Encode(strm, strd.Size); 
            for (int count = 0; count < strd.Template.Count; count++)
            { 
                // Now encode all members of the descriptor
                cbData += SerializationHelper.Encode(strm, (uint)strd.Template[count]);
            }
 
            return cbData;
        } 
 

        ///  
        /// This function serializes Transform Descriptor Table in the stream. For information on how they are serialized, please refer to the spec.
        /// 
        /// 
        ///  
        private uint SerializeTransformTable(Stream strm)
        { 
            // If there is only one entry in the TransformDescriptor table 
            //      and it is the default descriptor, skip serialization of transforms
            if (_transformTable.Count == 1 && _transformTable[0].Size == 0) 
            {
                return 0;
            }
 
            uint floatTotal = 0;
            uint doubleTotal = 0; 
 
            // First count the size of all transforms (handling both float && double versions)
            for (int i = 0; i < _transformTable.Count; i++) 
            {
                TransformDescriptor xform = _transformTable[i];
                uint cbLocal = SerializationHelper.VarSize((uint)xform.Tag);
 
                floatTotal += cbLocal;
                doubleTotal += cbLocal; 
                if (KnownTagCache.KnownTagIndex.TransformRotate == xform.Tag) 
                {
                    cbLocal = SerializationHelper.VarSize((uint)(xform.Transform[0] + 0.5f)); 
                    floatTotal += cbLocal;
                    doubleTotal += cbLocal;
                }
                else 
                {
                    cbLocal = xform.Size * Native.SizeOfFloat; 
                    floatTotal += cbLocal; 
                    doubleTotal += cbLocal * 2;
                } 
            }

            uint cbTotal = 0;
 
            // If there is only one entry in the TransformDescriptor table
            if (_transformTable.Count == 1) 
            { 
                TransformDescriptor xform = _transformTable[0];
 
                cbTotal = EncodeTransformDescriptor(strm, xform, false);
            }
            else
            { 
                // Now first write the block descriptor and then write all transforms
                cbTotal += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.TransformTable); 
                cbTotal += SerializationHelper.Encode(strm, floatTotal); 
                for (int i = 0; i < _transformTable.Count; i++)
                { 
                    cbTotal += EncodeTransformDescriptor(strm, _transformTable[i], false);
                }
            }
            // now write the Extended Transform table (using doubles instead of floats) 
            { // note that we do not distinguish between 1 and > 1 transforms for compression
                // Now first write the block descriptor and then write all transforms 
                cbTotal += SerializationHelper.Encode(strm, (uint)KnownTagCache.KnownTagIndex.ExtendedTransformTable); 
                cbTotal += SerializationHelper.Encode(strm, doubleTotal);
                for (int i = 0; i < _transformTable.Count; i++) 
                {
                    cbTotal += EncodeTransformDescriptor(strm, _transformTable[i], true);
                }
            } 
            return cbTotal;
        } 
 

        ///  
        /// Multibyte Encode if necessary a Transform Descriptor into the stream
        /// 
        /// 
        ///  
        /// 
        ///  
        private uint EncodeTransformDescriptor(Stream strm, TransformDescriptor xform, bool useDoubles) 
        {
            uint cbData = 0; 

            // First encode the tag
            cbData = SerializationHelper.Encode(strm, (uint)xform.Tag);
 
            // Encode specially if transform denotes rotation
            if (KnownTagCache.KnownTagIndex.TransformRotate == xform.Tag) 
            { 
                uint angle = (uint)(xform.Transform[0] + 0.5f);
 
                cbData += SerializationHelper.Encode(strm, angle);
            }
            else
            { 
                // samgeo - Presharp issue
                // Presharp gives a warning when local IDisposable variables are not closed 
                // in this case, we can't call Dispose since it will also close the underlying stream 
                // which still needs to be written to
#pragma warning disable 1634, 1691 
#pragma warning disable 6518
                BinaryWriter bw = new BinaryWriter(strm);

                for (int i = 0; i < xform.Size; i++) 
                {
                    // note that the binary writer changes serialization 
                    //      lengths depending on the Write parameter cast 
                    if (useDoubles)
                    { 
                        bw.Write(xform.Transform[i]);
                        cbData += Native.SizeOfDouble;
                    }
                    else 
                    {
                        bw.Write((float)xform.Transform[i]); 
                        cbData += Native.SizeOfFloat; 
                    }
                } 
#pragma warning restore 6518
#pragma warning restore 1634, 1691
            }
 
            return cbData;
        } 
 
#if OLD_ISF
        ///  
        /// This function serializes Drawing Attributes Table in the stream. For information on how they are serialized, please refer to the spec.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///     Critical - Calls the critical method 
        ///         DrawingAttributeSerializer.EncodeAsISF
        /// 
        ///     This directly called by StrokeCollectionSerializer.EncodeISF
        ///
        ///     TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF
        /// 
        /// 
        [SecurityCritical] 
#else 
        /// 
        /// This function serializes Drawing Attributes Table in the stream. For information on how they are serialized, please refer to the spec. 
        /// 
        /// 
        /// 
#endif 
        private uint SerializeDrawingAttrsTable(Stream stream, GuidList guidList)
        { 
            uint totalSizeOfSerializedBytes = 0; 
            uint sizeOfHeaderInBytes = 0;
 
            if (1 == _drawingAttributesTable.Count)
            {
                //we always serialize a single DA, even if it has default values so we will write width back to the stream
                DrawingAttributes drawingAttributes = _drawingAttributesTable[0]; 

                // There is single drawing attribute. Save it along with the size 
                totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesBlock); 

                // Get the size of the saved bytes 
                using (MemoryStream drawingAttributeStream = new MemoryStream(16)) //reasonable default based onn profiling
                {
                    sizeOfHeaderInBytes = DrawingAttributeSerializer.EncodeAsISF(drawingAttributes, drawingAttributeStream, guidList, 0, true);
 
                    // Write the size first
                    totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizeOfHeaderInBytes); 
 
                    // write the data
                    uint bytesWritten = Convert.ToUInt32(drawingAttributeStream.Position); 
                    totalSizeOfSerializedBytes += bytesWritten;
                    Debug.Assert(sizeOfHeaderInBytes == bytesWritten);

                    stream.Write(   drawingAttributeStream.GetBuffer(), //returns a direct ref, no copied 
                                    0,
                                    Convert.ToInt32(bytesWritten)); 
 
                    drawingAttributeStream.Dispose();
                } 
            }
            else
            {
                // Temporarily declare an array to hold the size of the saved drawing attributes 
                uint[] sizes = new uint[_drawingAttributesTable.Count];
                MemoryStream[] drawingAttributeStreams = new MemoryStream[_drawingAttributesTable.Count]; 
 
                // First calculate the size of each attribute
                for (int i = 0; i < _drawingAttributesTable.Count; i++) 
                {
                    DrawingAttributes drawingAttributes = _drawingAttributesTable[i];
                    drawingAttributeStreams[i] = new MemoryStream(16); //reasonable default based on profiling
 
                    sizes[i] = DrawingAttributeSerializer.EncodeAsISF(drawingAttributes, drawingAttributeStreams[i], guidList, 0, true);
                    sizeOfHeaderInBytes += SerializationHelper.VarSize(sizes[i]) + sizes[i]; 
                } 

                // Now write the KnownTagCache.KnownTagIndex.DrawingAttributesTable first, then sizeOfHeaderInBytes and then individual Drawing Attributes 
                totalSizeOfSerializedBytes = SerializationHelper.Encode(stream, (uint)KnownTagCache.KnownTagIndex.DrawingAttributesTable);

                totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizeOfHeaderInBytes);
                for (int i = 0; i < _drawingAttributesTable.Count; i++) 
                {
                    DrawingAttributes drawingAttributes = _drawingAttributesTable[i]; 
 
                    // write the size of the block
                    totalSizeOfSerializedBytes += SerializationHelper.Encode(stream, sizes[i]); 

                    // write the saved data
                    uint bytesWritten = Convert.ToUInt32(drawingAttributeStreams[i].Position);
                    totalSizeOfSerializedBytes += bytesWritten; 
                    Debug.Assert(sizes[i] == bytesWritten);
 
                    stream.Write(   drawingAttributeStreams[i].GetBuffer(), //returns a direct ref, no copies 
                                    0,
                                    Convert.ToInt32(bytesWritten)); 

                    drawingAttributeStreams[i].Dispose();
                }
            } 

            return totalSizeOfSerializedBytes; 
        } 

        ///  
        /// This function builds list of all unique Tables, ie Stroke Descriptor Table, Metric Descriptor Table, Transform Descriptor Table
        /// and Drawing Attributes Table based on all the strokes. Each entry in the Table is unique with respect to the table.
        /// 
        ///  
        private void BuildTables(GuidList guidList)
        { 
            _transformTable.Clear(); 
            _strokeDescriptorTable.Clear();
            _metricTable.Clear(); 
            _drawingAttributesTable.Clear();

            int count = 0;
 
            for (count = 0; count < _coreStrokes.Count; count++)
            { 
                Stroke stroke = _coreStrokes[count]; 

                // First get the updated descriptor from the stroke 
                StrokeDescriptor strokeDescriptor;
                MetricBlock metricBlock;
                StrokeSerializer.BuildStrokeDescriptor(stroke, guidList, _strokeLookupTable[stroke], out strokeDescriptor, out metricBlock);
                bool fMatch = false; 

                // Compare this with all the global stroke descriptor for a match 
                for (int descriptorIndex = 0; descriptorIndex < _strokeDescriptorTable.Count; descriptorIndex++) 
                {
                    if (strokeDescriptor.IsEqual(_strokeDescriptorTable[descriptorIndex])) 
                    {
                        fMatch = true;
                        _strokeLookupTable[stroke].StrokeDescriptorTableIndex = (uint)descriptorIndex;
                        break; 
                    }
                } 
                if (false == fMatch) 
                {
                    _strokeDescriptorTable.Add(strokeDescriptor); 
                    _strokeLookupTable[stroke].StrokeDescriptorTableIndex = (uint)_strokeDescriptorTable.Count - 1;
                }

                // If there is at least one entry in the metric block, check if the current Block is equvalent to 
                // any of the existing one.
                fMatch = false; 
                for (int tmp = 0; tmp < _metricTable.Count; tmp++) 
                {
                    MetricBlock block = _metricTable[tmp]; 
                    SetType type = SetType.SubSet;

                    if (block.CompareMetricBlock(metricBlock, ref type))
                    { 
                        // This entry exists in the list. If it is a subset of the element, do nothing.
                        // Otherwise, replace the entry with this one 
                        if (type == SetType.SuperSet) 
                        {
                            _metricTable[tmp] = metricBlock; 
                        }

                        fMatch = true;
                        _strokeLookupTable[stroke].MetricDescriptorTableIndex = (uint)tmp; 
                        break;
                    } 
                } 

                if (false == fMatch) 
                {
                    _metricTable.Add(metricBlock);
                    _strokeLookupTable[stroke].MetricDescriptorTableIndex = (uint)(_metricTable.Count - 1);
                } 

                // Now build the Transform Table 
                fMatch = false; 

                // 
                // always identity
                //
                TransformDescriptor xform = StrokeCollectionSerializer.IdentityTransformDescriptor;
 
                // First check to see if this matches with any existing Transform Blocks
                for (int i = 0; i < _transformTable.Count; i++) 
                { 
                    if (true == xform.Compare(_transformTable[i]))
                    { 
                        fMatch = true;
                        _strokeLookupTable[stroke].TransformTableIndex = (uint)i;
                        break;
                    } 
                }
 
                if (false == fMatch) 
                {
                    _transformTable.Add(xform); 
                    _strokeLookupTable[stroke].TransformTableIndex = (uint)(_transformTable.Count - 1);
                }

                // Now build the drawing attributes table 
                fMatch = false;
 
                DrawingAttributes drattrs = _coreStrokes[count].DrawingAttributes; 

                // First check to see if this matches with any existing transform blocks 
                for (int i = 0; i < _drawingAttributesTable.Count; i++)
                {
                    if (true == drattrs.Equals(_drawingAttributesTable[i]))
                    { 
                        fMatch = true;
                        _strokeLookupTable[stroke].DrawingAttributesTableIndex = (uint)i; 
                        break; 
                    }
                } 

                if (false == fMatch)
                {
                    _drawingAttributesTable.Add(drattrs); 
                    _strokeLookupTable[stroke].DrawingAttributesTableIndex = (uint)_drawingAttributesTable.Count - 1;
                } 
            } 
        }
 
        #endregion // Private Methods

        internal class StrokeLookupEntry
        { 
            internal uint MetricDescriptorTableIndex = 0;
            internal uint StrokeDescriptorTableIndex = 0; 
            internal uint TransformTableIndex = 0; 
            internal uint DrawingAttributesTableIndex = 0;
 
            // Compression algorithm data
            internal byte CompressionData = 0;

            internal int[][] ISFReadyStrokeData = null; 
            internal bool StorePressure = false;
        } 
 
        #endregion // Encoding
 
        #region Debugging Methods

        [System.Diagnostics.Conditional("DEBUG_ISF")]
        static void ISFDebugTrace(string message) 
        {
            System.Diagnostics.Debug.WriteLine(message); 
        } 
        #endregion
 
        // [System.Diagnostics.Conditional("DEBUG_ISF")]
        internal static string ISFDebugMessage(string debugMessage)
        {
#if DEBUG 
            return debugMessage;
#else 
            return SR.Get(SRID.IsfOperationFailed); 
#endif
        } 

        #region Private Fields

        StrokeCollection _coreStrokes; 
        private System.Collections.Generic.List _strokeDescriptorTable = null;
        private System.Collections.Generic.List _transformTable = null; 
        private System.Collections.Generic.List _drawingAttributesTable = null; 
        private System.Collections.Generic.List _metricTable = null;
        private Vector _himetricSize = new Vector(0.0f, 0.0f); 


            // The ink space rectangle (e.g. bounding box for GIF) is stored
            //      with the serialization info so that load/save roundtrip the 
            //      rectangle
        private Rect _inkSpaceRectangle = new Rect(); 
 
        System.Collections.Generic.Dictionary _strokeLookupTable = null;
 
        #endregion
    }

    ///  
    /// Simple static method for generating StrokeIds
    ///  
    internal static class StrokeIdGenerator 
    {
        ///  
        /// Generates backwards compatible StrokeID's for the strokes
        /// 
        /// strokes
        ///  
        internal static int[] GetStrokeIds(StrokeCollection strokes)
        { 
            System.Diagnostics.Debug.Assert(strokes != null); 

            int[] strokeIds = new int[strokes.Count]; 
            for (int x = 0; x < strokeIds.Length; x++)
            {
                //stroke ID's are 1 based (1,2,3...)
                strokeIds[x] = x + 1; 
            }
            return strokeIds; 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK