Example #1
0
        /// <Summary>
        /// Encodes the StylusTip in the ISF stream.
        /// </Summary>
#else
        /// <Summary>
        /// Encodes the StylusTip in the ISF stream.
        /// </Summary>
#endif
        private static void PersistStylusTip(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            //
            // persist the StylusTip
            //
            if (da.ContainsPropertyData(KnownIds.StylusTip))
            {
                System.Diagnostics.Debug.Assert(da.StylusTip != StylusTip.Ellipse, "StylusTip was put in the EPC for the default value!");

                //
                // persist PenTip.Rectangle for V1 ISF
                //
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.PenTip, true));
                cbData += SerializationHelper.Encode(stream, (uint)PenTip.Rectangle);

                using (MemoryStream localStream = new MemoryStream(6)) //reasonable default
                {
                    Int32 stylusTip = Convert.ToInt32(da.StylusTip, System.Globalization.CultureInfo.InvariantCulture);
                    System.Runtime.InteropServices.VarEnum type = SerializationHelper.ConvertToVarEnum(PersistenceTypes.StylusTip, true);
                    ExtendedPropertySerializer.EncodeAttribute(KnownIds.StylusTip, stylusTip, type, localStream);

                    cbData += ExtendedPropertySerializer.EncodeAsISF(KnownIds.StylusTip, localStream.ToArray(), stream, guidList, 0, true);
                }
            }
        }
Example #2
0
 /// <summary>
 /// Retrieve the guids for the custom attributes that are not known by
 /// the v1 ISF decoder
 /// </summary>
 /// <param name="attributes"></param>
 /// <param name="count">count of guids returned (can be less than return.Length</param>
 /// <returns></returns>
 internal static Guid[] GetUnknownGuids(ExtendedPropertyCollection attributes, out int count)
 {
     Guid[] guids = new Guid[attributes.Count];
     count = 0;
     for (int x = 0; x < attributes.Count; x++)
     {
         ExtendedProperty attribute = attributes[x];
         if (0 == GuidList.FindKnownTag(attribute.Id))
         {
             guids[count++] = attribute.Id;
         }
     }
     return(guids);
 }
Example #3
0
        private static void PersistDrawingFlags(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            //
            // always serialize DrawingFlags, even when it is the default of AntiAliased.  V1 loaders
            // expect it.
            //
            Debug.Assert(bw != null);
            cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.DrawingFlags, true));
            cbData += SerializationHelper.Encode(stream, (uint)(int)da.DrawingFlags);

            if (da.ContainsPropertyData(KnownIds.CurveFittingError))
            {
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.CurveFittingError, true));
                cbData += SerializationHelper.Encode(stream, (uint)(int)da.GetPropertyData(KnownIds.CurveFittingError));
            }
        }
Example #4
0
        /// <summary>
        /// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="size"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="drawingAttributes"></param>
        /// <param name="transform"></param>
        /// <param name="compressor">Compression module</param>
        /// <param name="stroke">Newly decoded stroke</param>
        /// <returns></returns>
#else
        /// <summary>
        /// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="size"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="drawingAttributes"></param>
        /// <param name="transform"></param>
        /// <param name="stroke">Newly decoded stroke</param>
#endif
        internal static uint DecodeStroke(Stream stream,
                                          uint size,
                                          GuidList guidList,
                                          StrokeDescriptor strokeDescriptor,
                                          StylusPointDescription stylusPointDescription,
                                          DrawingAttributes drawingAttributes,
                                          Matrix transform,
#if OLD_ISF
                                          Compressor compressor,
#endif
                                          out Stroke stroke)
        {
            ExtendedPropertyCollection extendedProperties;
            StylusPointCollection      stylusPoints;

            uint cb = DecodeISFIntoStroke(
#if OLD_ISF
                compressor,
#endif
                stream,
                size,
                guidList,
                strokeDescriptor,
                stylusPointDescription,
                transform,
                out stylusPoints,
                out extendedProperties);

            if (cb != size)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Stroke size (" +
                                                                                       cb.ToString(System.Globalization.CultureInfo.InvariantCulture) + ") != expected (" +
                                                                                       size.ToString(System.Globalization.CultureInfo.InvariantCulture) + ")"));
            }

            stroke = new Stroke(stylusPoints, drawingAttributes, extendedProperties);

            return(cb);
        }
Example #5
0
        /// <summary>
        /// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="size"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="drawingAttributes"></param>
        /// <param name="transform"></param>
        /// <param name="stroke">Newly decoded stroke</param>
#endif
        internal static uint DecodeStroke(Stream stream,
                                 uint size,
                                 GuidList guidList,
                                 StrokeDescriptor strokeDescriptor,
                                 StylusPointDescription stylusPointDescription,
                                 DrawingAttributes drawingAttributes,
                                 Matrix transform,
#if OLD_ISF
                                 Compressor compressor,
#endif
                                 out Stroke stroke)
        {
            ExtendedPropertyCollection extendedProperties;
            StylusPointCollection stylusPoints;

            uint cb = DecodeISFIntoStroke(
#if OLD_ISF
                compressor, 
#endif 
                stream, 
                size, 
                guidList, 
                strokeDescriptor, 
                stylusPointDescription, 
                transform, 
                out stylusPoints, 
                out extendedProperties);

            if (cb != size)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Stroke size (" +
                    cb.ToString(System.Globalization.CultureInfo.InvariantCulture) + ") != expected (" + 
                    size.ToString(System.Globalization.CultureInfo.InvariantCulture) + ")"));
            }

            stroke = new Stroke(stylusPoints, drawingAttributes, extendedProperties);

            return cb;
        }
Example #6
0
        private static void PersistRasterOperation(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            // write any non-default RasterOp value that we might have picked up from
            // V1 interop or by setting IsHighlighter.
            if (da.RasterOperation != DrawingAttributeSerializer.RasterOperationDefaultV1)
            {
                uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation);
                if (ropSize == 0)
                {
                    throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data size was not found"));
                }

                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.RasterOperation, true));
                long currentPosition = stream.Position;
                bw.Write(da.RasterOperation);
                if ((uint)(stream.Position - currentPosition) != ropSize)
                {
                    throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data was incorrectly serialized"));
                }
                cbData += ropSize;
            }
        }
Example #7
0
        /// <summary>
        /// Returns an array of bytes of the saved stroke
        /// </summary>
        /// <param name="stroke">Stroke to save</param>
        /// <param name="stream">null to calculate only the size</param>
        /// <param name="compressor"></param>
        /// <param name="compressionAlgorithm"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeLookupEntry"></param>
#else
        /// <summary>
        /// Returns an array of bytes of the saved stroke
        /// </summary>
        /// <param name="stroke">Stroke to save</param>
        /// <param name="stream">null to calculate only the size</param>
        /// <param name="compressionAlgorithm"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeLookupEntry"></param>
#endif
        internal static uint EncodeStroke(
            Stroke stroke,
            Stream stream,
#if OLD_ISF
            Compressor compressor,
#endif
            byte compressionAlgorithm,
            GuidList guidList,
            StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry)
        {
            uint cbWrite = SavePackets(stroke,
                                       stream,
#if OLD_ISF
                                       compressor,
#endif
                                       strokeLookupEntry);

            if (stroke.ExtendedProperties.Count > 0)
            {
                cbWrite += ExtendedPropertySerializer.EncodeAsISF(stroke.ExtendedProperties, stream, guidList, compressionAlgorithm, false);
            }

            return(cbWrite);
        }
Example #8
0
        /// <Summary>
        /// Encodes a DrawingAttriubtesin the ISF stream.
        /// </Summary>
#else
        /// <Summary>
        /// Encodes a DrawingAttriubtesin the ISF stream.
        /// </Summary>
#endif
        internal static uint EncodeAsISF(DrawingAttributes da, Stream stream, GuidList guidList, byte compressionAlgorithm, bool fTag)
        {
#if DEBUG
            System.Diagnostics.Debug.Assert(compressionAlgorithm == 0);
            System.Diagnostics.Debug.Assert(fTag == true);
#endif
            Debug.Assert(stream != null);
            uint         cbData = 0;
            BinaryWriter bw     = new BinaryWriter(stream);

            PersistDrawingFlags(da, stream, guidList, ref cbData, ref bw);

            PersistColorAndTransparency(da, stream, guidList, ref cbData, ref bw);

            PersistRasterOperation(da, stream, guidList, ref cbData, ref bw);

            PersistWidthHeight(da, stream, guidList, ref cbData, ref bw);

            PersistStylusTip(da, stream, guidList, ref cbData, ref bw);

            PersistExtendedProperties(da, stream, guidList, ref cbData, ref bw, compressionAlgorithm, fTag);

            return(cbData);
        }
Example #9
0
        /// <summary>
        /// This functions loads a stroke from a memory stream based on the descriptor and GuidList. It returns
        /// the no of bytes it has read from the stream to correctly load the stream, which should be same as
        /// the value of the size parameter. If they are unequal throws ArgumentException. Stroke descriptor is
        /// used to load the packetproperty as well as ExtendedPropertyCollection on this stroke. Compressor is used
        /// to decompress the data.
        /// </summary>
        /// <param name="compressor"></param>
        /// <param name="stream"></param>
        /// <param name="totalBytesInStrokeBlockOfIsfStream"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="transform"></param>
        /// <param name="stylusPoints"></param>
        /// <param name="extendedProperties"></param>
        /// <returns></returns>
#else
        /// <summary>
        /// This functions loads a stroke from a memory stream based on the descriptor and GuidList. It returns
        /// the no of bytes it has read from the stream to correctly load the stream, which should be same as
        /// the value of the size parameter. If they are unequal throws ArgumentException. Stroke descriptor is
        /// used to load the packetproperty as well as ExtendedPropertyCollection on this stroke. Compressor is used
        /// to decompress the data.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="totalBytesInStrokeBlockOfIsfStream"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="transform"></param>
        /// <param name="stylusPoints"></param>
        /// <param name="extendedProperties"></param>
