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