Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Runtime / XmlQueryStaticData.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlQueryStaticData.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.IO;
11 using System.Reflection;
12 using System.Xml.Xsl.IlGen;
13 using System.Xml.Xsl.Qil;
14
15 namespace System.Xml.Xsl.Runtime {
16     /// <summary>
17     /// Contains all static data that is used by the runtime.
18     /// </summary>
19     internal class XmlQueryStaticData {
20         // Name of the field to serialize to
21         public const string DataFieldName   = "staticData";
22         public const string TypesFieldName  = "ebTypes";
23
24         // Format version marker to support versioning: (major << 8) | minor
25         private const int CurrentFormatVersion = (0 << 8) | 0;
26
27         private XmlWriterSettings defaultWriterSettings;
28         private IList<WhitespaceRule> whitespaceRules;
29         private string[] names;
30         private StringPair[][] prefixMappingsList;
31         private Int32Pair[] filters;
32         private XmlQueryType[] types;
33         private XmlCollation[] collations;
34         private string[] globalNames;
35         private EarlyBoundInfo[] earlyBound;
36
37         /// <summary>
38         /// Constructor.
39         /// </summary>
40         public XmlQueryStaticData(XmlWriterSettings defaultWriterSettings, IList<WhitespaceRule> whitespaceRules, StaticDataManager staticData) {
41             Debug.Assert(defaultWriterSettings != null && staticData != null);
42             this.defaultWriterSettings = defaultWriterSettings;
43             this.whitespaceRules = whitespaceRules;
44             this.names = staticData.Names;
45             this.prefixMappingsList = staticData.PrefixMappingsList;
46             this.filters = staticData.NameFilters;
47             this.types = staticData.XmlTypes;
48             this.collations = staticData.Collations;
49             this.globalNames = staticData.GlobalNames;
50             this.earlyBound = staticData.EarlyBound;
51
52         #if DEBUG
53             // Round-trip check
54             byte[] data;
55             Type[] ebTypes;
56             this.GetObjectData(out data, out ebTypes);
57             XmlQueryStaticData copy = new XmlQueryStaticData(data, ebTypes);
58
59             this.defaultWriterSettings = copy.defaultWriterSettings;
60             this.whitespaceRules = copy.whitespaceRules;
61             this.names = copy.names;
62             this.prefixMappingsList = copy.prefixMappingsList;
63             this.filters = copy.filters;
64             this.types = copy.types;
65             this.collations = copy.collations;
66             this.globalNames = copy.globalNames;
67             this.earlyBound = copy.earlyBound;
68         #endif
69         }
70
71         /// <summary>
72         /// Deserialize XmlQueryStaticData object from a byte array.
73         /// </summary>
74         public XmlQueryStaticData(byte[] data, Type[] ebTypes) {
75             MemoryStream dataStream = new MemoryStream(data, /*writable:*/false);
76             XmlQueryDataReader dataReader = new XmlQueryDataReader(dataStream);
77             int length;
78
79             // Read a format version
80             int formatVersion = dataReader.ReadInt32Encoded();
81
82             // Changes in the major part of version are not supported
83             if ((formatVersion & ~0xff) > CurrentFormatVersion)
84                 throw new NotSupportedException();
85
86             // XmlWriterSettings defaultWriterSettings;
87             defaultWriterSettings = new XmlWriterSettings(dataReader);
88
89             // IList<WhitespaceRule> whitespaceRules;
90             length = dataReader.ReadInt32();
91             if (length != 0) {
92                 this.whitespaceRules = new WhitespaceRule[length];
93                 for (int idx = 0; idx < length; idx++) {
94                     this.whitespaceRules[idx] = new WhitespaceRule(dataReader);
95                 }
96             }
97
98             // string[] names;
99             length = dataReader.ReadInt32();
100             if (length != 0) {
101                 this.names = new string[length];
102                 for (int idx = 0; idx < length; idx++) {
103                     this.names[idx] = dataReader.ReadString();
104                 }
105             }
106
107             // StringPair[][] prefixMappingsList;
108             length = dataReader.ReadInt32();
109             if (length != 0) {
110                 this.prefixMappingsList = new StringPair[length][];
111                 for (int idx = 0; idx < length; idx++) {
112                     int length2 = dataReader.ReadInt32();
113                     this.prefixMappingsList[idx] = new StringPair[length2];
114                     for (int idx2 = 0; idx2 < length2; idx2++) {
115                         this.prefixMappingsList[idx][idx2] = new StringPair(dataReader.ReadString(), dataReader.ReadString());
116                     }
117                 }
118             }
119
120             // Int32Pair[] filters;
121             length = dataReader.ReadInt32();
122             if (length != 0) {
123                 this.filters = new Int32Pair[length];
124                 for (int idx = 0; idx < length; idx++) {
125                     this.filters[idx] = new Int32Pair(dataReader.ReadInt32Encoded(), dataReader.ReadInt32Encoded());
126                 }
127             }
128
129             // XmlQueryType[] types;
130             length = dataReader.ReadInt32();
131             if (length != 0) {
132                 this.types = new XmlQueryType[length];
133                 for (int idx = 0; idx < length; idx++) {
134                     this.types[idx] = XmlQueryTypeFactory.Deserialize(dataReader);
135                 }
136             }
137
138             // XmlCollation[] collations;
139             length = dataReader.ReadInt32();
140             if (length != 0) {
141                 this.collations = new XmlCollation[length];
142                 for (int idx = 0; idx < length; idx++) {
143                     this.collations[idx] = new XmlCollation(dataReader);
144                 }
145             }
146
147             // string[] globalNames;
148             length = dataReader.ReadInt32();
149             if (length != 0) {
150                 this.globalNames = new string[length];
151                 for (int idx = 0; idx < length; idx++) {
152                     this.globalNames[idx] = dataReader.ReadString();
153                 }
154             }
155
156             // EarlyBoundInfo[] earlyBound;
157             length = dataReader.ReadInt32();
158             if (length != 0) {
159                 this.earlyBound = new EarlyBoundInfo[length];
160                 for (int idx = 0; idx < length; idx++) {
161                     this.earlyBound[idx] = new EarlyBoundInfo(dataReader.ReadString(), ebTypes[idx]);
162                 }
163             }
164
165             Debug.Assert(formatVersion != CurrentFormatVersion || dataReader.Read() == -1, "Extra data at the end of the stream");
166             dataReader.Close();
167         }
168
169         /// <summary>
170         /// Serialize XmlQueryStaticData object into a byte array.
171         /// </summary>
172         public void GetObjectData(out byte[] data, out Type[] ebTypes) {
173             MemoryStream dataStream = new MemoryStream(4096);
174             XmlQueryDataWriter dataWriter = new XmlQueryDataWriter(dataStream);
175
176             // First put the format version
177             dataWriter.WriteInt32Encoded(CurrentFormatVersion);
178
179             // XmlWriterSettings defaultWriterSettings;
180             defaultWriterSettings.GetObjectData(dataWriter);
181
182             // IList<WhitespaceRule> whitespaceRules;
183             if (this.whitespaceRules == null) {
184                 dataWriter.Write(0);
185             }
186             else {
187                 dataWriter.Write(this.whitespaceRules.Count);
188                 foreach (WhitespaceRule rule in this.whitespaceRules) {
189                     rule.GetObjectData(dataWriter);
190                 }
191             }
192
193             // string[] names;
194             if (this.names == null) {
195                 dataWriter.Write(0);
196             }
197             else {
198                 dataWriter.Write(this.names.Length);
199                 foreach (string name in this.names) {
200                     dataWriter.Write(name);
201                 }
202             }
203
204             // StringPair[][] prefixMappingsList;
205             if (this.prefixMappingsList == null) {
206                 dataWriter.Write(0);
207             }
208             else {
209                 dataWriter.Write(this.prefixMappingsList.Length);
210                 foreach (StringPair[] mappings in this.prefixMappingsList) {
211                     dataWriter.Write(mappings.Length);
212                     foreach (StringPair mapping in mappings) {
213                         dataWriter.Write(mapping.Left);
214                         dataWriter.Write(mapping.Right);
215                     }
216                 }
217             }
218
219             // Int32Pair[] filters;
220             if (this.filters == null) {
221                 dataWriter.Write(0);
222             }
223             else {
224                 dataWriter.Write(this.filters.Length);
225                 foreach (Int32Pair filter in this.filters) {
226                     dataWriter.WriteInt32Encoded(filter.Left);
227                     dataWriter.WriteInt32Encoded(filter.Right);
228                 }
229             }
230
231             // XmlQueryType[] types;
232             if (this.types == null) {
233                 dataWriter.Write(0);
234             }
235             else {
236                 dataWriter.Write(this.types.Length);
237                 foreach (XmlQueryType type in this.types) {
238                     XmlQueryTypeFactory.Serialize(dataWriter, type);                    
239                 }
240             }
241
242             // XmlCollation[] collations;
243             if (collations == null) {
244                 dataWriter.Write(0);
245             }
246             else {
247                 dataWriter.Write(this.collations.Length);
248                 foreach (XmlCollation collation in this.collations) {
249                     collation.GetObjectData(dataWriter);
250                 }
251             }
252
253             // string[] globalNames;
254             if (this.globalNames == null) {
255                 dataWriter.Write(0);
256             }
257             else {
258                 dataWriter.Write(this.globalNames.Length);
259                 foreach (string name in this.globalNames) {
260                     dataWriter.Write(name);
261                 }
262             }
263
264             // EarlyBoundInfo[] earlyBound;
265             if (this.earlyBound == null) {
266                 dataWriter.Write(0);
267                 ebTypes = null;
268             }
269             else {
270                 dataWriter.Write(this.earlyBound.Length);
271                 ebTypes = new Type[this.earlyBound.Length];
272                 int idx = 0;
273                 foreach (EarlyBoundInfo info in this.earlyBound) {
274                     dataWriter.Write(info.NamespaceUri);
275                     ebTypes[idx++] = info.EarlyBoundType;
276                 }
277             }
278
279             dataWriter.Close();
280             data = dataStream.ToArray();
281         }
282
283         /// <summary>
284         /// Return the default writer settings.
285         /// </summary>
286         public XmlWriterSettings DefaultWriterSettings {
287             get { return this.defaultWriterSettings; }
288         }
289
290         /// <summary>
291         /// Return the rules used for whitespace stripping/preservation.
292         /// </summary>
293         public IList<WhitespaceRule> WhitespaceRules {
294             get { return this.whitespaceRules; }
295         }
296
297         /// <summary>
298         /// Return array of names used by this query.
299         /// </summary>
300         public string[] Names {
301             get { return this.names; }
302         }
303
304         /// <summary>
305         /// Return array of prefix mappings used by this query.
306         /// </summary>
307         public StringPair[][] PrefixMappingsList {
308             get { return this.prefixMappingsList; }
309         }
310
311         /// <summary>
312         /// Return array of name filter specifications used by this query.
313         /// </summary>
314         public Int32Pair[] Filters {
315             get { return this.filters; }
316         }
317
318         /// <summary>
319         /// Return array of types used by this query.
320         /// </summary>
321         public XmlQueryType[] Types {
322             get { return this.types; }
323         }
324
325         /// <summary>
326         /// Return array of collations used by this query.
327         /// </summary>
328         public XmlCollation[] Collations {
329             get { return this.collations; }
330         }
331
332         /// <summary>
333         /// Return names of all global variables and parameters used by this query.
334         /// </summary>
335         public string[] GlobalNames {
336             get { return this.globalNames; }
337         }
338
339         /// <summary>
340         /// Return array of early bound object information related to this query.
341         /// </summary>
342         public EarlyBoundInfo[] EarlyBound {
343             get { return this.earlyBound; }
344         }
345     }
346
347     /// <summary>
348     /// Subclass of BinaryReader used to serialize query static data.
349     /// </summary>
350     internal class XmlQueryDataReader : BinaryReader {
351         public XmlQueryDataReader(Stream input) : base(input) { }
352
353         /// <summary>
354         /// Read in a 32-bit integer in compressed format.
355         /// </summary>
356         public int ReadInt32Encoded() {
357             return Read7BitEncodedInt();
358         }
359
360         /// <summary>
361         /// Read a string value from the stream. Value can be null.
362         /// </summary>
363         public string ReadStringQ() {
364             return ReadBoolean() ? ReadString() : null;
365         }
366
367         /// <summary>
368         /// Read a signed byte value from the stream and check if it belongs to the given diapason.
369         /// </summary>
370         public sbyte ReadSByte(sbyte minValue, sbyte maxValue) {
371             sbyte value = ReadSByte();
372             if (value < minValue)
373                 throw new ArgumentOutOfRangeException("minValue");
374             if (maxValue < value)
375                 throw new ArgumentOutOfRangeException("maxValue");
376
377             return value;
378         }
379     }
380
381     /// <summary>
382     /// Subclass of BinaryWriter used to deserialize query static data.
383     /// </summary>
384     internal class XmlQueryDataWriter : BinaryWriter {
385         public XmlQueryDataWriter(Stream output) : base(output) { }
386
387         /// <summary>
388         /// Write a 32-bit integer in a compressed format.
389         /// </summary>
390         public void WriteInt32Encoded(int value) {
391             Write7BitEncodedInt(value);
392         }
393
394         /// <summary>
395         /// Write a string value to the stream. Value can be null.
396         /// </summary>
397         public void WriteStringQ(string value) {
398             Write(value != null);
399             if (value != null) {
400                 Write(value);
401             }
402         }
403     }
404 }