#endif
        static uint DecodeISFIntoStroke(
#if OLD_ISF
            Compressor compressor,
#endif
            Stream stream,
            uint totalBytesInStrokeBlockOfIsfStream,
            GuidList guidList,
            StrokeDescriptor strokeDescriptor,
            StylusPointDescription stylusPointDescription,
            Matrix transform,
            out StylusPointCollection stylusPoints,
            out ExtendedPropertyCollection extendedProperties)
        {
            stylusPoints       = null;
            extendedProperties = null;

            // We do allow a stroke with no packet data
            if (0 == totalBytesInStrokeBlockOfIsfStream)
            {
                return(0);
            }

            uint locallyDecodedBytes;
            uint remainingBytesInStrokeBlock = totalBytesInStrokeBlockOfIsfStream;

            // First try to load any packet data
            locallyDecodedBytes = LoadPackets(stream,
                                              remainingBytesInStrokeBlock,
#if OLD_ISF
                                              compressor,
#endif
                                              stylusPointDescription,
                                              transform,
                                              out stylusPoints);

            if (locallyDecodedBytes > remainingBytesInStrokeBlock)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packet buffer overflowed the ISF stream"));
            }

            remainingBytesInStrokeBlock -= locallyDecodedBytes;
            if (0 == remainingBytesInStrokeBlock)
            {
                return(locallyDecodedBytes);
            }

            // Now read the extended propertes
            for (int iTag = 1; iTag < strokeDescriptor.Template.Count && remainingBytesInStrokeBlock > 0; iTag++)
            {
                KnownTagCache.KnownTagIndex tag = strokeDescriptor.Template[iTag - 1];

                switch (tag)
                {
                case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.StrokePropertyList:
                {
                    // we've found the stroke extended properties. Load them now.
                    while (iTag < strokeDescriptor.Template.Count && remainingBytesInStrokeBlock > 0)
                    {
                        tag = strokeDescriptor.Template[iTag];

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

                        // load the extended property data from the stream (and decode the type)
                        locallyDecodedBytes = ExtendedPropertySerializer.DecodeAsISF(stream, remainingBytesInStrokeBlock, guidList, tag, ref guid, out data);

                        // add the guid/data pair into the property collection (don't redecode the type)
                        if (extendedProperties == null)
                        {
                            extendedProperties = new ExtendedPropertyCollection();
                        }
                        extendedProperties[guid] = data;
                        if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                        }

                        remainingBytesInStrokeBlock -= locallyDecodedBytes;
                        iTag++;
                    }
                }
                break;

                case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Buttons:
                {
                    // Next tag is count of buttons and the tags for the button guids
                    iTag += (int)((uint)strokeDescriptor.Template[iTag]) + 1;
                }
                break;

                // ignore any tags embedded in the Stroke block that this
                //      version of the ISF decoder doesn't understand
                default:
                {
                    System.Diagnostics.Trace.WriteLine("Ignoring unhandled stroke tag in ISF stroke descriptor");
                }
                break;
                }
            }

            // Now try to load any tagged property data or point property data
            while (remainingBytesInStrokeBlock > 0)
            {
                // Read the tag first
                KnownTagCache.KnownTagIndex tag;
                uint uiTag;

                locallyDecodedBytes = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;
                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                }

                remainingBytesInStrokeBlock -= locallyDecodedBytes;

                // if it is a point property block
                switch (tag)
                {
                case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.PointProperty:
                {
                    // First load the totalBytesInStrokeBlockOfIsfStream of the point property block
                    uint cbsize;

                    locallyDecodedBytes = SerializationHelper.Decode(stream, out cbsize);
                    if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                    }

                    remainingBytesInStrokeBlock -= locallyDecodedBytes;
                    while (remainingBytesInStrokeBlock > 0)
                    {
                        // First read the tag corresponding to the property
                        locallyDecodedBytes = SerializationHelper.Decode(stream, out uiTag);
                        tag = (KnownTagCache.KnownTagIndex)uiTag;
                        if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                        }

                        remainingBytesInStrokeBlock -= locallyDecodedBytes;

                        // Now read the packet index for which the property will apply
                        uint propindex;

                        locallyDecodedBytes = SerializationHelper.Decode(stream, out propindex);
                        if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                        }

                        remainingBytesInStrokeBlock -= locallyDecodedBytes;

                        uint propsize;

                        locallyDecodedBytes = SerializationHelper.Decode(stream, out propsize);
                        if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                        }

                        remainingBytesInStrokeBlock -= locallyDecodedBytes;

                        // Compressed data totalBytesInStrokeBlockOfIsfStream
                        propsize += 1;

                        // Make sure we have enough data to read
                        if (propsize > remainingBytesInStrokeBlock)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
                        }

                        byte[] in_buffer = new byte[propsize];

                        uint bytesRead = StrokeCollectionSerializer.ReliableRead(stream, in_buffer, propsize);
                        if (propsize != bytesRead)
                        {
                            throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"));
                        }

                        byte[] out_buffer = Compressor.DecompressPropertyData(in_buffer);

                        System.Diagnostics.Debug.Assert(false, "ExtendedProperties for points are not supported");

                        // skip the bytes in both success & failure cases
                        // Note: Point ExtendedProperties are discarded
                        remainingBytesInStrokeBlock -= propsize;
                    }
                }
                break;

                default:
                {
                    object data;
                    Guid   guid = guidList.FindGuid(tag);
                    if (guid == Guid.Empty)
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Stroke Custom Attribute tag embedded in ISF stream does not match guid table"));
                    }

                    // load the extended property data from the stream (and decode the type)
                    locallyDecodedBytes = ExtendedPropertySerializer.DecodeAsISF(stream, remainingBytesInStrokeBlock, guidList, tag, ref guid, out data);

                    // add the guid/data pair into the property collection (don't redecode the type)
                    if (extendedProperties == null)
                    {
                        extendedProperties = new ExtendedPropertyCollection();
                    }
                    extendedProperties[guid] = data;
                    if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                    {
                        throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ExtendedProperty decoded totalBytesInStrokeBlockOfIsfStream exceeded ISF stream totalBytesInStrokeBlockOfIsfStream"));
                    }

                    remainingBytesInStrokeBlock -= locallyDecodedBytes;
                }
                break;
                }
            }

            if (0 != remainingBytesInStrokeBlock)
            {
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));
            }

            return(totalBytesInStrokeBlockOfIsfStream);
        }
        private static void PersistColorAndTransparency(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        { 
            // if the color is non-default (e.g. not black), then store it
            // the v1 encoder throws away the default color (Black) so it isn't valuable
            // to save.
            if (da.ContainsPropertyData(KnownIds.Color)) 
            {
                Color daColor = da.Color; 
                System.Diagnostics.Debug.Assert(da.Color != (Color)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.Color), "Color was put in the EPC for the default value!"); 

                //Note: we don't store the alpha value of the color (we don't use it) 
                uint r = (uint)daColor.R, g = (uint)daColor.G, b = (uint)(daColor.B);
                uint colorVal = r + (g << Native.BitsPerByte) + (b << (Native.BitsPerByte * 2));

                Debug.Assert(bw != null); 
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Color, true));
                cbData += SerializationHelper.Encode(stream, colorVal); 
            } 

            //set transparency if Color.A is set 
            byte alphaChannel = da.Color.A;
            if (alphaChannel != 255)
            {
                //note: Color.A is set to 255 by default, which means fully opaque 
                //transparency is just the opposite - 0 means fully opaque so
                //we need to flip the values 
                int transparency = MathHelper.AbsNoThrow(( (int)alphaChannel ) - 255); 
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Transparency, true)); 
                cbData += SerializationHelper.Encode(stream, Convert.ToUInt32(transparency));
            }
        }
        /// <Summary>
        /// Encodes a DrawingAttriubtesin the ISF stream. 
        /// </Summary> 
#endif
        internal static uint EncodeAsISF(DrawingAttributes da, Stream stream, GuidList guidList, byte compressionAlgorithm, bool fTag) 
        {
#if DEBUG
            System.Diagnostics.Debug.Assert(compressionAlgorithm == 0);
            System.Diagnostics.Debug.Assert(fTag == true); 
#endif
            Debug.Assert(stream != null); 
            uint cbData = 0; 
            BinaryWriter bw = new BinaryWriter(stream);
 
            PersistDrawingFlags(da, stream, guidList, ref cbData, ref bw);

            PersistColorAndTransparency(da, stream, guidList, ref cbData, ref bw);
 
            PersistRasterOperation(da, stream, guidList, ref cbData, ref bw);
 
            PersistWidthHeight(da, stream, guidList, ref cbData, ref bw); 

            PersistStylusTip(da, stream, guidList, ref cbData, ref bw); 

            PersistExtendedProperties(da, stream, guidList, ref cbData, ref bw, compressionAlgorithm, fTag);

            return cbData; 
        }
    /// <summary>
    /// Loads a DrawingAttributes Table from the stream and adds individual drawing attributes to the drawattr
    /// list passed
    /// </summary>
#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;
    }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="guidList"></param>
        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;
                }
            }
        }
Example #14
0
        private static void PersistColorAndTransparency(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            // if the color is non-default (e.g. not black), then store it
            // the v1 encoder throws away the default color (Black) so it isn't valuable
            // to save.
            if (da.ContainsPropertyData(KnownIds.Color))
            {
                Color daColor = da.Color;
                System.Diagnostics.Debug.Assert(da.Color != (Color)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.Color), "Color was put in the EPC for the default value!");

                //Note: we don't store the alpha value of the color (we don't use it)
                uint r = (uint)daColor.R, g = (uint)daColor.G, b = (uint)(daColor.B);
                uint colorVal = r + (g << Native.BitsPerByte) + (b << (Native.BitsPerByte * 2));

                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Color, true));
                cbData += SerializationHelper.Encode(stream, colorVal);
            }

            //set transparency if Color.A is set
            byte alphaChannel = da.Color.A;

            if (alphaChannel != 255)
            {
                //note: Color.A is set to 255 by default, which means fully opaque
                //transparency is just the opposite - 0 means fully opaque so
                //we need to flip the values
                int transparency = MathHelper.AbsNoThrow(((int)alphaChannel) - 255);
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Transparency, true));
                cbData += SerializationHelper.Encode(stream, Convert.ToUInt32(transparency));
            }
        }
