Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / Ink / InkSerializedFormat / GorillaCodec.cs / 1305600 / GorillaCodec.cs
using MS.Utility; using System; using System.Runtime.InteropServices; using System.Security; using System.Globalization; using System.Windows; using System.Windows.Input; using System.Windows.Ink; using MS.Internal.Ink.InkSerializedFormat; using System.Collections.Generic; using System.Diagnostics; using SR = MS.Internal.PresentationCore.SR; using SRID = MS.Internal.PresentationCore.SRID; namespace MS.Internal.Ink.InkSerializedFormat { ////// Represents a simple encoding scheme that removes non-significant bits /// internal class GorillaCodec { ////// GorillaCodec /// public GorillaCodec() { } ////// Static ctor /// static GorillaCodec() { //magic numbers _gorIndexMap = new GorillaAlgoByte[] { // cBits cPads Index new GorillaAlgoByte(8, 0), // 0 // for 1 new GorillaAlgoByte(1, 0), // 1 new GorillaAlgoByte(1, 1), // 2 new GorillaAlgoByte(1, 2), // 3 new GorillaAlgoByte(1, 3), // 4 new GorillaAlgoByte(1, 4), // 5 new GorillaAlgoByte(1, 5), // 6 new GorillaAlgoByte(1, 6), // 7 new GorillaAlgoByte(1, 7), // 8 // for 2 new GorillaAlgoByte(2, 0), // 9 new GorillaAlgoByte(2, 1), // 10 new GorillaAlgoByte(2, 2), // 11 new GorillaAlgoByte(2, 3), // 12 // for 3 new GorillaAlgoByte(3, 0), // 13 new GorillaAlgoByte(3, 1), // 14 new GorillaAlgoByte(3, 2), // 15 // for 4 new GorillaAlgoByte(4, 0), // 16 new GorillaAlgoByte(4, 1), // 17 // for 5 new GorillaAlgoByte(5, 0), // 18 new GorillaAlgoByte(5, 1), // 19 // for 6 new GorillaAlgoByte(6, 0), // 20 new GorillaAlgoByte(6, 1), // 21 // for 7 new GorillaAlgoByte(7, 0), // 22 new GorillaAlgoByte(7, 1)}; // 23 _gorIndexOffset = new byte[]{ 0, // for 0, never used 1, // [ 1, 8] for 1 9, // [ 9, 12] for 2 13, // [13, 15] for 3 16, // [16, 17] for 4 18, // [18, 19] for 5 20, // [20, 21] for 6 22};// [22, 23] for 7 } ////// FindPacketAlgoByte /// /// input stream to find the best compression for /// internal byte FindPacketAlgoByte(int[] input, bool testDelDel) { if (input == null) { throw new ArgumentNullException("input"); } // Check for the input item count if (0 == input.Length) { return 0; } // If the input count is less than 3, we cannot do del del testDelDel = testDelDel && (input.Length < 3); int minVal, maxVal; int minDelDel, maxDelDel; uint startIndex = 1; int xfData = 0, xfExtra = 0; DeltaDelta delDel = new DeltaDelta(); // Initialize all the max-min's to initial value minVal = maxVal = minDelDel = maxDelDel = input[0]; // Skip first two elements for del-del if (testDelDel) { delDel.Transform(input[0], ref xfData, ref xfExtra); delDel.Transform(input[1], ref xfData, ref xfExtra); // if we need extra bits, we cannot do del-del if (0 != xfExtra) { testDelDel = false; } } // Initialize DelDelMax/Min if we can do del-del if (testDelDel) { delDel.Transform(input[2], ref xfData, ref xfExtra); // Again, if nExtra is non-zero, we cannot do del-del if (0 != xfExtra) { testDelDel = false; } else { minDelDel = maxDelDel = xfData; // Update raw max/min for two elements UpdateMinMax(input[1], ref maxVal, ref minVal); UpdateMinMax(input[2], ref maxVal, ref minVal); // Following loop starts from 3 startIndex = 3; } } for (uint dataIndex = startIndex; dataIndex < input.Length; dataIndex++) { // Update the raw min-max first UpdateMinMax(input[dataIndex], ref maxVal, ref minVal); if (testDelDel) { // If we can do del-del, first do the transformation delDel.Transform(input[dataIndex], ref xfData, ref xfExtra); // again, cannot do del-del if xfExtra is non-zero // otherwise, update the del-del min/max if (0 != xfExtra) { testDelDel = false; } else { UpdateMinMax(xfData, ref maxDelDel, ref minDelDel); } } } // Find the absolute max for del-del uint ulAbsMaxDelDel = (uint)Math.Max(MathHelper.AbsNoThrow(minDelDel), MathHelper.AbsNoThrow(maxDelDel)); // Find the Math.Abs max for raw uint ulAbsMax = (uint)Math.Max(MathHelper.AbsNoThrow(minVal), MathHelper.AbsNoThrow(maxVal)); // If we could do del-del and Math.Abs max of del-del is at least twice smaller than // original, we do del-del, otherwise, we bitpack raw data if (testDelDel && ((ulAbsMaxDelDel >> 1) < ulAbsMax)) { ulAbsMax = ulAbsMaxDelDel; } else { testDelDel = false; } // Absolute bits int bitCount = 0; while ((0 != (ulAbsMax >> bitCount)) && (31 > bitCount)) { bitCount++; } // Sign bit bitCount++; // Return the algo data return (byte)((byte)(bitCount & 0x1F) | (testDelDel ? (byte)0x20 : (byte)0)); } ////// FindPropAlgoByte - find the best way to compress the input array /// /// internal byte FindPropAlgoByte(byte[] input) { // Empty buffer case if(0 == input.Length) { return 0; } // We test for int's only if the data size is multiple of 4 int countOfInts = ((0 == (input.Length & 0x03)) ? input.Length >> 2 : 0); BitStreamReader intReader = null; if (countOfInts > 0) { intReader = new BitStreamReader(input); } // We test for shorts's if datasize is multiple of 2 int countOfShorts = ((0 == (input.Length & 0x01)) ? input.Length >> 1 : 0); BitStreamReader shortReader = null; if (countOfShorts > 0) { shortReader = new BitStreamReader(input); } // Min Max variables for different data type int maxInt = 0, minInt = 0; // Unsigned min vals ushort maxShort = 0; // byte min/max byte maxByte = input[0]; // Find min/max of all data // This loop covers: // All of int data, if there is any // First half of Word data, if there is int data, there MUST be word data // First quarter of byte data. uint n = 0; for(n = 0; n < countOfInts; ++n) { Debug.Assert(intReader != null); Debug.Assert(shortReader != null); maxByte = Math.Max(input[n], maxByte); maxShort = Math.Max((ushort)shortReader.ReadUInt16Reverse(Native.BitsPerShort), maxShort); UpdateMinMax((int)intReader.ReadUInt32Reverse(Native.BitsPerInt), ref maxInt, ref minInt); } // This loop covers: // Second half of short data, if there were int data, // or all of short data, if there were no int data // Upto half of byte data for(; n < countOfShorts; ++n) { Debug.Assert(shortReader != null); maxByte = Math.Max(input[n], maxByte); maxShort = Math.Max((ushort)shortReader.ReadUInt16Reverse(Native.BitsPerShort), maxShort); } // This loop covers last half of byte data if word data existed // or, all of bytes data for (; n < input.Length; ++n) { maxByte = Math.Max(input[n], maxByte); } // Which one gives the best result? int bitCount = 1; // Find the Math.Abs max for byte uint ulAbsMax = (uint)maxByte; // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> bitCount)) && (bitCount < (uint)Native.BitsPerByte)) { bitCount++; } // Also compute the padding required int padCount = ((((~(bitCount * input.Length)) & 0x07) + 1) & 0x07) / bitCount; // Compare the result with word partition if (countOfShorts > 0) { int shortBitCount = 1; // Find the Math.Abs max for word ulAbsMax = (uint)maxShort; // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> shortBitCount)) && (shortBitCount < (uint)Native.BitsPerShort)) { shortBitCount++; } // Determine which scheme requires lesser number of bytes if (shortBitCount < (bitCount << 1)) { bitCount = shortBitCount; padCount = ((((~(bitCount * countOfShorts)) & 0x07) + 1) & 0x07) / bitCount; } else { countOfShorts = 0; } } // Compare the best with int if(countOfInts > 0) { int intBitCount = 0; // Find the Math.Abs max for int ulAbsMax = (uint)Math.Max(MathHelper.AbsNoThrow(minInt), MathHelper.AbsNoThrow(maxInt)); // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> intBitCount)) && (31 > intBitCount)) { intBitCount++; } // Adjust for the sign bit intBitCount++; // Determine which one is better if (intBitCount < ((0 < countOfShorts) ? (bitCount << 1) : (bitCount << 2))) { bitCount = intBitCount; padCount = ((((~(bitCount * countOfInts)) & 0x07) + 1) & 0x07) / bitCount; // Set the countOfShorts to 0 to indicate int wins over word countOfShorts = 0; } else { countOfInts = 0; } } // AlgoByte starts with 000, 001 and 01 for byte, word and int correspondingly byte algorithmByte = (byte)((0 < countOfInts) ? 0x40 : ((0 < countOfShorts) ? 0x20 : 0x00)); // If byte, and bitCount is 8, we revert use 0 as algo byte if ((8 == bitCount) && (0 == (countOfInts + countOfShorts))) { algorithmByte = 0; } // If bitCount is more than 7, we add 16 to make the index else if (bitCount > 7) { algorithmByte |= (byte)(16 + bitCount); } // Otherwise, we find the index from the table else { algorithmByte |= (byte)(_gorIndexOffset[bitCount] + padCount); } return algorithmByte; } ////// GetPropertyBitCount /// /// /// /// /// internal void GetPropertyBitCount(byte algorithmByte, ref int countPerItem, ref int bitCount, ref int padCount) { int index = 0; if (0 != (algorithmByte & 0x40)) { countPerItem = 4; index = (int)algorithmByte & 0x3F; } else { countPerItem = (0 != (algorithmByte & 0x20)) ? 2 : 1; index = (int)algorithmByte & 0x1F; } bitCount = index - 16; padCount = 0; if (index < _gorIndexMap.Length && index >= 0) { bitCount = (int)_gorIndexMap[index].BitCount; padCount = (int)_gorIndexMap[index].PadCount; } } ////// Compress - compress the input[] into compressedData /// /// The count of bits needed for all elements /// input buffer /// offset into the input buffer /// data transform. can be null /// The list of bytes to write the compressed input to internal void Compress(int bitCount, int[] input, int startInputIndex, DeltaDelta dtxf, ListcompressedData) { if (null == input || null == compressedData) { throw new ArgumentNullException(StrokeCollectionSerializer.ISFDebugMessage("input or compressed data was null in Compress")); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) bitCount = (int)(Native.SizeOfInt << 3); } //have the writer adapt to the List passed in and write to it BitStreamWriter writer = new BitStreamWriter(compressedData); if (null != dtxf) { int xfData = 0; int xfExtra = 0; for (int i = startInputIndex; i < input.Length; i++) { dtxf.Transform(input[i], ref xfData, ref xfExtra); if (xfExtra != 0) { throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("Transform returned unexpected results")); } writer.Write((uint)xfData, bitCount); } } else { for (int i = startInputIndex; i < input.Length; i++) { writer.Write((uint)input[i], bitCount); } } } /// /// Compress - compresses the byte[] being read by the BitStreamReader into compressed data /// /// the number of bits to use for each element /// a reader over the byte[] to compress /// int, short or byte? /// number of logical units to encoded /// output write buffer internal void Compress(int bitCount, BitStreamReader reader, GorillaEncodingType encodingType, int unitsToEncode, ListcompressedData) { if (null == reader || null == compressedData) { throw new ArgumentNullException(StrokeCollectionSerializer.ISFDebugMessage("reader or compressedData was null in compress")); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (unitsToEncode < 0) { throw new ArgumentOutOfRangeException("unitsToEncode"); } if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) switch (encodingType) { case GorillaEncodingType.Int: { bitCount = Native.BitsPerInt; break; } case GorillaEncodingType.Short: { bitCount = Native.BitsPerShort; break; } case GorillaEncodingType.Byte: { bitCount = Native.BitsPerByte; break; } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to compress")); } } } //have the writer adapt to the List passed in and write to it BitStreamWriter writer = new BitStreamWriter(compressedData); while (!reader.EndOfStream && unitsToEncode > 0) { int data = GetDataFromReader(reader, encodingType); writer.Write((uint)data, bitCount); unitsToEncode--; } } /// /// Private helper used to read an int, short or byte (in reverse order) from the reader /// and return an int /// /// /// ///private int GetDataFromReader(BitStreamReader reader, GorillaEncodingType type) { switch (type) { case GorillaEncodingType.Int: { return (int)reader.ReadUInt32Reverse(Native.BitsPerInt); } case GorillaEncodingType.Short: { return (int)reader.ReadUInt16Reverse(Native.BitsPerShort); } case GorillaEncodingType.Byte: { return (int)reader.ReadByte(Native.BitsPerByte); } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to GetDataFromReader")); } } } /// /// Uncompress - uncompress a byte[] into an int[] of point data (x,x,x,x,x) /// /// The number of bits each element uses in input /// compressed data /// index to begin decoding at /// data xf, can be null /// output buffer that is prealloc'd to write to /// the index of the output buffer to write to internal uint Uncompress(int bitCount, byte[] input, int inputIndex, DeltaDelta dtxf, int[] outputBuffer, int outputBufferIndex) { if (null == input) { throw new ArgumentNullException("input"); } if (inputIndex >= input.Length) { throw new ArgumentOutOfRangeException("inputIndex"); } if (null == outputBuffer) { throw new ArgumentNullException("outputBuffer"); } if (outputBufferIndex >= outputBuffer.Length) { throw new ArgumentOutOfRangeException("outputBufferIndex"); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } // Adjust bit count if 0 passed in if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) bitCount = (int)(Native.SizeOfInt << 3); } // Test whether the items are signed. For unsigned number, we don't need mask // If we are trying to compress signed long values with bit count = 5 // The mask will be 1111 1111 1111 0000. The way it is done is, if the 5th // bit is 1, the number is negative numbe, othrwise it's positive. Testing // will be non-zero, ONLY if the 5th bit is 1, in which case we OR with the mask // otherwise we leave the number as it is. uint bitMask = (unchecked((uint)~0) << (bitCount - 1)); uint bitData = 0; BitStreamReader reader = new BitStreamReader(input, inputIndex); if(dtxf != null) { while (!reader.EndOfStream) { bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; int result = dtxf.InverseTransform((int)bitData, 0); Debug.Assert(outputBufferIndex < outputBuffer.Length); outputBuffer[outputBufferIndex++] = result; if (outputBufferIndex == outputBuffer.Length) { //only write as much as the outputbuffer can hold //this is assumed by calling code break; } } } else { while (!reader.EndOfStream) { bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; Debug.Assert(outputBufferIndex < outputBuffer.Length); outputBuffer[outputBufferIndex++] = (int)bitData; if (outputBufferIndex == outputBuffer.Length) { //only write as much as the outputbuffer can hold //this is assumed by calling code break; } } } // Calculate how many bytes were read from input buffer return (uint)((outputBuffer.Length * bitCount + 7) >> 3); } ////// Uncompress - uncompress the byte[] in the reader to a byte[] to return /// /// number of bits each element is compressed to /// a reader over the compressed byte[] /// int, short or byte? /// number of logical units to decode ///Uncompressed byte[] internal byte[] Uncompress(int bitCount, BitStreamReader reader, GorillaEncodingType encodingType, int unitsToDecode) { if (null == reader) { throw new ArgumentNullException("reader"); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (unitsToDecode < 0) { throw new ArgumentOutOfRangeException("unitsToDecode"); } int bitsToWrite = 0; // Test whether the items are signed. For unsigned number, we don't need mask // If we are trying to compress signed long values with bit count = 5 // The mask will be 1111 1111 1111 0000. The way it is done is, if the 5th // bit is 1, the number is negative numbe, othrwise it's positive. Testing // will be non-zero, ONLY if the 5th bit is 1, in which case we OR with the mask // otherwise we leave the number as it is. uint bitMask = 0; //adjust if the bitcount is 0 //(this makes bitCount 32) switch (encodingType) { case GorillaEncodingType.Int: { if (bitCount == 0) { bitCount = Native.BitsPerInt; } bitsToWrite = Native.BitsPerInt; //we decode int's as unsigned, so we need to create a mask bitMask = (unchecked((uint)~0) << (bitCount - 1)); break; } case GorillaEncodingType.Short: { if (bitCount == 0) { bitCount = Native.BitsPerShort; } bitsToWrite = Native.BitsPerShort; //shorts are decoded as unsigned values, no mask required bitMask = 0; break; } case GorillaEncodingType.Byte: { if (bitCount == 0) { bitCount = Native.BitsPerByte; } bitsToWrite = Native.BitsPerByte; //bytes are decoded as unsigned values, no mask required bitMask = 0; break; } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to Uncompress")); } } Listoutput = new List ((bitsToWrite / 8) * unitsToDecode); BitStreamWriter writer = new BitStreamWriter(output); uint bitData = 0; while (!reader.EndOfStream && unitsToDecode > 0) { //we're going to cast to an uint anyway, just read as one bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; writer.WriteReverse(bitData, bitsToWrite); unitsToDecode--; } return output.ToArray(); } /// /// UpdateMinMax /// /// number to evaluate /// a ref to the max, which will be updated if n is more /// a ref to the min, which will be updated if n is less private static void UpdateMinMax(int n, ref int max, ref int min) { if (n > max) { max = n; } else if (n < min) { min = n; } } ////// Private statics /// private static GorillaAlgoByte[] _gorIndexMap; private static byte[] _gorIndexOffset; } ////// Helper struct /// internal struct GorillaAlgoByte { public GorillaAlgoByte(uint bitCount, uint padCount) { BitCount = bitCount; PadCount = padCount; } public uint BitCount; public uint PadCount; } ////// Simple helper enum to control Gorilla encoding in Compress /// internal enum GorillaEncodingType { Byte = 0, Short, Int, } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using MS.Utility; using System; using System.Runtime.InteropServices; using System.Security; using System.Globalization; using System.Windows; using System.Windows.Input; using System.Windows.Ink; using MS.Internal.Ink.InkSerializedFormat; using System.Collections.Generic; using System.Diagnostics; using SR = MS.Internal.PresentationCore.SR; using SRID = MS.Internal.PresentationCore.SRID; namespace MS.Internal.Ink.InkSerializedFormat { ////// Represents a simple encoding scheme that removes non-significant bits /// internal class GorillaCodec { ////// GorillaCodec /// public GorillaCodec() { } ////// Static ctor /// static GorillaCodec() { //magic numbers _gorIndexMap = new GorillaAlgoByte[] { // cBits cPads Index new GorillaAlgoByte(8, 0), // 0 // for 1 new GorillaAlgoByte(1, 0), // 1 new GorillaAlgoByte(1, 1), // 2 new GorillaAlgoByte(1, 2), // 3 new GorillaAlgoByte(1, 3), // 4 new GorillaAlgoByte(1, 4), // 5 new GorillaAlgoByte(1, 5), // 6 new GorillaAlgoByte(1, 6), // 7 new GorillaAlgoByte(1, 7), // 8 // for 2 new GorillaAlgoByte(2, 0), // 9 new GorillaAlgoByte(2, 1), // 10 new GorillaAlgoByte(2, 2), // 11 new GorillaAlgoByte(2, 3), // 12 // for 3 new GorillaAlgoByte(3, 0), // 13 new GorillaAlgoByte(3, 1), // 14 new GorillaAlgoByte(3, 2), // 15 // for 4 new GorillaAlgoByte(4, 0), // 16 new GorillaAlgoByte(4, 1), // 17 // for 5 new GorillaAlgoByte(5, 0), // 18 new GorillaAlgoByte(5, 1), // 19 // for 6 new GorillaAlgoByte(6, 0), // 20 new GorillaAlgoByte(6, 1), // 21 // for 7 new GorillaAlgoByte(7, 0), // 22 new GorillaAlgoByte(7, 1)}; // 23 _gorIndexOffset = new byte[]{ 0, // for 0, never used 1, // [ 1, 8] for 1 9, // [ 9, 12] for 2 13, // [13, 15] for 3 16, // [16, 17] for 4 18, // [18, 19] for 5 20, // [20, 21] for 6 22};// [22, 23] for 7 } ////// FindPacketAlgoByte /// /// input stream to find the best compression for /// internal byte FindPacketAlgoByte(int[] input, bool testDelDel) { if (input == null) { throw new ArgumentNullException("input"); } // Check for the input item count if (0 == input.Length) { return 0; } // If the input count is less than 3, we cannot do del del testDelDel = testDelDel && (input.Length < 3); int minVal, maxVal; int minDelDel, maxDelDel; uint startIndex = 1; int xfData = 0, xfExtra = 0; DeltaDelta delDel = new DeltaDelta(); // Initialize all the max-min's to initial value minVal = maxVal = minDelDel = maxDelDel = input[0]; // Skip first two elements for del-del if (testDelDel) { delDel.Transform(input[0], ref xfData, ref xfExtra); delDel.Transform(input[1], ref xfData, ref xfExtra); // if we need extra bits, we cannot do del-del if (0 != xfExtra) { testDelDel = false; } } // Initialize DelDelMax/Min if we can do del-del if (testDelDel) { delDel.Transform(input[2], ref xfData, ref xfExtra); // Again, if nExtra is non-zero, we cannot do del-del if (0 != xfExtra) { testDelDel = false; } else { minDelDel = maxDelDel = xfData; // Update raw max/min for two elements UpdateMinMax(input[1], ref maxVal, ref minVal); UpdateMinMax(input[2], ref maxVal, ref minVal); // Following loop starts from 3 startIndex = 3; } } for (uint dataIndex = startIndex; dataIndex < input.Length; dataIndex++) { // Update the raw min-max first UpdateMinMax(input[dataIndex], ref maxVal, ref minVal); if (testDelDel) { // If we can do del-del, first do the transformation delDel.Transform(input[dataIndex], ref xfData, ref xfExtra); // again, cannot do del-del if xfExtra is non-zero // otherwise, update the del-del min/max if (0 != xfExtra) { testDelDel = false; } else { UpdateMinMax(xfData, ref maxDelDel, ref minDelDel); } } } // Find the absolute max for del-del uint ulAbsMaxDelDel = (uint)Math.Max(MathHelper.AbsNoThrow(minDelDel), MathHelper.AbsNoThrow(maxDelDel)); // Find the Math.Abs max for raw uint ulAbsMax = (uint)Math.Max(MathHelper.AbsNoThrow(minVal), MathHelper.AbsNoThrow(maxVal)); // If we could do del-del and Math.Abs max of del-del is at least twice smaller than // original, we do del-del, otherwise, we bitpack raw data if (testDelDel && ((ulAbsMaxDelDel >> 1) < ulAbsMax)) { ulAbsMax = ulAbsMaxDelDel; } else { testDelDel = false; } // Absolute bits int bitCount = 0; while ((0 != (ulAbsMax >> bitCount)) && (31 > bitCount)) { bitCount++; } // Sign bit bitCount++; // Return the algo data return (byte)((byte)(bitCount & 0x1F) | (testDelDel ? (byte)0x20 : (byte)0)); } ////// FindPropAlgoByte - find the best way to compress the input array /// /// internal byte FindPropAlgoByte(byte[] input) { // Empty buffer case if(0 == input.Length) { return 0; } // We test for int's only if the data size is multiple of 4 int countOfInts = ((0 == (input.Length & 0x03)) ? input.Length >> 2 : 0); BitStreamReader intReader = null; if (countOfInts > 0) { intReader = new BitStreamReader(input); } // We test for shorts's if datasize is multiple of 2 int countOfShorts = ((0 == (input.Length & 0x01)) ? input.Length >> 1 : 0); BitStreamReader shortReader = null; if (countOfShorts > 0) { shortReader = new BitStreamReader(input); } // Min Max variables for different data type int maxInt = 0, minInt = 0; // Unsigned min vals ushort maxShort = 0; // byte min/max byte maxByte = input[0]; // Find min/max of all data // This loop covers: // All of int data, if there is any // First half of Word data, if there is int data, there MUST be word data // First quarter of byte data. uint n = 0; for(n = 0; n < countOfInts; ++n) { Debug.Assert(intReader != null); Debug.Assert(shortReader != null); maxByte = Math.Max(input[n], maxByte); maxShort = Math.Max((ushort)shortReader.ReadUInt16Reverse(Native.BitsPerShort), maxShort); UpdateMinMax((int)intReader.ReadUInt32Reverse(Native.BitsPerInt), ref maxInt, ref minInt); } // This loop covers: // Second half of short data, if there were int data, // or all of short data, if there were no int data // Upto half of byte data for(; n < countOfShorts; ++n) { Debug.Assert(shortReader != null); maxByte = Math.Max(input[n], maxByte); maxShort = Math.Max((ushort)shortReader.ReadUInt16Reverse(Native.BitsPerShort), maxShort); } // This loop covers last half of byte data if word data existed // or, all of bytes data for (; n < input.Length; ++n) { maxByte = Math.Max(input[n], maxByte); } // Which one gives the best result? int bitCount = 1; // Find the Math.Abs max for byte uint ulAbsMax = (uint)maxByte; // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> bitCount)) && (bitCount < (uint)Native.BitsPerByte)) { bitCount++; } // Also compute the padding required int padCount = ((((~(bitCount * input.Length)) & 0x07) + 1) & 0x07) / bitCount; // Compare the result with word partition if (countOfShorts > 0) { int shortBitCount = 1; // Find the Math.Abs max for word ulAbsMax = (uint)maxShort; // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> shortBitCount)) && (shortBitCount < (uint)Native.BitsPerShort)) { shortBitCount++; } // Determine which scheme requires lesser number of bytes if (shortBitCount < (bitCount << 1)) { bitCount = shortBitCount; padCount = ((((~(bitCount * countOfShorts)) & 0x07) + 1) & 0x07) / bitCount; } else { countOfShorts = 0; } } // Compare the best with int if(countOfInts > 0) { int intBitCount = 0; // Find the Math.Abs max for int ulAbsMax = (uint)Math.Max(MathHelper.AbsNoThrow(minInt), MathHelper.AbsNoThrow(maxInt)); // Find the number of bits required to encode that number while ((0 != (ulAbsMax >> intBitCount)) && (31 > intBitCount)) { intBitCount++; } // Adjust for the sign bit intBitCount++; // Determine which one is better if (intBitCount < ((0 < countOfShorts) ? (bitCount << 1) : (bitCount << 2))) { bitCount = intBitCount; padCount = ((((~(bitCount * countOfInts)) & 0x07) + 1) & 0x07) / bitCount; // Set the countOfShorts to 0 to indicate int wins over word countOfShorts = 0; } else { countOfInts = 0; } } // AlgoByte starts with 000, 001 and 01 for byte, word and int correspondingly byte algorithmByte = (byte)((0 < countOfInts) ? 0x40 : ((0 < countOfShorts) ? 0x20 : 0x00)); // If byte, and bitCount is 8, we revert use 0 as algo byte if ((8 == bitCount) && (0 == (countOfInts + countOfShorts))) { algorithmByte = 0; } // If bitCount is more than 7, we add 16 to make the index else if (bitCount > 7) { algorithmByte |= (byte)(16 + bitCount); } // Otherwise, we find the index from the table else { algorithmByte |= (byte)(_gorIndexOffset[bitCount] + padCount); } return algorithmByte; } ////// GetPropertyBitCount /// /// /// /// /// internal void GetPropertyBitCount(byte algorithmByte, ref int countPerItem, ref int bitCount, ref int padCount) { int index = 0; if (0 != (algorithmByte & 0x40)) { countPerItem = 4; index = (int)algorithmByte & 0x3F; } else { countPerItem = (0 != (algorithmByte & 0x20)) ? 2 : 1; index = (int)algorithmByte & 0x1F; } bitCount = index - 16; padCount = 0; if (index < _gorIndexMap.Length && index >= 0) { bitCount = (int)_gorIndexMap[index].BitCount; padCount = (int)_gorIndexMap[index].PadCount; } } ////// Compress - compress the input[] into compressedData /// /// The count of bits needed for all elements /// input buffer /// offset into the input buffer /// data transform. can be null /// The list of bytes to write the compressed input to internal void Compress(int bitCount, int[] input, int startInputIndex, DeltaDelta dtxf, ListcompressedData) { if (null == input || null == compressedData) { throw new ArgumentNullException(StrokeCollectionSerializer.ISFDebugMessage("input or compressed data was null in Compress")); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) bitCount = (int)(Native.SizeOfInt << 3); } //have the writer adapt to the List passed in and write to it BitStreamWriter writer = new BitStreamWriter(compressedData); if (null != dtxf) { int xfData = 0; int xfExtra = 0; for (int i = startInputIndex; i < input.Length; i++) { dtxf.Transform(input[i], ref xfData, ref xfExtra); if (xfExtra != 0) { throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("Transform returned unexpected results")); } writer.Write((uint)xfData, bitCount); } } else { for (int i = startInputIndex; i < input.Length; i++) { writer.Write((uint)input[i], bitCount); } } } /// /// Compress - compresses the byte[] being read by the BitStreamReader into compressed data /// /// the number of bits to use for each element /// a reader over the byte[] to compress /// int, short or byte? /// number of logical units to encoded /// output write buffer internal void Compress(int bitCount, BitStreamReader reader, GorillaEncodingType encodingType, int unitsToEncode, ListcompressedData) { if (null == reader || null == compressedData) { throw new ArgumentNullException(StrokeCollectionSerializer.ISFDebugMessage("reader or compressedData was null in compress")); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (unitsToEncode < 0) { throw new ArgumentOutOfRangeException("unitsToEncode"); } if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) switch (encodingType) { case GorillaEncodingType.Int: { bitCount = Native.BitsPerInt; break; } case GorillaEncodingType.Short: { bitCount = Native.BitsPerShort; break; } case GorillaEncodingType.Byte: { bitCount = Native.BitsPerByte; break; } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to compress")); } } } //have the writer adapt to the List passed in and write to it BitStreamWriter writer = new BitStreamWriter(compressedData); while (!reader.EndOfStream && unitsToEncode > 0) { int data = GetDataFromReader(reader, encodingType); writer.Write((uint)data, bitCount); unitsToEncode--; } } /// /// Private helper used to read an int, short or byte (in reverse order) from the reader /// and return an int /// /// /// ///private int GetDataFromReader(BitStreamReader reader, GorillaEncodingType type) { switch (type) { case GorillaEncodingType.Int: { return (int)reader.ReadUInt32Reverse(Native.BitsPerInt); } case GorillaEncodingType.Short: { return (int)reader.ReadUInt16Reverse(Native.BitsPerShort); } case GorillaEncodingType.Byte: { return (int)reader.ReadByte(Native.BitsPerByte); } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to GetDataFromReader")); } } } /// /// Uncompress - uncompress a byte[] into an int[] of point data (x,x,x,x,x) /// /// The number of bits each element uses in input /// compressed data /// index to begin decoding at /// data xf, can be null /// output buffer that is prealloc'd to write to /// the index of the output buffer to write to internal uint Uncompress(int bitCount, byte[] input, int inputIndex, DeltaDelta dtxf, int[] outputBuffer, int outputBufferIndex) { if (null == input) { throw new ArgumentNullException("input"); } if (inputIndex >= input.Length) { throw new ArgumentOutOfRangeException("inputIndex"); } if (null == outputBuffer) { throw new ArgumentNullException("outputBuffer"); } if (outputBufferIndex >= outputBuffer.Length) { throw new ArgumentOutOfRangeException("outputBufferIndex"); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } // Adjust bit count if 0 passed in if (bitCount == 0) { //adjust if the bitcount is 0 //(this makes bitCount 32) bitCount = (int)(Native.SizeOfInt << 3); } // Test whether the items are signed. For unsigned number, we don't need mask // If we are trying to compress signed long values with bit count = 5 // The mask will be 1111 1111 1111 0000. The way it is done is, if the 5th // bit is 1, the number is negative numbe, othrwise it's positive. Testing // will be non-zero, ONLY if the 5th bit is 1, in which case we OR with the mask // otherwise we leave the number as it is. uint bitMask = (unchecked((uint)~0) << (bitCount - 1)); uint bitData = 0; BitStreamReader reader = new BitStreamReader(input, inputIndex); if(dtxf != null) { while (!reader.EndOfStream) { bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; int result = dtxf.InverseTransform((int)bitData, 0); Debug.Assert(outputBufferIndex < outputBuffer.Length); outputBuffer[outputBufferIndex++] = result; if (outputBufferIndex == outputBuffer.Length) { //only write as much as the outputbuffer can hold //this is assumed by calling code break; } } } else { while (!reader.EndOfStream) { bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; Debug.Assert(outputBufferIndex < outputBuffer.Length); outputBuffer[outputBufferIndex++] = (int)bitData; if (outputBufferIndex == outputBuffer.Length) { //only write as much as the outputbuffer can hold //this is assumed by calling code break; } } } // Calculate how many bytes were read from input buffer return (uint)((outputBuffer.Length * bitCount + 7) >> 3); } ////// Uncompress - uncompress the byte[] in the reader to a byte[] to return /// /// number of bits each element is compressed to /// a reader over the compressed byte[] /// int, short or byte? /// number of logical units to decode ///Uncompressed byte[] internal byte[] Uncompress(int bitCount, BitStreamReader reader, GorillaEncodingType encodingType, int unitsToDecode) { if (null == reader) { throw new ArgumentNullException("reader"); } if (bitCount < 0) { throw new ArgumentOutOfRangeException("bitCount"); } if (unitsToDecode < 0) { throw new ArgumentOutOfRangeException("unitsToDecode"); } int bitsToWrite = 0; // Test whether the items are signed. For unsigned number, we don't need mask // If we are trying to compress signed long values with bit count = 5 // The mask will be 1111 1111 1111 0000. The way it is done is, if the 5th // bit is 1, the number is negative numbe, othrwise it's positive. Testing // will be non-zero, ONLY if the 5th bit is 1, in which case we OR with the mask // otherwise we leave the number as it is. uint bitMask = 0; //adjust if the bitcount is 0 //(this makes bitCount 32) switch (encodingType) { case GorillaEncodingType.Int: { if (bitCount == 0) { bitCount = Native.BitsPerInt; } bitsToWrite = Native.BitsPerInt; //we decode int's as unsigned, so we need to create a mask bitMask = (unchecked((uint)~0) << (bitCount - 1)); break; } case GorillaEncodingType.Short: { if (bitCount == 0) { bitCount = Native.BitsPerShort; } bitsToWrite = Native.BitsPerShort; //shorts are decoded as unsigned values, no mask required bitMask = 0; break; } case GorillaEncodingType.Byte: { if (bitCount == 0) { bitCount = Native.BitsPerByte; } bitsToWrite = Native.BitsPerByte; //bytes are decoded as unsigned values, no mask required bitMask = 0; break; } default: { throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("bogus GorillaEncodingType passed to Uncompress")); } } Listoutput = new List ((bitsToWrite / 8) * unitsToDecode); BitStreamWriter writer = new BitStreamWriter(output); uint bitData = 0; while (!reader.EndOfStream && unitsToDecode > 0) { //we're going to cast to an uint anyway, just read as one bitData = reader.ReadUInt32(bitCount); // Construct the item bitData = ((bitData & bitMask) != 0) ? bitMask | bitData : bitData; writer.WriteReverse(bitData, bitsToWrite); unitsToDecode--; } return output.ToArray(); } /// /// UpdateMinMax /// /// number to evaluate /// a ref to the max, which will be updated if n is more /// a ref to the min, which will be updated if n is less private static void UpdateMinMax(int n, ref int max, ref int min) { if (n > max) { max = n; } else if (n < min) { min = n; } } ////// Private statics /// private static GorillaAlgoByte[] _gorIndexMap; private static byte[] _gorIndexOffset; } ////// Helper struct /// internal struct GorillaAlgoByte { public GorillaAlgoByte(uint bitCount, uint padCount) { BitCount = bitCount; PadCount = padCount; } public uint BitCount; public uint PadCount; } ////// Simple helper enum to control Gorilla encoding in Compress /// internal enum GorillaEncodingType { Byte = 0, Short, Int, } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CodeCommentStatement.cs
- Trace.cs
- BaseValidator.cs
- FormsIdentity.cs
- SizeKeyFrameCollection.cs
- EncoderReplacementFallback.cs
- sitestring.cs
- UriSection.cs
- While.cs
- DefaultPropertyAttribute.cs
- PowerEase.cs
- WebBrowserBase.cs
- WebReferenceCollection.cs
- UIElementPropertyUndoUnit.cs
- KeyValueInternalCollection.cs
- ToolStripContentPanelRenderEventArgs.cs
- NetCodeGroup.cs
- DesignerHelpers.cs
- XmlSchemaInfo.cs
- BitmapEffectDrawingContextWalker.cs
- QueryOperatorEnumerator.cs
- ConfigXmlSignificantWhitespace.cs
- Button.cs
- SerializationInfoEnumerator.cs
- AutoScrollHelper.cs
- Base64Encoder.cs
- coordinatorscratchpad.cs
- PrintDialog.cs
- LeftCellWrapper.cs
- DescendantOverDescendantQuery.cs
- MarkupCompiler.cs
- SubclassTypeValidator.cs
- NonClientArea.cs
- NameTable.cs
- SocketElement.cs
- UserMapPath.cs
- HMACSHA256.cs
- RenderDataDrawingContext.cs
- CollectionChangedEventManager.cs
- XmlEntityReference.cs
- MissingMethodException.cs
- CodeAccessPermission.cs
- ForeignKeyConstraint.cs
- HyperLinkField.cs
- hebrewshape.cs
- LabelExpression.cs
- SponsorHelper.cs
- WebPartEventArgs.cs
- WebServiceReceiveDesigner.cs
- TextReader.cs
- DispatchOperationRuntime.cs
- WebControlAdapter.cs
- GradientSpreadMethodValidation.cs
- HitTestResult.cs
- XmlDesignerDataSourceView.cs
- GridViewUpdateEventArgs.cs
- XPathExpr.cs
- WindowsScrollBarBits.cs
- OverrideMode.cs
- ModelPropertyCollectionImpl.cs
- NamespaceMapping.cs
- MailAddressCollection.cs
- SoapIgnoreAttribute.cs
- AddInContractAttribute.cs
- ComponentCodeDomSerializer.cs
- PointValueSerializer.cs
- XmlDeclaration.cs
- Floater.cs
- DelegateHelpers.Generated.cs
- WindowClosedEventArgs.cs
- DuplicateWaitObjectException.cs
- ToggleButton.cs
- DataContext.cs
- TextTreeExtractElementUndoUnit.cs
- DataGridViewColumnCollection.cs
- EntityDataSourceChangingEventArgs.cs
- StyleXamlParser.cs
- EventPropertyMap.cs
- TextEffectCollection.cs
- DbConnectionPoolGroupProviderInfo.cs
- InstalledFontCollection.cs
- ActivityCodeDomSerializer.cs
- CharEnumerator.cs
- TdsValueSetter.cs
- DbConnectionPoolIdentity.cs
- DataGridViewColumnCollectionEditor.cs
- CacheForPrimitiveTypes.cs
- EventTrigger.cs
- ParameterBuilder.cs
- TextComposition.cs
- InternalConfigEventArgs.cs
- CTreeGenerator.cs
- SafeCoTaskMem.cs
- Padding.cs
- NativeMethods.cs
- PropertyGridCommands.cs
- ProfessionalColors.cs
- DetailsViewCommandEventArgs.cs
- _NTAuthentication.cs
- Simplifier.cs