8628650ad5d7e6779c435f9eede951cf64a1fadb
[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)\r
8 //
9 // Copyright (C) Tim Coleman, 2002
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 //
12
13 using System;
14 using System.Collections;
15 using System.Xml;
16
17 namespace System.Xml.Serialization {
18         public abstract class XmlSerializationReader {
19
20                 #region Fields
21
22                 XmlDocument document;
23                 XmlReader reader;
24                 ArrayList fixups;
25                 ArrayList collFixups;
26                 Hashtable readCallbacks;
27                 Hashtable typesCallbacks;
28                 ArrayList noIDTargets;
29                 Hashtable targets;
30                 XmlSerializer eventSource;
31
32                 string w3SchemaNS;
33                 string w3SchemaNS2000;
34                 string w3SchemaNS1999;
35                 string w3InstanceNS;
36                 string w3InstanceNS2000;
37                 string w3InstanceNS1999;
38                 string soapNS;
39                 string schema;
40                 string wsdlNS;
41                 string wsdlArrayType;
42                 string nullX;
43                 string nil;
44                 string typeX;
45                 string arrayType;
46                 string anyType;
47                 #endregion
48
49                 internal void Initialize (XmlReader reader, XmlSerializer eventSource)
50                 {
51                         w3SchemaNS = reader.NameTable.Add ("http://www.w3.org/2001/XMLSchema");
52                         w3SchemaNS2000 = reader.NameTable.Add ("http://www.w3.org/2000/10/XMLSchema");
53                         w3SchemaNS1999 = reader.NameTable.Add ("http://www.w3.org/1999/XMLSchema");
54                         w3InstanceNS = reader.NameTable.Add ("http://www.w3.org/2001/XMLSchema-instance");
55                         w3InstanceNS2000 = reader.NameTable.Add ("http://www.w3.org/2000/10/XMLSchema-instance");
56                         w3InstanceNS1999 = reader.NameTable.Add ("http://www.w3.org/1999/XMLSchema-instance");
57                         soapNS = reader.NameTable.Add ("http://schemas.xmlsoap.org/soap/encoding/");
58                         schema = reader.NameTable.Add ("schema");
59                         wsdlNS = reader.NameTable.Add ("http://schemas.xmlsoap.org/wsdl/");
60                         wsdlArrayType = reader.NameTable.Add ("arrayType");
61                         nullX = reader.NameTable.Add ("null");
62                         nil = reader.NameTable.Add ("nil");
63                         typeX = reader.NameTable.Add ("type");
64                         arrayType = reader.NameTable.Add ("arrayType");
65                         anyType = reader.NameTable.Add ("anyType");
66                         this.reader = reader;
67                         this.eventSource = eventSource;
68                         InitIDs ();
69                 }
70                         
71                 internal virtual object ReadObject ()\r
72                 {\r
73                         throw new NotImplementedException ();
74                 }\r
75 \r
76                 private ArrayList EnsureArrayList (ArrayList list)
77                 {
78                         if (list == null)
79                                 list = new ArrayList ();
80                         return list;
81                 }
82                 
83                 private Hashtable EnsureHashtable (Hashtable hash)
84                 {
85                         if (hash == null)
86                                 hash = new Hashtable ();
87                         return hash;
88                 }
89                 
90                 protected XmlSerializationReader ()
91                 {
92                 }
93
94                 protected XmlDocument Document
95                 {
96                         get {
97                                 if (document == null)
98                                         document = new XmlDocument (reader.NameTable);
99
100                                 return document;
101                         }
102                 }
103
104                 protected XmlReader Reader {
105                         get { return reader; }
106                 }
107
108                 #region Methods
109
110                 protected void AddFixup (CollectionFixup fixup)
111                 {
112                         collFixups = EnsureArrayList (collFixups);
113                         collFixups.Add(fixup);
114                 }
115
116                 protected void AddFixup (Fixup fixup)
117                 {
118                         fixups = EnsureArrayList (fixups);
119                         fixups.Add(fixup);
120                 }
121
122                 protected void AddReadCallback (string name, string ns, Type type, XmlSerializationReadCallback read)
123                 {
124                         XmlNameTable nt = reader.NameTable;
125                         XmlQualifiedName xqn = new XmlQualifiedName (nt.Add (name), nt.Add (ns));
126                         readCallbacks = EnsureHashtable (readCallbacks);
127                         readCallbacks.Add (xqn, read);
128                         typesCallbacks = EnsureHashtable (typesCallbacks);
129                         typesCallbacks.Add (xqn, type);
130                 }
131
132                 protected void AddTarget (string id, object o)
133                 {
134                         if (id != null) {
135                                 targets = EnsureHashtable (targets);
136                                 if (targets [id] == null)
137                                         targets.Add (id, o);
138                         } else {
139                                 if (o != null)
140                                         return;
141                                 noIDTargets = EnsureArrayList (noIDTargets);
142                                 noIDTargets.Add (o);
143                         }
144                 }
145
146                 private string CurrentTag ()
147                 {
148                         switch (reader.NodeType) {
149                         case XmlNodeType.None:
150                                 return String.Format ("<{0} xmlns='{1}'>", reader.LocalName,
151                                                                            reader.NamespaceURI);
152                         case XmlNodeType.Attribute:
153                                 return reader.Value;
154                         case XmlNodeType.Text:
155                                 return "CDATA";
156                         case XmlNodeType.ProcessingInstruction:
157                                 return "<--";
158                         case XmlNodeType.Entity:
159                                 return "<?";
160                         case XmlNodeType.EndElement:
161                                 return ">";
162                         default:
163                                 return "(unknown)";
164                         }
165                 }
166
167                 protected Exception CreateAbstractTypeException (string name, string ns)
168                 {
169                         string message = "Error at " + name + " " + ns + ":" + CurrentTag ();
170                         return new InvalidOperationException (message);
171                 }
172
173                 protected Exception CreateInvalidCastException (Type type, object value)
174                 {
175                         string message = String.Format ("Cannot assign object of type {0} to an object of " +
176                                                         "type {1}.", value.GetType (), type);
177                         return new InvalidCastException (message);
178                 }
179
180                 protected Exception CreateReadOnlyCollectionException (string name)
181                 {
182                         string message = String.Format ("Could not serialize {0}. Default constructors are " +
183                                                         "required for collections and enumerators.", name);
184                         return new InvalidOperationException (message);
185                 }
186
187                 protected Exception CreateUnknownConstantException (string value, Type enumType)
188                 {
189                         string message = String.Format ("'{0}' is not a valid value for {1}.", value, enumType);
190                         return new InvalidOperationException (message);
191                 }
192
193                 protected Exception CreateUnknownNodeException ()
194                 {
195                         string message = "Unknown xml node -> " + CurrentTag ();
196                         return new InvalidOperationException (message);
197                 }
198
199                 protected Exception CreateUnknownTypeException (XmlQualifiedName type)
200                 {
201                         string message = "Unknown type " + type.Namespace + ":" + type.Name + " " + CurrentTag ();
202                         return new InvalidOperationException (message);
203                 }
204
205                 protected Array EnsureArrayIndex (Array a, int index, Type elementType)
206                 {
207                         if (a != null && index < a.Length)
208                                 return a;
209
210                         int size;
211                         if (a == null) {
212                                 size = 32;
213                         } else {
214                                 size = a.Length * 2;
215                         }
216
217                         Array result = Array.CreateInstance (elementType, size);
218                         if (a != null)
219                                 Array.Copy (a, result, index);
220
221                         return result;
222                 }
223
224                 [MonoTODO ("Implement")]
225                 protected void FixupArrayRefs (object fixup)
226                 {
227                         throw new NotImplementedException ();
228                 }
229
230                 [MonoTODO ("Implement")]
231                 protected int GetArrayLength (string name, string ns)
232                 {
233                         throw new NotImplementedException ();
234                 }
235
236                 protected bool GetNullAttr ()
237                 {
238                         string na = reader.GetAttribute (nullX, w3InstanceNS);
239                         if (na == string.Empty) {
240                                 na = reader.GetAttribute (nil, w3InstanceNS);
241                                 if (na == string.Empty) {
242                                         na = reader.GetAttribute (nullX, w3InstanceNS2000);
243                                         if (na == string.Empty)
244                                                 na = reader.GetAttribute (nullX, w3InstanceNS1999);
245                                 }
246                         }
247                         return (na != string.Empty);
248                 }
249
250                 [MonoTODO ("Implement")]
251                 protected object GetTarget (string id)
252                 {
253                         throw new NotImplementedException ();
254                 }
255
256                 [MonoTODO ("Implement")]
257                 protected XmlQualifiedName GetXsiType ()
258                 {
259                         string typeName = Reader.GetAttribute ("xsi:type");
260                         if (typeName == string.Empty || typeName == null) return null;
261                         int i = typeName.IndexOf (":");
262                         if (i == -1) return new XmlQualifiedName (typeName, "");
263                         else 
264                         {
265                                 string prefix = typeName.Substring(0,i);
266                                 string name = typeName.Substring (i+1);
267                                 return new XmlQualifiedName (name, Reader.LookupNamespace (prefix));
268                         }
269                 }
270
271                 protected abstract void InitCallbacks ();
272                 protected abstract void InitIDs ();
273
274                 protected bool IsXmlnsAttribute (string name)
275                 {
276                         int length = name.Length;
277                         if (length < 5)
278                                 return false;
279
280                         if (length == 5)
281                                 return (name == "xmlns");
282
283                         return name.StartsWith ("xmlns:");
284                 }
285
286                 [MonoTODO ("Implement")]
287                 protected void ParseWsdlArrayType (XmlAttribute attr)
288                 {
289                         throw new NotImplementedException ();
290                 }
291
292                 protected XmlQualifiedName ReadElementQualifiedName ()
293                 {
294                         if (reader.IsEmptyElement) {
295                                 reader.Skip();
296                                 return ToXmlQualifiedName (String.Empty);
297                         }
298
299                         XmlQualifiedName xqn = ToXmlQualifiedName(reader.ReadString ());
300                         reader.ReadEndElement ();
301                         return xqn;
302                 }
303
304                 protected void ReadEndElement ()
305                 {
306                         while (reader.NodeType == XmlNodeType.Whitespace)
307                                 reader.Skip ();
308
309                         if (reader.NodeType != XmlNodeType.None) {
310                                 reader.ReadEndElement ();
311                         } else {
312                                 reader.Skip ();
313                         }
314                 }
315
316                 protected bool ReadNull ()
317                 {
318                         if (!GetNullAttr ())
319                                 return false;
320
321                         if (reader.IsEmptyElement) {
322                                 reader.Skip();
323                                 return true;
324                         }
325
326                         reader.ReadStartElement();
327                         while (reader.NodeType != XmlNodeType.EndElement)
328                                 UnknownNode (null);
329
330                         ReadEndElement ();
331                         return true;
332                 }
333
334                 protected XmlQualifiedName ReadNullableQualifiedName ()
335                 {
336                         if (ReadNull ())
337                                 return null;
338
339                         return ReadElementQualifiedName ();
340                 }
341
342                 protected string ReadNullableString ()
343                 {
344                         if (ReadNull ())
345                                 return null;
346
347                         return reader.ReadElementString ();
348                 }
349
350                 protected bool ReadReference (out string fixupReference)
351                 {
352                         string href = reader.GetAttribute ("href");
353                         if (href == null) {
354                                 fixupReference = null;
355                                 return false;
356                         }
357
358                         if (href [0] != '#')
359                                 throw new InvalidOperationException("href not found: " + href);
360
361                         fixupReference = href.Substring (1);
362                         if (!reader.IsEmptyElement) {
363                                 reader.ReadStartElement ();
364                                 ReadEndElement ();
365                         } else {
366                                 reader.Skip ();
367                         }
368                         return true;
369                 }
370
371                 protected object ReadReferencedElement ()
372                 {
373                         return ReadReferencedElement (null, null);
374                 }
375
376                 protected object ReadReferencedElement (string name, string ns)
377                 {
378                         string unused;
379                         return ReadReferencingElement (name, ns, false, out unused);
380                 }
381
382                 protected void ReadReferencedElements ()
383                 {
384                         string unused;
385
386                         reader.MoveToContent();
387                         XmlNodeType nt = reader.NodeType;
388                         while (nt != XmlNodeType.EndElement && nt != XmlNodeType.None) {
389                                 ReadReferencingElement (null, null, true, out unused);
390                                 reader.MoveToContent ();
391                                 nt = reader.NodeType;
392                         }
393                 }
394
395                 [MonoTODO ("Implement")]
396                 protected object ReadReferencingElement (out string fixupReference)
397                 {
398                         return ReadReferencingElement (null, null, false, out fixupReference);
399                 }
400
401                 protected object ReadReferencingElement (string name, string ns, out string fixupReference)
402                 {
403                         return ReadReferencingElement (name, ns, false, out fixupReference);
404                 }
405
406                 [MonoTODO]
407                 protected object ReadReferencingElement (string name,
408                                                          string ns,
409                                                          bool elementCanBeType,
410                                                          out string fixupReference)
411                 {
412                         throw new NotImplementedException ();
413                 }
414
415                 protected IXmlSerializable ReadSerializable (IXmlSerializable serializable)
416                 {
417                         serializable.ReadXml (reader);
418                         return serializable;
419                 }
420
421                 protected string ReadString (string value)
422                 {
423                         if (value == null || value == String.Empty)
424                                 return reader.ReadString ();
425
426                         return (value + reader.ReadString ());
427                 }
428
429                 protected object ReadTypedPrimitive (XmlQualifiedName type)
430                 {
431                         XmlQualifiedName qname = GetXsiType ();
432                         TypeData typeData = TypeTranslator.GetPrimitiveTypeData (qname.Name);
433                         if (typeData == null || typeData.SchemaType != SchemaTypes.Primitive) throw new InvalidOperationException ("Unknown type: " + qname.Name);
434                         return XmlCustomFormatter.FromXmlString (typeData.Type, Reader.ReadElementString ());
435                 }
436
437                 protected XmlNode ReadXmlNode (bool wrapped)
438                 {
439                         XmlNode node = Document.ReadNode (reader);
440                         if (wrapped)
441                                 return node.FirstChild;
442                         else
443                                 return node;
444                 }
445
446                 [MonoTODO ("Implement")]
447                 protected void Referenced (object o)
448                 {
449                         throw new NotImplementedException ();
450                 }
451
452                 protected Array ShrinkArray (Array a, int length, Type elementType, bool isNullable)
453                 {
454                         if (length == 0 && isNullable) return null;
455                         if (a == null) return Array.CreateInstance (elementType, length);
456                         if (a.Length == length) return a;
457
458                         Array result = Array.CreateInstance (elementType, length);
459                         Array.Copy (a, result, length);
460                         return result;
461                 }
462
463                 protected byte[] ToByteArrayBase64 (bool isNull)
464                 {
465                         return Convert.FromBase64String (Reader.ReadString());
466                 }
467
468                 [MonoTODO ("Implement")]
469                 protected static byte[] ToByteArrayBase64 (string value)
470                 {
471                         throw new NotImplementedException ();
472                 }
473
474                 [MonoTODO ("Implement")]
475                 protected byte[] ToByteArrayHex (bool isNull)
476                 {
477                         throw new NotImplementedException ();
478                 }
479
480                 [MonoTODO ("Implement")]
481                 protected static byte[] ToByteArrayHex (string value)
482                 {
483                         throw new NotImplementedException ();
484                 }
485
486                 protected static char ToChar (string value)
487                 {
488                         return XmlCustomFormatter.ToChar (value);
489                 }
490
491                 protected static DateTime ToDate (string value)
492                 {
493                         return XmlCustomFormatter.ToDate (value);
494                 }
495
496                 protected static DateTime ToDateTime (string value)
497                 {
498                         return XmlCustomFormatter.ToDateTime (value);
499                 }
500
501                 protected static long ToEnum (string value, Hashtable h, string typeName)
502                 {
503                         return XmlCustomFormatter.ToEnum (value, h, typeName, true);
504                 }
505
506                 protected static DateTime ToTime (string value)
507                 {
508                         return XmlCustomFormatter.ToTime (value);
509                 }
510
511                 protected static string ToXmlName (string value)
512                 {
513                         return XmlCustomFormatter.ToXmlName (value);
514                 }
515
516                 protected static string ToXmlNCName (string value)
517                 {
518                         return XmlCustomFormatter.ToXmlNCName (value);
519                 }
520
521                 protected static string ToXmlNmToken (string value)
522                 {
523                         return XmlCustomFormatter.ToXmlNmToken (value);
524                 }
525
526                 protected static string ToXmlNmTokens (string value)
527                 {
528                         return XmlCustomFormatter.ToXmlNmTokens (value);
529                 }
530
531                 protected XmlQualifiedName ToXmlQualifiedName (string value)
532                 {
533                         string name;
534                         string ns;
535                         int lastColon = value.LastIndexOf (':');
536                         string decodedValue = XmlConvert.DecodeName (value);
537                         if (lastColon < 0) {
538                                 name = reader.NameTable.Add (decodedValue);
539                                 ns = reader.LookupNamespace (String.Empty);
540                         } else {
541                                 string prefix = value.Substring (0, lastColon);
542                                 ns = reader.LookupNamespace (prefix);
543                                 if (ns == null)
544                                         throw new InvalidOperationException ("namespace " + prefix + "not defined");
545
546                                 name = reader.NameTable.Add (value.Substring (lastColon + 1));
547                         }
548
549                         return new XmlQualifiedName (name, ns);
550                 }
551
552                 protected void UnknownAttribute (object o, XmlAttribute attr)
553                 {
554                         // TODO: line numbers
555                         eventSource.OnUnknownAttribute (new XmlAttributeEventArgs (attr,0,0,o));
556                 }
557
558                 protected void UnknownElement (object o, XmlElement elem)
559                 {
560                         // TODO: line numbers
561                         eventSource.OnUnknownElement (new XmlElementEventArgs(elem,0,0,o));
562                 }
563
564                 protected void UnknownNode (object o)
565                 {
566                         // TODO: line numbers
567                         eventSource.OnUnknownNode (new XmlNodeEventArgs(0, 0, Reader.LocalName, Reader.Name, Reader.NamespaceURI, Reader.NodeType, o, Reader.Value));
568                         if (Reader.NodeType != XmlNodeType.Attribute)
569                         {
570                                 Reader.Skip();
571                                 if (Reader.ReadState == ReadState.EndOfFile) 
572                                         throw new InvalidOperationException ("End of document found");
573                         }
574                 }
575
576                 protected void UnreferencedObject (string id, object o)
577                 {
578                         eventSource.OnUnreferencedObject (new UnreferencedObjectEventArgs (o,id));
579                 }
580
581                 #endregion // Methods
582
583                 protected class CollectionFixup {
584                         
585                         #region Fields
586
587                         XmlSerializationCollectionFixupCallback callback;
588                         object collection;
589                         object collectionItems;
590
591                         #endregion // Fields
592
593                         #region Constructors
594
595                         [MonoTODO]
596                         public CollectionFixup (object collection, XmlSerializationCollectionFixupCallback callback, object collectionItems)
597                         {
598                                 this.callback = callback;
599                                 this.collection = collection;
600                                 this.collectionItems = collectionItems;
601                         }
602
603                         #endregion // Constructors
604
605                         #region Properties
606
607                         public XmlSerializationCollectionFixupCallback Callback { 
608                                 get { return callback; }
609                         }
610
611                         public object Collection {
612                                 get { return collection; }
613                         }
614
615                         public object CollectionItems {
616                                 get { return collectionItems; }
617                         }
618
619                         #endregion // Properties
620                 }
621
622                 protected class Fixup {
623
624                         #region Fields
625
626                         object source;
627                         string[] ids;
628                         XmlSerializationFixupCallback callback;
629
630                         #endregion // Fields
631
632                         #region Constructors
633
634                         [MonoTODO]
635                         public Fixup (object o, XmlSerializationFixupCallback callback, int count) 
636                         {
637                                 this.callback = callback;
638                         }
639
640                         [MonoTODO]
641                         public Fixup (object o, XmlSerializationFixupCallback callback, string[] ids)
642                         {
643                                 this.callback = callback;
644                         }
645
646                         #endregion // Constructors
647
648                         #region Properties
649
650                         public XmlSerializationFixupCallback Callback {
651                                 get { return callback; }
652                         }
653
654                         public string[] Ids {
655                                 get { return ids; }
656                         }
657
658                         public object Source {
659                                 get { return source; }
660                                 set { source = value; }
661                         }
662
663                         #endregion // Properties
664                 }
665         }
666 }
667