1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Xml;
7 using System.Collections.Generic;
8 using System.Globalization;
9 
10 namespace System.Runtime.Serialization
11 {
12     public sealed class ExtensionDataObject
13     {
14         private IList<ExtensionDataMember> _members;
15 
16 #if USE_REFEMIT || uapaot
ExtensionDataObject()17         public ExtensionDataObject()
18 #else
19         internal ExtensionDataObject()
20 #endif
21         {
22         }
23 
24 #if USE_REFEMIT || uapaot
25         public IList<ExtensionDataMember> Members
26 #else
27         internal IList<ExtensionDataMember> Members
28 #endif
29         {
30             get { return _members; }
31             set { _members = value; }
32         }
33     }
34 
35 #if USE_REFEMIT || uapaot
36     public class ExtensionDataMember
37 #else
38     internal class ExtensionDataMember
39 #endif
40     {
41         private string _name;
42         private string _ns;
43         private IDataNode _value;
44         private int _memberIndex;
45         public string Name
46         {
47             get { return _name; }
48             set { _name = value; }
49         }
50 
51         public string Namespace
52         {
53             get { return _ns; }
54             set { _ns = value; }
55         }
56 
57         public IDataNode Value
58         {
59             get { return _value; }
60             set { _value = value; }
61         }
62 
63         public int MemberIndex
64         {
65             get { return _memberIndex; }
66             set { _memberIndex = value; }
67         }
68     }
69 
70 #if USE_REFEMIT || uapaot
71     public interface IDataNode
72 #else
73     internal interface IDataNode
74 #endif
75     {
76         Type DataType { get; }
77         object Value { get; set; }  // boxes for primitives
78         string DataContractName { get; set; }
79         string DataContractNamespace { get; set; }
80         string ClrTypeName { get; set; }
81         string ClrAssemblyName { get; set; }
82         string Id { get; set; }
83         bool PreservesReferences { get; }
84 
85         // NOTE: consider moving below APIs to DataNode<T> if IDataNode API is made public
GetData(ElementData element)86         void GetData(ElementData element);
87         bool IsFinalValue { get; set; }
Clear()88         void Clear();
89     }
90 
91     internal class DataNode<T> : IDataNode
92     {
93         protected Type dataType;
94         private T _value;
95         private string _dataContractName;
96         private string _dataContractNamespace;
97         private string _clrTypeName;
98         private string _clrAssemblyName;
99         private string _id = Globals.NewObjectId;
100         private bool _isFinalValue;
101 
DataNode()102         internal DataNode()
103         {
104             this.dataType = typeof(T);
105             _isFinalValue = true;
106         }
107 
DataNode(T value)108         internal DataNode(T value)
109             : this()
110         {
111             _value = value;
112         }
113 
114         public Type DataType
115         {
116             get { return dataType; }
117         }
118 
119         public object Value
120         {
121             get { return _value; }
122             set { _value = (T)value; }
123         }
124 
125         bool IDataNode.IsFinalValue
126         {
127             get { return _isFinalValue; }
128             set { _isFinalValue = value; }
129         }
130 
GetValue()131         public T GetValue()
132         {
133             return _value;
134         }
135 
136 #if NotUsed
SetValue(T value)137         public void SetValue(T value)
138         {
139             this.value = value;
140         }
141 #endif
142 
143         public string DataContractName
144         {
145             get { return _dataContractName; }
146             set { _dataContractName = value; }
147         }
148 
149         public string DataContractNamespace
150         {
151             get { return _dataContractNamespace; }
152             set { _dataContractNamespace = value; }
153         }
154 
155         public string ClrTypeName
156         {
157             get { return _clrTypeName; }
158             set { _clrTypeName = value; }
159         }
160 
161         public string ClrAssemblyName
162         {
163             get { return _clrAssemblyName; }
164             set { _clrAssemblyName = value; }
165         }
166 
167         public bool PreservesReferences
168         {
169             get { return (Id != Globals.NewObjectId); }
170         }
171 
172         public string Id
173         {
174             get { return _id; }
175             set { _id = value; }
176         }
177 
GetData(ElementData element)178         public virtual void GetData(ElementData element)
179         {
180             element.dataNode = this;
181             element.attributeCount = 0;
182             element.childElementIndex = 0;
183 
184             if (DataContractName != null)
185                 AddQualifiedNameAttribute(element, Globals.XsiPrefix, Globals.XsiTypeLocalName, Globals.SchemaInstanceNamespace, DataContractName, DataContractNamespace);
186             if (ClrTypeName != null)
187                 element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrTypeLocalName, ClrTypeName);
188             if (ClrAssemblyName != null)
189                 element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, ClrAssemblyName);
190         }
191 
Clear()192         public virtual void Clear()
193         {
194             // dataContractName not cleared because it is used when re-serializing from unknown data
195             _clrTypeName = _clrAssemblyName = null;
196         }
197 
AddQualifiedNameAttribute(ElementData element, string elementPrefix, string elementName, string elementNs, string valueName, string valueNs)198         internal void AddQualifiedNameAttribute(ElementData element, string elementPrefix, string elementName, string elementNs, string valueName, string valueNs)
199         {
200             string prefix = ExtensionDataReader.GetPrefix(valueNs);
201             element.AddAttribute(elementPrefix, elementNs, elementName, String.Format(CultureInfo.InvariantCulture, "{0}:{1}", prefix, valueName));
202 
203             bool prefixDeclaredOnElement = false;
204             if (element.attributes != null)
205             {
206                 for (int i = 0; i < element.attributes.Length; i++)
207                 {
208                     AttributeData attribute = element.attributes[i];
209                     if (attribute != null && attribute.prefix == Globals.XmlnsPrefix && attribute.localName == prefix)
210                     {
211                         prefixDeclaredOnElement = true;
212                         break;
213                     }
214                 }
215             }
216             if (!prefixDeclaredOnElement)
217                 element.AddAttribute(Globals.XmlnsPrefix, Globals.XmlnsNamespace, prefix, valueNs);
218         }
219     }
220 
221     internal class ClassDataNode : DataNode<object>
222     {
223         private IList<ExtensionDataMember> _members;
224 
ClassDataNode()225         internal ClassDataNode()
226         {
227             dataType = Globals.TypeOfClassDataNode;
228         }
229 
230         internal IList<ExtensionDataMember> Members
231         {
232             get { return _members; }
233             set { _members = value; }
234         }
235 
Clear()236         public override void Clear()
237         {
238             base.Clear();
239             _members = null;
240         }
241     }
242 
243     internal class XmlDataNode : DataNode<object>
244     {
245         private IList<XmlAttribute> _xmlAttributes;
246         private IList<XmlNode> _xmlChildNodes;
247         private XmlDocument _ownerDocument;
248 
XmlDataNode()249         internal XmlDataNode()
250         {
251             dataType = Globals.TypeOfXmlDataNode;
252         }
253 
254         internal IList<XmlAttribute> XmlAttributes
255         {
256             get { return _xmlAttributes; }
257             set { _xmlAttributes = value; }
258         }
259 
260         internal IList<XmlNode> XmlChildNodes
261         {
262             get { return _xmlChildNodes; }
263             set { _xmlChildNodes = value; }
264         }
265 
266         internal XmlDocument OwnerDocument
267         {
268             get { return _ownerDocument; }
269             set { _ownerDocument = value; }
270         }
271 
Clear()272         public override void Clear()
273         {
274             base.Clear();
275             _xmlAttributes = null;
276             _xmlChildNodes = null;
277             _ownerDocument = null;
278         }
279     }
280 
281     internal class CollectionDataNode : DataNode<Array>
282     {
283         private IList<IDataNode> _items;
284         private string _itemName;
285         private string _itemNamespace;
286         private int _size = -1;
287 
CollectionDataNode()288         internal CollectionDataNode()
289         {
290             dataType = Globals.TypeOfCollectionDataNode;
291         }
292 
293         internal IList<IDataNode> Items
294         {
295             get { return _items; }
296             set { _items = value; }
297         }
298 
299         internal string ItemName
300         {
301             get { return _itemName; }
302             set { _itemName = value; }
303         }
304 
305         internal string ItemNamespace
306         {
307             get { return _itemNamespace; }
308             set { _itemNamespace = value; }
309         }
310 
311         internal int Size
312         {
313             get { return _size; }
314             set { _size = value; }
315         }
316 
GetData(ElementData element)317         public override void GetData(ElementData element)
318         {
319             base.GetData(element);
320 
321             element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ArraySizeLocalName, Size.ToString(NumberFormatInfo.InvariantInfo));
322         }
323 
Clear()324         public override void Clear()
325         {
326             base.Clear();
327             _items = null;
328             _size = -1;
329         }
330     }
331 
332     internal class ISerializableDataNode : DataNode<object>
333     {
334         private string _factoryTypeName;
335         private string _factoryTypeNamespace;
336         private IList<ISerializableDataMember> _members;
337 
ISerializableDataNode()338         internal ISerializableDataNode()
339         {
340             dataType = Globals.TypeOfISerializableDataNode;
341         }
342 
343         internal string FactoryTypeName
344         {
345             get { return _factoryTypeName; }
346             set { _factoryTypeName = value; }
347         }
348 
349         internal string FactoryTypeNamespace
350         {
351             get { return _factoryTypeNamespace; }
352             set { _factoryTypeNamespace = value; }
353         }
354 
355         internal IList<ISerializableDataMember> Members
356         {
357             get { return _members; }
358             set { _members = value; }
359         }
360 
GetData(ElementData element)361         public override void GetData(ElementData element)
362         {
363             base.GetData(element);
364 
365             if (FactoryTypeName != null)
366                 AddQualifiedNameAttribute(element, Globals.SerPrefix, Globals.ISerializableFactoryTypeLocalName, Globals.SerializationNamespace, FactoryTypeName, FactoryTypeNamespace);
367         }
368 
Clear()369         public override void Clear()
370         {
371             base.Clear();
372             _members = null;
373             _factoryTypeName = _factoryTypeNamespace = null;
374         }
375     }
376 
377     internal class ISerializableDataMember
378     {
379         private string _name;
380         private IDataNode _value;
381 
382         internal string Name
383         {
384             get { return _name; }
385             set { _name = value; }
386         }
387 
388         internal IDataNode Value
389         {
390             get { return _value; }
391             set { _value = value; }
392         }
393     }
394 }
395