/// <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; }
public MetricEntryList (KnownTagCache.KnownTagIndex tag, StylusPointPropertyInfo prop) { Tag = tag; PropertyMetrics = prop; }
/// <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> /// 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> /// 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; } }
/// <summary> /// Sets the Property Metrics for a property based on Tag and metric descriptor block /// </summary> /// <param name="guid"></param> /// <param name="tag"></param> /// <param name="block"></param> /// <returns></returns> private StylusPointPropertyInfo GetStylusPointPropertyInfo(Guid guid, KnownTagCache.KnownTagIndex tag, MetricBlock block) { int dw = 0; bool fSetDefault = false; uint cbEntry; // StylusPointPropertyInfo values that we need to read in. int minimum = 0; int maximum = 0; StylusPointPropertyUnit unit = StylusPointPropertyUnit.None; float resolution = 1.0f; // To begin with initialize the property metrics with respective default valuses // first check if this property belongs to optional list for (dw = 0; dw < 11; dw++) { if (MetricEntry.MetricEntry_Optional[dw].Tag == tag) { minimum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Minimum; maximum = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Maximum; resolution = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Resolution; unit = MetricEntry.MetricEntry_Optional[dw].PropertyMetrics.Unit; fSetDefault = true; break; } } if (false == fSetDefault) { // We will come here if the property is not found in the Optional List // All other cases, we will have only default values minimum = Int32.MinValue; maximum = Int32.MaxValue; unit = StylusPointPropertyUnit.None; resolution = 1.0f; fSetDefault = true; } // Now see if there is a valid MetricBlock. If there is one, update the PROPERTY_METRICS with // values from this Block if (null != block) { MetricEntry entry = block.GetMetricEntryList(); while (null != entry) { if (entry.Tag == tag) { cbEntry = 0; int range; using (MemoryStream strm = new MemoryStream(entry.Data)) { // Decoded the Logical Min cbEntry += SerializationHelper.SignDecode(strm, out range); if (cbEntry >= entry.Size) { break; // return false; } minimum = range; // Logical Max cbEntry += SerializationHelper.SignDecode(strm, out range); if (cbEntry >= entry.Size) { break; // return false; } maximum = range; uint cb; // Units cbEntry += SerializationHelper.Decode(strm, out cb); unit = (StylusPointPropertyUnit)cb; if (cbEntry >= entry.Size) { break; // return false; } using (BinaryReader br = new BinaryReader(strm)) { resolution = br.ReadSingle(); cbEntry += Native.SizeOfFloat; } } break; } entry = entry.Next; } } // return a new StylusPointPropertyInfo return new StylusPointPropertyInfo( new StylusPointProperty(guid, StylusPointPropertyIds.IsKnownButton(guid)), minimum, maximum, unit, resolution); }
/// <summary> /// Reads and Decodes a Transfrom Descriptor Block from the stream. For information on how it is stored in the stream, /// please refer to the spec. /// </summary> /// <param name="strm"></param> /// <param name="tag"></param> /// <param name="cbSize"></param> /// <param name="useDoubles"></param> /// <param name="xform"></param> /// <returns></returns> private uint DecodeTransformBlock(Stream strm, KnownTagCache.KnownTagIndex tag, uint cbSize, bool useDoubles, out TransformDescriptor xform) { xform = new TransformDescriptor(); xform.Tag = tag; uint cbRead = 0; uint cbTotal = cbSize; if (0 == cbSize) return 0; // samgeo - Presharp issue // Presharp gives a warning when local IDisposable variables are not closed // in this case, we can't call Dispose since it will also close the underlying stream // which still needs to be read from #pragma warning disable 1634, 1691 #pragma warning disable 6518 BinaryReader bw = new BinaryReader(strm); if (KnownTagCache.KnownTagIndex.TransformRotate == tag) { uint angle; cbRead = SerializationHelper.Decode(strm, out angle); if (cbRead > cbSize) throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); xform.Transform[0] = (double)angle; xform.Size = 1; } else { if (tag == KnownTagCache.KnownTagIndex.TransformIsotropicScale) { xform.Size = 1; } else if (tag == KnownTagCache.KnownTagIndex.TransformAnisotropicScale || tag == KnownTagCache.KnownTagIndex.TransformTranslate) { xform.Size = 2; } else if (tag == KnownTagCache.KnownTagIndex.TransformScaleAndTranslate) { xform.Size = 4; } else { xform.Size = 6; } if (useDoubles) { cbRead = xform.Size * Native.SizeOfDouble; } else { cbRead = xform.Size * Native.SizeOfFloat; } if (cbRead > cbSize) throw new ArgumentException(ISFDebugMessage("Invalid ISF data"),"strm"); for (int i = 0; i < xform.Size; i++) { if (useDoubles) { xform.Transform[i] = bw.ReadDouble(); } else { xform.Transform[i] = (double)bw.ReadSingle(); } } } return cbRead; #pragma warning restore 6518 #pragma warning restore 1634, 1691 }
/// <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> /// 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]; }