Example #15
0
        /// <summary>
        /// Saves all elements in this list in the stream passed with the tags being generated based on the GuidList
        /// by the caller and using compressionAlgorithm as the preferred algorith identifier. For ExtendedPropertyCollection associated
        /// with Ink, drawing attributes and Point properties, we need to write the tag while saving them and hence
        /// fTag param is true. For strokes, the Tag is stored in the stroke descriptor and hence we don't store the
        /// tag
        /// </summary>
        /// <param name="attributes">Custom attributes to encode</param>
        /// <param name="stream">If stream is null, then size is calculated only.</param>
        /// <param name="guidList"></param>
        /// <param name="compressionAlgorithm"></param>
        /// <param name="fTag"></param>
#endif
        internal static uint EncodeAsISF(ExtendedPropertyCollection attributes, Stream stream, GuidList guidList, byte compressionAlgorithm, bool fTag)
        {
            uint cbWrite = 0;

            for (int i = 0; i < attributes.Count; i++)
            {
                ExtendedProperty prop = attributes[i];

                using (MemoryStream localStream = new MemoryStream(10)) //reasonable default
                {
                    ExtendedPropertySerializer.EncodeToStream(prop, localStream);

                    byte[] data = localStream.ToArray();

                    cbWrite += ExtendedPropertySerializer.EncodeAsISF(prop.Id, data, stream, guidList, compressionAlgorithm, fTag);
                }
            }

            return(cbWrite);
        }
Example #16
0
        /// <summary>
        /// Loads drawing attributes from a memory buffer.
        /// </summary>
        /// <param name="stream">Memory buffer to read from</param>
        /// <param name="guidList">Guid tags if extended properties are used</param>
        /// <param name="maximumStreamSize">Maximum size of buffer to read through</param>
        /// <param name="da">The drawing attributes collection to decode into</param>
        /// <returns>Number of bytes read</returns>
#else
        /// <summary>
        /// Loads drawing attributes from a memory buffer.
        /// </summary>
        /// <param name="stream">Memory buffer to read from</param>
        /// <param name="guidList">Guid tags if extended properties are used</param>
        /// <param name="maximumStreamSize">Maximum size of buffer to read through</param>
        /// <param name="da">The drawing attributes collection to decode into</param>
        /// <returns>Number of bytes read</returns>
#endif
        internal static uint DecodeAsISF(Stream stream, GuidList guidList, uint maximumStreamSize, DrawingAttributes da)
        {
            PenTip   penTip           = PenTip.Default;
            PenStyle penStyle         = PenStyle.Default;
            double   stylusWidth      = DrawingAttributeSerializer.V1PenWidthWhenWidthIsMissing;
            double   stylusHeight     = DrawingAttributeSerializer.V1PenHeightWhenHeightIsMissing;
            uint     rasterOperation  = DrawingAttributeSerializer.RasterOperationDefaultV1;
            int      transparency     = DrawingAttributeSerializer.TransparencyDefaultV1;
            bool     widthIsSetInISF  = false; //did we find KnownIds.Width?
            bool     heightIsSetInISF = false; //did we find KnownIds.Height?


            uint cbTotal = maximumStreamSize;

            while (maximumStreamSize > 0)
            {
                KnownTagCache.KnownTagIndex tag;
                uint uiTag;
                // First read the tag
                uint cb = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;

                if (maximumStreamSize < cb)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("ISF size is larger than maximum stream size"));
                }

                maximumStreamSize -= cb;

                // Get the guid based on the tag
                Guid guid = guidList.FindGuid(tag);
                if (guid == Guid.Empty)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Drawing Attribute tag embedded in ISF stream does not match guid table"));
                }

                uint dw = 0;

                if (KnownIds.PenTip == guid)
                {
                    cb     = SerializationHelper.Decode(stream, out dw);
                    penTip = (PenTip)dw;
                    if (!PenTipHelper.IsDefined(penTip))
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid PenTip value found in ISF stream"));
                    }
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.PenStyle == guid)
                {
                    cb                 = SerializationHelper.Decode(stream, out dw);
                    penStyle           = (PenStyle)dw;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.DrawingFlags == guid)
                {
                    // Encode the drawing flags with considerations for v2 model
                    cb = SerializationHelper.Decode(stream, out dw);
                    DrawingFlags flags = (DrawingFlags)dw;
                    da.DrawingFlags    = flags;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.RasterOperation == guid)
                {
                    uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation);
                    if (ropSize == 0)
                    {
                        throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data size was not found"));
                    }

                    byte[] data = new byte[ropSize];
                    stream.Read(data, 0, (int)ropSize);

                    if (data != null && data.Length > 0)
                    {
                        //data[0] holds the allowable values of 0-255
                        rasterOperation = Convert.ToUInt32(data[0]);
                    }

                    maximumStreamSize -= ropSize;
                }
                else if (KnownIds.CurveFittingError == guid)
                {
                    cb = SerializationHelper.Decode(stream, out dw);
                    da.FittingError    = (int)dw;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.StylusHeight == guid || KnownIds.StylusWidth == guid)
                {
                    double _size;
                    cb                 = SerializationHelper.Decode(stream, out dw);
                    _size              = (double)dw;
                    maximumStreamSize -= cb;
                    if (maximumStreamSize > 0)
                    {
                        cb = SerializationHelper.Decode(stream, out dw);
                        maximumStreamSize -= cb;
                        if (KnownTagCache.KnownTagIndex.Mantissa == (KnownTagCache.KnownTagIndex)dw)
                        {
                            uint cbInSize;
                            // First thing that is in there is maximumStreamSize of the data
                            cb = SerializationHelper.Decode(stream, out cbInSize);
                            maximumStreamSize -= cb;

                            // in maximumStreamSize is one more than the decoded no
                            cbInSize++;
                            if (cbInSize > maximumStreamSize)
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("ISF size if greater then maximum stream size"));
                            }
                            byte[] in_data = new byte[cbInSize];

                            uint bytesRead = (uint)stream.Read(in_data, 0, (int)cbInSize);
                            if (cbInSize != bytesRead)
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"));
                            }

                            byte[] out_buffer = Compressor.DecompressPropertyData(in_data);
                            using (MemoryStream localStream = new MemoryStream(out_buffer))
                                using (BinaryReader rdr = new BinaryReader(localStream))
                                {
                                    short sFraction = rdr.ReadInt16();
                                    _size += (double)(sFraction / DrawingAttributes.StylusPrecision);

                                    maximumStreamSize -= cbInSize;
                                }
                        }
                        else
                        {
                            // Seek it back by cb
                            stream.Seek(-cb, SeekOrigin.Current);
                            maximumStreamSize += cb;
                        }
                    }
                    if (KnownIds.StylusWidth == guid)
                    {
                        widthIsSetInISF = true;
                        stylusWidth     = _size;
                    }
                    else
                    {
                        heightIsSetInISF = true;
                        stylusHeight     = _size;
                    }
                }
                else if (KnownIds.Transparency == guid)
                {
                    cb                 = SerializationHelper.Decode(stream, out dw);
                    transparency       = (int)dw;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.Color == guid)
                {
                    cb = SerializationHelper.Decode(stream, out dw);

                    Color color = Color.FromRgb((byte)(dw & 0xff), (byte)((dw & 0xff00) >> Native.BitsPerByte), (byte)((dw & 0xff0000) >> (Native.BitsPerByte * 2)));
                    da.Color           = color;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.StylusTipTransform == guid)
                {
                    try
                    {
                        object data;
                        cb = ExtendedPropertySerializer.DecodeAsISF(stream, maximumStreamSize, guidList, tag, ref guid, out data);

                        Matrix matrix = Matrix.Parse((string)data);
                        da.StylusTipTransform = matrix;
                    }
                    catch (InvalidOperationException) // Matrix.Parse failed.
                    {
                        System.Diagnostics.Debug.Assert(false, "Corrupt Matrix in the ExtendedPropertyCollection!");
                    }
                    finally
                    {
                        maximumStreamSize -= cb;
                    }
                }
                else
                {
                    object data;
                    cb = ExtendedPropertySerializer.DecodeAsISF(stream, maximumStreamSize, guidList, tag, ref guid, out data);
                    maximumStreamSize -= cb;
                    da.AddPropertyData(guid, data);
                }
            }

            if (0 != maximumStreamSize)
            {
                throw new ArgumentException();
            }

            //
            // time to create our drawing attributes.
            //
            // 1) First we need to evaluate PenTip / StylusTip
            // Here is the V1 - V2 mapping
            //
            // PenTip.Circle == StylusTip.Ellipse
            // PenTip.Rectangle == StylusTip.Rectangle
            // PenTip.Rectangle == StylusTip.Diamond
            if (penTip == PenTip.Default)
            {
                //Since StylusTip is stored in the EPC at this point (if set), we can compare against it here.
                if (da.StylusTip != StylusTip.Ellipse)
                {
                    //
                    // StylusTip was set to something other than Ellipse
                    // when we last serialized (or else StylusTip would be Ellipse, the default)
                    // when StylusTip is != Ellipse and we serialize, we set PenTip to Rectangle
                    // which is not the default.  Therefore, if PenTip is back to Circle,
                    // that means someone set it in V1 and we should respect that by
                    // changing StylusTip back to Ellipse
                    //
                    da.StylusTip = StylusTip.Ellipse;
                }
                //else da.StylusTip is already set
            }
            else
            {
                System.Diagnostics.Debug.Assert(penTip == PenTip.Rectangle);
                if (da.StylusTip == StylusTip.Ellipse)
                {
                    //
                    // PenTip is Rectangle and StylusTip was either not set
                    // before or was set to Ellipse and PenTip was changed
                    // in a V1 ink object.  Either way, we need to change StylusTip to Rectangle
                    da.StylusTip = StylusTip.Rectangle;
                }
                //else da.StylusTip is already set
            }

            //
            // 2) next we need to set hight and width
            //
            if (da.StylusTip == StylusTip.Ellipse &&
                widthIsSetInISF &&
                !heightIsSetInISF)
            {
                //
                // special case: V1 PenTip of Circle only used Width to compute the circle size
                // and so it only serializes Width of 53
                // but since our default is Ellipse, if Height is unset and we use the default
                // height of 30, then your ink that looked like 53,53 in V1 will look
                // like 30,53 here.
                //
                //
                stylusHeight = stylusWidth;
                da.HeightChangedForCompatabity = true;
            }
            // need to convert width/height into Avalon, since they are stored in HIMETRIC in ISF
            stylusHeight *= StrokeCollectionSerializer.HimetricToAvalonMultiplier;
            stylusWidth  *= StrokeCollectionSerializer.HimetricToAvalonMultiplier;

            // Map 0.0 width to DrawingAttributes.DefaultXXXXXX (V1 53 equivalent)
            double height = DoubleUtil.IsZero(stylusHeight) ? (Double)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.StylusHeight) : stylusHeight;
            double width  = DoubleUtil.IsZero(stylusWidth) ? (Double)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.StylusWidth) : stylusWidth;

            da.Height = GetCappedHeightOrWidth(height);
            da.Width  = GetCappedHeightOrWidth(width);

            //
            // 3) next we need to set IsHighlighter (by looking for RasterOperation.MaskPen)
            //

            //
            // always store raster op
            //
            da.RasterOperation = rasterOperation;
            if (rasterOperation == DrawingAttributeSerializer.RasterOperationDefaultV1)
            {
                //
                // if rasterop is default, make sure IsHighlighter isn't in the EPC
                //
                if (da.ContainsPropertyData(KnownIds.IsHighlighter))
                {
                    da.RemovePropertyData(KnownIds.IsHighlighter);
                }
            }
            else
            {
                if (rasterOperation == DrawingAttributeSerializer.RasterOperationMaskPen)
                {
                    da.IsHighlighter = true;
                }
            }
            //else, IsHighlighter will be set to false by default, no need to set it

            //
            // 4) see if there is a transparency we need to add to color
            //
            if (transparency > DrawingAttributeSerializer.TransparencyDefaultV1)
            {
                //note: Color.A is set to 255 by default, which means fully opaque
                //transparency is just the opposite - 0 means fully opaque so
                //we need to flip the values
                int   alpha = MathHelper.AbsNoThrow(transparency - 255);
                Color color = da.Color;
                color.A  = Convert.ToByte(alpha);
                da.Color = color;
            }
            return(cbTotal);
        }
