aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Capabilities/LLSD.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Capabilities/LLSD.cs')
-rw-r--r--OpenSim/Framework/Capabilities/LLSD.cs1358
1 files changed, 679 insertions, 679 deletions
diff --git a/OpenSim/Framework/Capabilities/LLSD.cs b/OpenSim/Framework/Capabilities/LLSD.cs
index c8bc273..84f43c1 100644
--- a/OpenSim/Framework/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
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Globalization; 30using System.Globalization;
31using System.IO; 31using System.IO;
32using System.Security.Cryptography; 32using System.Security.Cryptography;
33using System.Text; 33using System.Text;
34using System.Xml; 34using System.Xml;
35using OpenMetaverse; 35using OpenMetaverse;
36 36
37namespace OpenSim.Framework.Capabilities 37namespace OpenSim.Framework.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}