corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28  
29 namespace OpenMetaverse
30 {
31 /// <summary>
32 /// Wrapper around a byte array that allows bit to be packed and unpacked
33 /// one at a time or by a variable amount. Useful for very tightly packed
34 /// data like LayerData packets
35 /// </summary>
36 public class BitPack
37 {
38 /// <summary></summary>
39 public byte[] Data;
40  
41 /// <summary></summary>
42 public int BytePos
43 {
44 get
45 {
46 if (bytePos != 0 && bitPos == 0)
47 return bytePos - 1;
48 else
49 return bytePos;
50 }
51 }
52  
53 /// <summary></summary>
54 public int BitPos { get { return bitPos; } }
55  
56  
57 private const int MAX_BITS = 8;
58 private static readonly byte[] ON = new byte[] { 1 };
59 private static readonly byte[] OFF = new byte[] { 0 };
60  
61 private int bytePos;
62 private int bitPos;
63 private bool weAreBigEndian = !BitConverter.IsLittleEndian;
64  
65  
66 /// <summary>
67 /// Default constructor, initialize the bit packer / bit unpacker
68 /// with a byte array and starting position
69 /// </summary>
70 /// <param name="data">Byte array to pack bits in to or unpack from</param>
71 /// <param name="pos">Starting position in the byte array</param>
72 public BitPack(byte[] data, int pos)
73 {
74 Data = data;
75 bytePos = pos;
76 }
77  
78 /// <summary>
79 /// Pack a floating point value in to the data
80 /// </summary>
81 /// <param name="data">Floating point value to pack</param>
82 public void PackFloat(float data)
83 {
84 byte[] input = BitConverter.GetBytes(data);
85 if (weAreBigEndian) Array.Reverse(input);
86 PackBitArray(input, 32);
87 }
88  
89 /// <summary>
90 /// Pack part or all of an integer in to the data
91 /// </summary>
92 /// <param name="data">Integer containing the data to pack</param>
93 /// <param name="totalCount">Number of bits of the integer to pack</param>
94 public void PackBits(int data, int totalCount)
95 {
96 byte[] input = BitConverter.GetBytes(data);
97 if (weAreBigEndian) Array.Reverse(input);
98 PackBitArray(input, totalCount);
99 }
100  
101 /// <summary>
102 /// Pack part or all of an unsigned integer in to the data
103 /// </summary>
104 /// <param name="data">Unsigned integer containing the data to pack</param>
105 /// <param name="totalCount">Number of bits of the integer to pack</param>
106 public void PackBits(uint data, int totalCount)
107 {
108 byte[] input = BitConverter.GetBytes(data);
109 if (weAreBigEndian) Array.Reverse(input);
110 PackBitArray(input, totalCount);
111 }
112  
113 /// <summary>
114 /// Pack a single bit in to the data
115 /// </summary>
116 /// <param name="bit">Bit to pack</param>
117 public void PackBit(bool bit)
118 {
119 if (bit)
120 PackBitArray(ON, 1);
121 else
122 PackBitArray(OFF, 1);
123 }
124  
125 /// <summary>
126 ///
127 /// </summary>
128 /// <param name="data"></param>
129 /// <param name="isSigned"></param>
130 /// <param name="intBits"></param>
131 /// <param name="fracBits"></param>
132 public void PackFixed(float data, bool isSigned, int intBits, int fracBits)
133 {
134 int unsignedBits = intBits + fracBits;
135 int totalBits = unsignedBits;
136 int min, max;
137  
138 if (isSigned)
139 {
140 totalBits++;
141 min = 1 << intBits;
142 min *= -1;
143 }
144 else
145 {
146 min = 0;
147 }
148  
149 max = 1 << intBits;
150  
151 float fixedVal = Utils.Clamp(data, (float)min, (float)max);
152 if (isSigned) fixedVal += max;
153 fixedVal *= 1 << fracBits;
154  
155 if (totalBits <= 8)
156 PackBits((uint)fixedVal, 8);
157 else if (totalBits <= 16)
158 PackBits((uint)fixedVal, 16);
159 else if (totalBits <= 31)
160 PackBits((uint)fixedVal, 32);
161 else
162 throw new Exception("Can't use fixed point packing for " + totalBits);
163 }
164  
165 /// <summary>
166 ///
167 /// </summary>
168 /// <param name="data"></param>
169 public void PackUUID(UUID data)
170 {
171 byte[] bytes = data.GetBytes();
172  
173 // Not sure if our PackBitArray function can handle 128-bit byte
174 //arrays, so using this for now
175 for (int i = 0; i < 16; i++)
176 PackBits(bytes[i], 8);
177 }
178  
179 /// <summary>
180 ///
181 /// </summary>
182 /// <param name="data"></param>
183 public void PackColor(Color4 data)
184 {
185 byte[] bytes = data.GetBytes();
186 PackBitArray(bytes, 32);
187 }
188  
189 /// <summary>
190 /// Unpacking a floating point value from the data
191 /// </summary>
192 /// <returns>Unpacked floating point value</returns>
193 public float UnpackFloat()
194 {
195 byte[] output = UnpackBitsArray(32);
196  
197 if (weAreBigEndian) Array.Reverse(output);
198 return BitConverter.ToSingle(output, 0);
199 }
200  
201 /// <summary>
202 /// Unpack a variable number of bits from the data in to integer format
203 /// </summary>
204 /// <param name="totalCount">Number of bits to unpack</param>
205 /// <returns>An integer containing the unpacked bits</returns>
206 /// <remarks>This function is only useful up to 32 bits</remarks>
207 public int UnpackBits(int totalCount)
208 {
209 byte[] output = UnpackBitsArray(totalCount);
210  
211 if (weAreBigEndian) Array.Reverse(output);
212 return BitConverter.ToInt32(output, 0);
213 }
214  
215 /// <summary>
216 /// Unpack a variable number of bits from the data in to unsigned
217 /// integer format
218 /// </summary>
219 /// <param name="totalCount">Number of bits to unpack</param>
220 /// <returns>An unsigned integer containing the unpacked bits</returns>
221 /// <remarks>This function is only useful up to 32 bits</remarks>
222 public uint UnpackUBits(int totalCount)
223 {
224 byte[] output = UnpackBitsArray(totalCount);
225  
226 if (weAreBigEndian) Array.Reverse(output);
227 return BitConverter.ToUInt32(output, 0);
228 }
229  
230 /// <summary>
231 /// Unpack a 16-bit signed integer
232 /// </summary>
233 /// <returns>16-bit signed integer</returns>
234 public short UnpackShort()
235 {
236 return (short)UnpackBits(16);
237 }
238  
239 /// <summary>
240 /// Unpack a 16-bit unsigned integer
241 /// </summary>
242 /// <returns>16-bit unsigned integer</returns>
243 public ushort UnpackUShort()
244 {
245 return (ushort)UnpackUBits(16);
246 }
247  
248 /// <summary>
249 /// Unpack a 32-bit signed integer
250 /// </summary>
251 /// <returns>32-bit signed integer</returns>
252 public int UnpackInt()
253 {
254 return UnpackBits(32);
255 }
256  
257 /// <summary>
258 /// Unpack a 32-bit unsigned integer
259 /// </summary>
260 /// <returns>32-bit unsigned integer</returns>
261 public uint UnpackUInt()
262 {
263 return UnpackUBits(32);
264 }
265  
266 public byte UnpackByte()
267 {
268 byte[] output = UnpackBitsArray(8);
269 return output[0];
270 }
271  
272 public float UnpackFixed(bool signed, int intBits, int fracBits)
273 {
274 int minVal;
275 int maxVal;
276 int unsignedBits = intBits + fracBits;
277 int totalBits = unsignedBits;
278 float fixedVal;
279  
280 if (signed)
281 {
282 totalBits++;
283  
284 minVal = 1 << intBits;
285 minVal *= -1;
286 }
287 maxVal = 1 << intBits;
288  
289 if (totalBits <= 8)
290 fixedVal = (float)UnpackByte();
291 else if (totalBits <= 16)
292 fixedVal = (float)UnpackUBits(16);
293 else if (totalBits <= 31)
294 fixedVal = (float)UnpackUBits(32);
295 else
296 return 0.0f;
297  
298 fixedVal /= (float)(1 << fracBits);
299  
300 if (signed) fixedVal -= (float)maxVal;
301  
302 return fixedVal;
303 }
304  
305 public string UnpackString(int size)
306 {
307 if (bitPos != 0 || bytePos + size > Data.Length) throw new IndexOutOfRangeException();
308  
309 string str = System.Text.UTF8Encoding.UTF8.GetString(Data, bytePos, size);
310 bytePos += size;
311 return str;
312 }
313  
314 public UUID UnpackUUID()
315 {
316 if (bitPos != 0) throw new IndexOutOfRangeException();
317  
318 UUID val = new UUID(Data, bytePos);
319 bytePos += 16;
320 return val;
321 }
322  
323 private void PackBitArray(byte[] data, int totalCount)
324 {
325 int count = 0;
326 int curBytePos = 0;
327 int curBitPos = 0;
328  
329 while (totalCount > 0)
330 {
331 if (totalCount > MAX_BITS)
332 {
333 count = MAX_BITS;
334 totalCount -= MAX_BITS;
335 }
336 else
337 {
338 count = totalCount;
339 totalCount = 0;
340 }
341  
342 while (count > 0)
343 {
344 byte curBit = (byte)(0x80 >> bitPos);
345  
346 if ((data[curBytePos] & (0x01 << (count - 1))) != 0)
347 Data[bytePos] |= curBit;
348 else
349 Data[bytePos] &= (byte)~curBit;
350  
351 --count;
352 ++bitPos;
353 ++curBitPos;
354  
355 if (bitPos >= MAX_BITS)
356 {
357 bitPos = 0;
358 ++bytePos;
359 }
360 if (curBitPos >= MAX_BITS)
361 {
362 curBitPos = 0;
363 ++curBytePos;
364 }
365 }
366 }
367 }
368  
369 private byte[] UnpackBitsArray(int totalCount)
370 {
371 int count = 0;
372 byte[] output = new byte[4];
373 int curBytePos = 0;
374 int curBitPos = 0;
375  
376 while (totalCount > 0)
377 {
378 if (totalCount > MAX_BITS)
379 {
380 count = MAX_BITS;
381 totalCount -= MAX_BITS;
382 }
383 else
384 {
385 count = totalCount;
386 totalCount = 0;
387 }
388  
389 while (count > 0)
390 {
391 // Shift the previous bits
392 output[curBytePos] <<= 1;
393  
394 // Grab one bit
395 if ((Data[bytePos] & (0x80 >> bitPos++)) != 0)
396 ++output[curBytePos];
397  
398 --count;
399 ++curBitPos;
400  
401 if (bitPos >= MAX_BITS)
402 {
403 bitPos = 0;
404 ++bytePos;
405 }
406 if (curBitPos >= MAX_BITS)
407 {
408 curBitPos = 0;
409 ++curBytePos;
410 }
411 }
412 }
413  
414 return output;
415 }
416 }
417 }