Example #17
0
        /// <summary>
        /// Builds the Stroke Descriptor for this stroke based on Packet Layout and Extended Properties
        /// For details on how this is strored please refer to the spec.
        /// </summary>
        internal static void BuildStrokeDescriptor(
            Stroke stroke, 
            GuidList guidList, 
            StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry,
            out StrokeDescriptor strokeDescriptor, 
            out MetricBlock metricBlock)
        {
            // Initialize the metric block for this stroke
            metricBlock = new MetricBlock();

            // Clear any existing template
            strokeDescriptor = new StrokeDescriptor();

            // Uninitialized variable passed in AddMetricEntry
            MetricEntryType metricEntryType;
            StylusPointDescription stylusPointDescription = stroke.StylusPoints.Description;

            KnownTagCache.KnownTagIndex tag = guidList.FindTag(KnownIds.X, true);
            metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.X), tag);

            tag = guidList.FindTag(KnownIds.Y, true);
            metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.Y), tag);

            ReadOnlyCollection<StylusPointPropertyInfo> propertyInfos
                = stylusPointDescription.GetStylusPointProperties();

            int i = 0; //i is defined out of the for loop so we can use it later for buttons
            for (i = 2/*past x,y*/; i < propertyInfos.Count; i++)
            {
                if (i == StylusPointDescription.RequiredPressureIndex/*2*/ && 
                    !strokeLookupEntry.StorePressure)
                {
                    //
                    // don't store pressure information
                    //
                    continue;
                }
                StylusPointPropertyInfo propertyInfo = propertyInfos[i];
                if (propertyInfo.IsButton)
                {
                    //we don't serialize buttons
                    break;
                }

                tag = guidList.FindTag(propertyInfo.Id, true);

                strokeDescriptor.Template.Add(tag);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);

                // Create the MetricEntry for this property if necessary
                metricEntryType = metricBlock.AddMetricEntry(propertyInfo, tag);
            }

            /*
            we drop button data on the floor.  See Windows OS Bugs 1413460 for details
            int buttonCount = stylusPointDescription.ButtonCount;
            // Now write the button tags in the Template
            if (buttonCount > 0)
            {
                // First write the TAG_BUTTONS
                strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.Buttons);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.Buttons);

                // Next write the i of buttons
                strokeDescriptor.Template.Add((KnownTagCache.KnownTagIndex)buttonCount);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)buttonCount);

                //we broke above on i when it was a button, it still
                //points to the first button
                for (; i < propertyInfos.Count; i++)
                {
                    StylusPointPropertyInfo propertyInfo = propertyInfos[i];
                    tag = guidList.FindTag(propertyInfo.Id, false);

                    strokeDescriptor.Template.Add(tag);
                    strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);
                }
            }
            */

            // Now write the extended properties in the template
            if (stroke.ExtendedProperties.Count > 0)
            {
                strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.StrokePropertyList);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.StrokePropertyList);

                // Now write the tags corresponding to each extended properties of the stroke
                for (int x = 0; x < stroke.ExtendedProperties.Count; x++)
                {
                    tag = guidList.FindTag(stroke.ExtendedProperties[(int)x].Id, false);

                    strokeDescriptor.Template.Add(tag);
                    strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);
                }
            }
        }
Example #18
0
        /// <summary>
        /// Returns an array of bytes of the saved stroke
        /// </summary>
        /// <param name="stroke">Stroke to save</param>
        /// <param name="stream">null to calculate only the size</param>
        /// <param name="compressionAlgorithm"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeLookupEntry"></param>
#endif
        internal static uint EncodeStroke(
            Stroke stroke, 
            Stream stream, 
#if OLD_ISF
            Compressor compressor, 
#endif
            byte compressionAlgorithm, 
            GuidList guidList,
            StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry)
        {
            uint cbWrite = SavePackets( stroke, 
                                        stream, 
#if OLD_ISF
                                        compressor, 
#endif
                                        strokeLookupEntry);

            if (stroke.ExtendedProperties.Count > 0)
                cbWrite += ExtendedPropertySerializer.EncodeAsISF(stroke.ExtendedProperties, stream, guidList, compressionAlgorithm, false);

            return cbWrite;
        }
Example #19
0
        /// <summary>
        /// Loads a single ExtendedProperty from the stream and add that to the list. Tag may be passed as in
        /// the case of Stroke ExtendedPropertyCollection where tag is stored in the stroke descriptor or 0 when tag
        /// is embeded in the stream
        /// </summary>
        /// <param name="stream">Memory buffer to load from</param>
        /// <param name="cbSize">Maximum length of buffer to read</param>
        /// <param name="guidList">Guid cache to read from</param>
        /// <param name="tag">Guid tag to lookup</param>
        /// <param name="guid">Guid of property</param>
        /// <param name="data">Data of property</param>
        /// <returns>Length of buffer read</returns>
#endif
        internal static uint DecodeAsISF(Stream stream, uint cbSize, GuidList guidList, KnownTagCache.KnownTagIndex tag, ref Guid guid, out object data)
        {
            uint cb, cbRead = 0;
            uint cbTotal = cbSize;

            if (0 == cbSize)
            {
                throw new InvalidOperationException(SR.Get(SRID.EmptyDataToLoad));
            }

            if (0 == tag) // no tag is passed, it must be embedded in the data
            {
                uint uiTag;
                cb  = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;
                if (cb > cbTotal)
                {
                    throw new ArgumentException(SR.Get(SRID.InvalidSizeSpecified), "cbSize");
                }

                cbTotal -= cb;
                cbRead  += cb;
                System.Diagnostics.Debug.Assert(guid == Guid.Empty);
                guid = guidList.FindGuid(tag);
            }

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

            // Try and find the size
            uint size = GuidList.GetDataSizeIfKnownGuid(guid);

            if (size > cbTotal)
            {
                throw new ArgumentException(SR.Get(SRID.InvalidSizeSpecified), "cbSize");
            }

            // if the size is 0
            if (0 == size)
            {
                // Size must be embedded in the stream. Find out the compressed data size
                cb = SerializationHelper.Decode(stream, out size);

                uint cbInsize = size + 1;

                cbRead  += cb;
                cbTotal -= cb;
                if (cbInsize > cbTotal)
                {
                    throw new ArgumentException();
                }

                byte[] bytes = new byte[cbInsize];

                uint bytesRead = (uint)stream.Read(bytes, 0, (int)cbInsize);
                if (cbInsize != bytesRead)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "cbSize");
                }

                cbRead  += cbInsize;
                cbTotal -= cbInsize;

                //Find out the Decompressed buffer size
                using (MemoryStream decompressedStream = new MemoryStream(Compressor.DecompressPropertyData(bytes)))
                {
                    // Add the property
                    data = ExtendedPropertySerializer.DecodeAttribute(guid, decompressedStream);
                }
            }
            else
            {
                // For known size data, we just read the data directly from the stream
                byte[] bytes = new byte[size];

                uint bytesRead = (uint)stream.Read(bytes, 0, (int)size);
                if (size != bytesRead)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "cbSize");
                }

                using (MemoryStream subStream = new MemoryStream(bytes))
                {
                    data = ExtendedPropertySerializer.DecodeAttribute(guid, subStream);
                }

                cbTotal -= size;
                cbRead  += size;
            }

            return(cbRead);
        }
        /// <summary>
        /// This function serializes Drawing Attributes Table in the stream. For information on how they are serialized, please refer to the spec.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="guidList"></param>
#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;
        }
Example #21
0
        /// <Summary>
        /// Encodes the ExtendedProperties in the ISF stream.
        /// </Summary>
#else
        /// <Summary>
        /// Encodes the ExtendedProperties in the ISF stream.
        /// </Summary>
