2 // This file is part of the LWES .NET Binding (LWES.net)
4 // COPYRIGHT© 2009, Phillip Clark (phillip[at*flitbit[dot*org)
5 // original .NET implementation
7 // LWES.net is free software: you can redistribute it and/or modify
8 // it under the terms of the Lesser GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
12 // LWES.net is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // Lesser GNU General Public License for more details.
17 // You should have received a copy of the Lesser GNU General Public License
18 // along with LWES.net. If not, see <http://www.gnu.org/licenses/>.
29 /// Serialization utility implementing the LWES binary format.
31 public static class LwesSerializer
36 /// Deserializes an LWES event from a byte array.
38 /// <param name="buffer">the byte array containing the event</param>
39 /// <param name="offset">offset to the first byte of the event</param>
40 /// <param name="count">number of bytes to deserialize</param>
41 /// <param name="db">an event template DB for creating events</param>
42 /// <returns>the deserialized event</returns>
43 public static Event
Deserialize(byte[] buffer
, int offset
, int count
, IEventTemplateDB db
)
45 return Event
.BinaryDecode(db
, buffer
, offset
, count
);
49 /// Reads an ATTRIBUTEWORD from the byte buffer.
51 /// <param name="buffer">buffer containing serialized data</param>
52 /// <param name="offset">reference to an offset variable; upon entry offset
53 /// reflects the position within the buffer where reading should begin.
54 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
55 /// <param name="coder">Decoder used to translate byte data to character data</param>
56 /// <returns>an ATTRIBUTEWORD value taken from the buffer</returns>
57 public static string ReadATTRIBUTEWORD(byte[] buffer
, ref int offset
, Decoder coder
)
60 if (buffer
== null) throw new ArgumentNullException("buffer");
61 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new BadLwesDataException(String
.Concat("Expected ATTRIBUTEWORD at offset ", offset
));
63 return ReadStringWithByteLengthPrefix(buffer
, ref offset
, coder
);
67 /// Reads a boolean from the byte buffer.
69 /// <param name="buffer">buffer containing serialized data</param>
70 /// <param name="offset">reference to an offset variable; reflects the position
71 /// within the buffer where reading should begin. Upon success the offset is incremented
72 /// by the number of bytes that are used.</param>
73 /// <returns>a boolean value taken from the buffer</returns>
74 public static bool ReadBoolean(byte[] buffer
, ref int offset
)
76 if (buffer
== null) throw new ArgumentNullException("buffer");
77 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new BadLwesDataException(String
.Concat("Expected Boolean at offset ", offset
));
79 return buffer
[offset
++] == 1;
83 /// Reads a byte from the byte buffer.
85 /// <param name="buffer">buffer containing serialized data</param>
86 /// <param name="offset">reference to an offset variable; upon entry offset
87 /// reflects the position within the buffer where reading should begin.
88 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
89 /// <returns>a byte value taken from the buffer</returns>
90 public static byte ReadByte(byte[] buffer
, ref int offset
)
92 if (buffer
== null) throw new ArgumentNullException("buffer");
93 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new BadLwesDataException(String
.Concat("Expected byte at offset ", offset
));
95 return buffer
[offset
++];
99 /// Reads an EVENTWORD from the byte buffer.
101 /// <param name="buffer">buffer containing serialized data</param>
102 /// <param name="offset">reference to an offset variable; upon entry offset
103 /// reflects the position within the buffer where reading should begin.
104 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
105 /// <param name="coder">decoder used for transforming byte data to character data</param>
106 /// <returns>an EVENTWORD value taken from the buffer</returns>
107 public static string ReadEVENTWORD(byte[] buffer
, ref int offset
, Decoder coder
)
110 if (buffer
== null) throw new ArgumentNullException("buffer");
111 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new BadLwesDataException(String
.Concat("Expected EVENTWORD at offset ", offset
));
113 return ReadStringWithByteLengthPrefix(buffer
, ref offset
, coder
);
117 /// Reads an IPAddress from the byte buffer.
119 /// <param name="buffer">buffer containing serialized data</param>
120 /// <param name="offset">reference to an offset variable; upon entry offset
121 /// reflects the position within the buffer where reading should begin.
122 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
123 /// <returns>an IPAddress value taken from the buffer</returns>
124 public static IPAddress
ReadIPAddress(byte[] buffer
, ref int offset
)
126 if (buffer
== null) throw new ArgumentNullException("buffer");
127 if (offset
< 0 || offset
> buffer
.Length
- 4) throw new BadLwesDataException(String
.Concat("Expected IPAddress at offset ", offset
));
132 result
= (((uint)buffer
[offset
] << 24)
133 | ((uint)buffer
[offset
+ 1] << 16)
134 | ((uint)buffer
[offset
+ 2] << 8)
135 | (uint)buffer
[offset
+ 3]);
139 return new IPAddress(result
);
143 /// Reads a Int16 from the byte buffer.
145 /// <param name="buffer">buffer containing serialized data</param>
146 /// <param name="offset">reference to an offset variable; upon entry offset
147 /// reflects the position within the buffer where reading should begin.
148 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
149 /// <returns>a Int16 value taken from the buffer</returns>
150 public static Int16
ReadInt16(byte[] buffer
, ref int offset
)
154 return (short)ReadUInt16(buffer
, ref offset
);
159 /// Reads a Int16 from the byte buffer.
161 /// <param name="buffer">buffer containing serialized data</param>
162 /// <param name="offset">reference to an offset variable; upon entry offset
163 /// reflects the position within the buffer where reading should begin.
164 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
165 /// <returns>a Int16 value taken from the buffer</returns>
166 public static Int32
ReadInt32(byte[] buffer
, ref int offset
)
170 return (int)ReadUInt32(buffer
, ref offset
);
175 /// Reads a Int64 from the byte buffer.
177 /// <param name="buffer">buffer containing serialized data</param>
178 /// <param name="offset">reference to an offset variable; upon entry offset
179 /// reflects the position within the buffer where reading should begin.
180 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
181 /// <returns>a Int64 value taken from the buffer</returns>
182 public static Int64
ReadInt64(byte[] buffer
, ref int offset
)
186 return (long)ReadUInt64(buffer
, ref offset
);
191 /// Reads a String from the byte buffer.
193 /// <param name="buffer">buffer containing serialized data</param>
194 /// <param name="offset">reference to an offset variable; upon entry offset
195 /// reflects the position within the buffer where reading should begin.
196 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
197 /// <param name="coder">Decoder used to translate byte data to character data</param>
198 /// <returns>a String value taken from the buffer</returns>
199 public static string ReadString(byte[] buffer
, ref int offset
, Decoder coder
)
202 if (buffer
== null) throw new ArgumentNullException("buffer");
203 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new BadLwesDataException(String
.Concat("Expected String at offset ", offset
));
205 return ReadStringWithUInt16LengthPrefix(buffer
, ref offset
, coder
);
209 /// Reads a UInt16 from the byte buffer.
211 /// <param name="buffer">buffer containing serialized data</param>
212 /// <param name="offset">reference to an offset variable; upon entry offset
213 /// reflects the position within the buffer where reading should begin.
214 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
215 /// <returns>a UInt16 value taken from the buffer</returns>
216 public static ushort ReadUInt16(byte[] buffer
, ref int offset
)
218 if (buffer
== null) throw new ArgumentNullException("buffer");
219 if (offset
< 0 || offset
> buffer
.Length
- 2) throw new BadLwesDataException(String
.Concat("Expected UInt16 at offset ", offset
));
224 result
= (ushort)(((uint)buffer
[offset
] << 8) | (uint)buffer
[offset
+ 1]);
231 /// Reads a UInt32 from the byte buffer.
233 /// <param name="buffer">buffer containing serialized data</param>
234 /// <param name="offset">reference to an offset variable; upon entry offset
235 /// reflects the position within the buffer where reading should begin.
236 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
237 /// <returns>a UInt32 value taken from the buffer</returns>
238 public static uint ReadUInt32(byte[] buffer
, ref int offset
)
240 if (buffer
== null) throw new ArgumentNullException("buffer");
241 if (offset
< 0 || offset
> buffer
.Length
- 4) throw new BadLwesDataException(String
.Concat("Expected UInt32 at offset ", offset
));
246 result
= (((uint)buffer
[offset
] << 24)
247 | ((uint)buffer
[offset
+ 1] << 16)
248 | ((uint)buffer
[offset
+ 2] << 8)
249 | (uint)buffer
[offset
+ 3]);
256 /// Reads a UInt64 from the byte buffer.
258 /// <param name="buffer">buffer containing serialized data</param>
259 /// <param name="offset">reference to an offset variable; upon entry offset
260 /// reflects the position within the buffer where reading should begin.
261 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
262 /// <returns>a UInt64 value taken from the buffer</returns>
263 public static ulong ReadUInt64(byte[] buffer
, ref int offset
)
265 if (buffer
== null) throw new ArgumentNullException("buffer");
266 if (offset
< 0 || offset
> buffer
.Length
- 8) throw new BadLwesDataException(String
.Concat("Expected UInt64 at offset ", offset
));
271 result
= (((ulong)buffer
[offset
] << 56)
272 | ((ulong)buffer
[offset
+ 1] << 48)
273 | ((ulong)buffer
[offset
+ 2] << 40)
274 | ((ulong)buffer
[offset
+ 3] << 32)
275 | ((ulong)buffer
[offset
+ 4] << 24)
276 | ((ulong)buffer
[offset
+ 5] << 16)
277 | ((ulong)buffer
[offset
+ 6] << 8)
278 | (ulong)buffer
[offset
+ 7]);
285 /// Serializes an LWES event to a byte array.
287 /// <param name="ev">an event to serialize</param>
288 /// <returns>a byte array containing the event's serialized bytes</returns>
289 public static byte[] Serialize(Event ev
)
291 byte[] buffer
= new byte[ev
.CalculateEncodedByteCount()];
292 ev
.BinaryEncode(buffer
, 0);
297 /// Serializes an LWES event to a byte array taken from the MemoryBuffer
298 /// class so that memory limits are enforced.
300 /// <param name="ev">an event to serialize</param>
301 /// <returns>a byte array containing the event's serialized bytes</returns>
302 public static byte[] SerializeToMemoryBuffer(Event ev
)
304 byte[] buffer
= BufferManager
.AcquireBuffer(ev
.CalculateEncodedByteCount(), null);
305 ev
.BinaryEncode(buffer
, 0);
310 /// Writes a boolean value to the byte buffer.
312 /// <param name="buffer">target buffer for the serialized data</param>
313 /// <param name="offset">reference to an offset variable; upon entry offset
314 /// reflects the position within the buffer where writing should begin.
315 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
316 /// <param name="value">boolean value to be written</param>
317 /// <returns>number of bytes used</returns>
318 public static int Write(byte[] buffer
, ref int offset
, bool value)
321 if (buffer
== null) throw new ArgumentNullException("buffer");
322 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new ArgumentOutOfRangeException("offset");
324 buffer
[offset
++] = (byte)((value) ? 1 : 0);
329 /// Writes a byte value to the byte buffer.
331 /// <param name="buffer">target buffer for the serialized data</param>
332 /// <param name="offset">reference to an offset variable; upon entry offset
333 /// reflects the position within the buffer where writing should begin.
334 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
335 /// <param name="value">byte value to be written</param>
336 /// <returns>number of bytes used</returns>
337 public static int Write(byte[] buffer
, ref int offset
, byte value)
340 if (buffer
== null) throw new ArgumentNullException("buffer");
341 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new ArgumentOutOfRangeException("offset");
343 buffer
[offset
++] = value;
348 /// Writes a Int16 value to the byte buffer.
350 /// <param name="buffer">target buffer for the serialized data</param>
351 /// <param name="offset">reference to an offset variable; upon entry offset
352 /// reflects the position within the buffer where writing should begin.
353 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
354 /// <param name="value">Int16 value to be written</param>
355 /// <returns>number of bytes used</returns>
356 public static int Write(byte[] buffer
, ref int offset
, Int16
value)
358 return Write(buffer
, ref offset
, (UInt16
)value);
362 /// Writes a Int32 value to the byte buffer.
364 /// <param name="buffer">target buffer for the serialized data</param>
365 /// <param name="offset">reference to an offset variable; upon entry offset
366 /// reflects the position within the buffer where writing should begin.
367 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
368 /// <param name="value">Int32 value to be written</param>
369 /// <returns>number of bytes used</returns>
370 public static int Write(byte[] buffer
, ref int offset
, Int32
value)
372 return Write(buffer
, ref offset
, (UInt32
)value);
376 /// Writes a Int64 value to the byte buffer.
378 /// <param name="buffer">target buffer for the serialized data</param>
379 /// <param name="offset">reference to an offset variable; upon entry offset
380 /// reflects the position within the buffer where writing should begin.
381 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
382 /// <param name="value">Int64 value to be written</param>
383 /// <returns>number of bytes used</returns>
384 public static int Write(byte[] buffer
, ref int offset
, Int64
value)
386 return Write(buffer
, ref offset
, (UInt64
)value);
390 /// Writes a UInt16 value to the byte buffer.
392 /// <param name="buffer">target buffer for the serialized data</param>
393 /// <param name="offset">reference to an offset variable; upon entry offset
394 /// reflects the position within the buffer where writing should begin.
395 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
396 /// <param name="value">UInt16 value to be written</param>
397 /// <returns>number of bytes used</returns>
398 public static int Write(byte[] buffer
, ref int offset
, UInt16
value)
401 if (buffer
== null) throw new ArgumentNullException("buffer");
402 if (offset
< 0 || offset
> buffer
.Length
- sizeof(UInt16
)) throw new ArgumentOutOfRangeException("offset");
408 buffer
[offset
] = (byte)((v
>> 8) & 0xFF);
409 buffer
[offset
+1] = (byte)(v
& 0xFF);
411 offset
+= sizeof(UInt16
);
412 return sizeof(UInt16
);
416 /// Writes a UInt32 value to the byte buffer.
418 /// <param name="buffer">target buffer for the serialized data</param>
419 /// <param name="offset">reference to an offset variable; upon entry offset
420 /// reflects the position within the buffer where writing should begin.
421 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
422 /// <param name="value">UInt32 value to be written</param>
423 /// <returns>number of bytes used</returns>
424 public static int Write(byte[] buffer
, ref int offset
, UInt32
value)
427 if (buffer
== null) throw new ArgumentNullException("buffer");
428 if (offset
< 0 || offset
> buffer
.Length
- sizeof(UInt32
)) throw new ArgumentOutOfRangeException("offset");
433 buffer
[offset
] = (byte)((value >> 24) & 0xFF);
434 buffer
[offset
+ 1] = (byte)((value >> 16) & 0xFF);
435 buffer
[offset
+ 2] = (byte)((value >> 8) & 0xFF);
436 buffer
[offset
+ 3] = (byte)(byte)(value & 0xFF);
438 offset
+= sizeof(UInt32
);
439 return sizeof(UInt32
);
443 /// Writes a UInt64 value to the byte buffer.
445 /// <param name="buffer">target buffer for the serialized data</param>
446 /// <param name="offset">reference to an offset variable; upon entry offset
447 /// reflects the position within the buffer where writing should begin.
448 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
449 /// <param name="value">UInt64 value to be written</param>
450 /// <returns>number of bytes used</returns>
451 public static int Write(byte[] buffer
, ref int offset
, UInt64
value)
454 if (buffer
== null) throw new ArgumentNullException("buffer");
455 if (offset
< 0 || offset
> buffer
.Length
- sizeof(UInt64
)) throw new ArgumentOutOfRangeException("offset");
460 buffer
[offset
] = (byte)((value >> 56) & 0xFF);
461 buffer
[offset
+ 1] = (byte)((value >> 48) & 0xFF);
462 buffer
[offset
+ 2] = (byte)((value >> 40) & 0xFF);
463 buffer
[offset
+ 3] = (byte)((value >> 32) & 0xFF);
464 buffer
[offset
+ 4] = (byte)((value >> 24) & 0xFF);
465 buffer
[offset
+ 5] = (byte)((value >> 16) & 0xFF);
466 buffer
[offset
+ 6] = (byte)((value >> 8) & 0xFF);
467 buffer
[offset
+ 7] = (byte)(value & 0xFF);
469 offset
+= sizeof(UInt64
);
470 return sizeof(UInt64
);
474 /// Writes a String value to the byte buffer.
476 /// <param name="buffer">target buffer for the serialized data</param>
477 /// <param name="offset">reference to an offset variable; upon entry offset
478 /// reflects the position within the buffer where writing should begin.
479 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
480 /// <param name="value">String value to be written</param>
481 /// <param name="coder">encoder used to transform the characters to bytes.</param>
482 /// <returns>number of bytes used</returns>
483 public static int Write(byte[] buffer
, ref int offset
, string value, Encoder coder
)
486 if (value == null) throw new ArgumentNullException("value");
488 return WriteWithUInt16LengthPrefix(buffer
, ref offset
, value.ToCharArray(), coder
);
492 /// Writes a ATTRIBUTEWORD value to the byte buffer.
494 /// <param name="buffer">target buffer for the serialized data</param>
495 /// <param name="offset">reference to an offset variable; upon entry offset
496 /// reflects the position within the buffer where writing should begin.
497 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
498 /// <param name="value">ATTRIBUTEWORD value to be written</param>
499 /// <param name="coder">encoder used to transform the characters to bytes.</param>
500 /// <returns>number of bytes used</returns>
501 public static int WriteATTRIBUTEWORD(byte[] buffer
, ref int offset
, string value, Encoder coder
)
504 if (value == null) throw new ArgumentNullException("value");
506 return WriteWithByteLengthPrefix(buffer
, ref offset
, value.ToCharArray(), coder
);
510 /// Writes a EVENTWORD value to the byte buffer.
512 /// <param name="buffer">target buffer for the serialized data</param>
513 /// <param name="offset">reference to an offset variable; upon entry offset
514 /// reflects the position within the buffer where writing should begin.
515 /// Upon success the offset will be incremented by the number of bytes that are used.</param>
516 /// <param name="value">EVENTWORD value to be written</param>
517 /// <param name="coder">encoder used to transform the characters to bytes.</param>
518 /// <returns>number of bytes used</returns>
519 public static int WriteEVENTWORD(byte[] buffer
, ref int offset
, string value, Encoder coder
)
522 if (value == null) throw new ArgumentNullException("value");
524 return WriteWithByteLengthPrefix(buffer
, ref offset
, value.ToCharArray(), coder
);
527 private static string ReadStringWithByteLengthPrefix(byte[] buffer
, ref int offset
, Decoder coder
)
530 if (buffer
== null) throw new ArgumentNullException("buffer");
531 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new ArgumentOutOfRangeException("offset");
532 if (coder
== null) throw new ArgumentNullException("coder");
535 int count
= ReadByte(buffer
, ref ofs
);
536 if (ofs
+ count
> buffer
.Length
) throw new BadLwesDataException(
537 String
.Concat("Cannot deserialize incoming string at offset ", ofs
));
538 char[] result
= new char[count
];
542 coder
.Convert(buffer
, ofs
, count
, result
, 0, count
, true
547 throw new ArgumentException(String
.Format(
548 Properties
.Resources
.Error_BufferOutOfSpace
), "buffer");
549 offset
= ofs
+ bytesUsed
;
550 return new String(result
, 0, charsUsed
);
553 private static string ReadStringWithUInt16LengthPrefix(byte[] buffer
, ref int offset
, Decoder coder
)
556 if (buffer
== null) throw new ArgumentNullException("buffer");
557 if (offset
< 0 || offset
> buffer
.Length
- 1) throw new ArgumentOutOfRangeException("offset");
558 if (coder
== null) throw new ArgumentNullException("coder");
561 int count
= ReadUInt16(buffer
, ref ofs
);
562 if (ofs
+ count
> buffer
.Length
)
563 throw new BadLwesDataException(String
.Concat("Cannot deserialize incoming string at offset ", ofs
));
564 char[] result
= new char[count
];
568 coder
.Convert(buffer
, ofs
, count
, result
, 0, count
, true
573 throw new ArgumentException(String
.Format(
574 Properties
.Resources
.Error_BufferOutOfSpace
), "buffer");
575 offset
= ofs
+ bytesUsed
;
576 return new String(result
, 0, charsUsed
);
579 private static int WriteWithByteLengthPrefix(byte[] buffer
, ref int offset
, Char
[] value, Encoder coder
)
582 if (buffer
== null) throw new ArgumentNullException("buffer");
583 if (value == null) throw new ArgumentNullException("value");
584 if (coder
== null) throw new ArgumentNullException("coder");
587 int count
= coder
.GetByteCount(value, 0, value.Length
, true);
591 Write(buffer
, ref ofs
, (byte)count
);
592 coder
.Convert(value, 0, value.Length
, buffer
, ofs
, buffer
.Length
- ofs
, true
597 throw new ArgumentException(String
.Format(
598 Properties
.Resources
.Error_BufferOutOfSpace
), "buffer");
599 offset
= ofs
+ bytesUsed
;
600 return bytesUsed
+ 1;
603 private static int WriteWithUInt16LengthPrefix(byte[] buffer
, ref int offset
, Char
[] value, Encoder coder
)
606 if (buffer
== null) throw new ArgumentNullException("buffer");
607 if (value == null) throw new ArgumentNullException("value");
608 if (coder
== null) throw new ArgumentNullException("coder");
611 int count
= coder
.GetByteCount(value, 0, value.Length
, true);
615 Write(buffer
, ref ofs
, (UInt16
)count
);
616 coder
.Convert(value, 0, value.Length
, buffer
, ofs
, buffer
.Length
- ofs
, true
621 throw new ArgumentException(String
.Format(
622 Properties
.Resources
.Error_BufferOutOfSpace
), "buffer");
623 offset
= ofs
+ bytesUsed
;
624 return bytesUsed
+ 2;