Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationReader.cs
1 //
2 // System.Xml.Serialization.XmlSerializationReader.cs
3 //
4 // Authors:
5 //      Tim Coleman (tim@timcoleman.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //  Lluis Sanchez Gual (lluis@ximian.com)
8 //
9 // Copyright (C) Tim Coleman, 2002
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 //
12
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Collections;
36 using System.Globalization;
37 using System.Xml;
38 using System.Xml.Schema;
39 using System.Reflection;
40
41 namespace System.Xml.Serialization 
42 {
43 #if NET_2_0
44         [MonoTODO]
45         // FIXME: provide expected elements/attributes on unknown elements/attributs
46 #endif
47         public abstract class XmlSerializationReader 
48 #if NET_2_0
49                 : XmlSerializationGeneratedCode
50 #endif
51         {
52
53                 #region Fields
54
55 #if !MOONLIGHT
56                 XmlDocument document;
57 #endif
58                 XmlReader reader;
59                 ArrayList fixups;
60                 Hashtable collFixups;
61                 ArrayList collItemFixups;
62                 Hashtable typesCallbacks;
63                 ArrayList noIDTargets;
64                 Hashtable targets;
65                 Hashtable delayedListFixups;
66                 XmlSerializer eventSource;
67                 int delayedFixupId = 0;
68                 Hashtable referencedObjects;
69                 int readCount, whileIterationCount;
70
71                 string w3SchemaNS;
72                 string w3InstanceNS;
73                 string w3InstanceNS2000;
74                 string w3InstanceNS1999;
75                 string soapNS;
76                 string wsdlNS;
77                 string nullX;
78                 string nil;
79                 string typeX;
80                 string arrayType;
81                 XmlQualifiedName arrayQName;
82                 #endregion
83
84                 internal void Initialize (XmlReader reader, XmlSerializer eventSource)
85                 {
86                         w3SchemaNS = reader.NameTable.Add (XmlSchema.Namespace);
87                         w3InstanceNS = reader.NameTable.Add (XmlSchema.InstanceNamespace);
88                         w3InstanceNS2000 = reader.NameTable.Add ("http://www.w3.org/2000/10/XMLSchema-instance");
89                         w3InstanceNS1999 = reader.NameTable.Add ("http://www.w3.org/1999/XMLSchema-instance");
90                         soapNS = reader.NameTable.Add (XmlSerializer.EncodingNamespace);
91                         wsdlNS = reader.NameTable.Add (XmlSerializer.WsdlNamespace);
92                         nullX = reader.NameTable.Add ("null");
93                         nil = reader.NameTable.Add ("nil");
94                         typeX = reader.NameTable.Add ("type");
95                         arrayType = reader.NameTable.Add ("arrayType");
96                         this.reader = reader;
97                         this.eventSource = eventSource;
98                         arrayQName = new XmlQualifiedName ("Array", soapNS);
99                         InitIDs ();
100                 }
101                         
102                 private ArrayList EnsureArrayList (ArrayList list)
103                 {
104                         if (list == null)
105                                 list = new ArrayList ();
106                         return list;
107                 }
108                 
109                 private Hashtable EnsureHashtable (Hashtable hash)
110                 {
111                         if (hash == null)
112                                 hash = new Hashtable ();
113                         return hash;
114                 }
115                 
116                 protected XmlSerializationReader ()
117                 {
118                 }
119
120 #if !MOONLIGHT
121                 protected XmlDocument Document
122                 {
123                         get {
124                                 if (document == null)
125                                         document = new XmlDocument (reader.NameTable);
126
127                                 return document;
128                         }
129                 }
130 #endif
131
132                 protected XmlReader Reader {
133                         get { return reader; }
134                 }
135
136                 [MonoTODO]
137                 protected bool IsReturnValue
138                 {
139                         get {
140                                 throw new NotImplementedException ();
141                         }
142                         set {
143                                 throw new NotImplementedException ();
144                         }
145
146                 }
147
148 #if NET_2_0
149                 protected int ReaderCount {
150                         get { return readCount; }
151                 }
152 #endif
153
154                 #region Methods
155
156                 protected void AddFixup (CollectionFixup fixup)
157                 {
158                         collFixups = EnsureHashtable (collFixups);
159                         collFixups [fixup.Id] = fixup;
160
161                         if (delayedListFixups != null && delayedListFixups.ContainsKey (fixup.Id)) {
162                                 fixup.CollectionItems = delayedListFixups [fixup.Id];
163                                 delayedListFixups.Remove (fixup.Id);
164                         }
165                 }
166
167                 protected void AddFixup (Fixup fixup)
168                 {
169                         fixups = EnsureArrayList (fixups);
170                         fixups.Add (fixup);
171                 }
172
173                 void AddFixup (CollectionItemFixup fixup)
174                 {
175                         collItemFixups = EnsureArrayList (collItemFixups);
176                         collItemFixups.Add(fixup);
177                 }
178
179                 protected void AddReadCallback (string name, string ns, Type type, XmlSerializationReadCallback read)
180                 {
181                         WriteCallbackInfo info = new WriteCallbackInfo ();
182                         info.Type = type;
183                         info.TypeName = name;
184                         info.TypeNs = ns;
185                         info.Callback = read;
186                         typesCallbacks = EnsureHashtable (typesCallbacks);
187                         typesCallbacks.Add (new XmlQualifiedName (name, ns), info);
188                 }
189
190                 protected void AddTarget (string id, object o)
191                 {
192                         if (id != null) {
193                                 targets = EnsureHashtable (targets);
194                                 if (targets [id] == null)
195                                         targets.Add (id, o);
196                         } else {
197                                 if (o != null)
198                                         return;
199                                 noIDTargets = EnsureArrayList (noIDTargets);
200                                 noIDTargets.Add (o);
201                         }
202                 }
203
204                 private string CurrentTag ()
205                 {
206                         switch (reader.NodeType) {
207                         case XmlNodeType.Element:
208                                 return String.Format ("<{0} xmlns='{1}'>", reader.LocalName,
209                                                                            reader.NamespaceURI);
210                         case XmlNodeType.Attribute:
211                                 return reader.Value;
212                         case XmlNodeType.Text:
213                                 return "CDATA";
214                         case XmlNodeType.ProcessingInstruction:
215                                 return "<--";
216                         case XmlNodeType.Entity:
217                                 return "<?";
218                         case XmlNodeType.EndElement:
219                                 return ">";
220                         default:
221                                 return "(unknown)";
222                         }
223                 }
224
225                 protected Exception CreateCtorHasSecurityException (string typeName)
226                 {
227                         string message = string.Format ("The type '{0}' cannot"
228                                 + " be serialized because its parameterless"
229                                 + " constructor is decorated with declarative"
230                                 + " security permission attributes."
231                                 + " Consider using imperative asserts or demands"
232                                 + " in the constructor.", typeName);
233                         return new InvalidOperationException (message);
234                 }
235
236                 protected Exception CreateInaccessibleConstructorException (string typeName)
237                 {
238                         string message = string.Format ("{0} cannot be serialized"
239                                 + " because it does not have a default public"
240                                 + " constructor.", typeName);
241                         return new InvalidOperationException (message);
242                 }
243
244                 protected Exception CreateAbstractTypeException (string name, string ns)
245                 {
246                         string message = "The specified type is abstrace: name='" + name + "' namespace='" + ns + "', at " + CurrentTag ();
247                         return new InvalidOperationException (message);
248                 }
249
250                 protected Exception CreateInvalidCastException (Type type, object value)
251                 {
252                         string message = String.Format (CultureInfo.InvariantCulture, "Cannot assign object of type {0} to an object of " +
253                                                         "type {1}.", value.GetType (), type);
254                         return new InvalidCastException (message);
255                 }
256
257                 protected Exception CreateReadOnlyCollectionException (string name)
258                 {
259                         string message = String.Format ("Could not serialize {0}. Default constructors are " +
260                                                         "required for collections and enumerators.", name);
261                         return new InvalidOperationException (message);
262                 }
263
264                 protected Exception CreateUnknownConstantException (string value, Type enumType)
265                 {
266                         string message = String.Format ("'{0}' is not a valid value for {1}.", value, enumType);
267                         return new InvalidOperationException (message);
268                 }
269
270                 protected Exception CreateUnknownNodeException ()
271                 {
272                         string message = CurrentTag () + " was not expected";
273                         return new InvalidOperationException (message);
274                 }
275
276                 protected Exception CreateUnknownTypeException (XmlQualifiedName type)
277                 {
278                         string message = "The specified type was not recognized: name='" + type.Name + "' namespace='" + type.Namespace + "', at " + CurrentTag ();
279                         return new InvalidOperationException (message);
280                 }
281
282 #if NET_2_0
283                 protected void CheckReaderCount (ref int whileIterations, ref int readerCount)
284                 {
285                         whileIterations = whileIterationCount;
286                         readerCount = readCount;
287                 }
288 #endif
289
290                 protected Array EnsureArrayIndex (Array a, int index, Type elementType)
291                 {
292                         if (a != null && index < a.Length)
293                                 return a;
294
295                         int size;
296                         if (a == null) {
297                                 size = 32;
298                         } else {
299                                 size = a.Length * 2;
300                         }
301
302                         Array result = Array.CreateInstance (elementType, size);
303                         if (a != null)
304                                 Array.Copy (a, result, index);
305
306                         return result;
307                 }
308
309                 [MonoTODO]
310                 protected void FixupArrayRefs (object fixup)
311                 {
312                         throw new NotImplementedException ();
313                 }
314
315                 [MonoTODO]
316                 protected int GetArrayLength (string name, string ns)
317                 {
318                         throw new NotImplementedException ();
319                 }
320
321                 protected bool GetNullAttr ()
322                 {
323                         string na = reader.GetAttribute (nullX, w3InstanceNS);
324                         if (na == null) {
325                                 na = reader.GetAttribute (nil, w3InstanceNS);
326                                 if (na == null) {
327                                         na = reader.GetAttribute (nullX, w3InstanceNS2000);
328                                         if (na == null)
329                                                 na = reader.GetAttribute (nullX, w3InstanceNS1999);
330                                 }
331                         }
332                         return (na != null);
333                 }
334
335                 protected object GetTarget (string id)
336                 {
337                         if (targets == null) return null;
338                         object ob = targets [id];
339                         if (ob != null) {
340                                 if (referencedObjects == null) referencedObjects = new Hashtable ();
341                                 referencedObjects [ob] = ob;
342                         }
343                         return ob;
344                 }
345
346                 bool TargetReady (string id)
347                 {
348                         if (targets == null) return false;
349                         return targets.ContainsKey (id);
350                 }
351
352                 protected XmlQualifiedName GetXsiType ()
353                 {
354                         string typeName = Reader.GetAttribute (typeX, XmlSchema.InstanceNamespace);
355                         
356                         if (typeName == string.Empty || typeName == null) {
357                                 typeName = Reader.GetAttribute (typeX, w3InstanceNS1999);
358                                 if (typeName == string.Empty || typeName == null) {
359                                         typeName = Reader.GetAttribute (typeX, w3InstanceNS2000);
360                                         if (typeName == string.Empty || typeName == null)
361                                                 return null;
362                                 }
363                         }
364                         
365                         int i = typeName.IndexOf (":");
366                         if (i == -1) return new XmlQualifiedName (typeName, Reader.NamespaceURI);
367                         else 
368                         {
369                                 string prefix = typeName.Substring(0,i);
370                                 string name = typeName.Substring (i+1);
371                                 return new XmlQualifiedName (name, Reader.LookupNamespace (prefix));
372                         }
373                 }
374
375                 protected abstract void InitCallbacks ();
376                 protected abstract void InitIDs ();
377
378                 protected bool IsXmlnsAttribute (string name)
379                 {
380                         int length = name.Length;
381                         if (length < 5)
382                                 return false;
383
384                         if (length == 5)
385                                 return (name == "xmlns");
386
387                         return name.StartsWith ("xmlns:");
388                 }
389
390 #if !MOONLIGHT
391                 protected void ParseWsdlArrayType (XmlAttribute attr)
392                 {
393                         if (attr.NamespaceURI == wsdlNS && attr.LocalName == arrayType)
394                         {
395                                 string ns = "", type, dimensions;
396                                 TypeTranslator.ParseArrayType (attr.Value, out type, out ns, out dimensions);
397                                 if (ns != "") ns = Reader.LookupNamespace (ns) + ":";
398                                 attr.Value = ns + type + dimensions;
399                         }
400                 }
401 #endif
402
403                 protected XmlQualifiedName ReadElementQualifiedName ()
404                 {
405                         readCount++;
406
407                         if (reader.IsEmptyElement) {
408                                 reader.Skip();
409                                 return ToXmlQualifiedName (String.Empty);
410                         }
411
412                         reader.ReadStartElement ();
413                         XmlQualifiedName xqn = ToXmlQualifiedName(reader.ReadString ());
414                         reader.ReadEndElement ();
415                         return xqn;
416                 }
417
418                 protected void ReadEndElement ()
419                 {
420                         readCount++;
421
422                         while (reader.NodeType == XmlNodeType.Whitespace)
423                                 reader.Skip ();
424
425                         if (reader.NodeType != XmlNodeType.None) {
426                                 reader.ReadEndElement ();
427                         } else {
428                                 reader.Skip ();
429                         }
430                 }
431
432                 protected bool ReadNull ()
433                 {
434                         if (!GetNullAttr ())
435                                 return false;
436
437                         readCount++;
438
439                         if (reader.IsEmptyElement) {
440                                 reader.Skip();
441                                 return true;
442                         }
443
444                         reader.ReadStartElement();
445 #if MOONLIGHT
446                         while (reader.NodeType != XmlNodeType.EndElement)
447                                 reader.Skip ();
448 #else
449                         while (reader.NodeType != XmlNodeType.EndElement)
450                                 UnknownNode (null);
451 #endif
452
453                         ReadEndElement ();
454                         return true;
455                 }
456
457                 protected XmlQualifiedName ReadNullableQualifiedName ()
458                 {
459                         if (ReadNull ())
460                                 return null;
461
462                         return ReadElementQualifiedName ();
463                 }
464
465                 protected string ReadNullableString ()
466                 {
467                         if (ReadNull ())
468                                 return null;
469
470                         readCount++;
471                         return reader.ReadElementString ();
472                 }
473
474                 protected bool ReadReference (out string fixupReference)
475                 {
476                         string href = reader.GetAttribute ("href");
477                         if (href == null) {
478                                 fixupReference = null;
479                                 return false;
480                         }
481
482                         if (href [0] != '#')
483                                 throw new InvalidOperationException("href not found: " + href);
484
485                         fixupReference = href.Substring (1);
486                         readCount++;
487                         if (!reader.IsEmptyElement) {
488                                 reader.ReadStartElement ();
489                                 ReadEndElement ();
490                         } else {
491                                 reader.Skip ();
492                         }
493                         return true;
494                 }
495
496                 protected object ReadReferencedElement ()
497                 {
498                         return ReadReferencedElement (Reader.LocalName, Reader.NamespaceURI);
499                 }
500
501                 WriteCallbackInfo GetCallbackInfo (XmlQualifiedName qname)
502                 {
503                         if (typesCallbacks == null) 
504                         {
505                                 typesCallbacks = new Hashtable ();
506                                 InitCallbacks ();
507                         }
508                         return (WriteCallbackInfo) typesCallbacks[qname];
509                 }
510
511                 protected object ReadReferencedElement (string name, string ns)
512                 {
513                         XmlQualifiedName qname = GetXsiType ();
514                         if (qname == null) qname = new XmlQualifiedName (name, ns);
515
516                         string id = Reader.GetAttribute ("id");
517                         object ob;
518
519                         // it takes precedence over xsi:type.
520                         // Sometimes there are array types in WSDL,
521                         // which are not reflected in client proxies.
522                         // In SOAP messages, they are marked
523                         // soap-env:arrayType, so use it (this could coexist
524                         // with xsi:type, which indicates the type in WSDL).
525                         // See bug #79057.
526                         string arrayTypeVal = Reader.GetAttribute (arrayType, soapNS);
527
528                         if (qname == arrayQName || arrayTypeVal != null && arrayTypeVal.Length > 0)
529                         {
530                                 CollectionFixup fixup = (collFixups != null) ? (CollectionFixup) collFixups[id] : null;
531                                 if (ReadList (out ob))
532                                 {
533                                         // List complete (does not contain references)
534                                         if (fixup != null)
535                                         {
536                                                 fixup.Callback (fixup.Collection, ob);
537                                                 collFixups.Remove (id);
538                                                 ob = fixup.Collection;
539                                         }
540                                 }
541                                 else if (fixup != null) 
542                                 {
543                                         fixup.CollectionItems = (object[])ob;
544                                         ob = fixup.Collection;
545                                 }
546                         }
547                         else
548                         {
549                                 WriteCallbackInfo info = GetCallbackInfo (qname);
550                                 if (info == null)
551                                         ob = ReadTypedPrimitive (qname, id != null);
552                                 else
553                                         ob = info.Callback();
554                         }
555                         AddTarget (id, ob);
556                         return ob;
557                 }
558                 
559                 bool ReadList (out object resultList)
560                 {
561                         string arrayTypeAttr = Reader.GetAttribute (arrayType, soapNS);
562                         if (arrayTypeAttr == null) arrayTypeAttr = Reader.GetAttribute (arrayType, wsdlNS);
563                         
564                         XmlQualifiedName qn = ToXmlQualifiedName (arrayTypeAttr);
565                         int i = qn.Name.LastIndexOf ('[');
566                         string dim = qn.Name.Substring (i);
567                         string itemType = qn.Name.Substring (0,i);
568                         int count = Int32.Parse (dim.Substring (1, dim.Length - 2), CultureInfo.InvariantCulture);
569
570                         Array list;
571
572                         i = itemType.IndexOf ('['); if (i == -1) i = itemType.Length;
573                         string baseType = itemType.Substring (0,i);
574                         string arrayTypeName;
575
576                         if (qn.Namespace == w3SchemaNS)
577                                 arrayTypeName = TypeTranslator.GetPrimitiveTypeData (baseType).Type.FullName + itemType.Substring (i);
578                         else
579                         {
580                                 WriteCallbackInfo info = GetCallbackInfo (new XmlQualifiedName (baseType,qn.Namespace));
581                                 arrayTypeName = info.Type.FullName + itemType.Substring (i) + ", " + info.Type.Assembly.FullName;
582                         }
583
584                         list = Array.CreateInstance (Type.GetType (arrayTypeName), count);
585
586                         bool listComplete = true;
587
588                         if (Reader.IsEmptyElement) {
589                                 readCount++;
590                                 Reader.Skip ();
591                         } else {
592                                 Reader.ReadStartElement ();
593                                 for (int n=0; n<count; n++)
594                                 {
595                                         whileIterationCount++;
596                                         readCount++;
597                                         Reader.MoveToContent ();
598                                         string id;
599                                         object item = ReadReferencingElement (itemType, qn.Namespace, out id);
600                                         if (id == null) 
601                                                 list.SetValue (item,n);
602                                         else
603                                         {
604                                                 AddFixup (new CollectionItemFixup (list, n, id));
605                                                 listComplete = false;
606                                         }
607                                 }
608                                 whileIterationCount = 0;
609                                 Reader.ReadEndElement ();
610                         }
611
612                         resultList = list;
613                         return listComplete;
614                 }
615                 
616                 protected void ReadReferencedElements ()
617                 {
618                         reader.MoveToContent();
619                         XmlNodeType nt = reader.NodeType;
620                         while (nt != XmlNodeType.EndElement && nt != XmlNodeType.None) {
621                                 whileIterationCount++;
622                                 readCount++;
623                                 ReadReferencedElement ();
624                                 reader.MoveToContent ();
625                                 nt = reader.NodeType;
626                         }
627                         whileIterationCount = 0;
628
629                         // Registers delayed list
630                         
631                         if (delayedListFixups != null)
632                         {
633                                 foreach (DictionaryEntry entry in delayedListFixups)
634                                         AddTarget ((string)entry.Key, entry.Value);
635                         }
636                         // Fix arrays
637
638                         if (collItemFixups != null)
639                         {
640                                 foreach (CollectionItemFixup itemFixup in collItemFixups)
641                                         itemFixup.Collection.SetValue (GetTarget (itemFixup.Id), itemFixup.Index);
642                         }
643
644                         // Fills collections
645
646                         if (collFixups != null)
647                         {
648                                 ICollection cfixups = collFixups.Values;
649                                 foreach (CollectionFixup fixup in cfixups)
650                                         fixup.Callback (fixup.Collection, fixup.CollectionItems);
651                         }
652
653                         // Fills class instances
654
655                         if (fixups != null)
656                         {
657                                 foreach (Fixup fixup in fixups)
658                                         fixup.Callback (fixup);
659                         }
660                         
661                         if (targets != null) {
662                                 foreach (DictionaryEntry e in targets) {
663                                         if (e.Value != null && (referencedObjects == null || !referencedObjects.Contains (e.Value)))
664                                                 UnreferencedObject ((string)e.Key, e.Value);
665                                 }
666                         }
667                 }
668
669                 protected object ReadReferencingElement (out string fixupReference)
670                 {
671                         return ReadReferencingElement (Reader.LocalName, Reader.NamespaceURI, false, out fixupReference);
672                 }
673
674                 protected object ReadReferencingElement (string name, string ns, out string fixupReference)
675                 {
676                         return ReadReferencingElement (name, ns, false, out fixupReference);
677                 }
678
679                 protected object ReadReferencingElement (string name,
680                                                          string ns,
681                                                          bool elementCanBeType,
682                                                          out string fixupReference)
683                 {
684                         if (ReadNull ())
685                         {
686                                 fixupReference = null;
687                                 return null;
688                         }
689
690                         string refid = Reader.GetAttribute ("href");
691
692                         if (refid == string.Empty || refid == null)
693                         {
694                                 fixupReference = null;
695
696                                 XmlQualifiedName qname = GetXsiType ();
697                                 if (qname == null) qname = new XmlQualifiedName (name, ns);
698                                 string arrayTypeAttr = Reader.GetAttribute (arrayType, soapNS);
699
700                                 if (qname == arrayQName || arrayTypeAttr != null)
701                                 {
702                                         delayedListFixups = EnsureHashtable (delayedListFixups);
703                                         fixupReference = "__<" + (delayedFixupId++) + ">";
704                                         object items;
705                                         ReadList (out items);
706                                         delayedListFixups [fixupReference] = items;
707                                         return null;
708                                 }
709                                 else
710                                 {
711                                         WriteCallbackInfo info = GetCallbackInfo (qname);
712                                         if (info == null)
713                                                 return ReadTypedPrimitive (qname, true);
714                                         else
715                                                 return info.Callback();
716                                 }
717                         }
718                         else
719                         {
720                                 if (refid.StartsWith ("#")) refid = refid.Substring (1);
721
722                                 readCount++;
723                                 Reader.Skip ();
724                                 if (TargetReady (refid))
725                                 {
726                                         fixupReference = null;
727                                         return GetTarget (refid);
728                                 }
729                                 else
730                                 {
731                                         fixupReference = refid;
732                                         return null;
733                                 }
734                         }
735                 }
736
737                 protected IXmlSerializable ReadSerializable (IXmlSerializable serializable)
738                 {
739                         if (ReadNull ()) return null;
740                         int depth = reader.Depth;
741                         readCount++;
742                         serializable.ReadXml (reader);
743                         Reader.MoveToContent ();
744                         while (reader.Depth > depth)
745                                 reader.Skip ();
746                         if (reader.Depth == depth && reader.NodeType == XmlNodeType.EndElement)
747                                 reader.ReadEndElement ();
748                         return serializable;
749                 }
750
751                 protected string ReadString (string value)
752                 {
753                         readCount++;
754                         if (value == null || value == String.Empty)
755                                 return reader.ReadString ();
756
757                         return (value + reader.ReadString ());
758                 }
759
760                 protected object ReadTypedPrimitive (XmlQualifiedName type)
761                 {
762                         return ReadTypedPrimitive (type, false);
763                 }
764                 
765                 object ReadTypedPrimitive (XmlQualifiedName qname, bool reportUnknown)
766                 {
767                         if (qname == null) qname = GetXsiType ();
768                         
769                         TypeData typeData = TypeTranslator.FindPrimitiveTypeData (qname.Name);
770                         if (typeData == null || typeData.SchemaType != SchemaTypes.Primitive)
771                         {
772 #if MOONLIGHT
773                                 // skip everything
774                                 reader.Skip ();
775                                 return new Object ();
776 #else
777                                 // Put everything into a node array
778                                 readCount++;
779                                 XmlNode node = Document.ReadNode (reader);
780                                 
781                                 if (reportUnknown)
782                                         OnUnknownNode (node, null, null);
783
784                                 if (node.ChildNodes.Count == 0 && node.Attributes.Count == 0)
785                                         return new Object ();
786
787                                 XmlElement elem = node as XmlElement;
788                                 
789                                 if (elem == null)
790                                         return new XmlNode[] {node};
791                                 else {
792                                         XmlNode[] nodes = new XmlNode[elem.Attributes.Count + elem.ChildNodes.Count];
793                                         int n = 0;
794                                         foreach (XmlNode no in elem.Attributes)
795                                                 nodes[n++] = no;
796                                         foreach (XmlNode no in elem.ChildNodes)
797                                                 nodes[n++] = no;
798                                         return nodes;
799                                 }
800 #endif
801                         }
802
803                         if (typeData.Type == typeof (XmlQualifiedName)) return ReadNullableQualifiedName ();
804                         readCount++;
805                         return XmlCustomFormatter.FromXmlString (typeData, Reader.ReadElementString ());
806                 }
807
808 #if !MOONLIGHT
809                 protected XmlNode ReadXmlNode (bool wrapped)
810                 {
811                         readCount++;
812                         XmlNode node = Document.ReadNode (reader);
813                         if (wrapped)
814                                 return node.FirstChild;
815                         else
816                                 return node;
817                 }
818
819                 protected XmlDocument ReadXmlDocument (bool wrapped)
820                 {
821                         readCount++;
822
823                         if (wrapped)
824                                 reader.ReadStartElement ();
825                         reader.MoveToContent ();
826                         XmlDocument doc = new XmlDocument ();
827                         XmlNode node = doc.ReadNode (reader);
828                         doc.AppendChild (node);
829                         
830                         if (wrapped)
831                                 reader.ReadEndElement ();
832                                 
833                         return doc;
834                 }
835 #endif
836
837                 protected void Referenced (object o)
838                 {
839                         if (o != null) {
840                                 if (referencedObjects == null) referencedObjects = new Hashtable ();
841                                 referencedObjects [o] = o;
842                         }
843                 }
844
845                 protected Array ShrinkArray (Array a, int length, Type elementType, bool isNullable)
846                 {
847                         if (length == 0 && isNullable) return null;
848                         if (a == null) return Array.CreateInstance (elementType, length);
849                         if (a.Length == length) return a;
850
851                         Array result = Array.CreateInstance (elementType, length);
852                         Array.Copy (a, result, length);
853                         return result;
854                 }
855
856                 protected byte[] ToByteArrayBase64 (bool isNull)
857                 {
858                         readCount++;
859                         if (isNull) {
860                                 Reader.ReadString ();
861                                 return null;
862                         }
863                         else
864                                 return ToByteArrayBase64 (Reader.ReadString ());
865                 }
866
867                 protected static byte[] ToByteArrayBase64 (string value)
868                 {
869                         return Convert.FromBase64String (value);
870                 }
871
872                 protected byte[] ToByteArrayHex (bool isNull)
873                 {
874                         readCount++;
875                         if (isNull) {
876                                 Reader.ReadString ();
877                                 return null;
878                         }
879                         else
880                                 return ToByteArrayHex (Reader.ReadString ());
881                 }
882
883                 protected static byte[] ToByteArrayHex (string value)
884                 {
885                         return XmlConvert.FromBinHexString (value);
886                 }
887
888                 protected static char ToChar (string value)
889                 {
890                         return XmlCustomFormatter.ToChar (value);
891                 }
892
893                 protected static DateTime ToDate (string value)
894                 {
895                         return XmlCustomFormatter.ToDate (value);
896                 }
897
898                 protected static DateTime ToDateTime (string value)
899                 {
900                         return XmlCustomFormatter.ToDateTime (value);
901                 }
902
903 #if MOONLIGHT
904                 protected static long ToEnum (string value, IDictionary h, string typeName)
905                 {
906                         return XmlCustomFormatter.ToEnum (value, (Hashtable) h, typeName, true);
907                 }
908 #else
909                 protected static long ToEnum (string value, Hashtable h, string typeName)
910                 {
911                         return XmlCustomFormatter.ToEnum (value, h, typeName, true);
912                 }
913 #endif
914
915                 protected static DateTime ToTime (string value)
916                 {
917                         return XmlCustomFormatter.ToTime (value);
918                 }
919
920                 protected static string ToXmlName (string value)
921                 {
922                         return XmlCustomFormatter.ToXmlName (value);
923                 }
924
925                 protected static string ToXmlNCName (string value)
926                 {
927                         return XmlCustomFormatter.ToXmlNCName (value);
928                 }
929
930                 protected static string ToXmlNmToken (string value)
931                 {
932                         return XmlCustomFormatter.ToXmlNmToken (value);
933                 }
934
935                 protected static string ToXmlNmTokens (string value)
936                 {
937                         return XmlCustomFormatter.ToXmlNmTokens (value);
938                 }
939
940                 protected XmlQualifiedName ToXmlQualifiedName (string value)
941                 {
942                         string name;
943                         string ns;
944                         int lastColon = value.LastIndexOf (':');
945                         string decodedValue = XmlConvert.DecodeName (value);
946                         if (lastColon < 0) {
947                                 name = reader.NameTable.Add (decodedValue);
948                                 ns = reader.LookupNamespace (String.Empty);
949                         } else {
950                                 string prefix = value.Substring (0, lastColon);
951                                 ns = reader.LookupNamespace (prefix);
952                                 if (ns == null)
953                                         throw new InvalidOperationException ("namespace " + prefix + " not defined");
954
955                                 name = reader.NameTable.Add (value.Substring (lastColon + 1));
956                         }
957
958                         return new XmlQualifiedName (name, ns);
959                 }
960
961 #if MOONLIGHT
962                 protected void UnknownNode (object o)
963                 {
964                         throw new NotSupportedException ();
965                 }
966 #else
967                 protected void UnknownAttribute (object o, XmlAttribute attr)
968                 {
969                         UnknownAttribute (o, attr, null);
970                 }
971
972 #if NET_2_0
973                 protected
974 #endif
975                 void UnknownAttribute (object o, XmlAttribute attr, string qnames)
976                 {
977                         int line_number, line_position;
978                         
979                         if (Reader is XmlTextReader){
980                                 line_number = ((XmlTextReader)Reader).LineNumber;
981                                 line_position = ((XmlTextReader)Reader).LinePosition;
982                         } else {
983                                 line_number = 0;
984                                 line_position = 0;
985                         }
986
987                         XmlAttributeEventArgs args = new XmlAttributeEventArgs (attr, line_number, line_position, o);
988 #if NET_2_0
989                         args.ExpectedAttributes = qnames;
990 #endif
991
992                         if (eventSource != null)
993                                 eventSource.OnUnknownAttribute (args);
994                 }
995
996                 protected void UnknownElement (object o, XmlElement elem)
997                 {
998                         UnknownElement (o, elem, null);
999                 }
1000
1001 #if NET_2_0
1002                 protected
1003 #endif
1004                 void UnknownElement (object o, XmlElement elem, string qnames)
1005                 {
1006                         int line_number, line_position;
1007                         
1008                         if (Reader is XmlTextReader){
1009                                 line_number = ((XmlTextReader)Reader).LineNumber;
1010                                 line_position = ((XmlTextReader)Reader).LinePosition;
1011                         } else {
1012                                 line_number = 0;
1013                                 line_position = 0;
1014                         }
1015
1016                         XmlElementEventArgs args = new XmlElementEventArgs (elem, line_number, line_position, o);
1017 #if NET_2_0
1018                         args.ExpectedElements = qnames;
1019 #endif
1020
1021                         if (eventSource != null)
1022                                 eventSource.OnUnknownElement (args);
1023                 }
1024
1025                 protected void UnknownNode (object o)
1026                 {
1027                         UnknownNode (o, null);
1028                 }
1029
1030 #if NET_2_0
1031                 protected
1032 #endif
1033                 void UnknownNode (object o, string qnames)
1034                 {
1035                         OnUnknownNode (ReadXmlNode (false), o, qnames);
1036                 }
1037                 
1038                 void OnUnknownNode (XmlNode node, object o, string qnames)
1039                 {
1040                         int line_number, line_position;
1041                         
1042                         if (Reader is XmlTextReader){
1043                                 line_number = ((XmlTextReader)Reader).LineNumber;
1044                                 line_position = ((XmlTextReader)Reader).LinePosition;
1045                         } else {
1046                                 line_number = 0;
1047                                 line_position = 0;
1048                         }
1049         
1050                         if (node is XmlAttribute)
1051                         {
1052                                 UnknownAttribute (o, (XmlAttribute)node, qnames);
1053                                 return;
1054                         }
1055                         else if (node is XmlElement)
1056                         {
1057                                 UnknownElement (o, (XmlElement) node, qnames);
1058                                 return;
1059                         }
1060                         else
1061                         {
1062                                 if (eventSource != null)
1063                                         eventSource.OnUnknownNode (new XmlNodeEventArgs(line_number, line_position, node.LocalName, node.Name, node.NamespaceURI, node.NodeType, o, node.Value));
1064         
1065                                 if (Reader.ReadState == ReadState.EndOfFile) 
1066                                         throw new InvalidOperationException ("End of document found");
1067                         }
1068                 }
1069 #endif // !NET_2_1
1070
1071                 protected void UnreferencedObject (string id, object o)
1072                 {
1073                         if (eventSource != null)
1074                                 eventSource.OnUnreferencedObject (new UnreferencedObjectEventArgs (o,id));
1075                 }
1076
1077                 #endregion // Methods
1078
1079                 class WriteCallbackInfo
1080                 {
1081                         public Type Type;
1082                         public string TypeName;
1083                         public string TypeNs;
1084                         public XmlSerializationReadCallback Callback;
1085                 }
1086
1087                 protected class CollectionFixup {
1088                         
1089                         XmlSerializationCollectionFixupCallback callback;
1090                         object collection;
1091                         object collectionItems;
1092                         string id;
1093
1094                         public CollectionFixup (object collection, XmlSerializationCollectionFixupCallback callback, string id)
1095                         {
1096                                 this.callback = callback;
1097                                 this.collection = collection;
1098                                 this.id = id;
1099                         }
1100
1101                         public XmlSerializationCollectionFixupCallback Callback { 
1102                                 get { return callback; }
1103                         }
1104
1105                         public object Collection {
1106                                 get { return collection; }
1107                         }
1108
1109                         public object Id {
1110                                 get { return id; }
1111                         }
1112
1113                         internal object CollectionItems
1114                         {
1115                                 get { return collectionItems; }
1116                                 set { collectionItems = value; }
1117                         }
1118                 }
1119
1120                 protected class Fixup {
1121
1122                         object source;
1123                         string[] ids;
1124                         XmlSerializationFixupCallback callback;
1125
1126                         public Fixup (object o, XmlSerializationFixupCallback callback, int count) 
1127                         {
1128                                 this.source = o;
1129                                 this.callback = callback;
1130                                 this.ids = new string[count];
1131                         }
1132
1133                         public Fixup (object o, XmlSerializationFixupCallback callback, string[] ids)
1134                         {
1135                                 this.source = o;
1136                                 this.ids = ids;
1137                                 this.callback = callback;
1138                         }
1139
1140                         public XmlSerializationFixupCallback Callback {
1141                                 get { return callback; }
1142                         }
1143
1144                         public string[] Ids {
1145                                 get { return ids; }
1146                         }
1147
1148                         public object Source {
1149                                 get { return source; }
1150                                 set { source = value; }
1151                         }
1152                 }
1153
1154                 protected class CollectionItemFixup 
1155                 {
1156                         Array list;
1157                         int index;
1158                         string id;
1159
1160                         public CollectionItemFixup (Array list, int index, string id)
1161                         {
1162                                 this.list = list;
1163                                 this.index = index;
1164                                 this.id = id;
1165                         }
1166
1167                         public Array Collection
1168                         {
1169                                 get { return list; }
1170                         }
1171
1172                         public int Index
1173                         {
1174                                 get { return index; }
1175                         }
1176
1177                         public string Id
1178                         {
1179                                 get { return id; }
1180                         }
1181                 }
1182                 
1183 #if NET_2_0
1184                 [MonoTODO]
1185                 protected bool DecodeName
1186                 {
1187                         get { throw new NotImplementedException(); }
1188                         set { throw new NotImplementedException(); }
1189                 }
1190
1191                 protected string CollapseWhitespace (string value)
1192                 {
1193                         return value == null ? null : value.Trim ();
1194                 }
1195                                 
1196                 [MonoTODO]
1197                 protected Exception CreateBadDerivationException (
1198                         string xsdDerived, 
1199                         string nsDerived, 
1200                         string xsdBase, 
1201                         string nsBase, 
1202                         string clrDerived, 
1203                         string clrBase)
1204                 {
1205                         throw new NotImplementedException ();
1206                 }
1207                 
1208                 [MonoTODO]
1209                 protected Exception CreateInvalidCastException (Type type, object value, string id)
1210                 {
1211                         throw new NotImplementedException ();
1212                 }
1213                 
1214                 [MonoTODO]
1215                 protected Exception CreateMissingIXmlSerializableType (string name, string ns, string clrType)
1216                 {
1217                         throw new NotImplementedException ();
1218                 }
1219
1220                 [MonoTODO]
1221                 protected string ReadString (string value, bool trim)
1222                 {
1223                         throw new NotImplementedException ();
1224                 }
1225                 
1226                 [MonoTODO]
1227                 protected object ReadTypedNull (XmlQualifiedName type)
1228                 {
1229                         throw new NotImplementedException ();
1230                 }
1231                 
1232                 [MonoTODO]
1233                 protected static Assembly ResolveDynamicAssembly (string assemblyFullName)
1234                 {
1235                         throw new NotImplementedException ();
1236                 }
1237
1238 #endif
1239
1240         }
1241 }