#endif
        private static void PersistExtendedProperties(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw, byte compressionAlgorithm, bool fTag)
        {
            // Now save the extended properties
            ExtendedPropertyCollection epcClone = da.CopyPropertyData();

            //walk from the back removing EPs that are uses for DrawingAttributes
            for (int x = epcClone.Count - 1; x >= 0; x--)
            {
                //
                // look for StylusTipTransform while we're at it and turn it into a string
                // for serialization
                //
                if (epcClone[x].Id == KnownIds.StylusTipTransform)
                {
                    Matrix matrix       = (Matrix)epcClone[x].Value;
                    string matrixString = matrix.ToString(System.Globalization.CultureInfo.InvariantCulture);
                    epcClone[x].Value = matrixString;
                    continue;
                }

                if (DrawingAttributes.RemoveIdFromExtendedProperties(epcClone[x].Id))
                {
                    epcClone.Remove(epcClone[x].Id);
                }
            }

            cbData += ExtendedPropertySerializer.EncodeAsISF(epcClone, stream, guidList, compressionAlgorithm, fTag);
        }
        /// <summary>
        /// Takes an ISF Stream and populates the StrokeCollection
        ///  attached to this StrokeCollectionSerializer.
        /// </summary>
        /// <param name="inputStream">a Stream the raw isf to decode</param>
#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<StrokeDescriptor>();
            _drawingAttributesTable = new System.Collections.Generic.List<DrawingAttributes>();
            _transformTable = new System.Collections.Generic.List<TransformDescriptor>();
            _metricTable = new System.Collections.Generic.List<MetricBlock>();

            // 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");
    }
        /// <Summary> 
        /// Encodes the ExtendedProperties in the ISF stream. 
        /// </Summary>
#endif 
        private static void PersistExtendedProperties(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw, byte compressionAlgorithm, bool fTag)
        {
            // Now save the extended properties
            ExtendedPropertyCollection epcClone = da.CopyPropertyData(); 

            //walk from the back removing EPs that are uses for DrawingAttributes 
            for (int x = epcClone.Count - 1; x >= 0; x--) 
            {
                // 
                // look for StylusTipTransform while we're at it and turn it into a string
                // for serialization
                //
                if (epcClone[x].Id == KnownIds.StylusTipTransform) 
                {
                    Matrix matrix = (Matrix)epcClone[x].Value; 
                    string matrixString = matrix.ToString(System.Globalization.CultureInfo.InvariantCulture); 
                    epcClone[x].Value = matrixString;
                    continue; 
                }

                if (DrawingAttributes.RemoveIdFromExtendedProperties(epcClone[x].Id))
                { 
                    epcClone.Remove(epcClone[x].Id);
                } 
            } 

            cbData += ExtendedPropertySerializer.EncodeAsISF(epcClone, stream, guidList, compressionAlgorithm, fTag); 
        }
        /// <summary>
        /// Loads drawing attributes from a memory buffer. 
        /// </summary> 
        /// <param name="stream">Memory buffer to read from</param>
        /// <param name="guidList">Guid tags if extended properties are used</param> 
        /// <param name="maximumStreamSize">Maximum size of buffer to read through</param>
        /// <param name="da">The drawing attributes collection to decode into</param>
        /// <returns>Number of bytes read</returns>
#endif 
        internal static uint DecodeAsISF(Stream stream, GuidList guidList, uint maximumStreamSize, DrawingAttributes da)
        { 
            PenTip penTip = PenTip.Default; 
            PenStyle penStyle = PenStyle.Default;
            double stylusWidth = DrawingAttributeSerializer.V1PenWidthWhenWidthIsMissing; 
            double stylusHeight = DrawingAttributeSerializer.V1PenHeightWhenHeightIsMissing;
            uint rasterOperation = DrawingAttributeSerializer.RasterOperationDefaultV1;
            int transparency = DrawingAttributeSerializer.TransparencyDefaultV1;
            bool widthIsSetInISF = false; //did we find KnownIds.Width? 
            bool heightIsSetInISF = false; //did we find KnownIds.Height?
 
 
            uint cbTotal = maximumStreamSize;
            while (maximumStreamSize > 0) 
            {
                KnownTagCache.KnownTagIndex tag;
                uint uiTag;
                // First read the tag 
                uint cb = SerializationHelper.Decode (stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag; 
 
                if (maximumStreamSize < cb)
                { 
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("ISF size is larger than maximum stream size"));
                }

                maximumStreamSize -= cb; 

                // Get the guid based on the tag 
                Guid guid = guidList.FindGuid (tag); 
                if (guid == Guid.Empty)
                { 
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Drawing Attribute tag embedded in ISF stream does not match guid table"));
                }

                uint dw = 0; 

                if (KnownIds.PenTip == guid) 
                { 
                    cb = SerializationHelper.Decode (stream, out dw);
                    penTip = (PenTip)dw; 
                    if (!PenTipHelper.IsDefined(penTip))
                    {
                        throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid PenTip value found in ISF stream"));
                    } 
                    maximumStreamSize -= cb;
                } 
                else if (KnownIds.PenStyle == guid) 
                {
                    cb = SerializationHelper.Decode(stream, out dw); 
                    penStyle = (PenStyle)dw;
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.DrawingFlags == guid) 
                {
                    // Encode the drawing flags with considerations for v2 model 
                    cb = SerializationHelper.Decode (stream, out dw); 
                    DrawingFlags flags = (DrawingFlags)dw;
                    da.DrawingFlags = flags; 
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.RasterOperation == guid)
                { 
                    uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation);
                    if (ropSize == 0) 
                    { 
                        throw new InvalidOperationException(StrokeCollectionSerializer. ISFDebugMessage("ROP data size was not found"));
                    } 

                    byte[] data = new byte[ropSize];
                    stream.Read (data, 0, (int)ropSize);
 
                    if (data != null && data.Length > 0)
                    { 
                        //data[0] holds the allowable values of 0-255 
                        rasterOperation = Convert.ToUInt32(data[0]);
                    } 

                    maximumStreamSize -= ropSize;
                }
                else if (KnownIds.CurveFittingError == guid) 
                {
                    cb = SerializationHelper.Decode (stream, out dw); 
                    da.FittingError = (int)dw; 
                    maximumStreamSize -= cb;
                } 
                else if (KnownIds.StylusHeight == guid || KnownIds.StylusWidth == guid)
                {
                    double _size;
                    cb = SerializationHelper.Decode (stream, out dw); 
                    _size = (double)dw;
                    maximumStreamSize -= cb; 
                    if (maximumStreamSize > 0) 
                    {
                        cb = SerializationHelper.Decode (stream, out dw); 
                        maximumStreamSize -= cb;
                        if (KnownTagCache.KnownTagIndex.Mantissa == (KnownTagCache.KnownTagIndex)dw)
                        {
                            uint cbInSize; 
                            // First thing that is in there is maximumStreamSize of the data
                            cb = SerializationHelper.Decode (stream, out cbInSize); 
                            maximumStreamSize -= cb; 

                            // in maximumStreamSize is one more than the decoded no 
                            cbInSize++;
                            if (cbInSize > maximumStreamSize)
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("ISF size if greater then maximum stream size")); 
                            }
                            byte[] in_data = new byte[cbInSize]; 
 							 
                            uint bytesRead = (uint) stream.Read (in_data, 0, (int)cbInSize);
                            if (cbInSize != bytesRead) 
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"));
                            }
 
                            byte[] out_buffer = Compressor.DecompressPropertyData (in_data);
                            using (MemoryStream localStream = new MemoryStream(out_buffer)) 
                            using (BinaryReader rdr = new BinaryReader(localStream)) 
                            {
                                short sFraction = rdr.ReadInt16(); 
                                _size += (double)(sFraction / DrawingAttributes.StylusPrecision);

                                maximumStreamSize -= cbInSize;
			                } 
                        }
                        else 
                        { 
                            // Seek it back by cb
                            stream.Seek (-cb, SeekOrigin.Current); 
                            maximumStreamSize += cb;
                        }
                    }
                    if (KnownIds.StylusWidth == guid) 
                    {
                        widthIsSetInISF = true; 
                        stylusWidth = _size; 
                    }
                    else 
                    {
                        heightIsSetInISF = true;
                        stylusHeight = _size;
                    } 
                }
                else if (KnownIds.Transparency == guid) 
                { 
                    cb = SerializationHelper.Decode(stream, out dw);
                    transparency = (int)dw; 
                    maximumStreamSize -= cb;
                }
                else if (KnownIds.Color == guid)
                { 
                    cb = SerializationHelper.Decode(stream, out dw);
 
                    Color color = Color.FromRgb((byte)(dw & 0xff), (byte)((dw & 0xff00) >> Native.BitsPerByte), (byte)((dw & 0xff0000) >> (Native.BitsPerByte * 2))); 
                    da.Color = color;
                    maximumStreamSize -= cb; 
                }
                else if (KnownIds.StylusTipTransform == guid)
                {
                    try 
                    {
                        object data; 
                        cb = ExtendedPropertySerializer.DecodeAsISF(stream, maximumStreamSize, guidList, tag, ref guid, out data); 

                        Matrix matrix = Matrix.Parse((string)data); 
                        da.StylusTipTransform = matrix;
                    }
                    catch (InvalidOperationException) // Matrix.Parse failed.
                    { 
                        System.Diagnostics.Debug.Assert(false, "Corrupt Matrix in the ExtendedPropertyCollection!");
                    } 
                    finally 
                    {
                        maximumStreamSize -= cb; 
                    }
                }
                else
                { 
                    object data;
                    cb = ExtendedPropertySerializer.DecodeAsISF(stream, maximumStreamSize, guidList, tag, ref guid, out data); 
                    maximumStreamSize -= cb; 
                    da.AddPropertyData(guid,data);
                } 
            }

            if (0 != maximumStreamSize)
            { 
                throw new ArgumentException ();
            } 
 
            //
            // time to create our drawing attributes. 
            //
            // 1) First we need to evaluate PenTip / StylusTip
            // Here is the V1 - V2 mapping
            // 
            // PenTip.Circle == StylusTip.Ellipse
            // PenTip.Rectangle == StylusTip.Rectangle 
            // PenTip.Rectangle == StylusTip.Diamond 
            if (penTip == PenTip.Default)
            { 
                //Since StylusTip is stored in the EPC at this point (if set), we can compare against it here.
                if (da.StylusTip != StylusTip.Ellipse)
                {
                    // 
                    // StylusTip was set to something other than Ellipse
                    // when we last serialized (or else StylusTip would be Ellipse, the default) 
                    // when StylusTip is != Ellipse and we serialize, we set PenTip to Rectangle 
                    // which is not the default.  Therefore, if PenTip is back to Circle,
                    // that means someone set it in V1 and we should respect that by 
                    // changing StylusTip back to Ellipse
                    //
                    da.StylusTip = StylusTip.Ellipse;
                } 
                //else da.StylusTip is already set
            } 
            else 
            {
                System.Diagnostics.Debug.Assert(penTip == PenTip.Rectangle); 
                if (da.StylusTip == StylusTip.Ellipse)
                {
                    //
                    // PenTip is Rectangle and StylusTip was either not set 
                    // before or was set to Ellipse and PenTip was changed
                    // in a V1 ink object.  Either way, we need to change StylusTip to Rectangle 
                    da.StylusTip = StylusTip.Rectangle; 
                }
                //else da.StylusTip is already set 
            }

            //
            // 2) next we need to set hight and width 
            //
            if (da.StylusTip == StylusTip.Ellipse && 
                widthIsSetInISF && 
                !heightIsSetInISF)
            { 
                //
                // special case: V1 PenTip of Circle only used Width to compute the circle size
                // and so it only serializes Width of 53
                // but since our default is Ellipse, if Height is unset and we use the default 
                // height of 30, then your ink that looked like 53,53 in V1 will look
                // like 30,53 here. 
                // 
                //
                stylusHeight = stylusWidth; 
                da.HeightChangedForCompatabity = true;
            }
            // need to convert width/height into Avalon, since they are stored in HIMETRIC in ISF
            stylusHeight *= StrokeCollectionSerializer.HimetricToAvalonMultiplier; 
            stylusWidth *= StrokeCollectionSerializer.HimetricToAvalonMultiplier;
 
            // Map 0.0 width to DrawingAttributes.DefaultXXXXXX (V1 53 equivalent) 
            double height = DoubleUtil.IsZero(stylusHeight) ? (Double)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.StylusHeight) : stylusHeight;
            double width = DoubleUtil.IsZero(stylusWidth) ? (Double)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.StylusWidth) : stylusWidth; 

            da.Height = GetCappedHeightOrWidth(height);
            da.Width = GetCappedHeightOrWidth(width);
 
			//
            // 3) next we need to set IsHighlighter (by looking for RasterOperation.MaskPen) 
            // 

            // 
            // always store raster op
            //
            da.RasterOperation = rasterOperation;
            if (rasterOperation == DrawingAttributeSerializer.RasterOperationDefaultV1) 
            {
                // 
                // if rasterop is default, make sure IsHighlighter isn't in the EPC 
                //
                if (da.ContainsPropertyData(KnownIds.IsHighlighter)) 
                {
                    da.RemovePropertyData(KnownIds.IsHighlighter);
                }
            } 
            else
            { 
                if (rasterOperation == DrawingAttributeSerializer.RasterOperationMaskPen) 
                {
                    da.IsHighlighter = true; 
                }
            }
            //else, IsHighlighter will be set to false by default, no need to set it
 
            //
            // 4) see if there is a transparency we need to add to color 
            // 
            if (transparency > DrawingAttributeSerializer.TransparencyDefaultV1)
            { 
                //note: Color.A is set to 255 by default, which means fully opaque
                //transparency is just the opposite - 0 means fully opaque so
                //we need to flip the values
                int alpha = MathHelper.AbsNoThrow(transparency - 255); 
                Color color = da.Color;
                color.A = Convert.ToByte(alpha); 
                da.Color = color; 
            }
            return cbTotal; 
        }
        private static void PersistWidthHeight(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            //persist the height and width 
            // For v1 loaders we persist height and width in StylusHeight and StylusWidth
            double stylusWidth = da.Width; 
            double stylusHeight = da.Height; 

            // Save the pen tip's width and height. 
            for (int i = 0; i < 2; i++)
            {
                Guid guid = (i == 0) ? KnownIds.StylusWidth : KnownIds.StylusHeight;
                double size = (0 == i) ? stylusWidth : stylusHeight; 

                // 
                // the size is now in Avalon units, we need to convert to HIMETRIC 
                //
                size *= StrokeCollectionSerializer.AvalonToHimetricMultiplier; 

                double sizeWhenMissing = (0 == i) ? V1PenWidthWhenWidthIsMissing : V1PenHeightWhenHeightIsMissing;

                // 
                // only persist height / width if they are equal to the height / width
                // when missing in the isf stream OR for compatibility with V1 
                // 
                bool skipPersisting = DoubleUtil.AreClose(size, sizeWhenMissing);
                if ( stylusWidth == stylusHeight && 
                     da.StylusTip == StylusTip.Ellipse &&
                     guid == KnownIds.StylusHeight &&
                     da.HeightChangedForCompatabity)
                { 
                    //we need to put height in the ISF stream for compat
                    skipPersisting = true; 
                } 

 
                if (!skipPersisting)
                {
                    uint uIntegral = (uint)(size + 0.5f);
 
                    Debug.Assert(bw != null);
                    cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(guid, true)); 
                    cbData += SerializationHelper.Encode(stream, uIntegral); 

                    short sFraction = (size > uIntegral) ? (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) + 0.5f) : (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) - 0.5); 

                    // If the fractional values is non zero, we store this value along with TAG_MANTISSA and size with a precisson of 1000
                    if (0 != sFraction)
                    { 
                        uint cb = Native.SizeOfUShort; // For header NO_COMPRESS
 
                        Debug.Assert(bw != null); 
                        cbData += SerializationHelper.Encode(stream, (uint)MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Mantissa);
                        cbData += SerializationHelper.Encode(stream, cb); 
                        bw.Write((byte)0x00);
                        bw.Write((short)sFraction);

                        cbData += cb + 1; // include size of encoded 0 and encoded fraction value 
                    }
                } 
            } 
        }
        private static void PersistDrawingFlags(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        { 
            //
            // always serialize DrawingFlags, even when it is the default of AntiAliased.  V1 loaders
            // expect it.
            // 
            Debug.Assert(bw != null);
            cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.DrawingFlags, true)); 
            cbData += SerializationHelper.Encode(stream, (uint)(int)da.DrawingFlags); 

            if (da.ContainsPropertyData(KnownIds.CurveFittingError)) 
            {
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.CurveFittingError, true));
                cbData += SerializationHelper.Encode(stream, (uint)(int)da.GetPropertyData(KnownIds.CurveFittingError)); 
            }
        } 
        /// <summary>
        /// Loads a single ExtendedProperty from the stream and add that to the list. Tag may be passed as in
        /// the case of Stroke ExtendedPropertyCollection where tag is stored in the stroke descriptor or 0 when tag
        /// is embeded in the stream
        /// </summary>
        /// <param name="stream">Memory buffer to load from</param>
        /// <param name="cbSize">Maximum length of buffer to read</param>
        /// <param name="guidList">Guid cache to read from</param>
        /// <param name="tag">Guid tag to lookup</param>
        /// <param name="guid">Guid of property</param>
        /// <param name="data">Data of property</param>
        /// <returns>Length of buffer read</returns>
