diff options
author | diva | 2009-06-18 00:48:39 +0000 |
---|---|---|
committer | diva | 2009-06-18 00:48:39 +0000 |
commit | 913bc3bdb380cebebd11b657966486448962ab47 (patch) | |
tree | f41837093cd692b9fe42a21c9cb1473ef81dd0f1 /OpenSim/Framework/Capabilities/LLSD.cs | |
parent | Fix an uninitialized data block. Thanks, jhurliman (diff) | |
download | opensim-SC-913bc3bdb380cebebd11b657966486448962ab47.zip opensim-SC-913bc3bdb380cebebd11b657966486448962ab47.tar.gz opensim-SC-913bc3bdb380cebebd11b657966486448962ab47.tar.bz2 opensim-SC-913bc3bdb380cebebd11b657966486448962ab47.tar.xz |
Moved OpenSim/Framework/Communications/Capabilities up to OpenSim/Framework/Capabilities. Didn't change the namespace because VC# is not helping, and this would imply manually changing more than 50 files. So the namespace is still OpenSim.Framework.Communications.Capabilities, to be cleaned up later by someone with more energy.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Capabilities/LLSD.cs (renamed from OpenSim/Framework/Communications/Capabilities/LLSD.cs) | 1358 |
1 files changed, 679 insertions, 679 deletions
diff --git a/OpenSim/Framework/Communications/Capabilities/LLSD.cs b/OpenSim/Framework/Capabilities/LLSD.cs index c982092..73556fc 100644 --- a/OpenSim/Framework/Communications/Capabilities/LLSD.cs +++ b/OpenSim/Framework/Capabilities/LLSD.cs | |||
@@ -1,679 +1,679 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Globalization; | 30 | using System.Globalization; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Security.Cryptography; | 32 | using System.Security.Cryptography; |
33 | using System.Text; | 33 | using System.Text; |
34 | using System.Xml; | 34 | using System.Xml; |
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | 36 | ||
37 | namespace OpenSim.Framework.Communications.Capabilities | 37 | namespace OpenSim.Framework.Communications.Capabilities |
38 | { | 38 | { |
39 | /// <summary> | 39 | /// <summary> |
40 | /// Borrowed from (a older version of) libsl for now, as their new llsd code doesn't work we our decoding code. | 40 | /// Borrowed from (a older version of) libsl for now, as their new llsd code doesn't work we our decoding code. |
41 | /// </summary> | 41 | /// </summary> |
42 | public static class LLSD | 42 | public static class LLSD |
43 | { | 43 | { |
44 | /// <summary> | 44 | /// <summary> |
45 | /// | 45 | /// |
46 | /// </summary> | 46 | /// </summary> |
47 | public class LLSDParseException : Exception | 47 | public class LLSDParseException : Exception |
48 | { | 48 | { |
49 | public LLSDParseException(string message) : base(message) | 49 | public LLSDParseException(string message) : base(message) |
50 | { | 50 | { |
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | /// <summary> | 54 | /// <summary> |
55 | /// | 55 | /// |
56 | /// </summary> | 56 | /// </summary> |
57 | public class LLSDSerializeException : Exception | 57 | public class LLSDSerializeException : Exception |
58 | { | 58 | { |
59 | public LLSDSerializeException(string message) : base(message) | 59 | public LLSDSerializeException(string message) : base(message) |
60 | { | 60 | { |
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
64 | /// <summary> | 64 | /// <summary> |
65 | /// | 65 | /// |
66 | /// </summary> | 66 | /// </summary> |
67 | /// <param name="b"></param> | 67 | /// <param name="b"></param> |
68 | /// <returns></returns> | 68 | /// <returns></returns> |
69 | public static object LLSDDeserialize(byte[] b) | 69 | public static object LLSDDeserialize(byte[] b) |
70 | { | 70 | { |
71 | return LLSDDeserialize(new MemoryStream(b, false)); | 71 | return LLSDDeserialize(new MemoryStream(b, false)); |
72 | } | 72 | } |
73 | 73 | ||
74 | /// <summary> | 74 | /// <summary> |
75 | /// | 75 | /// |
76 | /// </summary> | 76 | /// </summary> |
77 | /// <param name="st"></param> | 77 | /// <param name="st"></param> |
78 | /// <returns></returns> | 78 | /// <returns></returns> |
79 | public static object LLSDDeserialize(Stream st) | 79 | public static object LLSDDeserialize(Stream st) |
80 | { | 80 | { |
81 | XmlTextReader reader = new XmlTextReader(st); | 81 | XmlTextReader reader = new XmlTextReader(st); |
82 | reader.Read(); | 82 | reader.Read(); |
83 | SkipWS(reader); | 83 | SkipWS(reader); |
84 | 84 | ||
85 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") | 85 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") |
86 | throw new LLSDParseException("Expected <llsd>"); | 86 | throw new LLSDParseException("Expected <llsd>"); |
87 | 87 | ||
88 | reader.Read(); | 88 | reader.Read(); |
89 | object ret = LLSDParseOne(reader); | 89 | object ret = LLSDParseOne(reader); |
90 | SkipWS(reader); | 90 | SkipWS(reader); |
91 | 91 | ||
92 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") | 92 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") |
93 | throw new LLSDParseException("Expected </llsd>"); | 93 | throw new LLSDParseException("Expected </llsd>"); |
94 | 94 | ||
95 | return ret; | 95 | return ret; |
96 | } | 96 | } |
97 | 97 | ||
98 | /// <summary> | 98 | /// <summary> |
99 | /// | 99 | /// |
100 | /// </summary> | 100 | /// </summary> |
101 | /// <param name="obj"></param> | 101 | /// <param name="obj"></param> |
102 | /// <returns></returns> | 102 | /// <returns></returns> |
103 | public static byte[] LLSDSerialize(object obj) | 103 | public static byte[] LLSDSerialize(object obj) |
104 | { | 104 | { |
105 | StringWriter sw = new StringWriter(); | 105 | StringWriter sw = new StringWriter(); |
106 | XmlTextWriter writer = new XmlTextWriter(sw); | 106 | XmlTextWriter writer = new XmlTextWriter(sw); |
107 | writer.Formatting = Formatting.None; | 107 | writer.Formatting = Formatting.None; |
108 | 108 | ||
109 | writer.WriteStartElement(String.Empty, "llsd", String.Empty); | 109 | writer.WriteStartElement(String.Empty, "llsd", String.Empty); |
110 | LLSDWriteOne(writer, obj); | 110 | LLSDWriteOne(writer, obj); |
111 | writer.WriteEndElement(); | 111 | writer.WriteEndElement(); |
112 | 112 | ||
113 | writer.Close(); | 113 | writer.Close(); |
114 | 114 | ||
115 | return Encoding.UTF8.GetBytes(sw.ToString()); | 115 | return Encoding.UTF8.GetBytes(sw.ToString()); |
116 | } | 116 | } |
117 | 117 | ||
118 | /// <summary> | 118 | /// <summary> |
119 | /// | 119 | /// |
120 | /// </summary> | 120 | /// </summary> |
121 | /// <param name="writer"></param> | 121 | /// <param name="writer"></param> |
122 | /// <param name="obj"></param> | 122 | /// <param name="obj"></param> |
123 | public static void LLSDWriteOne(XmlTextWriter writer, object obj) | 123 | public static void LLSDWriteOne(XmlTextWriter writer, object obj) |
124 | { | 124 | { |
125 | if (obj == null) | 125 | if (obj == null) |
126 | { | 126 | { |
127 | writer.WriteStartElement(String.Empty, "undef", String.Empty); | 127 | writer.WriteStartElement(String.Empty, "undef", String.Empty); |
128 | writer.WriteEndElement(); | 128 | writer.WriteEndElement(); |
129 | return; | 129 | return; |
130 | } | 130 | } |
131 | 131 | ||
132 | if (obj is string) | 132 | if (obj is string) |
133 | { | 133 | { |
134 | writer.WriteStartElement(String.Empty, "string", String.Empty); | 134 | writer.WriteStartElement(String.Empty, "string", String.Empty); |
135 | writer.WriteString((string) obj); | 135 | writer.WriteString((string) obj); |
136 | writer.WriteEndElement(); | 136 | writer.WriteEndElement(); |
137 | } | 137 | } |
138 | else if (obj is int) | 138 | else if (obj is int) |
139 | { | 139 | { |
140 | writer.WriteStartElement(String.Empty, "integer", String.Empty); | 140 | writer.WriteStartElement(String.Empty, "integer", String.Empty); |
141 | writer.WriteString(obj.ToString()); | 141 | writer.WriteString(obj.ToString()); |
142 | writer.WriteEndElement(); | 142 | writer.WriteEndElement(); |
143 | } | 143 | } |
144 | else if (obj is double) | 144 | else if (obj is double) |
145 | { | 145 | { |
146 | writer.WriteStartElement(String.Empty, "real", String.Empty); | 146 | writer.WriteStartElement(String.Empty, "real", String.Empty); |
147 | writer.WriteString(obj.ToString()); | 147 | writer.WriteString(obj.ToString()); |
148 | writer.WriteEndElement(); | 148 | writer.WriteEndElement(); |
149 | } | 149 | } |
150 | else if (obj is bool) | 150 | else if (obj is bool) |
151 | { | 151 | { |
152 | bool b = (bool) obj; | 152 | bool b = (bool) obj; |
153 | writer.WriteStartElement(String.Empty, "boolean", String.Empty); | 153 | writer.WriteStartElement(String.Empty, "boolean", String.Empty); |
154 | writer.WriteString(b ? "1" : "0"); | 154 | writer.WriteString(b ? "1" : "0"); |
155 | writer.WriteEndElement(); | 155 | writer.WriteEndElement(); |
156 | } | 156 | } |
157 | else if (obj is ulong) | 157 | else if (obj is ulong) |
158 | { | 158 | { |
159 | throw new Exception("ulong in LLSD is currently not implemented, fix me!"); | 159 | throw new Exception("ulong in LLSD is currently not implemented, fix me!"); |
160 | } | 160 | } |
161 | else if (obj is UUID) | 161 | else if (obj is UUID) |
162 | { | 162 | { |
163 | UUID u = (UUID) obj; | 163 | UUID u = (UUID) obj; |
164 | writer.WriteStartElement(String.Empty, "uuid", String.Empty); | 164 | writer.WriteStartElement(String.Empty, "uuid", String.Empty); |
165 | writer.WriteString(u.ToString()); | 165 | writer.WriteString(u.ToString()); |
166 | writer.WriteEndElement(); | 166 | writer.WriteEndElement(); |
167 | } | 167 | } |
168 | else if (obj is Hashtable) | 168 | else if (obj is Hashtable) |
169 | { | 169 | { |
170 | Hashtable h = obj as Hashtable; | 170 | Hashtable h = obj as Hashtable; |
171 | writer.WriteStartElement(String.Empty, "map", String.Empty); | 171 | writer.WriteStartElement(String.Empty, "map", String.Empty); |
172 | foreach (string key in h.Keys) | 172 | foreach (string key in h.Keys) |
173 | { | 173 | { |
174 | writer.WriteStartElement(String.Empty, "key", String.Empty); | 174 | writer.WriteStartElement(String.Empty, "key", String.Empty); |
175 | writer.WriteString(key); | 175 | writer.WriteString(key); |
176 | writer.WriteEndElement(); | 176 | writer.WriteEndElement(); |
177 | LLSDWriteOne(writer, h[key]); | 177 | LLSDWriteOne(writer, h[key]); |
178 | } | 178 | } |
179 | writer.WriteEndElement(); | 179 | writer.WriteEndElement(); |
180 | } | 180 | } |
181 | else if (obj is ArrayList) | 181 | else if (obj is ArrayList) |
182 | { | 182 | { |
183 | ArrayList a = obj as ArrayList; | 183 | ArrayList a = obj as ArrayList; |
184 | writer.WriteStartElement(String.Empty, "array", String.Empty); | 184 | writer.WriteStartElement(String.Empty, "array", String.Empty); |
185 | foreach (object item in a) | 185 | foreach (object item in a) |
186 | { | 186 | { |
187 | LLSDWriteOne(writer, item); | 187 | LLSDWriteOne(writer, item); |
188 | } | 188 | } |
189 | writer.WriteEndElement(); | 189 | writer.WriteEndElement(); |
190 | } | 190 | } |
191 | else if (obj is byte[]) | 191 | else if (obj is byte[]) |
192 | { | 192 | { |
193 | byte[] b = obj as byte[]; | 193 | byte[] b = obj as byte[]; |
194 | writer.WriteStartElement(String.Empty, "binary", String.Empty); | 194 | writer.WriteStartElement(String.Empty, "binary", String.Empty); |
195 | 195 | ||
196 | writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); | 196 | writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); |
197 | writer.WriteString("base64"); | 197 | writer.WriteString("base64"); |
198 | writer.WriteEndAttribute(); | 198 | writer.WriteEndAttribute(); |
199 | 199 | ||
200 | //// Calculate the length of the base64 output | 200 | //// Calculate the length of the base64 output |
201 | //long length = (long)(4.0d * b.Length / 3.0d); | 201 | //long length = (long)(4.0d * b.Length / 3.0d); |
202 | //if (length % 4 != 0) length += 4 - (length % 4); | 202 | //if (length % 4 != 0) length += 4 - (length % 4); |
203 | 203 | ||
204 | //// Create the char[] for base64 output and fill it | 204 | //// Create the char[] for base64 output and fill it |
205 | //char[] tmp = new char[length]; | 205 | //char[] tmp = new char[length]; |
206 | //int i = Convert.ToBase64CharArray(b, 0, b.Length, tmp, 0); | 206 | //int i = Convert.ToBase64CharArray(b, 0, b.Length, tmp, 0); |
207 | 207 | ||
208 | //writer.WriteString(new String(tmp)); | 208 | //writer.WriteString(new String(tmp)); |
209 | 209 | ||
210 | writer.WriteString(Convert.ToBase64String(b)); | 210 | writer.WriteString(Convert.ToBase64String(b)); |
211 | writer.WriteEndElement(); | 211 | writer.WriteEndElement(); |
212 | } | 212 | } |
213 | else | 213 | else |
214 | { | 214 | { |
215 | throw new LLSDSerializeException("Unknown type " + obj.GetType().Name); | 215 | throw new LLSDSerializeException("Unknown type " + obj.GetType().Name); |
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | /// <summary> | 219 | /// <summary> |
220 | /// | 220 | /// |
221 | /// </summary> | 221 | /// </summary> |
222 | /// <param name="reader"></param> | 222 | /// <param name="reader"></param> |
223 | /// <returns></returns> | 223 | /// <returns></returns> |
224 | public static object LLSDParseOne(XmlTextReader reader) | 224 | public static object LLSDParseOne(XmlTextReader reader) |
225 | { | 225 | { |
226 | SkipWS(reader); | 226 | SkipWS(reader); |
227 | if (reader.NodeType != XmlNodeType.Element) | 227 | if (reader.NodeType != XmlNodeType.Element) |
228 | throw new LLSDParseException("Expected an element"); | 228 | throw new LLSDParseException("Expected an element"); |
229 | 229 | ||
230 | string dtype = reader.LocalName; | 230 | string dtype = reader.LocalName; |
231 | object ret = null; | 231 | object ret = null; |
232 | 232 | ||
233 | switch (dtype) | 233 | switch (dtype) |
234 | { | 234 | { |
235 | case "undef": | 235 | case "undef": |
236 | { | 236 | { |
237 | if (reader.IsEmptyElement) | 237 | if (reader.IsEmptyElement) |
238 | { | 238 | { |
239 | reader.Read(); | 239 | reader.Read(); |
240 | return null; | 240 | return null; |
241 | } | 241 | } |
242 | 242 | ||
243 | reader.Read(); | 243 | reader.Read(); |
244 | SkipWS(reader); | 244 | SkipWS(reader); |
245 | ret = null; | 245 | ret = null; |
246 | break; | 246 | break; |
247 | } | 247 | } |
248 | case "boolean": | 248 | case "boolean": |
249 | { | 249 | { |
250 | if (reader.IsEmptyElement) | 250 | if (reader.IsEmptyElement) |
251 | { | 251 | { |
252 | reader.Read(); | 252 | reader.Read(); |
253 | return false; | 253 | return false; |
254 | } | 254 | } |
255 | 255 | ||
256 | reader.Read(); | 256 | reader.Read(); |
257 | string s = reader.ReadString().Trim(); | 257 | string s = reader.ReadString().Trim(); |
258 | 258 | ||
259 | if (s == String.Empty || s == "false" || s == "0") | 259 | if (s == String.Empty || s == "false" || s == "0") |
260 | ret = false; | 260 | ret = false; |
261 | else if (s == "true" || s == "1") | 261 | else if (s == "true" || s == "1") |
262 | ret = true; | 262 | ret = true; |
263 | else | 263 | else |
264 | throw new LLSDParseException("Bad boolean value " + s); | 264 | throw new LLSDParseException("Bad boolean value " + s); |
265 | 265 | ||
266 | break; | 266 | break; |
267 | } | 267 | } |
268 | case "integer": | 268 | case "integer": |
269 | { | 269 | { |
270 | if (reader.IsEmptyElement) | 270 | if (reader.IsEmptyElement) |
271 | { | 271 | { |
272 | reader.Read(); | 272 | reader.Read(); |
273 | return 0; | 273 | return 0; |
274 | } | 274 | } |
275 | 275 | ||
276 | reader.Read(); | 276 | reader.Read(); |
277 | ret = Convert.ToInt32(reader.ReadString().Trim()); | 277 | ret = Convert.ToInt32(reader.ReadString().Trim()); |
278 | break; | 278 | break; |
279 | } | 279 | } |
280 | case "real": | 280 | case "real": |
281 | { | 281 | { |
282 | if (reader.IsEmptyElement) | 282 | if (reader.IsEmptyElement) |
283 | { | 283 | { |
284 | reader.Read(); | 284 | reader.Read(); |
285 | return 0.0f; | 285 | return 0.0f; |
286 | } | 286 | } |
287 | 287 | ||
288 | reader.Read(); | 288 | reader.Read(); |
289 | ret = Convert.ToDouble(reader.ReadString().Trim()); | 289 | ret = Convert.ToDouble(reader.ReadString().Trim()); |
290 | break; | 290 | break; |
291 | } | 291 | } |
292 | case "uuid": | 292 | case "uuid": |
293 | { | 293 | { |
294 | if (reader.IsEmptyElement) | 294 | if (reader.IsEmptyElement) |
295 | { | 295 | { |
296 | reader.Read(); | 296 | reader.Read(); |
297 | return UUID.Zero; | 297 | return UUID.Zero; |
298 | } | 298 | } |
299 | 299 | ||
300 | reader.Read(); | 300 | reader.Read(); |
301 | ret = new UUID(reader.ReadString().Trim()); | 301 | ret = new UUID(reader.ReadString().Trim()); |
302 | break; | 302 | break; |
303 | } | 303 | } |
304 | case "string": | 304 | case "string": |
305 | { | 305 | { |
306 | if (reader.IsEmptyElement) | 306 | if (reader.IsEmptyElement) |
307 | { | 307 | { |
308 | reader.Read(); | 308 | reader.Read(); |
309 | return String.Empty; | 309 | return String.Empty; |
310 | } | 310 | } |
311 | 311 | ||
312 | reader.Read(); | 312 | reader.Read(); |
313 | ret = reader.ReadString(); | 313 | ret = reader.ReadString(); |
314 | break; | 314 | break; |
315 | } | 315 | } |
316 | case "binary": | 316 | case "binary": |
317 | { | 317 | { |
318 | if (reader.IsEmptyElement) | 318 | if (reader.IsEmptyElement) |
319 | { | 319 | { |
320 | reader.Read(); | 320 | reader.Read(); |
321 | return new byte[0]; | 321 | return new byte[0]; |
322 | } | 322 | } |
323 | 323 | ||
324 | if (reader.GetAttribute("encoding") != null && | 324 | if (reader.GetAttribute("encoding") != null && |
325 | reader.GetAttribute("encoding") != "base64") | 325 | reader.GetAttribute("encoding") != "base64") |
326 | { | 326 | { |
327 | throw new LLSDParseException("Unknown encoding: " + reader.GetAttribute("encoding")); | 327 | throw new LLSDParseException("Unknown encoding: " + reader.GetAttribute("encoding")); |
328 | } | 328 | } |
329 | 329 | ||
330 | reader.Read(); | 330 | reader.Read(); |
331 | FromBase64Transform b64 = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces); | 331 | FromBase64Transform b64 = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces); |
332 | byte[] inp = Encoding.UTF8.GetBytes(reader.ReadString()); | 332 | byte[] inp = Encoding.UTF8.GetBytes(reader.ReadString()); |
333 | ret = b64.TransformFinalBlock(inp, 0, inp.Length); | 333 | ret = b64.TransformFinalBlock(inp, 0, inp.Length); |
334 | break; | 334 | break; |
335 | } | 335 | } |
336 | case "date": | 336 | case "date": |
337 | { | 337 | { |
338 | reader.Read(); | 338 | reader.Read(); |
339 | throw new Exception("LLSD TODO: date"); | 339 | throw new Exception("LLSD TODO: date"); |
340 | } | 340 | } |
341 | case "map": | 341 | case "map": |
342 | { | 342 | { |
343 | return LLSDParseMap(reader); | 343 | return LLSDParseMap(reader); |
344 | } | 344 | } |
345 | case "array": | 345 | case "array": |
346 | { | 346 | { |
347 | return LLSDParseArray(reader); | 347 | return LLSDParseArray(reader); |
348 | } | 348 | } |
349 | default: | 349 | default: |
350 | throw new LLSDParseException("Unknown element <" + dtype + ">"); | 350 | throw new LLSDParseException("Unknown element <" + dtype + ">"); |
351 | } | 351 | } |
352 | 352 | ||
353 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != dtype) | 353 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != dtype) |
354 | { | 354 | { |
355 | throw new LLSDParseException("Expected </" + dtype + ">"); | 355 | throw new LLSDParseException("Expected </" + dtype + ">"); |
356 | } | 356 | } |
357 | 357 | ||
358 | reader.Read(); | 358 | reader.Read(); |
359 | return ret; | 359 | return ret; |
360 | } | 360 | } |
361 | 361 | ||
362 | /// <summary> | 362 | /// <summary> |
363 | /// | 363 | /// |
364 | /// </summary> | 364 | /// </summary> |
365 | /// <param name="reader"></param> | 365 | /// <param name="reader"></param> |
366 | /// <returns></returns> | 366 | /// <returns></returns> |
367 | public static Hashtable LLSDParseMap(XmlTextReader reader) | 367 | public static Hashtable LLSDParseMap(XmlTextReader reader) |
368 | { | 368 | { |
369 | Hashtable ret = new Hashtable(); | 369 | Hashtable ret = new Hashtable(); |
370 | 370 | ||
371 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map") | 371 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map") |
372 | throw new LLSDParseException("Expected <map>"); | 372 | throw new LLSDParseException("Expected <map>"); |
373 | 373 | ||
374 | if (reader.IsEmptyElement) | 374 | if (reader.IsEmptyElement) |
375 | { | 375 | { |
376 | reader.Read(); | 376 | reader.Read(); |
377 | return ret; | 377 | return ret; |
378 | } | 378 | } |
379 | 379 | ||
380 | reader.Read(); | 380 | reader.Read(); |
381 | 381 | ||
382 | while (true) | 382 | while (true) |
383 | { | 383 | { |
384 | SkipWS(reader); | 384 | SkipWS(reader); |
385 | if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "map") | 385 | if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "map") |
386 | { | 386 | { |
387 | reader.Read(); | 387 | reader.Read(); |
388 | break; | 388 | break; |
389 | } | 389 | } |
390 | 390 | ||
391 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "key") | 391 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "key") |
392 | throw new LLSDParseException("Expected <key>"); | 392 | throw new LLSDParseException("Expected <key>"); |
393 | 393 | ||
394 | string key = reader.ReadString(); | 394 | string key = reader.ReadString(); |
395 | 395 | ||
396 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "key") | 396 | if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "key") |
397 | throw new LLSDParseException("Expected </key>"); | 397 | throw new LLSDParseException("Expected </key>"); |
398 | 398 | ||
399 | reader.Read(); | 399 | reader.Read(); |
400 | object val = LLSDParseOne(reader); | 400 | object val = LLSDParseOne(reader); |
401 | ret[key] = val; | 401 | ret[key] = val; |
402 | } | 402 | } |
403 | 403 | ||
404 | return ret; // TODO | 404 | return ret; // TODO |
405 | } | 405 | } |
406 | 406 | ||
407 | /// <summary> | 407 | /// <summary> |
408 | /// | 408 | /// |
409 | /// </summary> | 409 | /// </summary> |
410 | /// <param name="reader"></param> | 410 | /// <param name="reader"></param> |
411 | /// <returns></returns> | 411 | /// <returns></returns> |
412 | public static ArrayList LLSDParseArray(XmlTextReader reader) | 412 | public static ArrayList LLSDParseArray(XmlTextReader reader) |
413 | { | 413 | { |
414 | ArrayList ret = new ArrayList(); | 414 | ArrayList ret = new ArrayList(); |
415 | 415 | ||
416 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array") | 416 | if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array") |
417 | throw new LLSDParseException("Expected <array>"); | 417 | throw new LLSDParseException("Expected <array>"); |
418 | 418 | ||
419 | if (reader.IsEmptyElement) | 419 | if (reader.IsEmptyElement) |
420 | { | 420 | { |
421 | reader.Read(); | 421 | reader.Read(); |
422 | return ret; | 422 | return ret; |
423 | } | 423 | } |
424 | 424 | ||
425 | reader.Read(); | 425 | reader.Read(); |
426 | 426 | ||
427 | while (true) | 427 | while (true) |
428 | { | 428 | { |
429 | SkipWS(reader); | 429 | SkipWS(reader); |
430 | 430 | ||
431 | if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "array") | 431 | if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "array") |
432 | { | 432 | { |
433 | reader.Read(); | 433 | reader.Read(); |
434 | break; | 434 | break; |
435 | } | 435 | } |
436 | 436 | ||
437 | ret.Insert(ret.Count, LLSDParseOne(reader)); | 437 | ret.Insert(ret.Count, LLSDParseOne(reader)); |
438 | } | 438 | } |
439 | 439 | ||
440 | return ret; // TODO | 440 | return ret; // TODO |
441 | } | 441 | } |
442 | 442 | ||
443 | /// <summary> | 443 | /// <summary> |
444 | /// | 444 | /// |
445 | /// </summary> | 445 | /// </summary> |
446 | /// <param name="count"></param> | 446 | /// <param name="count"></param> |
447 | /// <returns></returns> | 447 | /// <returns></returns> |
448 | private static string GetSpaces(int count) | 448 | private static string GetSpaces(int count) |
449 | { | 449 | { |
450 | StringBuilder b = new StringBuilder(); | 450 | StringBuilder b = new StringBuilder(); |
451 | for (int i = 0; i < count; i++) b.Append(" "); | 451 | for (int i = 0; i < count; i++) b.Append(" "); |
452 | return b.ToString(); | 452 | return b.ToString(); |
453 | } | 453 | } |
454 | 454 | ||
455 | /// <summary> | 455 | /// <summary> |
456 | /// | 456 | /// |
457 | /// </summary> | 457 | /// </summary> |
458 | /// <param name="obj"></param> | 458 | /// <param name="obj"></param> |
459 | /// <param name="indent"></param> | 459 | /// <param name="indent"></param> |
460 | /// <returns></returns> | 460 | /// <returns></returns> |
461 | public static String LLSDDump(object obj, int indent) | 461 | public static String LLSDDump(object obj, int indent) |
462 | { | 462 | { |
463 | if (obj == null) | 463 | if (obj == null) |
464 | { | 464 | { |
465 | return GetSpaces(indent) + "- undef\n"; | 465 | return GetSpaces(indent) + "- undef\n"; |
466 | } | 466 | } |
467 | else if (obj is string) | 467 | else if (obj is string) |
468 | { | 468 | { |
469 | return GetSpaces(indent) + "- string \"" + (string) obj + "\"\n"; | 469 | return GetSpaces(indent) + "- string \"" + (string) obj + "\"\n"; |
470 | } | 470 | } |
471 | else if (obj is int) | 471 | else if (obj is int) |
472 | { | 472 | { |
473 | return GetSpaces(indent) + "- integer " + obj.ToString() + "\n"; | 473 | return GetSpaces(indent) + "- integer " + obj.ToString() + "\n"; |
474 | } | 474 | } |
475 | else if (obj is double) | 475 | else if (obj is double) |
476 | { | 476 | { |
477 | return GetSpaces(indent) + "- float " + obj.ToString() + "\n"; | 477 | return GetSpaces(indent) + "- float " + obj.ToString() + "\n"; |
478 | } | 478 | } |
479 | else if (obj is UUID) | 479 | else if (obj is UUID) |
480 | { | 480 | { |
481 | return GetSpaces(indent) + "- uuid " + ((UUID) obj).ToString() + Environment.NewLine; | 481 | return GetSpaces(indent) + "- uuid " + ((UUID) obj).ToString() + Environment.NewLine; |
482 | } | 482 | } |
483 | else if (obj is Hashtable) | 483 | else if (obj is Hashtable) |
484 | { | 484 | { |
485 | StringBuilder ret = new StringBuilder(); | 485 | StringBuilder ret = new StringBuilder(); |
486 | ret.Append(GetSpaces(indent) + "- map" + Environment.NewLine); | 486 | ret.Append(GetSpaces(indent) + "- map" + Environment.NewLine); |
487 | Hashtable map = (Hashtable) obj; | 487 | Hashtable map = (Hashtable) obj; |
488 | 488 | ||
489 | foreach (string key in map.Keys) | 489 | foreach (string key in map.Keys) |
490 | { | 490 | { |
491 | ret.Append(GetSpaces(indent + 2) + "- key \"" + key + "\"" + Environment.NewLine); | 491 | ret.Append(GetSpaces(indent + 2) + "- key \"" + key + "\"" + Environment.NewLine); |
492 | ret.Append(LLSDDump(map[key], indent + 3)); | 492 | ret.Append(LLSDDump(map[key], indent + 3)); |
493 | } | 493 | } |
494 | 494 | ||
495 | return ret.ToString(); | 495 | return ret.ToString(); |
496 | } | 496 | } |
497 | else if (obj is ArrayList) | 497 | else if (obj is ArrayList) |
498 | { | 498 | { |
499 | StringBuilder ret = new StringBuilder(); | 499 | StringBuilder ret = new StringBuilder(); |
500 | ret.Append(GetSpaces(indent) + "- array\n"); | 500 | ret.Append(GetSpaces(indent) + "- array\n"); |
501 | ArrayList list = (ArrayList) obj; | 501 | ArrayList list = (ArrayList) obj; |
502 | 502 | ||
503 | foreach (object item in list) | 503 | foreach (object item in list) |
504 | { | 504 | { |
505 | ret.Append(LLSDDump(item, indent + 2)); | 505 | ret.Append(LLSDDump(item, indent + 2)); |
506 | } | 506 | } |
507 | 507 | ||
508 | return ret.ToString(); | 508 | return ret.ToString(); |
509 | } | 509 | } |
510 | else if (obj is byte[]) | 510 | else if (obj is byte[]) |
511 | { | 511 | { |
512 | return GetSpaces(indent) + "- binary\n" + Utils.BytesToHexString((byte[]) obj, GetSpaces(indent)) + | 512 | return GetSpaces(indent) + "- binary\n" + Utils.BytesToHexString((byte[]) obj, GetSpaces(indent)) + |
513 | Environment.NewLine; | 513 | Environment.NewLine; |
514 | } | 514 | } |
515 | else | 515 | else |
516 | { | 516 | { |
517 | return GetSpaces(indent) + "- unknown type " + obj.GetType().Name + Environment.NewLine; | 517 | return GetSpaces(indent) + "- unknown type " + obj.GetType().Name + Environment.NewLine; |
518 | } | 518 | } |
519 | } | 519 | } |
520 | 520 | ||
521 | public static object ParseTerseLLSD(string llsd) | 521 | public static object ParseTerseLLSD(string llsd) |
522 | { | 522 | { |
523 | int notused; | 523 | int notused; |
524 | return ParseTerseLLSD(llsd, out notused); | 524 | return ParseTerseLLSD(llsd, out notused); |
525 | } | 525 | } |
526 | 526 | ||
527 | public static object ParseTerseLLSD(string llsd, out int endPos) | 527 | public static object ParseTerseLLSD(string llsd, out int endPos) |
528 | { | 528 | { |
529 | if (llsd.Length == 0) | 529 | if (llsd.Length == 0) |
530 | { | 530 | { |
531 | endPos = 0; | 531 | endPos = 0; |
532 | return null; | 532 | return null; |
533 | } | 533 | } |
534 | 534 | ||
535 | // Identify what type of object this is | 535 | // Identify what type of object this is |
536 | switch (llsd[0]) | 536 | switch (llsd[0]) |
537 | { | 537 | { |
538 | case '!': | 538 | case '!': |
539 | throw new LLSDParseException("Undefined value type encountered"); | 539 | throw new LLSDParseException("Undefined value type encountered"); |
540 | case '1': | 540 | case '1': |
541 | endPos = 1; | 541 | endPos = 1; |
542 | return true; | 542 | return true; |
543 | case '0': | 543 | case '0': |
544 | endPos = 1; | 544 | endPos = 1; |
545 | return false; | 545 | return false; |
546 | case 'i': | 546 | case 'i': |
547 | { | 547 | { |
548 | if (llsd.Length < 2) throw new LLSDParseException("Integer value type with no value"); | 548 | if (llsd.Length < 2) throw new LLSDParseException("Integer value type with no value"); |
549 | int value; | 549 | int value; |
550 | endPos = FindEnd(llsd, 1); | 550 | endPos = FindEnd(llsd, 1); |
551 | 551 | ||
552 | if (Int32.TryParse(llsd.Substring(1, endPos - 1), out value)) | 552 | if (Int32.TryParse(llsd.Substring(1, endPos - 1), out value)) |
553 | return value; | 553 | return value; |
554 | else | 554 | else |
555 | throw new LLSDParseException("Failed to parse integer value type"); | 555 | throw new LLSDParseException("Failed to parse integer value type"); |
556 | } | 556 | } |
557 | case 'r': | 557 | case 'r': |
558 | { | 558 | { |
559 | if (llsd.Length < 2) throw new LLSDParseException("Real value type with no value"); | 559 | if (llsd.Length < 2) throw new LLSDParseException("Real value type with no value"); |
560 | double value; | 560 | double value; |
561 | endPos = FindEnd(llsd, 1); | 561 | endPos = FindEnd(llsd, 1); |
562 | 562 | ||
563 | if (Double.TryParse(llsd.Substring(1, endPos - 1), NumberStyles.Float, | 563 | if (Double.TryParse(llsd.Substring(1, endPos - 1), NumberStyles.Float, |
564 | Utils.EnUsCulture.NumberFormat, out value)) | 564 | Utils.EnUsCulture.NumberFormat, out value)) |
565 | return value; | 565 | return value; |
566 | else | 566 | else |
567 | throw new LLSDParseException("Failed to parse double value type"); | 567 | throw new LLSDParseException("Failed to parse double value type"); |
568 | } | 568 | } |
569 | case 'u': | 569 | case 'u': |
570 | { | 570 | { |
571 | if (llsd.Length < 17) throw new LLSDParseException("UUID value type with no value"); | 571 | if (llsd.Length < 17) throw new LLSDParseException("UUID value type with no value"); |
572 | UUID value; | 572 | UUID value; |
573 | endPos = FindEnd(llsd, 1); | 573 | endPos = FindEnd(llsd, 1); |
574 | 574 | ||
575 | if (UUID.TryParse(llsd.Substring(1, endPos - 1), out value)) | 575 | if (UUID.TryParse(llsd.Substring(1, endPos - 1), out value)) |
576 | return value; | 576 | return value; |
577 | else | 577 | else |
578 | throw new LLSDParseException("Failed to parse UUID value type"); | 578 | throw new LLSDParseException("Failed to parse UUID value type"); |
579 | } | 579 | } |
580 | case 'b': | 580 | case 'b': |
581 | //byte[] value = new byte[llsd.Length - 1]; | 581 | //byte[] value = new byte[llsd.Length - 1]; |
582 | // This isn't the actual binary LLSD format, just the terse format sent | 582 | // This isn't the actual binary LLSD format, just the terse format sent |
583 | // at login so I don't even know if there is a binary type | 583 | // at login so I don't even know if there is a binary type |
584 | throw new LLSDParseException("Binary value type is unimplemented"); | 584 | throw new LLSDParseException("Binary value type is unimplemented"); |
585 | case 's': | 585 | case 's': |
586 | case 'l': | 586 | case 'l': |
587 | if (llsd.Length < 2) throw new LLSDParseException("String value type with no value"); | 587 | if (llsd.Length < 2) throw new LLSDParseException("String value type with no value"); |
588 | endPos = FindEnd(llsd, 1); | 588 | endPos = FindEnd(llsd, 1); |
589 | return llsd.Substring(1, endPos - 1); | 589 | return llsd.Substring(1, endPos - 1); |
590 | case 'd': | 590 | case 'd': |
591 | // Never seen one before, don't know what the format is | 591 | // Never seen one before, don't know what the format is |
592 | throw new LLSDParseException("Date value type is unimplemented"); | 592 | throw new LLSDParseException("Date value type is unimplemented"); |
593 | case '[': | 593 | case '[': |
594 | { | 594 | { |
595 | if (llsd.IndexOf(']') == -1) throw new LLSDParseException("Invalid array"); | 595 | if (llsd.IndexOf(']') == -1) throw new LLSDParseException("Invalid array"); |
596 | 596 | ||
597 | int pos = 0; | 597 | int pos = 0; |
598 | ArrayList array = new ArrayList(); | 598 | ArrayList array = new ArrayList(); |
599 | 599 | ||
600 | while (llsd[pos] != ']') | 600 | while (llsd[pos] != ']') |
601 | { | 601 | { |
602 | ++pos; | 602 | ++pos; |
603 | 603 | ||
604 | // Advance past comma if need be | 604 | // Advance past comma if need be |
605 | if (llsd[pos] == ',') ++pos; | 605 | if (llsd[pos] == ',') ++pos; |
606 | 606 | ||
607 | // Allow a single whitespace character | 607 | // Allow a single whitespace character |
608 | if (pos < llsd.Length && llsd[pos] == ' ') ++pos; | 608 | if (pos < llsd.Length && llsd[pos] == ' ') ++pos; |
609 | 609 | ||
610 | int end; | 610 | int end; |
611 | array.Add(ParseTerseLLSD(llsd.Substring(pos), out end)); | 611 | array.Add(ParseTerseLLSD(llsd.Substring(pos), out end)); |
612 | pos += end; | 612 | pos += end; |
613 | } | 613 | } |
614 | 614 | ||
615 | endPos = pos + 1; | 615 | endPos = pos + 1; |
616 | return array; | 616 | return array; |
617 | } | 617 | } |
618 | case '{': | 618 | case '{': |
619 | { | 619 | { |
620 | if (llsd.IndexOf('}') == -1) throw new LLSDParseException("Invalid map"); | 620 | if (llsd.IndexOf('}') == -1) throw new LLSDParseException("Invalid map"); |
621 | 621 | ||
622 | int pos = 0; | 622 | int pos = 0; |
623 | Hashtable hashtable = new Hashtable(); | 623 | Hashtable hashtable = new Hashtable(); |
624 | 624 | ||
625 | while (llsd[pos] != '}') | 625 | while (llsd[pos] != '}') |
626 | { | 626 | { |
627 | ++pos; | 627 | ++pos; |
628 | 628 | ||
629 | // Advance past comma if need be | 629 | // Advance past comma if need be |
630 | if (llsd[pos] == ',') ++pos; | 630 | if (llsd[pos] == ',') ++pos; |
631 | 631 | ||
632 | // Allow a single whitespace character | 632 | // Allow a single whitespace character |
633 | if (pos < llsd.Length && llsd[pos] == ' ') ++pos; | 633 | if (pos < llsd.Length && llsd[pos] == ' ') ++pos; |
634 | 634 | ||
635 | if (llsd[pos] != '\'') throw new LLSDParseException("Expected a map key"); | 635 | if (llsd[pos] != '\'') throw new LLSDParseException("Expected a map key"); |
636 | int endquote = llsd.IndexOf('\'', pos + 1); | 636 | int endquote = llsd.IndexOf('\'', pos + 1); |
637 | if (endquote == -1 || (endquote + 1) >= llsd.Length || llsd[endquote + 1] != ':') | 637 | if (endquote == -1 || (endquote + 1) >= llsd.Length || llsd[endquote + 1] != ':') |
638 | throw new LLSDParseException("Invalid map format"); | 638 | throw new LLSDParseException("Invalid map format"); |
639 | string key = llsd.Substring(pos, endquote - pos); | 639 | string key = llsd.Substring(pos, endquote - pos); |
640 | key = key.Replace("'", String.Empty); | 640 | key = key.Replace("'", String.Empty); |
641 | pos += (endquote - pos) + 2; | 641 | pos += (endquote - pos) + 2; |
642 | 642 | ||
643 | int end; | 643 | int end; |
644 | hashtable.Add(key, ParseTerseLLSD(llsd.Substring(pos), out end)); | 644 | hashtable.Add(key, ParseTerseLLSD(llsd.Substring(pos), out end)); |
645 | pos += end; | 645 | pos += end; |
646 | } | 646 | } |
647 | 647 | ||
648 | endPos = pos + 1; | 648 | endPos = pos + 1; |
649 | return hashtable; | 649 | return hashtable; |
650 | } | 650 | } |
651 | default: | 651 | default: |
652 | throw new Exception("Unknown value type"); | 652 | throw new Exception("Unknown value type"); |
653 | } | 653 | } |
654 | } | 654 | } |
655 | 655 | ||
656 | private static int FindEnd(string llsd, int start) | 656 | private static int FindEnd(string llsd, int start) |
657 | { | 657 | { |
658 | int end = llsd.IndexOfAny(new char[] {',', ']', '}'}); | 658 | int end = llsd.IndexOfAny(new char[] {',', ']', '}'}); |
659 | if (end == -1) end = llsd.Length - 1; | 659 | if (end == -1) end = llsd.Length - 1; |
660 | return end; | 660 | return end; |
661 | } | 661 | } |
662 | 662 | ||
663 | /// <summary> | 663 | /// <summary> |
664 | /// | 664 | /// |
665 | /// </summary> | 665 | /// </summary> |
666 | /// <param name="reader"></param> | 666 | /// <param name="reader"></param> |
667 | private static void SkipWS(XmlTextReader reader) | 667 | private static void SkipWS(XmlTextReader reader) |
668 | { | 668 | { |
669 | while ( | 669 | while ( |
670 | reader.NodeType == XmlNodeType.Comment || | 670 | reader.NodeType == XmlNodeType.Comment || |
671 | reader.NodeType == XmlNodeType.Whitespace || | 671 | reader.NodeType == XmlNodeType.Whitespace || |
672 | reader.NodeType == XmlNodeType.SignificantWhitespace || | 672 | reader.NodeType == XmlNodeType.SignificantWhitespace || |
673 | reader.NodeType == XmlNodeType.XmlDeclaration) | 673 | reader.NodeType == XmlNodeType.XmlDeclaration) |
674 | { | 674 | { |
675 | reader.Read(); | 675 | reader.Read(); |
676 | } | 676 | } |
677 | } | 677 | } |
678 | } | 678 | } |
679 | } | 679 | } |