/// <summary> /// Adds a new metric entry in the existing list of metric entries /// </summary> /// <param name="property"></param> /// <param name="tag"></param> /// <returns></returns> public MetricEntryType AddMetricEntry(StylusPointPropertyInfo property, KnownTagCache.KnownTagIndex tag) { // Create a new metric entry based on the packet information passed. MetricEntry entry = new MetricEntry(); MetricEntryType type = entry.CreateMetricEntry(property, tag); // Don't add this entry to the global list if size is 0, means default metric values! if (0 == entry.Size) { return(type); } MetricEntry start = _Entry; if (null == start) { _Entry = entry; } else // tack on data at the end, want to keep x,y at the beginning { while (start.Next != null) { start = start.Next; } start.Next = entry; } _Count++; _size += entry.Size + SerializationHelper.VarSize(entry.Size) + SerializationHelper.VarSize((uint)_Entry.Tag); return(type); }
/// <summary> /// Finds a guid based on Tag /// </summary> /// <param name="tag"></param> /// <returns></returns> public Guid FindGuid(KnownTagCache.KnownTagIndex tag) { if (tag < (KnownTagCache.KnownTagIndex)KnownIdCache.CustomGuidBaseIndex) { Guid guid = FindKnownGuid(tag); if (Guid.Empty != guid) { return(guid); } return(FindCustomGuid(tag)); } else { Guid guid = FindCustomGuid(tag); if (Guid.Empty != guid) { return(guid); } return(FindKnownGuid(tag)); } }
/// <summary> /// Creates a metric entry based on a PropertyInfo and Tag and returns the Metric Entry Type created /// </summary> /// <param name="propertyInfo"></param> /// <param name="tag"></param> /// <returns></returns> public MetricEntryType CreateMetricEntry(StylusPointPropertyInfo propertyInfo, KnownTagCache.KnownTagIndex tag) { // First create the default Metric entry based on the property and type of metric entry and then use that to initialize the // metric entry data. uint index = 0; Tag = tag; MetricEntryType type; if (IsValidMetricEntry(propertyInfo, Tag, out type, out index)) { switch (type) { case MetricEntryType.Optional: { Initialize(propertyInfo, MetricEntry_Optional[index].PropertyMetrics); break; } case MetricEntryType.Must: case MetricEntryType.Custom: Initialize(propertyInfo, DefaultPropertyMetrics); break; default: throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("MetricEntryType was persisted with Never flag which should never happen")); } } return(type); }
/// <summary> /// Finds a Custom Guid based on a Tag /// </summary> /// <param name="tag"></param> /// <returns></returns> Guid FindCustomGuid(KnownTagCache.KnownTagIndex tag) { if ((int)tag < (int)KnownIdCache.CustomGuidBaseIndex) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Tag is outside of the known guid tag range")); } // Get the index in the OriginalISFIdTable array first int nIndex = (int)(tag - KnownIdCache.CustomGuidBaseIndex); // If invalid, return Guid.Empty if ((0 > nIndex) || (_CustomGuids.Count <= nIndex)) { return(Guid.Empty); } // Otherwise, return the guid return((Guid)_CustomGuids[(int)nIndex]); }
/// <summary> /// Finds a known guid based on a Tag /// </summary> /// <param name="tag"></param> /// <returns></returns> static Guid FindKnownGuid(KnownTagCache.KnownTagIndex tag) { if (tag < KnownIdCache.KnownGuidBaseIndex) { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Tag is outside of the known guid tag range")); } // Get the index in the OriginalISFIdTable array first uint nIndex = (uint)(tag - KnownIdCache.KnownGuidBaseIndex); // If invalid, return Guid.Empty if (KnownIdCache.OriginalISFIdTable.Length <= nIndex) { return(Guid.Empty); } // Otherwise, return the guid return(KnownIdCache.OriginalISFIdTable[nIndex]); }
/// <summary> /// Finds a tag corresponding to a guids /// </summary> /// <param name="guid"></param> /// <param name="bFindInKnownListFirst"></param> /// <returns></returns> public KnownTagCache.KnownTagIndex FindTag(Guid guid, bool bFindInKnownListFirst) { KnownTagCache.KnownTagIndex tag = KnownTagCache.KnownTagIndex.Unknown; if (bFindInKnownListFirst) { tag = FindKnownTag(guid); if (KnownTagCache.KnownTagIndex.Unknown == tag) { tag = FindCustomTag(guid); } } else { tag = FindCustomTag(guid); if (KnownTagCache.KnownTagIndex.Unknown == tag) { tag = FindKnownTag(guid); } } return(tag); }
/// <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); } } }
/// <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); }
public MetricEntryList (KnownTagCache.KnownTagIndex tag, StylusPointPropertyInfo prop) { Tag = tag; PropertyMetrics = prop; }
/// <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 checks if this packet property results in a valid metric entry. This will be a valid entry if /// 1. it is a custom property, 2. Does not belong to the global list of gaMetricEntry_Never, 3. Belongs to the /// global list of gaMetricEntry_Must and 4. Belongs to global list of gaMetricEntry_Optional and at least one of /// its metric values is different from the corresponding default. /// </summary> /// <param name="propertyInfo"></param> /// <param name="tag"></param> /// <param name="metricEntryType"></param> /// <param name="index"></param> /// <returns></returns> static bool IsValidMetricEntry(StylusPointPropertyInfo propertyInfo, KnownTagCache.KnownTagIndex tag, out MetricEntryType metricEntryType, out uint index) { index = 0; // If this is a custom property, check if all the Metric values are null or not. If they are then this is not a // valid metric entry if (tag >= (KnownTagCache.KnownTagIndex)KnownIdCache.CustomGuidBaseIndex) { metricEntryType = MetricEntryType.Custom; if (Int32.MinValue == propertyInfo.Minimum && Int32.MaxValue == propertyInfo.Maximum && StylusPointPropertyUnit.None == propertyInfo.Unit && DoubleUtil.AreClose(1.0, propertyInfo.Resolution)) { return(false); } else { return(true); } } else { int ul; // First find the property in the gaMetricEntry_Never. If it belongs to this list, // we will never write the metric table for this prop. So return FALSE; for (ul = 0; ul < MetricEntry_Never.Length; ul++) { if (MetricEntry_Never[ul] == tag) { metricEntryType = MetricEntryType.Never; return(false); } } // Then search the property in the gaMetricEntry_Must list. If it belongs to this list, // we must always write the metric table for this prop. So return TRUE; for (ul = 0; ul < MetricEntry_Must.Length; ul++) { if (MetricEntry_Must[ul] == tag) { metricEntryType = MetricEntryType.Must; if (propertyInfo.Minimum == DefaultPropertyMetrics.Minimum && propertyInfo.Maximum == DefaultPropertyMetrics.Maximum && propertyInfo.Unit == DefaultPropertyMetrics.Unit && DoubleUtil.AreClose(propertyInfo.Resolution, DefaultPropertyMetrics.Resolution)) { return(false); } else { return(true); } } } // Now seach it in the gaMetricEntry_Optional list. If it is there, check the metric values // agianst the default values and if there is any non default value, return TRUE; for (ul = 0; ul < MetricEntry_Optional.Length; ul++) { if (((MetricEntryList)MetricEntry_Optional[ul]).Tag == tag) { metricEntryType = MetricEntryType.Optional; if (propertyInfo.Minimum == MetricEntry_Optional[ul].PropertyMetrics.Minimum && propertyInfo.Maximum == MetricEntry_Optional[ul].PropertyMetrics.Maximum && propertyInfo.Unit == MetricEntry_Optional[ul].PropertyMetrics.Unit && DoubleUtil.AreClose(propertyInfo.Resolution, MetricEntry_Optional[ul].PropertyMetrics.Resolution)) { return(false); } else { index = (uint)ul; return(true); } } } // it is not found in any of the list. Force to write all metric entries for the property. metricEntryType = MetricEntryType.Must; return(true); } }
public MetricEntryList(KnownTagCache.KnownTagIndex tag, StylusPointPropertyInfo prop) { Tag = tag; PropertyMetrics = prop; }