#endif
        internal static uint DecodeAsISF(Stream stream, uint cbSize, GuidList guidList, KnownTagCache.KnownTagIndex tag, ref Guid guid, out object data)
        {
            uint cb, cbRead = 0;
            uint cbTotal = cbSize;

            if (0 == cbSize)
            {
                throw new InvalidOperationException(SR.Get(SRID.EmptyDataToLoad));
            }

            if (0 == tag) // no tag is passed, it must be embedded in the data
            {
                uint uiTag;
                cb = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;
                if (cb > cbTotal)
                    throw new ArgumentException(SR.Get(SRID.InvalidSizeSpecified), "cbSize");

                cbTotal -= cb;
                cbRead += cb;
                System.Diagnostics.Debug.Assert(guid == Guid.Empty);
                guid = guidList.FindGuid(tag);
            }

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

            // Try and find the size
            uint size = GuidList.GetDataSizeIfKnownGuid(guid);

            if (size > cbTotal)
                throw new ArgumentException(SR.Get(SRID.InvalidSizeSpecified), "cbSize");

            // if the size is 0
            if (0 == size)
            {
                // Size must be embedded in the stream. Find out the compressed data size
                cb = SerializationHelper.Decode(stream, out size);

                uint cbInsize = size + 1;

                cbRead += cb;
                cbTotal -= cb;
                if (cbInsize > cbTotal)
                    throw new ArgumentException();

                byte[] bytes = new byte[cbInsize];

                uint bytesRead = (uint) stream.Read(bytes, 0, (int)cbInsize);
                if (cbInsize != bytesRead)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "cbSize");
                }

                cbRead += cbInsize;
                cbTotal -= cbInsize;

		        //Find out the Decompressed buffer size
                using (MemoryStream decompressedStream = new MemoryStream(Compressor.DecompressPropertyData(bytes)))
                {
                    // Add the property
                    data = ExtendedPropertySerializer.DecodeAttribute(guid, decompressedStream);
                }
            }
            else
            {
                // For known size data, we just read the data directly from the stream
                byte[] bytes = new byte[size];

                uint bytesRead = (uint) stream.Read(bytes, 0, (int)size);
                if (size != bytesRead)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"), "cbSize");
                }

                using (MemoryStream subStream = new MemoryStream(bytes))
                {
                    data = ExtendedPropertySerializer.DecodeAttribute(guid, subStream);
                }

                cbTotal -= size;
                cbRead +=  size;
            }

            return cbRead;
        }
        private static void PersistRasterOperation(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        { 
            // write any non-default RasterOp value that we might have picked up from 
            // V1 interop or by setting IsHighlighter.
            if (da.RasterOperation != DrawingAttributeSerializer.RasterOperationDefaultV1) 
            {
                uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation);
                if (ropSize == 0)
                { 
                    throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data size was not found"));
                } 
 
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.RasterOperation, true)); 
                long currentPosition = stream.Position;
                bw.Write(da.RasterOperation);
                if ((uint)(stream.Position - currentPosition) != ropSize)
                { 
                    throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data was incorrectly serialized"));
                } 
                cbData += ropSize; 
            }
        } 
Example #29
0
        /// <summary>
        /// This functions loads a stroke from a memory stream based on the descriptor and GuidList. It returns
        /// the no of bytes it has read from the stream to correctly load the stream, which should be same as
        /// the value of the size parameter. If they are unequal throws ArgumentException. Stroke descriptor is
        /// used to load the packetproperty as well as ExtendedPropertyCollection on this stroke. Compressor is used
        /// to decompress the data.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="totalBytesInStrokeBlockOfIsfStream"></param>
        /// <param name="guidList"></param>
        /// <param name="strokeDescriptor"></param>
        /// <param name="stylusPointDescription"></param>
        /// <param name="transform"></param>
        /// <param name="stylusPoints"></param>
        /// <param name="extendedProperties"></param>
