7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
using System.Collections;
35
namespace Mono.Addins.Serialization
37
internal class BinaryXmlReader
41
internal const byte TagEndOfFile = 0;
42
internal const byte TagBeginElement = 1;
43
internal const byte TagEndElement = 2;
44
internal const byte TagValue = 4;
46
internal const byte TagObject = 5;
47
internal const byte TagObjectArray = 6;
48
internal const byte TagObjectDictionary = 7;
49
internal const byte TagObjectNull = 8;
53
ArrayList stringTable = new ArrayList ();
54
BinaryXmlTypeMap typeMap;
58
public BinaryXmlReader (Stream stream, BinaryXmlTypeMap typeMap)
60
reader = new BinaryReader (stream);
61
this.typeMap = typeMap;
65
public BinaryXmlTypeMap TypeMap {
66
get { return typeMap; }
67
set { typeMap = value; }
70
public object ContextData {
71
get { return contextData; }
72
set { contextData = value; }
75
// Returns 'true' if description data must be ignored when reading the contents of a file
76
public bool IgnoreDescriptionData {
77
get { return ignoreDesc; }
78
set { ignoreDesc = value; }
83
int b = reader.BaseStream.ReadByte ();
85
currentType = TagEndOfFile;
88
currentType = (byte) b;
89
if (currentType == TagBeginElement || currentType == TagValue)
90
currentName = ReadString ();
95
// The first integer means:
96
// >=0: string of the specified length
98
// <-1: a string from the string table
100
int len = reader.ReadInt32 ();
104
return (string) stringTable [-(len + 2)];
106
byte[] bytes = new byte [len];
109
int read = reader.Read (bytes, n, len - n);
111
throw new InvalidOperationException ("Length too high for string: " + len);
114
string s = Encoding.UTF8.GetString (bytes);
119
public string LocalName {
120
get { return currentName; }
123
public bool IsElement {
124
get { return currentType == TagBeginElement; }
127
public bool IsValue {
128
get { return currentType == TagValue; }
131
TypeCode ReadValueType (TypeCode type)
133
if (currentType != TagValue)
134
throw new InvalidOperationException ("Reader not positioned on a value.");
135
TypeCode t = (TypeCode) reader.ReadByte ();
136
if (t != type && type != TypeCode.Empty)
137
throw new InvalidOperationException ("Invalid value type. Expected " + type + ", found " + t);
141
public string ReadStringValue (string name)
143
if (!SkipToValue (name))
145
return ReadStringValue ();
148
public string ReadStringValue ()
150
if (currentType != TagValue)
151
throw new InvalidOperationException ("Reader not positioned on a value.");
153
TypeCode t = (TypeCode) reader.ReadByte ();
154
if (t == TypeCode.Empty) {
158
if (t != TypeCode.String)
159
throw new InvalidOperationException ("Invalid value type. Expected String, found " + t);
161
string s = ReadString ();
166
public bool ReadBooleanValue (string name)
168
if (!SkipToValue (name))
170
return ReadBooleanValue ();
173
public bool ReadBooleanValue ()
175
ReadValueType (TypeCode.Boolean);
176
bool value = reader.ReadBoolean ();
181
public char ReadCharValue (string name)
183
if (!SkipToValue (name))
185
return ReadCharValue ();
188
public char ReadCharValue ()
190
ReadValueType (TypeCode.Char);
191
char value = reader.ReadChar ();
196
public byte ReadByteValue (string name)
198
if (!SkipToValue (name))
200
return ReadByteValue ();
203
public byte ReadByteValue ()
205
ReadValueType (TypeCode.Byte);
206
byte value = reader.ReadByte ();
211
public short ReadInt16Value (string name)
213
if (!SkipToValue (name))
215
return ReadInt16Value ();
218
public short ReadInt16Value ()
220
ReadValueType (TypeCode.Int16);
221
short value = reader.ReadInt16 ();
226
public int ReadInt32Value (string name)
228
if (!SkipToValue (name))
230
return ReadInt32Value ();
233
public int ReadInt32Value ()
235
ReadValueType (TypeCode.Int32);
236
int value = reader.ReadInt32 ();
241
public long ReadInt64Value (string name)
243
if (!SkipToValue (name))
245
return ReadInt64Value ();
248
public long ReadInt64Value ()
250
ReadValueType (TypeCode.Int64);
251
long value = reader.ReadInt64 ();
256
public DateTime ReadDateTimeValue (string name)
258
if (!SkipToValue (name))
259
return DateTime.MinValue;
260
return ReadDateTimeValue ();
263
public DateTime ReadDateTimeValue ()
265
ReadValueType (TypeCode.DateTime);
266
DateTime value = new DateTime (reader.ReadInt64 ());
271
public object ReadValue (string name)
273
if (!SkipToValue (name))
278
public object ReadValue ()
280
object res = ReadValueInternal ();
285
public object ReadValue (string name, object targetInstance)
287
if (!SkipToValue (name))
289
return ReadValue (targetInstance);
292
public object ReadValue (object targetInstance)
294
TypeCode t = (TypeCode) reader.ReadByte ();
295
if (t == TypeCode.Empty) {
299
if (t != TypeCode.Object)
300
throw new InvalidOperationException ("Invalid value type. Expected Object, found " + t);
302
object res = ReadObject (targetInstance);
307
object ReadValueInternal ()
309
TypeCode t = (TypeCode) reader.ReadByte ();
310
if (t == TypeCode.Empty)
312
return ReadValueInternal (t);
315
object ReadValueInternal (TypeCode t)
319
case TypeCode.Boolean: res = reader.ReadBoolean (); break;
320
case TypeCode.Char: res = reader.ReadChar (); break;
321
case TypeCode.SByte: res = reader.ReadSByte (); break;
322
case TypeCode.Byte: res = reader.ReadByte (); break;
323
case TypeCode.Int16: res = reader.ReadInt16 (); break;
324
case TypeCode.UInt16: res = reader.ReadUInt16 (); break;
325
case TypeCode.Int32: res = reader.ReadInt32 (); break;
326
case TypeCode.UInt32: res = reader.ReadUInt32 (); break;
327
case TypeCode.Int64: res = reader.ReadInt64 (); break;
328
case TypeCode.UInt64: res = reader.ReadUInt64 (); break;
329
case TypeCode.Single: res = reader.ReadSingle (); break;
330
case TypeCode.Double: res = reader.ReadDouble (); break;
331
case TypeCode.DateTime: res = new DateTime (reader.ReadInt64 ()); break;
332
case TypeCode.String: res = ReadString (); break;
333
case TypeCode.Object: res = ReadObject (null); break;
334
case TypeCode.Empty: res = null; break;
336
throw new InvalidOperationException ("Unexpected value type: " + t);
341
bool SkipToValue (string name)
344
if ((currentType == TagBeginElement || currentType == TagValue) && currentName == name)
352
public void ReadBeginElement ()
354
if (currentType != TagBeginElement)
355
throw new InvalidOperationException ("Reader not positioned on an element.");
359
public void ReadEndElement ()
361
if (currentType != TagEndElement)
362
throw new InvalidOperationException ("Reader not positioned on an element.");
366
public bool EndOfElement {
367
get { return currentType == TagEndElement; }
372
if (currentType == TagValue)
374
else if (currentType == TagEndElement)
376
else if (currentType == TagBeginElement) {
378
while (!EndOfElement)
384
object ReadObject (object targetInstance)
386
byte ot = reader.ReadByte ();
387
if (ot == TagObjectNull) {
390
else if (ot == TagObject) {
391
string tname = ReadString ();
392
IBinaryXmlElement ob;
393
if (targetInstance != null) {
394
ob = targetInstance as IBinaryXmlElement;
396
throw new InvalidOperationException ("Target instance has an invalid type. Expected an IBinaryXmlElement implementation.");
398
ob = typeMap.CreateObject (tname);
402
while (currentType != TagEndElement)
406
else if (ot == TagObjectArray) {
407
TypeCode tc = (TypeCode) reader.ReadByte ();
408
int len = reader.ReadInt32 ();
409
if (targetInstance != null) {
410
IList list = targetInstance as IList;
412
throw new InvalidOperationException ("Target instance has an invalid type. Expected an IList implementation.");
413
for (int n=0; n<len; n++)
414
list.Add (ReadValueInternal ());
418
Array obs = CreateArray (tc, len);
419
for (int n=0; n<len; n++)
420
obs.SetValue (ReadValueInternal (), n);
424
else if (ot == TagObjectDictionary) {
425
int len = reader.ReadInt32 ();
427
if (targetInstance != null) {
428
table = targetInstance as IDictionary;
430
throw new InvalidOperationException ("Target instance has an invalid type. Expected an IDictionary implementation.");
432
table = new Hashtable ();
434
for (int n=0; n<len; n++) {
435
object key = ReadValueInternal ();
436
object val = ReadValueInternal ();
442
throw new InvalidOperationException ("Unknown object type tag: " + ot);
445
Array CreateArray (TypeCode t, int len)
448
case TypeCode.Boolean: return new bool [len];
449
case TypeCode.Char: return new Char [len];
450
case TypeCode.SByte: return new SByte [len];
451
case TypeCode.Byte: return new Byte [len];
452
case TypeCode.Int16: return new Int16 [len];
453
case TypeCode.UInt16: return new UInt16 [len];
454
case TypeCode.Int32: return new Int32 [len];
455
case TypeCode.UInt32: return new UInt32 [len];
456
case TypeCode.Int64: return new Int64 [len];
457
case TypeCode.UInt64: return new UInt64 [len];
458
case TypeCode.Single: return new Single [len];
459
case TypeCode.Double: return new Double [len];
460
case TypeCode.DateTime: return new DateTime [len];
461
case TypeCode.String: return new String [len];
462
case TypeCode.Object: return new Object [len];
464
throw new InvalidOperationException ("Unexpected value type: " + t);
468
const int IndSize = 2;
470
public static void DumpFile (string file)
472
Console.WriteLine ("FILE: " + file);
473
using (Stream s = File.OpenRead (file)) {
474
BinaryXmlReader r = new BinaryXmlReader (s, new BinaryXmlTypeMap ());
479
public void Dump (int ind)
481
if (currentType == TagValue) {
482
Console.Write (new string (' ', ind) + LocalName + ": ");
484
Console.WriteLine ();
486
else if (currentType == TagBeginElement) {
487
string name = LocalName;
488
Console.WriteLine (new string (' ', ind) + "<" + name + ">");
489
DumpElement (ind + IndSize);
490
Console.WriteLine (new string (' ', ind) + "</" + name + ">");
494
public void DumpElement (int ind)
497
while (currentType != TagEndElement) {
498
Dump (ind + IndSize);
503
void DumpValue (int ind)
505
TypeCode t = (TypeCode) reader.ReadByte ();
506
if (t != TypeCode.Object) {
507
object ob = ReadValueInternal (t);
508
if (ob == null) ob = "(null)";
511
byte ot = reader.ReadByte ();
513
case TagObjectNull: {
514
Console.Write ("(null)");
518
string tname = ReadString ();
519
Console.WriteLine ("(" + tname + ")");
520
DumpElement (ind + IndSize);
523
case TagObjectArray: {
524
TypeCode tc = (TypeCode) reader.ReadByte ();
525
int len = reader.ReadInt32 ();
526
Console.WriteLine ("(" + tc + "[" + len + "])");
527
for (int n=0; n<len; n++) {
528
Console.Write (new string (' ', ind + IndSize) + n + ": ");
529
DumpValue (ind + IndSize*2);
530
Console.WriteLine ();
534
case TagObjectDictionary: {
535
int len = reader.ReadInt32 ();
536
Console.WriteLine ("(IDictionary)");
537
for (int n=0; n<len; n++) {
538
Console.Write (new string (' ', ind + IndSize) + "key: ");
539
DumpValue (ind + IndSize*2);
540
Console.WriteLine ();
541
Console.Write (new string (' ', ind + IndSize) + "val: ");
542
DumpValue (ind + IndSize*2);
543
Console.WriteLine ();
548
throw new InvalidOperationException ("Invalid object tag: " + ot);