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