#endif
        static uint DecodeISFIntoStroke(
#if OLD_ISF
            Compressor compressor, 
#endif
            Stream stream, 
            uint totalBytesInStrokeBlockOfIsfStream, 
            GuidList guidList, 
            StrokeDescriptor strokeDescriptor,
            StylusPointDescription stylusPointDescription,
            Matrix transform,
            out StylusPointCollection stylusPoints, 
            out ExtendedPropertyCollection extendedProperties)
        {
            stylusPoints = null;
            extendedProperties = null;

            // We do allow a stroke with no packet data
            if (0 == totalBytesInStrokeBlockOfIsfStream)
            {
                return 0;
            }
             
            uint locallyDecodedBytes;
            uint remainingBytesInStrokeBlock = totalBytesInStrokeBlockOfIsfStream;

            // First try to load any packet data
            locallyDecodedBytes = LoadPackets(  stream, 
                                                remainingBytesInStrokeBlock, 
#if OLD_ISF
                                                compressor, 
#endif
                                                stylusPointDescription, 
                                                transform, 
                                                out stylusPoints);

            if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packet buffer overflowed the ISF stream"));

            remainingBytesInStrokeBlock -= locallyDecodedBytes;
            if (0 == remainingBytesInStrokeBlock)
            {
                return locallyDecodedBytes;
            }

            // Now read the extended propertes
            for (int iTag = 1; iTag < strokeDescriptor.Template.Count && remainingBytesInStrokeBlock > 0; iTag++)
            {
                KnownTagCache.KnownTagIndex tag = strokeDescriptor.Template[iTag - 1];

                switch (tag)
                {
                    case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.StrokePropertyList:
                        {
                            // we've found the stroke extended properties. Load them now.
                            while (iTag < strokeDescriptor.Template.Count && remainingBytesInStrokeBlock > 0)
                            {
                                tag = strokeDescriptor.Template[iTag];

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

                                // load the extended property data from the stream (and decode the type)
                                locallyDecodedBytes = ExtendedPropertySerializer.DecodeAsISF(stream, remainingBytesInStrokeBlock, guidList, tag, ref guid, out data);

                                // add the guid/data pair into the property collection (don't redecode the type)
                                if (extendedProperties == null)
                                {
                                    extendedProperties = new ExtendedPropertyCollection();
                                }
                                extendedProperties[guid] = data;
                                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                                remainingBytesInStrokeBlock -= locallyDecodedBytes;
                                iTag++;
                            }
                        }
                        break;

                    case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Buttons:
                        {
                            // Next tag is count of buttons and the tags for the button guids
                            iTag += (int)((uint)strokeDescriptor.Template[iTag]) + 1;
                        }
                        break;

                    // ignore any tags embedded in the Stroke block that this
                    //      version of the ISF decoder doesn't understand
                    default:
                        {
                            System.Diagnostics.Trace.WriteLine("Ignoring unhandled stroke tag in ISF stroke descriptor");
                        }
                        break;
                }
            }

            // Now try to load any tagged property data or point property data
            while (remainingBytesInStrokeBlock > 0)
            {
                // Read the tag first
                KnownTagCache.KnownTagIndex tag;
                uint uiTag;

                locallyDecodedBytes = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;
                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                remainingBytesInStrokeBlock -= locallyDecodedBytes;

                // if it is a point property block
                switch (tag)
                {
                    case MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.PointProperty:
                        {
                            // First load the totalBytesInStrokeBlockOfIsfStream of the point property block
                            uint cbsize;

                            locallyDecodedBytes = SerializationHelper.Decode(stream, out cbsize);
                            if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                            remainingBytesInStrokeBlock -= locallyDecodedBytes;
                            while (remainingBytesInStrokeBlock > 0)
                            {
                                // First read the tag corresponding to the property
                                locallyDecodedBytes = SerializationHelper.Decode(stream, out uiTag);
                                tag = (KnownTagCache.KnownTagIndex)uiTag;
                                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                                remainingBytesInStrokeBlock -= locallyDecodedBytes;

                                // Now read the packet index for which the property will apply
                                uint propindex;

                                locallyDecodedBytes = SerializationHelper.Decode(stream, out propindex);
                                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                                remainingBytesInStrokeBlock -= locallyDecodedBytes;

                                uint propsize;

                                locallyDecodedBytes = SerializationHelper.Decode(stream, out propsize);
                                if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                                remainingBytesInStrokeBlock -= locallyDecodedBytes;

                                // Compressed data totalBytesInStrokeBlockOfIsfStream
                                propsize += 1;

                                // Make sure we have enough data to read
                                if (propsize > remainingBytesInStrokeBlock)
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

                                byte[] in_buffer = new byte[propsize];

                                uint bytesRead = StrokeCollectionSerializer.ReliableRead(stream, in_buffer, propsize);
                                if (propsize != bytesRead)
                                {
                                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Read different size from stream then expected"));
                                }

                                byte[] out_buffer = Compressor.DecompressPropertyData(in_buffer);

                                System.Diagnostics.Debug.Assert(false, "ExtendedProperties for points are not supported");

                                // skip the bytes in both success & failure cases
                                // Note: Point ExtendedProperties are discarded
                                remainingBytesInStrokeBlock -= propsize;
                            }
                        }
                        break;

                    default:
                        {
                            object data;
                            Guid guid = guidList.FindGuid(tag);
                            if (guid == Guid.Empty)
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Stroke Custom Attribute tag embedded in ISF stream does not match guid table"));
                            }

                            // load the extended property data from the stream (and decode the type)
                            locallyDecodedBytes = ExtendedPropertySerializer.DecodeAsISF(stream, remainingBytesInStrokeBlock, guidList, tag, ref guid, out data);

                            // add the guid/data pair into the property collection (don't redecode the type)
                            if (extendedProperties == null)
                            {
                                extendedProperties = new ExtendedPropertyCollection();
                            }
                            extendedProperties[guid] = data;
                            if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                            {
                                throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ExtendedProperty decoded totalBytesInStrokeBlockOfIsfStream exceeded ISF stream totalBytesInStrokeBlockOfIsfStream"));
                            }

                            remainingBytesInStrokeBlock -= locallyDecodedBytes;
                        }
                        break;
                }
            }

            if (0 != remainingBytesInStrokeBlock)
                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data"));

            return totalBytesInStrokeBlockOfIsfStream;
        }
        /// <Summary> 
        /// Encodes the StylusTip in the ISF stream.
        /// </Summary> 
#endif
        private static void PersistStylusTip(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            // 
            // persist the StylusTip
            // 
            if (da.ContainsPropertyData(KnownIds.StylusTip)) 
            {
                System.Diagnostics.Debug.Assert(da.StylusTip != StylusTip.Ellipse, "StylusTip was put in the EPC for the default value!"); 

                //
                // persist PenTip.Rectangle for V1 ISF
                // 
                Debug.Assert(bw != null);
                cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.PenTip, true)); 
                cbData += SerializationHelper.Encode(stream, (uint)PenTip.Rectangle); 

                using (MemoryStream localStream = new MemoryStream(6)) //reasonable default 
                {
                    Int32 stylusTip = Convert.ToInt32(da.StylusTip, System.Globalization.CultureInfo.InvariantCulture);
                    System.Runtime.InteropServices.VarEnum type = SerializationHelper.ConvertToVarEnum(PersistenceTypes.StylusTip, true);
                    ExtendedPropertySerializer.EncodeAttribute(KnownIds.StylusTip, stylusTip, type, localStream); 

                    cbData += ExtendedPropertySerializer.EncodeAsISF(KnownIds.StylusTip, localStream.ToArray(), stream, guidList, 0, true); 
                } 
            }
        } 
Example #31
0
        private static void PersistWidthHeight(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
        {
            //persist the height and width
            // For v1 loaders we persist height and width in StylusHeight and StylusWidth
            double stylusWidth  = da.Width;
            double stylusHeight = da.Height;

            // Save the pen tip's width and height.
            for (int i = 0; i < 2; i++)
            {
                Guid   guid = (i == 0) ? KnownIds.StylusWidth : KnownIds.StylusHeight;
                double size = (0 == i) ? stylusWidth : stylusHeight;

                //
                // the size is now in Avalon units, we need to convert to HIMETRIC
                //
                size *= StrokeCollectionSerializer.AvalonToHimetricMultiplier;

                double sizeWhenMissing = (0 == i) ? V1PenWidthWhenWidthIsMissing : V1PenHeightWhenHeightIsMissing;

                //
                // only persist height / width if they are equal to the height / width
                // when missing in the isf stream OR for compatibility with V1
                //
                bool skipPersisting = DoubleUtil.AreClose(size, sizeWhenMissing);
                if (stylusWidth == stylusHeight &&
                    da.StylusTip == StylusTip.Ellipse &&
                    guid == KnownIds.StylusHeight &&
                    da.HeightChangedForCompatabity)
                {
                    //we need to put height in the ISF stream for compat
                    skipPersisting = true;
                }


                if (!skipPersisting)
                {
                    uint uIntegral = (uint)(size + 0.5f);

                    Debug.Assert(bw != null);
                    cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(guid, true));
                    cbData += SerializationHelper.Encode(stream, uIntegral);

                    short sFraction = (size > uIntegral) ? (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) + 0.5f) : (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) - 0.5);

                    // If the fractional values is non zero, we store this value along with TAG_MANTISSA and size with a precisson of 1000
                    if (0 != sFraction)
                    {
                        uint cb = Native.SizeOfUShort; // For header NO_COMPRESS

                        Debug.Assert(bw != null);
                        cbData += SerializationHelper.Encode(stream, (uint)MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Mantissa);
                        cbData += SerializationHelper.Encode(stream, cb);
                        bw.Write((byte)0x00);
                        bw.Write((short)sFraction);

                        cbData += cb + 1; // include size of encoded 0 and encoded fraction value
                    }
                }
            }
        }
        /// <summary>
        /// Encodes a custom attribute to the ISF stream
        /// </summary>
