1 //------------------------------------------------------------------------------
2 // <copyright file="XmlQueryStaticData.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System.Collections.Generic;
9 using System.Diagnostics;
11 using System.Reflection;
12 using System.Xml.Xsl.IlGen;
13 using System.Xml.Xsl.Qil;
15 namespace System.Xml.Xsl.Runtime {
17 /// Contains all static data that is used by the runtime.
19 internal class XmlQueryStaticData {
20 // Name of the field to serialize to
21 public const string DataFieldName = "staticData";
22 public const string TypesFieldName = "ebTypes";
24 // Format version marker to support versioning: (major << 8) | minor
25 private const int CurrentFormatVersion = (0 << 8) | 0;
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;
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;
56 this.GetObjectData(out data, out ebTypes);
57 XmlQueryStaticData copy = new XmlQueryStaticData(data, ebTypes);
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;
72 /// Deserialize XmlQueryStaticData object from a byte array.
74 public XmlQueryStaticData(byte[] data, Type[] ebTypes) {
75 MemoryStream dataStream = new MemoryStream(data, /*writable:*/false);
76 XmlQueryDataReader dataReader = new XmlQueryDataReader(dataStream);
79 // Read a format version
80 int formatVersion = dataReader.ReadInt32Encoded();
82 // Changes in the major part of version are not supported
83 if ((formatVersion & ~0xff) > CurrentFormatVersion)
84 throw new NotSupportedException();
86 // XmlWriterSettings defaultWriterSettings;
87 defaultWriterSettings = new XmlWriterSettings(dataReader);
89 // IList<WhitespaceRule> whitespaceRules;
90 length = dataReader.ReadInt32();
92 this.whitespaceRules = new WhitespaceRule[length];
93 for (int idx = 0; idx < length; idx++) {
94 this.whitespaceRules[idx] = new WhitespaceRule(dataReader);
99 length = dataReader.ReadInt32();
101 this.names = new string[length];
102 for (int idx = 0; idx < length; idx++) {
103 this.names[idx] = dataReader.ReadString();
107 // StringPair[][] prefixMappingsList;
108 length = dataReader.ReadInt32();
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());
120 // Int32Pair[] filters;
121 length = dataReader.ReadInt32();
123 this.filters = new Int32Pair[length];
124 for (int idx = 0; idx < length; idx++) {
125 this.filters[idx] = new Int32Pair(dataReader.ReadInt32Encoded(), dataReader.ReadInt32Encoded());
129 // XmlQueryType[] types;
130 length = dataReader.ReadInt32();
132 this.types = new XmlQueryType[length];
133 for (int idx = 0; idx < length; idx++) {
134 this.types[idx] = XmlQueryTypeFactory.Deserialize(dataReader);
138 // XmlCollation[] collations;
139 length = dataReader.ReadInt32();
141 this.collations = new XmlCollation[length];
142 for (int idx = 0; idx < length; idx++) {
143 this.collations[idx] = new XmlCollation(dataReader);
147 // string[] globalNames;
148 length = dataReader.ReadInt32();
150 this.globalNames = new string[length];
151 for (int idx = 0; idx < length; idx++) {
152 this.globalNames[idx] = dataReader.ReadString();
156 // EarlyBoundInfo[] earlyBound;
157 length = dataReader.ReadInt32();
159 this.earlyBound = new EarlyBoundInfo[length];
160 for (int idx = 0; idx < length; idx++) {
161 this.earlyBound[idx] = new EarlyBoundInfo(dataReader.ReadString(), ebTypes[idx]);
165 Debug.Assert(formatVersion != CurrentFormatVersion || dataReader.Read() == -1, "Extra data at the end of the stream");
170 /// Serialize XmlQueryStaticData object into a byte array.
172 public void GetObjectData(out byte[] data, out Type[] ebTypes) {
173 MemoryStream dataStream = new MemoryStream(4096);
174 XmlQueryDataWriter dataWriter = new XmlQueryDataWriter(dataStream);
176 // First put the format version
177 dataWriter.WriteInt32Encoded(CurrentFormatVersion);
179 // XmlWriterSettings defaultWriterSettings;
180 defaultWriterSettings.GetObjectData(dataWriter);
182 // IList<WhitespaceRule> whitespaceRules;
183 if (this.whitespaceRules == null) {
187 dataWriter.Write(this.whitespaceRules.Count);
188 foreach (WhitespaceRule rule in this.whitespaceRules) {
189 rule.GetObjectData(dataWriter);
194 if (this.names == null) {
198 dataWriter.Write(this.names.Length);
199 foreach (string name in this.names) {
200 dataWriter.Write(name);
204 // StringPair[][] prefixMappingsList;
205 if (this.prefixMappingsList == null) {
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);
219 // Int32Pair[] filters;
220 if (this.filters == null) {
224 dataWriter.Write(this.filters.Length);
225 foreach (Int32Pair filter in this.filters) {
226 dataWriter.WriteInt32Encoded(filter.Left);
227 dataWriter.WriteInt32Encoded(filter.Right);
231 // XmlQueryType[] types;
232 if (this.types == null) {
236 dataWriter.Write(this.types.Length);
237 foreach (XmlQueryType type in this.types) {
238 XmlQueryTypeFactory.Serialize(dataWriter, type);
242 // XmlCollation[] collations;
243 if (collations == null) {
247 dataWriter.Write(this.collations.Length);
248 foreach (XmlCollation collation in this.collations) {
249 collation.GetObjectData(dataWriter);
253 // string[] globalNames;
254 if (this.globalNames == null) {
258 dataWriter.Write(this.globalNames.Length);
259 foreach (string name in this.globalNames) {
260 dataWriter.Write(name);
264 // EarlyBoundInfo[] earlyBound;
265 if (this.earlyBound == null) {
270 dataWriter.Write(this.earlyBound.Length);
271 ebTypes = new Type[this.earlyBound.Length];
273 foreach (EarlyBoundInfo info in this.earlyBound) {
274 dataWriter.Write(info.NamespaceUri);
275 ebTypes[idx++] = info.EarlyBoundType;
280 data = dataStream.ToArray();
284 /// Return the default writer settings.
286 public XmlWriterSettings DefaultWriterSettings {
287 get { return this.defaultWriterSettings; }
291 /// Return the rules used for whitespace stripping/preservation.
293 public IList<WhitespaceRule> WhitespaceRules {
294 get { return this.whitespaceRules; }
298 /// Return array of names used by this query.
300 public string[] Names {
301 get { return this.names; }
305 /// Return array of prefix mappings used by this query.
307 public StringPair[][] PrefixMappingsList {
308 get { return this.prefixMappingsList; }
312 /// Return array of name filter specifications used by this query.
314 public Int32Pair[] Filters {
315 get { return this.filters; }
319 /// Return array of types used by this query.
321 public XmlQueryType[] Types {
322 get { return this.types; }
326 /// Return array of collations used by this query.
328 public XmlCollation[] Collations {
329 get { return this.collations; }
333 /// Return names of all global variables and parameters used by this query.
335 public string[] GlobalNames {
336 get { return this.globalNames; }
340 /// Return array of early bound object information related to this query.
342 public EarlyBoundInfo[] EarlyBound {
343 get { return this.earlyBound; }
348 /// Subclass of BinaryReader used to serialize query static data.
350 internal class XmlQueryDataReader : BinaryReader {
351 public XmlQueryDataReader(Stream input) : base(input) { }
354 /// Read in a 32-bit integer in compressed format.
356 public int ReadInt32Encoded() {
357 return Read7BitEncodedInt();
361 /// Read a string value from the stream. Value can be null.
363 public string ReadStringQ() {
364 return ReadBoolean() ? ReadString() : null;
368 /// Read a signed byte value from the stream and check if it belongs to the given diapason.
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");
382 /// Subclass of BinaryWriter used to deserialize query static data.
384 internal class XmlQueryDataWriter : BinaryWriter {
385 public XmlQueryDataWriter(Stream output) : base(output) { }
388 /// Write a 32-bit integer in a compressed format.
390 public void WriteInt32Encoded(int value) {
391 Write7BitEncodedInt(value);
395 /// Write a string value to the stream. Value can be null.
397 public void WriteStringQ(string value) {
398 Write(value != null);