Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / Ink / InkSerializedFormat / StrokeSerializer.cs / 1 / StrokeSerializer.cs
//#define OLD_ISF //------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------- using System; using System.IO; using System.Security; using System.Diagnostics; using System.Windows; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows.Media; using System.Windows.Input; using System.Windows.Ink; using MS.Internal.Ink; using MS.Internal.IO.Packaging; namespace MS.Internal.Ink.InkSerializedFormat { internal static class StrokeSerializer { #region Decoding #region Public Methods #if OLD_ISF ////// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList /// /// /// /// /// /// /// /// /// Compression module /// Newly decoded stroke ////// /// Critical - calls the StrokeSerializer.DecodeISFIntoStroke critical method /// /// Called directly by StrokeCollectionSerializer.DecodeRawISF /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList /// /// /// /// /// /// /// /// /// Newly decoded stroke #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; } #if OLD_ISF ////// 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. /// /// /// /// /// /// /// /// /// /// ////// /// Critical - calls the ExtendedPropertySerializer.DecodeAsISF /// StrokeSerializer.LoadPackets /// and Compressor.DecompressPropertyData critical methods /// /// Called directly by StrokeSerializer.DecodeStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// 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. /// /// /// /// /// /// /// /// /// #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; } #if OLD_ISF ////// Loads packets from the input stream. For example, packets are all of the x's in a stroke /// ////// Critical - calls the Compressor.DecompressPacketData critical method /// /// Called directly by StrokeSerializer.DecodeISFIntoStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// Loads packets from the input stream. For example, packets are all of the x's in a stroke /// #endif static uint LoadPackets(Stream inputStream, uint totalBytesInStrokeBlockOfIsfStream, #if OLD_ISF Compressor compressor, #endif StylusPointDescription stylusPointDescription, Matrix transform, out StylusPointCollection stylusPoints) { stylusPoints = null; if (0 == totalBytesInStrokeBlockOfIsfStream) return 0; uint locallyDecodedBytesRemaining = totalBytesInStrokeBlockOfIsfStream; uint localBytesRead; // First read the no of packets uint pointCount; localBytesRead = SerializationHelper.Decode(inputStream, out pointCount); if (locallyDecodedBytesRemaining < localBytesRead) throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); locallyDecodedBytesRemaining -= localBytesRead; if (0 == locallyDecodedBytesRemaining) return localBytesRead; // Allocate packet properties int intsPerPoint = stylusPointDescription.GetInputArrayLengthPerPoint(); int buttonCount = stylusPointDescription.ButtonCount; int buttonIntsPerPoint = (buttonCount > 0 ? 1 : 0); int valueIntsPerPoint = intsPerPoint - buttonIntsPerPoint; //add one int per point for button data if it exists int[] rawPointData = new int[pointCount * intsPerPoint]; int[] packetDataSet = new int[pointCount]; // copy the rest of the data from the stroke data byte[] inputBuffer = new byte[locallyDecodedBytesRemaining]; // Read the input data into the byte array uint bytesRead = StrokeCollectionSerializer.ReliableRead(inputStream, inputBuffer, locallyDecodedBytesRemaining); if ( bytesRead != locallyDecodedBytesRemaining ) { // Make sure the bytes read are expected. If not, we should bail out. // An exception will be thrown. throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); } // at this point, we have read all of the bytes remaining in the input // stream's packet block, and while we will keep the bytes remaining // variable for positioning within the local byte buffer, we should // not read from the stream again, or we risk reading into another // ISF tag's block. int originalPressureIndex = stylusPointDescription.OriginalPressureIndex; for (int i = 0; i < valueIntsPerPoint && locallyDecodedBytesRemaining > 0; i++) { localBytesRead = locallyDecodedBytesRemaining; Compressor.DecompressPacketData( #if OLD_ISF compressor, #endif inputBuffer, ref localBytesRead, packetDataSet); if (localBytesRead > locallyDecodedBytesRemaining) throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); // // packetDataSet is like this: // ------------- // |X|X|X|X|X|X| // ------------- // // we need to copy into rawPointData at // // ------------- // |X| |X| |X| | // ------------- // // additionally, for NormalPressure, if it exists and was // reordered in the StylusPointDescription, we need to account for that here // int tempi = i; if (tempi > 1 && originalPressureIndex != -1 && originalPressureIndex != StylusPointDescription.RequiredPressureIndex/*2*/) { // // NormalPressure exists in the packet stream and was not at index 2 // StylusPointDescription enforces that NormalPressure is at index 2 // so we need to copy packet data beyond X and Y into a different location // // take the example of the original StylusPointDescription // |X|Y|XTilt|YTilt|NormalPressure|Rotation| // // originalPressureIndex is 4, and we know it is now 2 // which means that everything before index 4 has been shifted one // and everything after index 4 is still good. Index 4 should be copied to index 2 if (tempi == originalPressureIndex) { tempi = 2; } else if (tempi < originalPressureIndex) { tempi++; } } locallyDecodedBytesRemaining -= localBytesRead; for (int j = 0, x = 0; j < pointCount; j++, x += intsPerPoint) { rawPointData[x + tempi] = packetDataSet[j]; } // Move the array elements to point to next set of compressed data for (uint u = 0; u < locallyDecodedBytesRemaining; u++) { inputBuffer[u] = inputBuffer[u + (int)localBytesRead]; } } // Now that we've read packet data, we must read button data if it is there byte[] buttonData = null; // since the button state is a simple bit value (either down or up), the button state // for a series of packets is packed into an array of bits rather than integers // For example, if there are 16 packets, and 2 buttons, then 32 bits can be used (e.g. 1 32-bit integer) if (0 != locallyDecodedBytesRemaining && buttonCount > 0) { // calculate the number of full bytes used for buttons per packet // Example: 10 buttons would require 1 full byte int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte; // calculate the number of bits that spill beyond the full byte boundary // Example: 10 buttons would require 2 extra bits (8 fit in a full byte) int partialBitsForButtonsPerPacket = buttonCount % Native.BitsPerByte; // Now figure out how many bytes we need to read for the button data localBytesRead = (uint)((buttonCount * pointCount + 7) / Native.BitsPerByte); if (localBytesRead > locallyDecodedBytesRemaining) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Buffer range is smaller than expected expected size")); } locallyDecodedBytesRemaining -= localBytesRead; int buttonSizeInBytes = (buttonCount + 7)/Native.BitsPerByte; buttonData = new byte[pointCount * buttonSizeInBytes]; // Create a bit reader to unpack the bits from the ISF stream into // loosely packed byte buffer (e.g. button data aligned on full byte // boundaries only) BitStreamReader bitReader = new BitStreamReader(inputBuffer, (uint)buttonCount * pointCount); // unpack the button data into each packet int byteCounter = 0; while (!bitReader.EndOfStream) { // unpack the fully bytes first for (int fullBytes = 0; fullBytes < fullBytesForButtonsPerPacket; fullBytes++) { buttonData[byteCounter++] = bitReader.ReadByte(Native.BitsPerByte); } // then unpack a single partial byte if necessary if (partialBitsForButtonsPerPacket > 0) { buttonData[byteCounter++] = bitReader.ReadByte((int)partialBitsForButtonsPerPacket); } } // if the number of bytes allocated != necessary byte amount then an error occurred if (byteCounter != buttonData.Length) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Button data length not equal to expected length")); } // // set the point data in the raw array // FillButtonData( (int)pointCount, buttonCount, valueIntsPerPoint, //gives the first button index rawPointData, buttonData); } stylusPoints = new StylusPointCollection(stylusPointDescription, rawPointData, null, transform); // if we read too far into the stream (e.g. the packets were compressed) // then move the stream pointer back to the end of the actual packet // data before returning. This keeps the return value on the function // (representing bytes read) honest and consistent with the stream // position movement in this function. if (0 != locallyDecodedBytesRemaining) { inputStream.Seek(0 - (long)locallyDecodedBytesRemaining, SeekOrigin.Current); } return totalBytesInStrokeBlockOfIsfStream - locallyDecodedBytesRemaining; } ////// Fill packet buffer with button data /// /// how many points in the stroke /// how many buttons /// the first index of the buttons in packets /// packet data /// button data to fill private static void FillButtonData( int pointCount, int buttonCount, int buttonIndex, int[] packets, byte[] buttonData) { int intsPerPoint = buttonIndex + 1; int iPacket; int iDim = buttonIndex; //count of value properties // Get button data if (null != buttonData) { // Count of bytes per button int nBtnDim = (buttonCount + 7) / Native.BitsPerByte; // Count of complete integers int pointCountOfFullIntegers = (int)(nBtnDim / Native.SizeOfInt); // Remaining number of bytes in button data int pointCountOfPartialBytes = (int)(nBtnDim % Native.SizeOfInt); // Index into button byte array int iBtnByte = 0; // Copy the complete integers for (int iInt = 0; iInt < pointCountOfFullIntegers; ++iInt, ++iDim) { // Index into button byte array iBtnByte = (int)(iInt * Native.SizeOfInt); iPacket = iDim; // Get the button integers from each packet for (int i = 0; i < pointCount; ++i, iPacket += intsPerPoint, iBtnByte += nBtnDim) { packets[iPacket] = ((int)((uint)((buttonData[iBtnByte] << (Native.BitsPerByte * 3)) | (buttonData[iBtnByte + 1] << (Native.BitsPerByte * 2)) | (buttonData[iBtnByte + 2] << Native.BitsPerByte) | (buttonData[iBtnByte + 3])))); } } // If remaining number of bytes per button is non-negative, // construct button data from those bytes if (0 < pointCountOfPartialBytes) { // Index into button byte array iBtnByte = (int)(pointCountOfFullIntegers * Native.SizeOfInt); iPacket = iDim; // Constructs ints from partial button bytes for (int i = 0; i < pointCount; ++i, iPacket += intsPerPoint, iBtnByte += nBtnDim) { // First byte will always be there uint btn = buttonData[iBtnByte]; // For the remaining bytes, shift left 8 bits for (int iPart = 1; iPart < pointCountOfPartialBytes; ++iPart) { btn = (btn << Native.BitsPerByte) | (buttonData[iBtnByte + iPart]); } // Assign the reconstructed button data to packet data packets[iPacket] = (int)btn; } } } } #endregion #endregion // Decoding #region Encoding #region Public Methods #if OLD_ISF ////// Returns an array of bytes of the saved stroke /// /// Stroke to save /// null to calculate only the size /// /// /// /// ////// Critical - Calls the critical methods /// StrokeSerializer.SavePackets /// ExtendedPropertySerializer.EncodeAsISF /// /// This directly called by StrokeCollectionSerializer.StoreStrokeData /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Returns an array of bytes of the saved stroke /// /// Stroke to save /// null to calculate only the size /// /// /// #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; } ////// 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. /// 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); ReadOnlyCollectionpropertyInfos = 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); } } } #endregion // Private Methods #region Private methods #if OLD_ISF /// /// Saves the packets into a stream of bytes /// /// Stroke to save /// null to calculate size only /// /// ////// /// Critical - Calls the critical method StrokeSerializer.SavePacketPropertyData /// /// This directly called by StrokeSerializer.EncodeStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Saves the packets into a stream of bytes /// /// Stroke to save /// null to calculate size only /// #endif static uint SavePackets( Stroke stroke, Stream stream, #if OLD_ISF Compressor compressor, #endif StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry) { // First write or calculate how many points are there uint pointCount = (uint)stroke.StylusPoints.Count; uint localBytesWritten = (stream != null) ? SerializationHelper.Encode(stream, pointCount) : SerializationHelper.VarSize(pointCount); byte compressionAlgorithm; int[][] outputArrays = strokeLookupEntry.ISFReadyStrokeData; //We don't serialize button data, see Windows OS Bugs 1413460 for details //int valuesPerPoint = stroke.StylusPoints.Description.GetOutputArrayLengthPerPoint(); //int buttonCount = stroke.StylusPoints.Description.ButtonCount; ReadOnlyCollectionpropertyInfos = stroke.StylusPoints.Description.GetStylusPointProperties(); int i = 0; for (; i < propertyInfos.Count; i++) { StylusPointPropertyInfo propertyInfo = propertyInfos[i]; if (i == 2 && !strokeLookupEntry.StorePressure) { // // only store pressure if we need to // continue; } if (propertyInfo.IsButton) { // // we're at the buttons, handle this below // break; } compressionAlgorithm = strokeLookupEntry.CompressionData; localBytesWritten += SavePacketPropertyData(outputArrays[i], stream, #if OLD_ISF compressor, #endif propertyInfo.Id, ref compressionAlgorithm); } /* We don't serialize button data, see Windows OS Bugs 1413460 for details // Now write all button data. Button data is stored as if it is another packet property // with size (cbuttoncount + 7)/8 bytes and corresponding guids are stored in the packet // description. Button data is only stored if buttons are present in the description and there // are packets in the stroke if (buttonCount > 0 && pointCount > 0) { Debug.Assert(i == valuesPerPoint - 1); BitStreamWriter bitWriter = new BitStreamWriter(); // // Get the array of button data (i is still pointing at it) // int[] buttonData = outputArrays[i]; for (int x = 0; x < pointCount; x++) { // // each int in the button data array contains buttonCount number // of bits that need to be written to the BitStreamWriter // the BitStreamWriter takes bytes at a time. We always write the most // signifigant bits first // int uncompactedButtonDataForPoint = buttonData[x]; // calculate the number of full bytes used for buttons per packet // Example: 10 buttons would require 1 full byte // but 8 would require int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte; // calculate the number of bits that spill beyond the full byte boundary // Example: 10 buttons would require 2 extra bits (8 fit in a full byte) int bitsToWrite = buttonCount % Native.BitsPerByte; for (; fullBytesForButtonsPerPacket >= 0; fullBytesForButtonsPerPacket--) { byte byteOfButtonData = Convert.ToByte(uncompactedButtonDataForPoint >> (fullBytesForButtonsPerPacket * Native.BitsPerByte)); // // write 8 or less bytes to the bitwriter // checking for 0 handles the case where we're writing 8, 16 or 24 bytes // and bitsToWrite is initialize to zero // if (bitsToWrite > 0) { bitWriter.Write(byteOfButtonData, bitsToWrite); } if (fullBytesForButtonsPerPacket > 0) { bitsToWrite = Native.BitsPerByte; } } } // retrieve the button bytes byte[] packedButtonData = bitWriter.ToBytes(); if (packedButtonData.Length != ((buttonCount * pointCount + 7) / Native.BitsPerByte)) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packed button length not equal to expected length")); } // write out the packed button data to the output stream stream.Write(packedButtonData, 0, packedButtonData.Length); localBytesWritten += (uint)packedButtonData.Length; } */ return localBytesWritten; } #if OLD_ISF /// /// Saves the packets data corresponding to a packet property (identified by the guid) into the stream /// based on the Compression algorithm and compress header /// /// packet data to save /// null to calculate only the size /// /// /// ////// /// Critical - Calls unmanaged code in Compressor.CompressPacketData to compress /// an int[] representing packet data /// /// This directly called by StrokeSerializer.SavePackets /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Saves the packets data corresponding to a packet property (identified by the guid) into the stream /// based on the Compression algorithm and compress header /// /// packet data to save /// null to calculate only the size /// /// #endif static uint SavePacketPropertyData( int[] packetdata, Stream stream, #if OLD_ISF Compressor compressor, #endif Guid guid, ref byte algo) { if (packetdata.Length == 0) { return 0; } byte[] data = Compressor.CompressPacketData( #if OLD_ISF compressor, #endif packetdata, ref algo); Debug.Assert(stream != null); // Now write the data in the stream stream.Write(data, 0, (int)data.Length); return (uint)data.Length; } #endregion #endregion // Encoding } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //#define OLD_ISF //------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------- using System; using System.IO; using System.Security; using System.Diagnostics; using System.Windows; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows.Media; using System.Windows.Input; using System.Windows.Ink; using MS.Internal.Ink; using MS.Internal.IO.Packaging; namespace MS.Internal.Ink.InkSerializedFormat { internal static class StrokeSerializer { #region Decoding #region Public Methods #if OLD_ISF ////// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList /// /// /// /// /// /// /// /// /// Compression module /// Newly decoded stroke ////// /// Critical - calls the StrokeSerializer.DecodeISFIntoStroke critical method /// /// Called directly by StrokeCollectionSerializer.DecodeRawISF /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// Loads a stroke from the stream based on Stroke Descriptor, StylusPointDescription, Drawing Attributes, Stroke IDs, transform and GuidList /// /// /// /// /// /// /// /// /// Newly decoded stroke #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; } #if OLD_ISF ////// 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. /// /// /// /// /// /// /// /// /// /// ////// /// Critical - calls the ExtendedPropertySerializer.DecodeAsISF /// StrokeSerializer.LoadPackets /// and Compressor.DecompressPropertyData critical methods /// /// Called directly by StrokeSerializer.DecodeStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// 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. /// /// /// /// /// /// /// /// /// #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; } #if OLD_ISF ////// Loads packets from the input stream. For example, packets are all of the x's in a stroke /// ////// Critical - calls the Compressor.DecompressPacketData critical method /// /// Called directly by StrokeSerializer.DecodeISFIntoStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.DecodeRawISF /// [SecurityCritical] #else ////// Loads packets from the input stream. For example, packets are all of the x's in a stroke /// #endif static uint LoadPackets(Stream inputStream, uint totalBytesInStrokeBlockOfIsfStream, #if OLD_ISF Compressor compressor, #endif StylusPointDescription stylusPointDescription, Matrix transform, out StylusPointCollection stylusPoints) { stylusPoints = null; if (0 == totalBytesInStrokeBlockOfIsfStream) return 0; uint locallyDecodedBytesRemaining = totalBytesInStrokeBlockOfIsfStream; uint localBytesRead; // First read the no of packets uint pointCount; localBytesRead = SerializationHelper.Decode(inputStream, out pointCount); if (locallyDecodedBytesRemaining < localBytesRead) throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); locallyDecodedBytesRemaining -= localBytesRead; if (0 == locallyDecodedBytesRemaining) return localBytesRead; // Allocate packet properties int intsPerPoint = stylusPointDescription.GetInputArrayLengthPerPoint(); int buttonCount = stylusPointDescription.ButtonCount; int buttonIntsPerPoint = (buttonCount > 0 ? 1 : 0); int valueIntsPerPoint = intsPerPoint - buttonIntsPerPoint; //add one int per point for button data if it exists int[] rawPointData = new int[pointCount * intsPerPoint]; int[] packetDataSet = new int[pointCount]; // copy the rest of the data from the stroke data byte[] inputBuffer = new byte[locallyDecodedBytesRemaining]; // Read the input data into the byte array uint bytesRead = StrokeCollectionSerializer.ReliableRead(inputStream, inputBuffer, locallyDecodedBytesRemaining); if ( bytesRead != locallyDecodedBytesRemaining ) { // Make sure the bytes read are expected. If not, we should bail out. // An exception will be thrown. throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); } // at this point, we have read all of the bytes remaining in the input // stream's packet block, and while we will keep the bytes remaining // variable for positioning within the local byte buffer, we should // not read from the stream again, or we risk reading into another // ISF tag's block. int originalPressureIndex = stylusPointDescription.OriginalPressureIndex; for (int i = 0; i < valueIntsPerPoint && locallyDecodedBytesRemaining > 0; i++) { localBytesRead = locallyDecodedBytesRemaining; Compressor.DecompressPacketData( #if OLD_ISF compressor, #endif inputBuffer, ref localBytesRead, packetDataSet); if (localBytesRead > locallyDecodedBytesRemaining) throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Invalid ISF data")); // // packetDataSet is like this: // ------------- // |X|X|X|X|X|X| // ------------- // // we need to copy into rawPointData at // // ------------- // |X| |X| |X| | // ------------- // // additionally, for NormalPressure, if it exists and was // reordered in the StylusPointDescription, we need to account for that here // int tempi = i; if (tempi > 1 && originalPressureIndex != -1 && originalPressureIndex != StylusPointDescription.RequiredPressureIndex/*2*/) { // // NormalPressure exists in the packet stream and was not at index 2 // StylusPointDescription enforces that NormalPressure is at index 2 // so we need to copy packet data beyond X and Y into a different location // // take the example of the original StylusPointDescription // |X|Y|XTilt|YTilt|NormalPressure|Rotation| // // originalPressureIndex is 4, and we know it is now 2 // which means that everything before index 4 has been shifted one // and everything after index 4 is still good. Index 4 should be copied to index 2 if (tempi == originalPressureIndex) { tempi = 2; } else if (tempi < originalPressureIndex) { tempi++; } } locallyDecodedBytesRemaining -= localBytesRead; for (int j = 0, x = 0; j < pointCount; j++, x += intsPerPoint) { rawPointData[x + tempi] = packetDataSet[j]; } // Move the array elements to point to next set of compressed data for (uint u = 0; u < locallyDecodedBytesRemaining; u++) { inputBuffer[u] = inputBuffer[u + (int)localBytesRead]; } } // Now that we've read packet data, we must read button data if it is there byte[] buttonData = null; // since the button state is a simple bit value (either down or up), the button state // for a series of packets is packed into an array of bits rather than integers // For example, if there are 16 packets, and 2 buttons, then 32 bits can be used (e.g. 1 32-bit integer) if (0 != locallyDecodedBytesRemaining && buttonCount > 0) { // calculate the number of full bytes used for buttons per packet // Example: 10 buttons would require 1 full byte int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte; // calculate the number of bits that spill beyond the full byte boundary // Example: 10 buttons would require 2 extra bits (8 fit in a full byte) int partialBitsForButtonsPerPacket = buttonCount % Native.BitsPerByte; // Now figure out how many bytes we need to read for the button data localBytesRead = (uint)((buttonCount * pointCount + 7) / Native.BitsPerByte); if (localBytesRead > locallyDecodedBytesRemaining) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Buffer range is smaller than expected expected size")); } locallyDecodedBytesRemaining -= localBytesRead; int buttonSizeInBytes = (buttonCount + 7)/Native.BitsPerByte; buttonData = new byte[pointCount * buttonSizeInBytes]; // Create a bit reader to unpack the bits from the ISF stream into // loosely packed byte buffer (e.g. button data aligned on full byte // boundaries only) BitStreamReader bitReader = new BitStreamReader(inputBuffer, (uint)buttonCount * pointCount); // unpack the button data into each packet int byteCounter = 0; while (!bitReader.EndOfStream) { // unpack the fully bytes first for (int fullBytes = 0; fullBytes < fullBytesForButtonsPerPacket; fullBytes++) { buttonData[byteCounter++] = bitReader.ReadByte(Native.BitsPerByte); } // then unpack a single partial byte if necessary if (partialBitsForButtonsPerPacket > 0) { buttonData[byteCounter++] = bitReader.ReadByte((int)partialBitsForButtonsPerPacket); } } // if the number of bytes allocated != necessary byte amount then an error occurred if (byteCounter != buttonData.Length) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Button data length not equal to expected length")); } // // set the point data in the raw array // FillButtonData( (int)pointCount, buttonCount, valueIntsPerPoint, //gives the first button index rawPointData, buttonData); } stylusPoints = new StylusPointCollection(stylusPointDescription, rawPointData, null, transform); // if we read too far into the stream (e.g. the packets were compressed) // then move the stream pointer back to the end of the actual packet // data before returning. This keeps the return value on the function // (representing bytes read) honest and consistent with the stream // position movement in this function. if (0 != locallyDecodedBytesRemaining) { inputStream.Seek(0 - (long)locallyDecodedBytesRemaining, SeekOrigin.Current); } return totalBytesInStrokeBlockOfIsfStream - locallyDecodedBytesRemaining; } ////// Fill packet buffer with button data /// /// how many points in the stroke /// how many buttons /// the first index of the buttons in packets /// packet data /// button data to fill private static void FillButtonData( int pointCount, int buttonCount, int buttonIndex, int[] packets, byte[] buttonData) { int intsPerPoint = buttonIndex + 1; int iPacket; int iDim = buttonIndex; //count of value properties // Get button data if (null != buttonData) { // Count of bytes per button int nBtnDim = (buttonCount + 7) / Native.BitsPerByte; // Count of complete integers int pointCountOfFullIntegers = (int)(nBtnDim / Native.SizeOfInt); // Remaining number of bytes in button data int pointCountOfPartialBytes = (int)(nBtnDim % Native.SizeOfInt); // Index into button byte array int iBtnByte = 0; // Copy the complete integers for (int iInt = 0; iInt < pointCountOfFullIntegers; ++iInt, ++iDim) { // Index into button byte array iBtnByte = (int)(iInt * Native.SizeOfInt); iPacket = iDim; // Get the button integers from each packet for (int i = 0; i < pointCount; ++i, iPacket += intsPerPoint, iBtnByte += nBtnDim) { packets[iPacket] = ((int)((uint)((buttonData[iBtnByte] << (Native.BitsPerByte * 3)) | (buttonData[iBtnByte + 1] << (Native.BitsPerByte * 2)) | (buttonData[iBtnByte + 2] << Native.BitsPerByte) | (buttonData[iBtnByte + 3])))); } } // If remaining number of bytes per button is non-negative, // construct button data from those bytes if (0 < pointCountOfPartialBytes) { // Index into button byte array iBtnByte = (int)(pointCountOfFullIntegers * Native.SizeOfInt); iPacket = iDim; // Constructs ints from partial button bytes for (int i = 0; i < pointCount; ++i, iPacket += intsPerPoint, iBtnByte += nBtnDim) { // First byte will always be there uint btn = buttonData[iBtnByte]; // For the remaining bytes, shift left 8 bits for (int iPart = 1; iPart < pointCountOfPartialBytes; ++iPart) { btn = (btn << Native.BitsPerByte) | (buttonData[iBtnByte + iPart]); } // Assign the reconstructed button data to packet data packets[iPacket] = (int)btn; } } } } #endregion #endregion // Decoding #region Encoding #region Public Methods #if OLD_ISF ////// Returns an array of bytes of the saved stroke /// /// Stroke to save /// null to calculate only the size /// /// /// /// ////// Critical - Calls the critical methods /// StrokeSerializer.SavePackets /// ExtendedPropertySerializer.EncodeAsISF /// /// This directly called by StrokeCollectionSerializer.StoreStrokeData /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Returns an array of bytes of the saved stroke /// /// Stroke to save /// null to calculate only the size /// /// /// #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; } ////// 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. /// 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); ReadOnlyCollectionpropertyInfos = 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); } } } #endregion // Private Methods #region Private methods #if OLD_ISF /// /// Saves the packets into a stream of bytes /// /// Stroke to save /// null to calculate size only /// /// ////// /// Critical - Calls the critical method StrokeSerializer.SavePacketPropertyData /// /// This directly called by StrokeSerializer.EncodeStroke /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Saves the packets into a stream of bytes /// /// Stroke to save /// null to calculate size only /// #endif static uint SavePackets( Stroke stroke, Stream stream, #if OLD_ISF Compressor compressor, #endif StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry) { // First write or calculate how many points are there uint pointCount = (uint)stroke.StylusPoints.Count; uint localBytesWritten = (stream != null) ? SerializationHelper.Encode(stream, pointCount) : SerializationHelper.VarSize(pointCount); byte compressionAlgorithm; int[][] outputArrays = strokeLookupEntry.ISFReadyStrokeData; //We don't serialize button data, see Windows OS Bugs 1413460 for details //int valuesPerPoint = stroke.StylusPoints.Description.GetOutputArrayLengthPerPoint(); //int buttonCount = stroke.StylusPoints.Description.ButtonCount; ReadOnlyCollectionpropertyInfos = stroke.StylusPoints.Description.GetStylusPointProperties(); int i = 0; for (; i < propertyInfos.Count; i++) { StylusPointPropertyInfo propertyInfo = propertyInfos[i]; if (i == 2 && !strokeLookupEntry.StorePressure) { // // only store pressure if we need to // continue; } if (propertyInfo.IsButton) { // // we're at the buttons, handle this below // break; } compressionAlgorithm = strokeLookupEntry.CompressionData; localBytesWritten += SavePacketPropertyData(outputArrays[i], stream, #if OLD_ISF compressor, #endif propertyInfo.Id, ref compressionAlgorithm); } /* We don't serialize button data, see Windows OS Bugs 1413460 for details // Now write all button data. Button data is stored as if it is another packet property // with size (cbuttoncount + 7)/8 bytes and corresponding guids are stored in the packet // description. Button data is only stored if buttons are present in the description and there // are packets in the stroke if (buttonCount > 0 && pointCount > 0) { Debug.Assert(i == valuesPerPoint - 1); BitStreamWriter bitWriter = new BitStreamWriter(); // // Get the array of button data (i is still pointing at it) // int[] buttonData = outputArrays[i]; for (int x = 0; x < pointCount; x++) { // // each int in the button data array contains buttonCount number // of bits that need to be written to the BitStreamWriter // the BitStreamWriter takes bytes at a time. We always write the most // signifigant bits first // int uncompactedButtonDataForPoint = buttonData[x]; // calculate the number of full bytes used for buttons per packet // Example: 10 buttons would require 1 full byte // but 8 would require int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte; // calculate the number of bits that spill beyond the full byte boundary // Example: 10 buttons would require 2 extra bits (8 fit in a full byte) int bitsToWrite = buttonCount % Native.BitsPerByte; for (; fullBytesForButtonsPerPacket >= 0; fullBytesForButtonsPerPacket--) { byte byteOfButtonData = Convert.ToByte(uncompactedButtonDataForPoint >> (fullBytesForButtonsPerPacket * Native.BitsPerByte)); // // write 8 or less bytes to the bitwriter // checking for 0 handles the case where we're writing 8, 16 or 24 bytes // and bitsToWrite is initialize to zero // if (bitsToWrite > 0) { bitWriter.Write(byteOfButtonData, bitsToWrite); } if (fullBytesForButtonsPerPacket > 0) { bitsToWrite = Native.BitsPerByte; } } } // retrieve the button bytes byte[] packedButtonData = bitWriter.ToBytes(); if (packedButtonData.Length != ((buttonCount * pointCount + 7) / Native.BitsPerByte)) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packed button length not equal to expected length")); } // write out the packed button data to the output stream stream.Write(packedButtonData, 0, packedButtonData.Length); localBytesWritten += (uint)packedButtonData.Length; } */ return localBytesWritten; } #if OLD_ISF /// /// Saves the packets data corresponding to a packet property (identified by the guid) into the stream /// based on the Compression algorithm and compress header /// /// packet data to save /// null to calculate only the size /// /// /// ////// /// Critical - Calls unmanaged code in Compressor.CompressPacketData to compress /// an int[] representing packet data /// /// This directly called by StrokeSerializer.SavePackets /// /// TreatAsSafe boundary is StrokeCollectionSerializer.EncodeISF /// /// [SecurityCritical] #else ////// Saves the packets data corresponding to a packet property (identified by the guid) into the stream /// based on the Compression algorithm and compress header /// /// packet data to save /// null to calculate only the size /// /// #endif static uint SavePacketPropertyData( int[] packetdata, Stream stream, #if OLD_ISF Compressor compressor, #endif Guid guid, ref byte algo) { if (packetdata.Length == 0) { return 0; } byte[] data = Compressor.CompressPacketData( #if OLD_ISF compressor, #endif packetdata, ref algo); Debug.Assert(stream != null); // Now write the data in the stream stream.Write(data, 0, (int)data.Length); return (uint)data.Length; } #endregion #endregion // Encoding } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HtmlInputButton.cs
- HttpListenerRequestUriBuilder.cs
- MetadataUtilsSmi.cs
- PathSegment.cs
- VideoDrawing.cs
- Collection.cs
- UnsafeNativeMethods.cs
- Transactions.cs
- IntSecurity.cs
- Ray3DHitTestResult.cs
- BinaryReader.cs
- ToggleButtonAutomationPeer.cs
- PageThemeParser.cs
- ProfileParameter.cs
- InternalSafeNativeMethods.cs
- MdImport.cs
- HierarchicalDataBoundControlAdapter.cs
- SymbolPair.cs
- XmlParser.cs
- WebPartDisplayMode.cs
- ListParagraph.cs
- MimeBasePart.cs
- NavigationPropertyAccessor.cs
- ImportContext.cs
- HandlerBase.cs
- Trace.cs
- Vector3D.cs
- MessageLogTraceRecord.cs
- SafeNativeMethodsMilCoreApi.cs
- GenerateDerivedKeyRequest.cs
- EditingCommands.cs
- UniqueIdentifierService.cs
- XmlUtil.cs
- SimpleApplicationHost.cs
- DataTable.cs
- XmlEncoding.cs
- EntityDataSourceContainerNameItem.cs
- DocumentSequenceHighlightLayer.cs
- LocalizationParserHooks.cs
- COM2PictureConverter.cs
- MarkupWriter.cs
- StringSource.cs
- ByteFacetDescriptionElement.cs
- TreeView.cs
- ReceiveActivityDesigner.cs
- SqlTopReducer.cs
- clipboard.cs
- SafeHandles.cs
- LinqDataSourceContextData.cs
- TextMarkerSource.cs
- DataGridViewCheckBoxColumn.cs
- TypeDescriptorFilterService.cs
- AccessedThroughPropertyAttribute.cs
- TimeSpanConverter.cs
- CodeNamespace.cs
- TextRangeEditTables.cs
- ResourceReferenceExpressionConverter.cs
- SoundPlayerAction.cs
- OLEDB_Enum.cs
- ArrayEditor.cs
- __ConsoleStream.cs
- Vector3DCollectionConverter.cs
- User.cs
- HMACSHA384.cs
- StringValidatorAttribute.cs
- DataReaderContainer.cs
- NumericExpr.cs
- SessionEndedEventArgs.cs
- ReflectionPermission.cs
- EmptyEnumerator.cs
- XMLSchema.cs
- DataGridSortCommandEventArgs.cs
- InternalBufferOverflowException.cs
- Rectangle.cs
- HandlerBase.cs
- StretchValidation.cs
- BroadcastEventHelper.cs
- SwitchElementsCollection.cs
- TypefaceMap.cs
- LinkClickEvent.cs
- PrimitiveCodeDomSerializer.cs
- FormConverter.cs
- ExpressionList.cs
- Rule.cs
- CodeCompiler.cs
- ObjectContext.cs
- ConnectionConsumerAttribute.cs
- SoapIgnoreAttribute.cs
- LineProperties.cs
- DBAsyncResult.cs
- HostVisual.cs
- DataGridCaption.cs
- SRDisplayNameAttribute.cs
- ScriptResourceInfo.cs
- UserNameSecurityTokenProvider.cs
- ListBase.cs
- GridViewSelectEventArgs.cs
- RuntimeCompatibilityAttribute.cs
- SubclassTypeValidatorAttribute.cs
- SocketManager.cs