#endif
        internal static uint EncodeAsISF(Guid id, byte[] data, Stream strm, GuidList guidList, byte compressionAlgorithm, bool fTag)
        {
            uint cbWrite = 0;
            uint cbSize = GuidList.GetDataSizeIfKnownGuid(id);
            Debug.Assert(strm != null);

            if (fTag)
            {
                uint uTag = (uint)guidList.FindTag(id, true);

                cbWrite += SerializationHelper.Encode(strm, uTag);
            }

            // If cbSize is 0, it is either a custom property or a known property with 0
            // size. In either case, we need to write the size of the individual object
            if (0 == cbSize)
            {
                // Now we need to write the actual data for the property
                cbSize = (uint)data.Length;

                byte[] compresseddata = Compressor.CompressPropertyData(data, compressionAlgorithm);

#if OLD_ISF
                byte nAlgo = compressionAlgorithm;
                uint cbOut = 0;

                Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, null);

                // Allocate a buffer big enough to hold the compressed data
                byte[] compresseddata2 = new byte[cbOut];

                // NativeCompressor the data
                Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, compresseddata2);

                if (compresseddata.Length != compresseddata2.Length)
                {
                    throw new InvalidOperationException("MAGIC EXCEPTION: Property bytes length when compressed didn't match with new compression");
                }
                for (int i = 0; i < compresseddata.Length; i++)
                {
                    if (compresseddata[i] != compresseddata2[i])
                    {
                        throw new InvalidOperationException("MAGIC EXCEPTION: Property data didn't match with new property compression at index " + i.ToString());
                    }
                }
#endif

                // write the encoded compressed size minus the algo byte
                cbWrite += SerializationHelper.Encode(strm, (uint)(compresseddata.Length - 1));

                // Write the raw data
                strm.Write(compresseddata, 0, (int)compresseddata.Length);
                cbWrite += (uint)compresseddata.Length;
            }
            else
            {
                //
                // note that we used to write the nocompression byte, but that
                // was incorrect.  We must not write it because loaders do not 
                // expect it for known guids
                //
                // write the algo byte
                //strm.WriteByte(Compressor.NoCompression);
                //cbWrite++;
        
                // write the raw data without compression
                strm.Write(data, 0, (int)data.Length);
                cbWrite += (uint)data.Length;
            }

            return cbWrite;
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="strd"></param>
        /// <param name="block"></param>
        /// <param name="guidList"></param>
        /// <returns></returns>
        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<KnownTagCache.KnownTagIndex> 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<KnownTagCache.KnownTagIndex>();
                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<StylusPointPropertyInfo> stylusPointPropertyInfos = new List<StylusPointPropertyInfo>();
            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);
        }
        /// <summary>
        /// Saves all elements in this list in the stream passed with the tags being generated based on the GuidList
        /// by the caller and using compressionAlgorithm as the preferred algorith identifier. For ExtendedPropertyCollection associated
        /// with Ink, drawing attributes and Point properties, we need to write the tag while saving them and hence
        /// fTag param is true. For strokes, the Tag is stored in the stroke descriptor and hence we don't store the
        /// tag
        /// </summary>
        /// <param name="attributes">Custom attributes to encode</param>
        /// <param name="stream">If stream is null, then size is calculated only.</param>
        /// <param name="guidList"></param>
        /// <param name="compressionAlgorithm"></param>
        /// <param name="fTag"></param>
#endif
        internal static uint EncodeAsISF(ExtendedPropertyCollection attributes, Stream stream, GuidList guidList, byte compressionAlgorithm, bool fTag)
        {
            uint cbWrite = 0;

            for (int i = 0; i < attributes.Count; i++)
            {
                ExtendedProperty prop = attributes[i];

                using (MemoryStream localStream = new MemoryStream(10)) //reasonable default
                {
                    ExtendedPropertySerializer.EncodeToStream(prop, localStream);

                    byte[] data = localStream.ToArray(); 

                    cbWrite += ExtendedPropertySerializer.EncodeAsISF(prop.Id, data, stream, guidList, compressionAlgorithm, fTag);
                }
            }

            return cbWrite;
        }
        /// <Summary>
        /// Encodes all of the strokes in a strokecollection to ISF
        /// </Summary>
#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"));
            }
        }
        /// <summary>
        /// Builds the GuidList based on ExtendedPropeties and StrokeCollection
        /// </summary>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// 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
        /// </summary>
        /// <param name="stroke"></param>
        /// <param name="guidList"></param>
        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);
                }
            }
        }
Example #38
0
        /// <summary>
        /// Builds the Stroke Descriptor for this stroke based on Packet Layout and Extended Properties
        /// For details on how this is strored please refer to the spec.
        /// </summary>
        internal static void BuildStrokeDescriptor(
            Stroke stroke,
            GuidList guidList,
            StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry,
            out StrokeDescriptor strokeDescriptor,
            out MetricBlock metricBlock)
        {
            // Initialize the metric block for this stroke
            metricBlock = new MetricBlock();

            // Clear any existing template
            strokeDescriptor = new StrokeDescriptor();

            // Uninitialized variable passed in AddMetricEntry
            MetricEntryType        metricEntryType;
            StylusPointDescription stylusPointDescription = stroke.StylusPoints.Description;

            KnownTagCache.KnownTagIndex tag = guidList.FindTag(KnownIds.X, true);
            metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.X), tag);

            tag             = guidList.FindTag(KnownIds.Y, true);
            metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.Y), tag);

            ReadOnlyCollection <StylusPointPropertyInfo> propertyInfos
                = stylusPointDescription.GetStylusPointProperties();

            int i = 0; //i is defined out of the for loop so we can use it later for buttons

            for (i = 2 /*past x,y*/; i < propertyInfos.Count; i++)
            {
                if (i == /*StylusPointDescription.RequiredPressureIndex //修复构建的代码 */ 2 &&
                    !strokeLookupEntry.StorePressure)
                {
                    //
                    // don't store pressure information
                    //
                    continue;
                }
                StylusPointPropertyInfo propertyInfo = propertyInfos[i];
                if (propertyInfo.IsButton)
                {
                    //we don't serialize buttons
                    break;
                }

                tag = guidList.FindTag(propertyInfo.Id, true);

                strokeDescriptor.Template.Add(tag);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);

                // Create the MetricEntry for this property if necessary
                metricEntryType = metricBlock.AddMetricEntry(propertyInfo, tag);
            }

            /*
             * we drop button data on the floor.
             * int buttonCount = stylusPointDescription.ButtonCount;
             * // Now write the button tags in the Template
             * if (buttonCount > 0)
             * {
             *  // First write the TAG_BUTTONS
             *  strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.Buttons);
             *  strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.Buttons);
             *
             *  // Next write the i of buttons
             *  strokeDescriptor.Template.Add((KnownTagCache.KnownTagIndex)buttonCount);
             *  strokeDescriptor.Size += SerializationHelper.VarSize((uint)buttonCount);
             *
             *  //we broke above on i when it was a button, it still
             *  //points to the first button
             *  for (; i < propertyInfos.Count; i++)
             *  {
             *      StylusPointPropertyInfo propertyInfo = propertyInfos[i];
             *      tag = guidList.FindTag(propertyInfo.Id, false);
             *
             *      strokeDescriptor.Template.Add(tag);
             *      strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);
             *  }
             * }
             */

            // Now write the extended properties in the template
            if (stroke.ExtendedProperties.Count > 0)
            {
                strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.StrokePropertyList);
                strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.StrokePropertyList);

                // Now write the tags corresponding to each extended properties of the stroke
                for (int x = 0; x < stroke.ExtendedProperties.Count; x++)
                {
                    tag = guidList.FindTag(stroke.ExtendedProperties[(int)x].Id, false);

                    strokeDescriptor.Template.Add(tag);
                    strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag);
                }
            }
        }
Example #39
0
        /// <summary>
        /// Encodes a custom attribute to the ISF stream
        /// </summary>
#endif
        internal static uint EncodeAsISF(Guid id, byte[] data, Stream strm, GuidList guidList, byte compressionAlgorithm, bool fTag)
        {
            uint cbWrite = 0;
            uint cbSize  = GuidList.GetDataSizeIfKnownGuid(id);

            Debug.Assert(strm != null);

            if (fTag)
            {
                uint uTag = (uint)guidList.FindTag(id, true);

                cbWrite += SerializationHelper.Encode(strm, uTag);
            }

            // If cbSize is 0, it is either a custom property or a known property with 0
            // size. In either case, we need to write the size of the individual object
            if (0 == cbSize)
            {
                // Now we need to write the actual data for the property
                cbSize = (uint)data.Length;

                byte[] compresseddata = Compressor.CompressPropertyData(data, compressionAlgorithm);

#if OLD_ISF
                byte nAlgo = compressionAlgorithm;
                uint cbOut = 0;

                Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, null);

                // Allocate a buffer big enough to hold the compressed data
                byte[] compresseddata2 = new byte[cbOut];

                // NativeCompressor the data
                Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, compresseddata2);

                if (compresseddata.Length != compresseddata2.Length)
                {
                    throw new InvalidOperationException("MAGIC EXCEPTION: Property bytes length when compressed didn't match with new compression");
                }
                for (int i = 0; i < compresseddata.Length; i++)
                {
                    if (compresseddata[i] != compresseddata2[i])
                    {
                        throw new InvalidOperationException("MAGIC EXCEPTION: Property data didn't match with new property compression at index " + i.ToString());
                    }
                }
#endif

                // write the encoded compressed size minus the algo byte
                cbWrite += SerializationHelper.Encode(strm, (uint)(compresseddata.Length - 1));

                // Write the raw data
                strm.Write(compresseddata, 0, (int)compresseddata.Length);
                cbWrite += (uint)compresseddata.Length;
            }
            else
            {
                //
                // note that we used to write the nocompression byte, but that
                // was incorrect.  We must not write it because loaders do not
                // expect it for known guids
                //
                // write the algo byte
                //strm.WriteByte(Compressor.NoCompression);
                //cbWrite++;

                // write the raw data without compression
                strm.Write(data, 0, (int)data.Length);
                cbWrite += (uint)data.Length;
            }

            return(cbWrite);
        }