+ /// Make an JSON external form string of this JSONArray. For compactness, no
+ /// unnecessary whitespace is added.
+ ///
+ /// a printable, displayable, transmittable representation of the array.
+ public override string ToString()
+ {
+ return '['+ join(",") + ']';
+ }
+ }
+}
diff --git a/libsecondlife-cs/JSONlib/JSONFacade.cs b/libsecondlife-cs/JSONlib/JSONFacade.cs
new file mode 100644
index 00000000..45cc4b4e
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/JSONFacade.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Reflection;
+using System.Text;
+
+namespace Nii.JSON
+{
+ ///
+ /// Summary description for JsonFacade.
+ ///
+ public sealed class JsonFacade
+ {
+ ///
+ /// Parse a Hashtable and return a JSON formatted string
+ ///
+ ///
+ ///
+ public static string toJSON(IDictionary idict)
+ {
+ JSONObject jsob = new JSONObject(idict);
+ return jsob.ToString();
+ }
+ ///
+ /// Parse JSON formatted string and return a Hashtable
+ ///
+ ///
+ ///
+ public static IDictionary fromJSON(string sJSON)
+ {
+ JSONObject jsob = new JSONObject(sJSON);
+ IDictionary idict = jsob.getDictionary();
+ return idict;
+ }
+ }
+}
diff --git a/libsecondlife-cs/JSONlib/JSONObject.cs b/libsecondlife-cs/JSONlib/JSONObject.cs
new file mode 100644
index 00000000..bd1f8521
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/JSONObject.cs
@@ -0,0 +1,882 @@
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Text;
+using System.Globalization;
+
+/*
+ * A JSONObject is an unordered collection of name/value pairs. Its
+ * external form is a string wrapped in curly braces with colons between the
+ * names and values, and commas between the values and names. The internal form
+ * is an object having get() and opt() methods for accessing the values by name,
+ * and put() methods for adding or replacing values by name. The values can be
+ * any of these types: Boolean, JSONArray, JSONObject, Number, String, or the
+ * JSONObject.NULL object.
+ *
+ * The constructor can convert an external form string into an internal form
+ * Java object. The toString() method creates an external form string.
+ *
+ * A get() method returns a value if one can be found, and throws an exception
+ * if one cannot be found. An opt() method returns a default value instead of
+ * throwing an exception, and so is useful for obtaining optional values.
+ *
+ * The generic get() and opt() methods return an object, which you can cast or
+ * query for type. There are also typed get() and opt() methods that do typing
+ * checking and type coersion for you.
+ *
+ * The texts produced by the toString() methods are very strict.
+ * The constructors are more forgiving in the texts they will accept.
+ *
+ * - An extra comma may appear just before the closing brace.
+ * - Strings may be quoted with single quotes.
+ * - Strings do not need to be quoted at all if they do not contain leading
+ * or trailing spaces, and if they do not contain any of these characters:
+ * { } [ ] / \ : ,
+ * - Numbers may have the 0- (octal) or 0x- (hex) prefix.
+ *
+ *
+ * Public Domain 2002 JSON.org
+ * @author JSON.org
+ * @version 0.1
+ *
+ * Ported to C# by Are Bjolseth, teleplan.no
+ * TODO:
+ * 1. Implement Custom exceptions
+ * 2. Add indexer JSONObject[i] = object, and object = JSONObject[i];
+ * 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"]
+ * 4. Add unit testing
+ * 5. Add log4net
+ */
+namespace Nii.JSON
+{
+ ///
+ ///
+ /// A JSONArray is an ordered sequence of values. Its external form is a string
+ /// wrapped in square brackets with commas between the values. The internal form
+ /// is an object having get() and opt() methods for accessing the values by
+ /// index, and put() methods for adding or replacing values. The values can be
+ /// any of these types: Boolean, JSONArray, JSONObject, Number, String, or the
+ /// JSONObject.NULL object.
+ ///
+ ///
+ /// The constructor can convert a JSON external form string into an
+ /// internal form Java object. The toString() method creates an external
+ /// form string.
+ ///
+ ///
+ /// A get() method returns a value if one can be found, and throws an exception
+ /// if one cannot be found. An opt() method returns a default value instead of
+ /// throwing an exception, and so is useful for obtaining optional values.
+ ///
+ ///
+ /// The generic get() and opt() methods return an object which you can cast or
+ /// query for type. There are also typed get() and opt() methods that do typing
+ /// checking and type coersion for you.
+ ///
+ ///
+ /// The texts produced by the toString() methods are very strict.
+ /// The constructors are more forgiving in the texts they will accept.
+ ///
+ ///
+ ///
+ /// - An extra comma may appear just before the closing bracket.
+ /// - Strings may be quoted with single quotes.
+ /// - Strings do not need to be quoted at all if they do not contain leading
+ /// or trailing spaces, and if they do not contain any of these characters:
+ /// { } [ ] / \ : ,
+ /// - Numbers may have the 0- (octal) or 0x- (hex) prefix.
+ ///
+ ///
+ ///
+ /// Public Domain 2002 JSON.org
+ /// @author JSON.org
+ /// @version 0.1
+ ///
+ /// Ported to C# by Are Bjolseth, teleplan.no
+ /// TODO:
+ /// 1. Implement Custom exceptions
+ /// 2. Add indexer JSONObject[i] = object, and object = JSONObject[i];
+ /// 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"]
+ /// 4. Add unit testing
+ /// 5. Add log4net
+ /// 6. Make get/put methods private, to force use of indexer instead?
+ ///
+ public class JSONObject
+ {
+ #region Local struct JSONNull
+ ///
+ /// Make a Null object
+ /// JSONObject.NULL is equivalent to the value that JavaScript calls null,
+ /// whilst C#'s null is equivalent to the value that JavaScript calls undefined.
+ ///
+ public struct JSONNull
+ {
+ /*
+ public object clone()
+ {
+ return this;
+ }
+ */
+ /*
+ public bool equals(object obj)
+ {
+ return (obj == null) || (obj == this);
+ }
+ */
+ ///
+ /// Overriden to return "null"
+ ///
+ /// null
+ public override string ToString()
+ {
+ //return base.ToString ();
+ return "null";
+ }
+ }
+ #endregion
+
+ ///The hash map where the JSONObject's properties are kept.
+ private Hashtable myHashMap;
+
+ ///A shadow list of keys to enable access by sequence of insertion
+ private ArrayList myKeyIndexList;
+
+ ///
+ /// It is sometimes more convenient and less ambiguous to have a NULL
+ /// object than to use C#'s null value.
+ /// JSONObject.NULL.toString() returns "null".
+ ///
+ public static readonly JSONNull NULL = new JSONNull();
+
+ #region Constructors for JSONObject
+ ///
+ /// Construct an empty JSONObject.
+ ///
+ public JSONObject()
+ {
+ myHashMap = new Hashtable();
+ myKeyIndexList = new ArrayList();
+ }
+
+ ///
+ /// Construct a JSONObject from a JSONTokener.
+ ///
+ /// A JSONTokener object containing the source string.
+ public JSONObject(JSONTokener x) : this()
+ {
+ char c;
+ string key;
+ if (x.next() == '%')
+ {
+ x.unescape();
+ }
+ x.back();
+ if (x.nextClean() != '{')
+ {
+ throw new Exception("A JSONObject must begin with '{'");
+ }
+ while (true)
+ {
+ c = x.nextClean();
+ switch (c)
+ {
+ case (char)0:
+ throw new Exception("A JSONObject must end with '}'");
+ case '}':
+ return;
+ default:
+ x.back();
+ key = x.nextObject().ToString();
+ break;
+ }
+ if (x.nextClean() != ':')
+ {
+ throw new Exception("Expected a ':' after a key");
+ }
+ object obj = x.nextObject();
+ myHashMap.Add(key, obj);
+ myKeyIndexList.Add(key);
+ switch (x.nextClean())
+ {
+ case ',':
+ if (x.nextClean() == '}')
+ {
+ return;
+ }
+ x.back();
+ break;
+ case '}':
+ return;
+ default:
+ throw new Exception("Expected a ',' or '}'");
+ }
+ }
+ }
+
+
+ ///
+ /// Construct a JSONObject from a string.
+ ///
+ /// A string beginning with '{' and ending with '}'.
+ public JSONObject(string sJSON) : this(new JSONTokener(sJSON))
+ {
+
+ }
+
+ // public JSONObject(Hashtable map)
+ // By changing to arg to interface, all classes that implements IDictionary can be used
+ // public interface IDictionary : ICollection, IEnumerable
+ // Classes that implements IDictionary
+ // 1. BaseChannelObjectWithProperties - Provides a base implementation of a channel object that wants to provide a dictionary interface to its properties.
+ // 2. DictionaryBase - Provides the abstract (MustInherit in Visual Basic) base class for a strongly typed collection of key-and-value pairs.
+ // 3. Hashtable - Represents a collection of key-and-value pairs that are organized based on the hash code of the key.
+ // 4. HybridDictionary - Implements IDictionary by using a ListDictionary while the collection is small, and then switching to a Hashtable when the collection gets large.
+ // 5. ListDictionary - Implements IDictionary using a singly linked list. Recommended for collections that typically contain 10 items or less.
+ // 6. PropertyCollection - Contains the properties of a DirectoryEntry.
+ // 7. PropertyDescriptorCollection - Represents a collection of PropertyDescriptor objects.
+ // 8. SortedList - Represents a collection of key-and-value pairs that are sorted by the keys and are accessible by key and by index.
+ // 9. StateBag - Manages the view state of ASP.NET server controls, including pages. This class cannot be inherited.
+ // See ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpref/html/frlrfsystemcollectionsidictionaryclasstopic.htm
+
+
+ ///
+ /// Construct a JSONObject from a IDictionary
+ ///
+ ///
+ public JSONObject(IDictionary map)
+ {
+ myHashMap = new Hashtable(map);
+ myKeyIndexList = new ArrayList(map);
+ }
+
+ #endregion
+
+ ///
+ /// Accumulate values under a key. It is similar to the put method except
+ /// that if there is already an object stored under the key then a
+ /// JSONArray is stored under the key to hold all of the accumulated values.
+ /// If there is already a JSONArray, then the new value is appended to it.
+ /// In contrast, the put method replaces the previous value.
+ ///
+ /// A key string.
+ /// An object to be accumulated under the key.
+ /// this
+ public JSONObject accumulate(string key, object val)
+ {
+ JSONArray a;
+ object obj = opt(key);
+ if (obj == null)
+ {
+ put(key, val);
+ }
+ else if (obj is JSONArray)
+ {
+ a = (JSONArray)obj;
+ a.put(val);
+ }
+ else
+ {
+ a = new JSONArray();
+ a.put(obj);
+ a.put(val);
+ put(key,a);
+ }
+ return this;
+ }
+
+
+ #region C# specific extensions
+ ///
+ /// Return the key for the associated index
+ ///
+ public string this[int i]
+ {
+ get
+ {
+ DictionaryEntry de = (DictionaryEntry)myKeyIndexList[i];
+ return de.Key.ToString();
+ }
+ }
+
+ ///
+ /// Get/Add an object with the associated key
+ ///
+ public object this[string key]
+ {
+ get
+ {
+ return getValue(key);
+ }
+ set
+ {
+ put(key,value);
+ }
+ }
+
+ ///
+ /// Return the number of JSON items in hashtable
+ ///
+ public int Count
+ {
+ get
+ {
+ return myHashMap.Count;
+ }
+ }
+ ///
+ /// C# convenience method
+ ///
+ /// The Hashtable
+ public IDictionary getDictionary()
+ {
+ return myHashMap;
+ }
+ #endregion
+
+
+ #region Gettes for a value associated with a key - use indexer instead
+ ///
+ /// Alias to Java get method
+ /// Get the value object associated with a key.
+ ///
+ /// A key string.
+ /// The object associated with the key.
+ public object getValue(string key)
+ {
+ //return myHashMap[key];
+ object obj = opt(key);
+ if (obj == null)
+ {
+ throw new Exception("No such element");
+ }
+ return obj;
+ }
+
+ ///
+ /// Get the boolean value associated with a key.
+ ///
+ /// A key string.
+ /// The truth.
+ public bool getBool(string key)
+ {
+ object o = getValue(key);
+ if (o is bool)
+ {
+ bool b = (bool)o;
+ return b;
+ }
+ string msg = string.Format("JSONObject[{0}] is not a Boolean",JSONUtils.Enquote(key));
+ throw new Exception(msg);
+ }
+
+ ///
+ /// Get the double value associated with a key.
+ ///
+ /// A key string.
+ /// The double value
+ public double getDouble(string key)
+ {
+ object o = getValue(key);
+ if (o is double)
+ return (double)o;
+ if (o is float)
+ return (double)o;
+
+ if (o is string)
+ {
+ return Convert.ToDouble(o);
+ }
+ string msg = string.Format("JSONObject[{0}] is not a double",JSONUtils.Enquote(key));
+ throw new Exception(msg);
+ }
+
+ ///
+ /// Get the int value associated with a key.
+ ///
+ /// A key string
+ /// The integer value.
+ public int getInt(string key)
+ {
+ object o = getValue(key);
+ if (o is int)
+ {
+ return (int)o;
+ }
+
+ if (o is string)
+ {
+ return Convert.ToInt32(o);
+ }
+ string msg = string.Format("JSONObject[{0}] is not a int",JSONUtils.Enquote(key));
+ throw new Exception(msg);
+ }
+
+ ///
+ /// Get the JSONArray value associated with a key.
+ ///
+ /// A key string
+ /// A JSONArray which is the value
+ public JSONArray getJSONArray(string key)
+ {
+ object o = getValue(key);
+ if (o is JSONArray)
+ {
+ return (JSONArray)o;
+ }
+ string msg = string.Format("JSONObject[{0}]={1} is not a JSONArray",JSONUtils.Enquote(key),o);
+ throw new Exception(msg);
+ }
+
+ ///
+ /// Get the JSONObject value associated with a key.
+ ///
+ /// A key string.
+ /// A JSONObject which is the value.
+ public JSONObject getJSONObject(string key)
+ {
+ object o = getValue(key);
+ if (o is JSONObject)
+ {
+ return (JSONObject)o;
+ }
+ string msg = string.Format("JSONObject[{0}]={1} is not a JSONArray",JSONUtils.Enquote(key),o);
+ throw new Exception(msg);
+ }
+
+ ///
+ /// Get the string associated with a key.
+ ///
+ /// A key string.
+ /// A string which is the value.
+ public string getString(string key)
+ {
+ return getValue(key).ToString();
+ }
+ #endregion
+
+
+ ///
+ /// Determine if the JSONObject contains a specific key.
+ ///
+ /// A key string.
+ /// true if the key exists in the JSONObject.
+ public bool has(string key)
+ {
+ return myHashMap.ContainsKey(key);
+ }
+
+
+ ///
+ /// Get an enumeration of the keys of the JSONObject.
+ /// Added to be true to orginal Java implementation
+ /// Indexers are easier to use
+ ///
+ ///
+ public IEnumerator keys()
+ {
+ return myHashMap.Keys.GetEnumerator();
+ }
+
+ ///
+ /// Determine if the value associated with the key is null or if there is no value.
+ ///
+ /// A key string
+ /// true if there is no value associated with the key or if the valus is the JSONObject.NULL object
+ public bool isNull(string key)
+ {
+ return JSONObject.NULL.Equals(opt(key));
+ }
+
+ ///
+ /// Get the number of keys stored in the JSONObject.
+ ///
+ /// The number of keys in the JSONObject.
+ public int Length()
+ {
+ return myHashMap.Count;
+ }
+
+ ///
+ /// Produce a JSONArray containing the names of the elements of this JSONObject
+ ///
+ /// A JSONArray containing the key strings, or null if the JSONObject
+ public JSONArray names()
+ {
+ JSONArray ja = new JSONArray();
+
+ //NOTE!! I choose to use keys stored in the ArrayList, to maintain sequence order
+ foreach (string key in myKeyIndexList)
+ {
+ ja.put(key);
+ }
+ if (ja.Length() == 0)
+ {
+ return null;
+ }
+ return ja;
+ }
+
+ ///
+ /// Produce a string from a number.
+ ///
+ /// Number value type object
+ /// String representation of the number
+ public string numberToString(object number)
+ {
+ if (number is float && ((float)number) == float.NaN)
+ {
+ string msg = string.Format("");
+ throw new ArgumentException("object must be a valid number", "number");
+ }
+ if (number is double && ((double)number) == double.NaN)
+ {
+ string msg = string.Format("");
+ throw new ArgumentException("object must be a valid number", "number");
+ }
+
+ // Shave off trailing zeros and decimal point, if possible
+
+ string s = ((double) number).ToString(NumberFormatInfo.InvariantInfo).ToLower();
+
+ if (s.IndexOf('e') < 0 && s.IndexOf('.') > 0)
+ {
+ while(s.EndsWith("0"))
+ {
+ s.Substring(0,s.Length-1);
+ }
+ if (s.EndsWith("."))
+ {
+ s.Substring(0,s.Length-1);
+ }
+ }
+ return s;
+ }
+
+ #region Get an optional value associated with a key.
+ ///
+ /// Get an optional value associated with a key.
+ ///
+ /// A key string
+ /// An object which is the value, or null if there is no value.
+ public object opt(string key)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key", "Null key");
+ }
+ return myHashMap[key];
+ }
+
+ ///
+ /// Get an optional value associated with a key.
+ /// It returns false if there is no such key, or if the value is not
+ /// Boolean.TRUE or the String "true".
+ ///
+ /// A key string.
+ /// bool value object
+ public bool optBoolean(string key)
+ {
+ return optBoolean(key, false);
+ }
+
+ ///
+ /// Get an optional value associated with a key.
+ /// It returns false if there is no such key, or if the value is not
+ /// Boolean.TRUE or the String "true".
+ ///
+ /// A key string.
+ /// The preferred return value if conversion fails
+ /// bool value object
+ public bool optBoolean(string key, bool defaultValue)
+ {
+ object obj = opt(key);
+ if (obj != null)
+ {
+ if (obj is bool)
+ return (bool)obj;
+ if (obj is string)
+ {
+ return Convert.ToBoolean(obj);
+ }
+ }
+ return defaultValue;
+ }
+
+ ///
+ /// Get an optional double associated with a key,
+ /// or NaN if there is no such key or if its value is not a number.
+ /// If the value is a string, an attempt will be made to evaluate it as
+ /// a number.
+ ///
+ /// A string which is the key.
+ /// A double value object
+ public double optDouble(string key)
+ {
+ return optDouble(key, double.NaN);
+ }
+
+ ///
+ /// Get an optional double associated with a key,
+ /// or NaN if there is no such key or if its value is not a number.
+ /// If the value is a string, an attempt will be made to evaluate it as
+ /// a number.
+ ///
+ /// A string which is the key.
+ /// The default
+ /// A double value object
+ public double optDouble(string key, double defaultValue)
+ {
+ object obj = opt(key);
+ if (obj != null)
+ {
+ if (obj is double)
+ return (double)obj;
+ if (obj is float)
+ return (double)obj;
+ if (obj is string)
+ {
+ return Convert.ToDouble(obj);
+ }
+ }
+ return defaultValue;
+ }
+
+ ///
+ /// Get an optional double associated with a key, or the
+ /// defaultValue if there is no such key or if its value is not a number.
+ /// If the value is a string, an attempt will be made to evaluate it as
+ /// number.
+ ///
+ /// A key string.
+ /// An int object value
+ public int optInt(string key)
+ {
+ return optInt(key, 0);
+ }
+
+ ///
+ /// Get an optional double associated with a key, or the
+ /// defaultValue if there is no such key or if its value is not a number.
+ /// If the value is a string, an attempt will be made to evaluate it as
+ /// number.
+ ///
+ /// A key string.
+ /// The default value
+ /// An int object value
+ public int optInt(string key, int defaultValue)
+ {
+ object obj = opt(key);
+ if (obj != null)
+ {
+ if (obj is int)
+ return (int)obj;
+ if (obj is string)
+ return Convert.ToInt32(obj);
+ }
+ return defaultValue;
+ }
+
+ ///
+ /// Get an optional JSONArray associated with a key.
+ /// It returns null if there is no such key, or if its value is not a JSONArray
+ ///
+ /// A key string
+ /// A JSONArray which is the value
+ public JSONArray optJSONArray(string key)
+ {
+ object obj = opt(key);
+ if (obj is JSONArray)
+ {
+ return (JSONArray)obj;
+ }
+ return null;
+ }
+
+ ///
+ /// Get an optional JSONObject associated with a key.
+ /// It returns null if there is no such key, or if its value is not a JSONObject.
+ ///
+ /// A key string.
+ /// A JSONObject which is the value
+ public JSONObject optJSONObject(string key)
+ {
+ object obj = opt(key);
+ if (obj is JSONObject)
+ {
+ return (JSONObject)obj;
+ }
+ return null;
+ }
+
+ ///
+ /// Get an optional string associated with a key.
+ /// It returns an empty string if there is no such key. If the value is not
+ /// a string and is not null, then it is coverted to a string.
+ ///
+ /// A key string.
+ /// A string which is the value.
+ public string optString(string key)
+ {
+ object obj = opt(key);
+
+ return optString(key, "");
+ }
+
+ ///
+ /// Get an optional string associated with a key.
+ /// It returns the defaultValue if there is no such key.
+ ///
+ /// A key string.
+ /// The default
+ /// A string which is the value.
+ public string optString(string key, string defaultValue)
+ {
+ object obj = opt(key);
+ if (obj != null)
+ {
+ return obj.ToString();
+ }
+ return defaultValue;
+ }
+ #endregion
+
+ #region Put methods for adding key/value pairs
+ // OMITTED - all put methods can be replaced by a indexer in C#
+ // - ===================================================
+ // public JSONObject put(String key, boolean value)
+ // public JSONObject put(String key, double value)
+ // public JSONObject put(String key, int value)
+
+ ///
+ /// Put a key/value pair in the JSONObject. If the value is null,
+ /// then the key will be removed from the JSONObject if it is present.
+ ///
+ /// A key string.
+ ///
+ /// An object which is the value. It should be of one of these
+ /// types: Boolean, Double, Integer, JSONArray, JSONObject, String, or the
+ /// JSONObject.NULL object.
+ ///
+ /// JSONObject
+ public JSONObject put(string key, object val)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key", "key cannot be null");
+ }
+ if (val != null)
+ {
+ if (!myHashMap.ContainsKey(key))
+ {
+ string test = key;
+ myHashMap.Add(key,val);
+ myKeyIndexList.Add(key);
+ }
+ else
+ {
+ myHashMap[key]=val;
+ }
+ }
+ else
+ {
+ remove(key);
+ }
+ return this;
+ }
+
+ ///
+ /// Add a key value pair
+ ///
+ ///
+ ///
+ ///
+ public JSONObject putOpt(string key, object val)
+ {
+ if (val != null)
+ {
+ put(key,val);
+ }
+ return this;
+ }
+ #endregion
+
+ ///
+ /// Remove a object assosiateted with the given key
+ ///
+ ///
+ ///
+ public object remove(string key)
+ {
+ if (myHashMap.ContainsKey(key))
+ {
+ // TODO - does it really work ???
+ object obj = myHashMap[key];
+ myHashMap.Remove(key);
+ myKeyIndexList.Remove(key);
+ return obj;
+ }
+ return null;
+ }
+
+ ///
+ /// Append an array of JSONObjects to current object
+ ///
+ ///
+ ///
+ public JSONArray toJSONArray(JSONArray names)
+ {
+ if (names == null | names.Length() == 0)
+ return null;
+
+ JSONArray ja = new JSONArray();
+ for (int i=0; i
+ /// Overridden to return a JSON formattet object as a string
+ ///
+ /// JSON object as formatted string
+ public override string ToString()
+ {
+ object obj = null;
+ //string s;
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append('{');
+ foreach (string key in myHashMap.Keys) //NOTE! Could also use myKeyIndexList !!!
+ {
+ if (obj != null)
+ sb.Append(',');
+ obj = myHashMap[key];
+ if (obj != null)
+ {
+ sb.Append(JSONUtils.Enquote(key));
+ sb.Append(':');
+
+ if (obj is string)
+ {
+ sb.Append(JSONUtils.Enquote((string)obj));
+ }
+ else if (obj is float || obj is double)
+ {
+ sb.Append(numberToString(obj));
+ }
+ else if (obj is bool)
+ {
+ sb.Append(obj.ToString().ToLower());
+ }
+ else
+ {
+ sb.Append(obj.ToString());
+ }
+ }
+ }
+ sb.Append('}');
+ return sb.ToString();
+ }
+ }
+}
diff --git a/libsecondlife-cs/JSONlib/JSONTokener.cs b/libsecondlife-cs/JSONlib/JSONTokener.cs
new file mode 100644
index 00000000..a4c7f7b1
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/JSONTokener.cs
@@ -0,0 +1,463 @@
+using System;
+using System.Text;
+using System.Globalization;
+
+namespace Nii.JSON
+{
+ ///
+ ///
+ /// A JSONTokener takes a source string and extracts characters and tokens from
+ /// it. It is used by the JSONObject and JSONArray constructors to parse
+ /// JSON source strings.
+ ///
+ ///
+ /// Public Domain 2002 JSON.org
+ /// @author JSON.org
+ /// @version 0.1
+ ///
+ /// Ported to C# by Are Bjolseth, teleplan.no
+ ///
+ ///
+ /// - Implement Custom exceptions
+ /// - Add unit testing
+ /// - Add log4net
+ ///
+ ///
+ ///
+ public class JSONTokener
+ {
+ /// The index of the next character.
+ private int myIndex;
+ /// The source string being tokenized.
+ private string mySource;
+
+ ///
+ /// Construct a JSONTokener from a string.
+ ///
+ /// A source string.
+ public JSONTokener(string s)
+ {
+ myIndex = 0;
+ mySource = s;
+ }
+
+ ///
+ /// Back up one character. This provides a sort of lookahead capability,
+ /// so that you can test for a digit or letter before attempting to parse
+ /// the next number or identifier.
+ ///
+ public void back()
+ {
+ if (myIndex > 0)
+ myIndex -= 1;
+ }
+
+ ///
+ /// Get the hex value of a character (base16).
+ ///
+ ///
+ /// A character between '0' and '9' or between 'A' and 'F' or
+ /// between 'a' and 'f'.
+ ///
+ /// An int between 0 and 15, or -1 if c was not a hex digit.
+ public static int dehexchar(char c)
+ {
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+ if (c >= 'A' && c <= 'F')
+ {
+ return c + 10 - 'A';
+ }
+ if (c >= 'a' && c <= 'f')
+ {
+ return c + 10 - 'a';
+ }
+ return -1;
+ }
+
+ ///
+ /// Determine if the source string still contains characters that next() can consume.
+ ///
+ /// true if not yet at the end of the source.
+ public bool more()
+ {
+ return myIndex < mySource.Length;
+ }
+
+ ///
+ /// Get the next character in the source string.
+ ///
+ /// The next character, or 0 if past the end of the source string.
+ public char next()
+ {
+ char c = more() ? mySource[myIndex] : (char)0;
+ myIndex +=1;
+ return c;
+ }
+
+ ///
+ /// Consume the next character, and check that it matches a specified character
+ ///
+ /// The character to match.
+ /// The character.
+ public char next(char c)
+ {
+ char n = next();
+ if (n != c)
+ {
+ string msg = "Expected '" + c + "' and instead saw '" + n + "'.";
+ throw (new Exception(msg));
+ }
+ return n;
+ }
+
+ ///
+ /// Get the next n characters.
+ ///
+ /// The number of characters to take.
+ /// A string of n characters.
+ public string next(int n)
+ {
+ int i = myIndex;
+ int j = i + n;
+ if (j >= mySource.Length)
+ {
+ string msg = "Substring bounds error";
+ throw (new Exception(msg));
+ }
+ myIndex += n;
+ return mySource.Substring(i,j);
+ }
+
+ ///
+ /// Get the next char in the string, skipping whitespace
+ /// and comments (slashslash and slashstar).
+ ///
+ /// A character, or 0 if there are no more characters.
+ public char nextClean()
+ {
+ while (true)
+ {
+ char c = next();
+ if (c == '/')
+ {
+ switch (next())
+ {
+ case '/':
+ do
+ {
+ c = next();
+ } while (c != '\n' && c != '\r' && c != 0);
+ break;
+ case '*':
+ while (true)
+ {
+ c = next();
+ if (c == 0)
+ {
+ throw (new Exception("Unclosed comment."));
+ }
+ if (c == '*')
+ {
+ if (next() == '/')
+ {
+ break;
+ }
+ back();
+ }
+ }
+ break;
+ default:
+ back();
+ return '/';
+ }
+ }
+ else if (c == 0 || c > ' ')
+ {
+ return c;
+ }
+ }
+ }
+
+ ///
+ /// Return the characters up to the next close quote character.
+ /// Backslash processing is done. The formal JSON format does not
+ /// allow strings in single quotes, but an implementation is allowed to
+ /// accept them.
+ ///
+ /// The quoting character, either " or '
+ /// A String.
+ public string nextString(char quote)
+ {
+ char c;
+ StringBuilder sb = new StringBuilder();
+ while (true)
+ {
+ c = next();
+ if ((c == 0x00) || (c == 0x0A) || (c == 0x0D))
+ {
+ throw (new Exception("Unterminated string"));
+ }
+ // CTRL chars
+ if (c == '\\')
+ {
+ c = next();
+ switch (c)
+ {
+ case 'b': //Backspace
+ sb.Append('\b');
+ break;
+ case 't': //Horizontal tab
+ sb.Append('\t');
+ break;
+ case 'n': //newline
+ sb.Append('\n');
+ break;
+ case 'f': //Form feed
+ sb.Append('\f');
+ break;
+ case 'r': // Carriage return
+ sb.Append('\r');
+ break;
+ case 'u':
+ //sb.append((char)Integer.parseInt(next(4), 16)); // 16 == radix, ie. hex
+ int iascii = int.Parse(next(4),System.Globalization.NumberStyles.HexNumber);
+ sb.Append((char)iascii);
+ break;
+ default:
+ sb.Append(c);
+ break;
+ }
+ }
+ else
+ {
+ if (c == quote)
+ {
+ return sb.ToString();
+ }
+ sb.Append(c);
+ }
+ }//END-while
+ }
+
+ ///
+ /// Get the text up but not including the specified character or the
+ /// end of line, whichever comes first.
+ ///
+ /// A delimiter character.
+ /// A string.
+ public string nextTo(char d)
+ {
+ StringBuilder sb = new StringBuilder();
+ while (true)
+ {
+ char c = next();
+ if (c == d || c == (char)0 || c == '\n' || c == '\r')
+ {
+ if (c != (char)0)
+ {
+ back();
+ }
+ return sb.ToString().Trim();
+ }
+ sb.Append(c);
+ }
+ }
+
+ ///
+ /// Get the text up but not including one of the specified delimeter
+ /// characters or the end of line, which ever comes first.
+ ///
+ /// A set of delimiter characters.
+ /// A string, trimmed.
+ public string nextTo(string delimiters)
+ {
+ char c;
+ StringBuilder sb = new StringBuilder();
+ while (true)
+ {
+ c = next();
+ if ((delimiters.IndexOf(c) >= 0) || (c == (char)0 ) || (c == '\n') || (c == '\r'))
+ {
+ if (c != (char)0)
+ {
+ back();
+ }
+ return sb.ToString().Trim();
+ }
+ sb.Append(c);
+ }
+ }
+
+ ///
+ /// Get the next value as object. The value can be a Boolean, Double, Integer,
+ /// JSONArray, JSONObject, or String, or the JSONObject.NULL object.
+ ///
+ /// An object.
+ public object nextObject()
+ {
+ char c = nextClean();
+ string s;
+
+ if (c == '"' || c == '\'')
+ {
+ return nextString(c);
+ }
+ // Object
+ if (c == '{')
+ {
+ back();
+ return new JSONObject(this);
+ }
+
+ // JSON Array
+ if (c == '[')
+ {
+ back();
+ return new JSONArray(this);
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ char b = c;
+ while (c >= ' ' && c != ':' && c != ',' && c != ']' && c != '}' && c != '/')
+ {
+ sb.Append(c);
+ c = next();
+ }
+ back();
+
+ s = sb.ToString().Trim();
+ if (s == "true")
+ return bool.Parse("true");
+ if (s == "false")
+ return bool.Parse("false");
+ if (s == "null")
+ return JSONObject.NULL;
+
+ if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+')
+ {
+ try
+ {
+ return Convert.ToInt32(s);
+ }
+ catch (Exception e)
+ {
+ string msg = e.Message;
+ }
+ try
+ {
+ return Convert.ToDouble(s, NumberFormatInfo.InvariantInfo);
+ }
+ catch (Exception e)
+ {
+ string msg = e.Message;
+ }
+ }
+ if (s == "")
+ {
+ throw (new Exception("Missing value"));
+ }
+ return s;
+ }
+
+ ///
+ /// Skip characters until the next character is the requested character.
+ /// If the requested character is not found, no characters are skipped.
+ ///
+ /// A character to skip to.
+ ///
+ /// The requested character, or zero if the requested character is not found.
+ ///
+ public char skipTo(char to)
+ {
+ char c;
+ int i = myIndex;
+ do
+ {
+ c = next();
+ if (c == (char)0)
+ {
+ myIndex = i;
+ return c;
+ }
+ }while (c != to);
+
+ back();
+ return c;
+ }
+
+ ///
+ /// Skip characters until past the requested string.
+ /// If it is not found, we are left at the end of the source.
+ ///
+ /// A string to skip past.
+ public void skipPast(string to)
+ {
+ myIndex = mySource.IndexOf(to, myIndex);
+ if (myIndex < 0)
+ {
+ myIndex = mySource.Length;
+ }
+ else
+ {
+ myIndex += to.Length;
+ }
+ }
+
+ // TODO implement exception SyntaxError
+
+
+ ///
+ /// Make a printable string of this JSONTokener.
+ ///
+ /// " at character [myIndex] of [mySource]"
+ public override string ToString()
+ {
+ return " at charachter " + myIndex + " of " + mySource;
+ }
+
+ ///
+ /// Unescape the source text. Convert %hh sequences to single characters,
+ /// and convert plus to space. There are Web transport systems that insist on
+ /// doing unnecessary URL encoding. This provides a way to undo it.
+ ///
+ public void unescape()
+ {
+ mySource = unescape(mySource);
+ }
+
+ ///
+ /// Convert %hh sequences to single characters, and convert plus to space.
+ ///
+ /// A string that may contain plus and %hh sequences.
+ /// The unescaped string.
+ public static string unescape(string s)
+ {
+ int len = s.Length;
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i < len; i++)
+ {
+ char c = s[i];
+ if (c == '+')
+ {
+ c = ' ';
+ }
+ else if (c == '%' && (i + 2 < len))
+ {
+ int d = dehexchar(s[i+1]);
+ int e = dehexchar(s[i+2]);
+ if (d >= 0 && e >= 0)
+ {
+ c = (char)(d*16 + e);
+ i += 2;
+ }
+ }
+ sb.Append(c);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/libsecondlife-cs/JSONlib/JSONUtils.cs b/libsecondlife-cs/JSONlib/JSONUtils.cs
new file mode 100644
index 00000000..6e5af027
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/JSONUtils.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Text;
+
+namespace Nii.JSON
+{
+ ///
+ /// Public Domain 2002 JSON.org
+ /// @author JSON.org
+ /// @version 0.1
+ /// Ported to C# by Are Bjolseth, teleplan.no
+ ///
+ public sealed class JSONUtils
+ {
+ ///
+ /// Produce a string in double quotes with backslash sequences in all the right places.
+ ///
+ /// A String
+ /// A String correctly formatted for insertion in a JSON message.
+ public static string Enquote(string s)
+ {
+ if (s == null || s.Length == 0)
+ {
+ return "\"\"";
+ }
+ char c;
+ int i;
+ int len = s.Length;
+ StringBuilder sb = new StringBuilder(len + 4);
+ string t;
+
+ sb.Append('"');
+ for (i = 0; i < len; i += 1)
+ {
+ c = s[i];
+ if ((c == '\\') || (c == '"') || (c == '>'))
+ {
+ sb.Append('\\');
+ sb.Append(c);
+ }
+ else if (c == '\b')
+ sb.Append("\\b");
+ else if (c == '\t')
+ sb.Append("\\t");
+ else if (c == '\n')
+ sb.Append("\\n");
+ else if (c == '\f')
+ sb.Append("\\f");
+ else if (c == '\r')
+ sb.Append("\\r");
+ else
+ {
+ if (c < ' ')
+ {
+ //t = "000" + Integer.toHexString(c);
+ string tmp = new string(c,1);
+ t = "000" + int.Parse(tmp,System.Globalization.NumberStyles.HexNumber);
+ sb.Append("\\u" + t.Substring(t.Length - 4));
+ }
+ else
+ {
+ sb.Append(c);
+ }
+ }
+ }
+ sb.Append('"');
+ return sb.ToString();
+ }
+ }
+}
diff --git a/libsecondlife-cs/JSONlib/Nii.JSON.csproj b/libsecondlife-cs/JSONlib/Nii.JSON.csproj
new file mode 100644
index 00000000..8c9be8a8
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/Nii.JSON.csproj
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsecondlife-cs/JSONlib/json.doc.xml b/libsecondlife-cs/JSONlib/json.doc.xml
new file mode 100644
index 00000000..0d0006f1
--- /dev/null
+++ b/libsecondlife-cs/JSONlib/json.doc.xml
@@ -0,0 +1,878 @@
+
+
+
+ JSON
+
+
+
+
+
+ A JSONArray is an ordered sequence of values. Its external form is a string
+ wrapped in square brackets with commas between the values. The internal form
+ is an object having get() and opt() methods for accessing the values by
+ index, and put() methods for adding or replacing values. The values can be
+ any of these types: Boolean, JSONArray, JSONObject, Number, String, or the
+ JSONObject.NULL object.
+
+
+ The constructor can convert a JSON external form string into an
+ internal form Java object. The toString() method creates an external
+ form string.
+
+
+ A get() method returns a value if one can be found, and throws an exception
+ if one cannot be found. An opt() method returns a default value instead of
+ throwing an exception, and so is useful for obtaining optional values.
+
+
+ The generic get() and opt() methods return an object which you can cast or
+ query for type. There are also typed get() and opt() methods that do typing
+ checking and type coersion for you.
+
+
+ The texts produced by the toString() methods are very strict.
+ The constructors are more forgiving in the texts they will accept.
+
+
+
+ - An extra comma may appear just before the closing bracket.
+ - Strings may be quoted with single quotes.
+ - Strings do not need to be quoted at all if they do not contain leading
+ or trailing spaces, and if they do not contain any of these characters:
+ { } [ ] / \ : ,
+ - Numbers may have the 0- (octal) or 0x- (hex) prefix.
+
+
+
+ Public Domain 2002 JSON.org
+ @author JSON.org
+ @version 0.1
+
+ Ported to C# by Are Bjolseth, teleplan.no
+ TODO:
+ 1. Implement Custom exceptions
+ 2. Add indexer JSONObject[i] = object, and object = JSONObject[i];
+ 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"]
+ 4. Add unit testing
+ 5. Add log4net
+ 6. Make get/put methods private, to force use of indexer instead?
+
+
+
+ The ArrayList where the JSONArray's properties are kept.
+
+
+
+ Construct an empty JSONArray
+
+
+
+
+ Construct a JSONArray from a JSONTokener.
+
+ A JSONTokener
+
+
+
+ Construct a JSONArray from a source string.
+
+ A string that begins with '[' and ends with ']'.
+
+
+
+ Construct a JSONArray from a Collection.
+
+ A Collection.
+
+
+
+ Get the object value associated with an index.
+ Use indexer instead!!! Added to be true to the original Java implementation
+
+ index subscript. The index must be between 0 and length()-1
+ An object value.
+
+
+
+ Get the ArrayList which is holding the elements of the JSONArray.
+ Use the indexer instead!! Added to be true to the orignal Java src
+
+ The ArrayList
+
+
+
+ Get the boolean value associated with an index.
+ The string values "true" and "false" are converted to boolean.
+
+ index subscript
+ The truth
+
+
+
+ Get the double value associated with an index.
+
+ index subscript
+ A double value
+
+
+
+ Get the int value associated with an index.
+
+ index subscript
+ The int value
+
+
+
+ Get the JSONArray associated with an index.
+
+ index subscript
+ A JSONArray value
+
+
+
+ Get the JSONObject associated with an index.
+
+ index subscript
+ A JSONObject value
+
+
+
+ Get the string associated with an index.
+
+ index subscript
+ A string value.
+
+
+
+ Determine if the value is null.
+
+ index subscript
+ true if the value at the index is null, or if there is no value.
+
+
+
+ Make a string from the contents of this JSONArray. The separator string
+ is inserted between each element.
+ Warning: This method assumes that the data structure is acyclical.
+
+ separator A string that will be inserted between the elements.
+ A string.
+
+
+
+ Get the length of the JSONArray.
+ Added to be true to the original Java implementation
+
+ Number of JSONObjects in array
+
+
+
+ Get the optional object value associated with an index.
+
+ index subscript
+ object at that index.
+
+
+
+ Get the optional boolean value associated with an index.
+
+ index subscript
+ The truth
+
+
+
+ Get the optional boolean value associated with an index.
+ It returns the defaultValue if there is no value at that index or if it is not
+ a Boolean or the String "true" or "false".
+
+ index subscript
+
+ The truth.
+
+
+
+ Get the optional double value associated with an index.
+ NaN is returned if the index is not found,
+ or if the value is not a number and cannot be converted to a number.
+
+ index subscript
+ The double value object
+
+
+
+ Get the optional double value associated with an index.
+ NaN is returned if the index is not found,
+ or if the value is not a number and cannot be converted to a number.
+
+ index subscript
+
+ The double value object
+
+
+
+ Get the optional int value associated with an index.
+ Zero is returned if the index is not found,
+ or if the value is not a number and cannot be converted to a number.
+
+ index subscript
+ The int value object
+
+
+
+ Get the optional int value associated with an index.
+ The defaultValue is returned if the index is not found,
+ or if the value is not a number and cannot be converted to a number.
+
+ index subscript
+ The default value
+ The int value object
+
+
+
+ Get the optional JSONArray associated with an index.
+
+ index subscript
+ A JSONArray value, or null if the index has no value, or if the value is not a JSONArray.
+
+
+
+ Get the optional JSONObject associated with an index.
+ Null is returned if the key is not found, or null if the index has
+ no value, or if the value is not a JSONObject.
+
+ index subscript
+ A JSONObject value
+
+
+
+ Get the optional string value associated with an index. It returns an
+ empty string if there is no value at that index. If the value
+ is not a string and is not null, then it is coverted to a string.
+
+ index subscript
+ A String value
+
+
+
+ Get the optional string associated with an index.
+ The defaultValue is returned if the key is not found.
+
+ index subscript
+ The default value
+ A string value
+
+
+ OMITTED:
+ public JSONArray put(bool val)
+ public JSONArray put(double val)
+ public JSONArray put(int val)
+
+ Append an object value.
+
+ An object value. The value should be a Boolean, Double, Integer, JSONArray, JSObject, or String, or the JSONObject.NULL object
+ this (JSONArray)
+
+
+
+ Put or replace a boolean value in the JSONArray.
+
+
+ The subscript. If the index is greater than the length of
+ the JSONArray, then null elements will be added as necessary to pad it out.
+
+ An object value.
+ this (JSONArray)
+
+
+
+ Produce a JSONObject by combining a JSONArray of names with the values
+ of this JSONArray.
+
+
+ A JSONArray containing a list of key strings. These will be paired with the values.
+
+ A JSONObject, or null if there are no names or if this JSONArray
+
+
+
+ Make an JSON external form string of this JSONArray. For compactness, no
+ unnecessary whitespace is added.
+
+ a printable, displayable, transmittable representation of the array.
+
+
+
+ Alternate to Java get/put method, by using indexer
+
+
+
+
+ Alternativ to Java, getArrayList, by using propery
+
+
+
+
+ Get the length of the JSONArray.
+ Using a propery instead of method
+
+
+
+
+ Summary description for JsonFacade.
+
+
+
+
+ Parse a Hashtable and return a JSON formatted string
+
+
+
+
+
+
+ Parse JSON formatted string and return a Hashtable
+
+
+
+
+
+
+
+ A JSONArray is an ordered sequence of values. Its external form is a string
+ wrapped in square brackets with commas between the values. The internal form
+ is an object having get() and opt() methods for accessing the values by
+ index, and put() methods for adding or replacing values. The values can be
+ any of these types: Boolean, JSONArray, JSONObject, Number, String, or the
+ JSONObject.NULL object.
+
+
+ The constructor can convert a JSON external form string into an
+ internal form Java object. The toString() method creates an external
+ form string.
+
+
+ A get() method returns a value if one can be found, and throws an exception
+ if one cannot be found. An opt() method returns a default value instead of
+ throwing an exception, and so is useful for obtaining optional values.
+
+
+ The generic get() and opt() methods return an object which you can cast or
+ query for type. There are also typed get() and opt() methods that do typing
+ checking and type coersion for you.
+
+
+ The texts produced by the toString() methods are very strict.
+ The constructors are more forgiving in the texts they will accept.
+
+
+
+ - An extra comma may appear just before the closing bracket.
+ - Strings may be quoted with single quotes.
+ - Strings do not need to be quoted at all if they do not contain leading
+ or trailing spaces, and if they do not contain any of these characters:
+ { } [ ] / \ : ,
+ - Numbers may have the 0- (octal) or 0x- (hex) prefix.
+
+
+
+ Public Domain 2002 JSON.org
+ @author JSON.org
+ @version 0.1
+
+ Ported to C# by Are Bjolseth, teleplan.no
+ TODO:
+ 1. Implement Custom exceptions
+ 2. Add indexer JSONObject[i] = object, and object = JSONObject[i];
+ 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"]
+ 4. Add unit testing
+ 5. Add log4net
+ 6. Make get/put methods private, to force use of indexer instead?
+
+
+
+ The hash map where the JSONObject's properties are kept.
+
+
+ A shadow list of keys to enable access by sequence of insertion
+
+
+
+ It is sometimes more convenient and less ambiguous to have a NULL
+ object than to use C#'s null value.
+ JSONObject.NULL.toString() returns "null".
+
+
+
+
+ Construct an empty JSONObject.
+
+
+
+
+ Construct a JSONObject from a JSONTokener.
+
+ A JSONTokener object containing the source string.
+
+
+
+ Construct a JSONObject from a string.
+
+ A string beginning with '{' and ending with '}'.
+
+
+
+ Construct a JSONObject from a IDictionary
+
+
+
+
+
+ Accumulate values under a key. It is similar to the put method except
+ that if there is already an object stored under the key then a
+ JSONArray is stored under the key to hold all of the accumulated values.
+ If there is already a JSONArray, then the new value is appended to it.
+ In contrast, the put method replaces the previous value.
+
+ A key string.
+ An object to be accumulated under the key.
+ this
+
+
+
+ C# convenience method
+
+ The Hashtable
+
+
+
+ Alias to Java get method
+ Get the value object associated with a key.
+
+ A key string.
+ The object associated with the key.
+
+
+
+ Get the boolean value associated with a key.
+
+ A key string.
+ The truth.
+
+
+
+ Get the double value associated with a key.
+
+ A key string.
+ The double value
+
+
+
+ Get the int value associated with a key.
+
+ A key string
+ The integer value.
+
+
+
+ Get the JSONArray value associated with a key.
+
+ A key string
+ A JSONArray which is the value
+
+
+
+ Get the JSONObject value associated with a key.
+
+ A key string.
+ A JSONObject which is the value.
+
+
+
+ Get the string associated with a key.
+
+ A key string.
+ A string which is the value.
+
+
+
+ Determine if the JSONObject contains a specific key.
+
+ A key string.
+ true if the key exists in the JSONObject.
+
+
+
+ Get an enumeration of the keys of the JSONObject.
+ Added to be true to orginal Java implementation
+ Indexers are easier to use
+
+
+
+
+
+ Determine if the value associated with the key is null or if there is no value.
+
+ A key string
+ true if there is no value associated with the key or if the valus is the JSONObject.NULL object
+
+
+
+ Get the number of keys stored in the JSONObject.
+
+ The number of keys in the JSONObject.
+
+
+
+ Produce a JSONArray containing the names of the elements of this JSONObject
+
+ A JSONArray containing the key strings, or null if the JSONObject
+
+
+
+ Produce a string from a number.
+
+ Number value type object
+ String representation of the number
+
+
+
+ Get an optional value associated with a key.
+
+ A key string
+ An object which is the value, or null if there is no value.
+
+
+
+ Get an optional value associated with a key.
+ It returns false if there is no such key, or if the value is not
+ Boolean.TRUE or the String "true".
+
+ A key string.
+ bool value object
+
+
+
+ Get an optional value associated with a key.
+ It returns false if there is no such key, or if the value is not
+ Boolean.TRUE or the String "true".
+
+ A key string.
+ The preferred return value if conversion fails
+ bool value object
+
+
+
+ Get an optional double associated with a key,
+ or NaN if there is no such key or if its value is not a number.
+ If the value is a string, an attempt will be made to evaluate it as
+ a number.
+
+ A string which is the key.
+ A double value object
+
+
+
+ Get an optional double associated with a key,
+ or NaN if there is no such key or if its value is not a number.
+ If the value is a string, an attempt will be made to evaluate it as
+ a number.
+
+ A string which is the key.
+ The default
+ A double value object
+
+
+
+ Get an optional double associated with a key, or the
+ defaultValue if there is no such key or if its value is not a number.
+ If the value is a string, an attempt will be made to evaluate it as
+ number.
+
+ A key string.
+ An int object value
+
+
+
+ Get an optional double associated with a key, or the
+ defaultValue if there is no such key or if its value is not a number.
+ If the value is a string, an attempt will be made to evaluate it as
+ number.
+
+ A key string.
+ The default value
+ An int object value
+
+
+
+ Get an optional JSONArray associated with a key.
+ It returns null if there is no such key, or if its value is not a JSONArray
+
+ A key string
+ A JSONArray which is the value
+
+
+
+ Get an optional JSONObject associated with a key.
+ It returns null if there is no such key, or if its value is not a JSONObject.
+
+ A key string.
+ A JSONObject which is the value
+
+
+
+ Get an optional string associated with a key.
+ It returns an empty string if there is no such key. If the value is not
+ a string and is not null, then it is coverted to a string.
+
+ A key string.
+ A string which is the value.
+
+
+
+ Get an optional string associated with a key.
+ It returns the defaultValue if there is no such key.
+
+ A key string.
+ The default
+ A string which is the value.
+
+
+
+ Put a key/value pair in the JSONObject. If the value is null,
+ then the key will be removed from the JSONObject if it is present.
+
+ A key string.
+
+ An object which is the value. It should be of one of these
+ types: Boolean, Double, Integer, JSONArray, JSONObject, String, or the
+ JSONObject.NULL object.
+
+ JSONObject
+
+
+
+ Add a key value pair
+
+
+
+
+
+
+
+ Remove a object assosiateted with the given key
+
+
+
+
+
+
+ Append an array of JSONObjects to current object
+
+
+
+
+
+
+ Overridden to return a JSON formattet object as a string
+
+ JSON object as formatted string
+
+
+
+ Return the key for the associated index
+
+
+
+
+ Get/Add an object with the associated key
+
+
+
+
+ Return the number of JSON items in hashtable
+
+
+
+
+ Make a Null object
+ JSONObject.NULL is equivalent to the value that JavaScript calls null,
+ whilst C#'s null is equivalent to the value that JavaScript calls undefined.
+
+
+
+
+ Overriden to return "null"
+
+ null
+
+
+
+
+ A JSONTokener takes a source string and extracts characters and tokens from
+ it. It is used by the JSONObject and JSONArray constructors to parse
+ JSON source strings.
+
+
+ Public Domain 2002 JSON.org
+ @author JSON.org
+ @version 0.1
+
+ Ported to C# by Are Bjolseth, teleplan.no
+
+
+ - Implement Custom exceptions
+ - Add unit testing
+ - Add log4net
+
+
+
+
+
+ The index of the next character.
+
+
+ The source string being tokenized.
+
+
+
+ Construct a JSONTokener from a string.
+
+ A source string.
+
+
+
+ Back up one character. This provides a sort of lookahead capability,
+ so that you can test for a digit or letter before attempting to parse
+ the next number or identifier.
+
+
+
+
+ Get the hex value of a character (base16).
+
+
+ A character between '0' and '9' or between 'A' and 'F' or
+ between 'a' and 'f'.
+
+ An int between 0 and 15, or -1 if c was not a hex digit.
+
+
+
+ Determine if the source string still contains characters that next() can consume.
+
+ true if not yet at the end of the source.
+
+
+
+ Get the next character in the source string.
+
+ The next character, or 0 if past the end of the source string.
+
+
+
+ Consume the next character, and check that it matches a specified character
+
+ The character to match.
+ The character.
+
+
+
+ Get the next n characters.
+
+ The number of characters to take.
+ A string of n characters.
+
+
+
+ Get the next char in the string, skipping whitespace
+ and comments (slashslash and slashstar).
+
+ A character, or 0 if there are no more characters.
+
+
+
+ Return the characters up to the next close quote character.
+ Backslash processing is done. The formal JSON format does not
+ allow strings in single quotes, but an implementation is allowed to
+ accept them.
+
+ The quoting character, either " or '
+ A String.
+
+
+
+ Get the text up but not including the specified character or the
+ end of line, whichever comes first.
+
+ A delimiter character.
+ A string.
+
+
+
+ Get the text up but not including one of the specified delimeter
+ characters or the end of line, which ever comes first.
+
+ A set of delimiter characters.
+ A string, trimmed.
+
+
+
+ Get the next value as object. The value can be a Boolean, Double, Integer,
+ JSONArray, JSONObject, or String, or the JSONObject.NULL object.
+
+ An object.
+
+
+
+ Skip characters until the next character is the requested character.
+ If the requested character is not found, no characters are skipped.
+
+ A character to skip to.
+
+ The requested character, or zero if the requested character is not found.
+
+
+
+
+ Skip characters until past the requested string.
+ If it is not found, we are left at the end of the source.
+
+ A string to skip past.
+
+
+
+ Make a printable string of this JSONTokener.
+
+ " at character [myIndex] of [mySource]"
+
+
+
+ Unescape the source text. Convert %hh sequences to single characters,
+ and convert plus to space. There are Web transport systems that insist on
+ doing unnecessary URL encoding. This provides a way to undo it.
+
+
+
+
+ Convert %hh sequences to single characters, and convert plus to space.
+
+ A string that may contain plus and %hh sequences.
+ The unescaped string.
+
+
+
+ Public Domain 2002 JSON.org
+ @author JSON.org
+ @version 0.1
+ Ported to C# by Are Bjolseth, teleplan.no
+
+
+
+
+ Produce a string in double quotes with backslash sequences in all the right places.
+
+ A String
+ A String correctly formatted for insertion in a JSON message.
+
+
+
diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index 54b4ff8f..8fb42bbb 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -33,6 +33,7 @@ using System.Net.Sockets;
using System.Threading;
using System.Security.Cryptography;
using Nwc.XmlRpc;
+using Nii.JSON;
namespace libsecondlife
{
@@ -608,6 +609,7 @@ namespace libsecondlife
public Hashtable UserCallbacks;
public Hashtable InternalCallbacks;
public Circuit CurrentCircuit;
+ public Hashtable LoginValues;
private SecondLife Client;
private ProtocolManager Protocol;
@@ -623,6 +625,7 @@ namespace libsecondlife
UserCallbacks = new Hashtable();
InternalCallbacks = new Hashtable();
CurrentCircuit = null;
+ LoginValues = null;
// Register the internal callbacks
InternalCallbacks["RegionHandshake"] = new PacketCallback(RegionHandshakeHandler);
@@ -680,12 +683,12 @@ namespace libsecondlife
return values;
}
- public bool Login(Hashtable loginParams, out Hashtable values)
+ public bool Login(Hashtable loginParams)
{
- return Login(loginParams, "https://login.agni.lindenlab.com/cgi-bin/login.cgi", out values);
+ return Login(loginParams, "https://login.agni.lindenlab.com/cgi-bin/login.cgi");
}
- public bool Login(Hashtable loginParams, string url, out Hashtable values)
+ public bool Login(Hashtable loginParams, string url)
{
XmlRpcResponse result;
XmlRpcRequest xmlrpc = new XmlRpcRequest();
@@ -701,7 +704,7 @@ namespace libsecondlife
{
Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
LoginError = e.Message;
- values = null;
+ LoginValues = null;
return false;
}
@@ -709,28 +712,74 @@ namespace libsecondlife
{
Helpers.Log("Fault " + result.FaultCode + ": " + result.FaultString, Helpers.LogLevel.Error);
LoginError = "Fault " + result.FaultCode + ": " + result.FaultString;
- values = null;
+ LoginValues = null;
return false;
}
- values = (Hashtable)result.Value;
+ LoginValues = (Hashtable)result.Value;
- if ((string)values["login"] == "false")
+ // Replace LLSD variables with object representations
+ System.Text.RegularExpressions.Regex LLSDtoJSON =
+ new System.Text.RegularExpressions.Regex(@"('|r([0-9]))");
+
+ // Convert LLSD string to JSON
+ string json = "{vector:" + LLSDtoJSON.Replace((string)LoginValues["look_at"], "$2") + "}";
+
+ // Convert JSON string to a JSON object
+ IDictionary jsonObject = JsonFacade.fromJSON(json);
+ JSONArray jsonVector = (JSONArray)jsonObject["vector"];
+
+ // Convert the JSON object to an LLVector3d
+ LLVector3d vector = new LLVector3d((double)jsonVector[0], (double)jsonVector[1],
+ (double)jsonVector[2]);
+
+ LoginValues["look_at"] = vector;
+
+ // Convert LLSD string to JSON
+ json = LLSDtoJSON.Replace((string)LoginValues["home"], "$2");
+
+ // Convert JSON string to an object
+ jsonObject = JsonFacade.fromJSON(json);
+
+ // Create the position vector
+ JSONArray array = (JSONArray)jsonObject["position"];
+ LLVector3d posVector = new LLVector3d((double)array[0], (double)array[1], (double)array[2]);
+
+ // Create the look_at vector
+ array = (JSONArray)jsonObject["look_at"];
+ LLVector3d lookatVector = new LLVector3d((double)array[0], (double)array[1], (double)array[2]);
+
+ // Create the regionhandle U64
+ array = (JSONArray)jsonObject["region_handle"];
+ U64 regionhandle = new U64((int)array[0], (int)array[1]);
+
+ // Create a hashtable to hold the home values
+ Hashtable home = new Hashtable();
+ home["position"] = posVector;
+ home["look_at"] = lookatVector;
+ home["region_handle"] = regionhandle;
+
+ LoginValues["home"] = home;
+
+ if ((string)LoginValues["login"] == "false")
{
- LoginError = values["reason"] + ": " + values["message"];
+ LoginError = LoginValues["reason"] + ": " + LoginValues["message"];
return false;
}
- AgentID = new LLUUID((string)values["agent_id"]);
- SessionID = new LLUUID((string)values["session_id"]);
- Client.Avatar.ID = new LLUUID((string)values["agent_id"]);
- Client.Avatar.FirstName = (string)values["first_name"];
- Client.Avatar.LastName = (string)values["last_name"];
- uint circuitCode = (uint)(int)values["circuit_code"];
+ AgentID = new LLUUID((string)LoginValues["agent_id"]);
+ SessionID = new LLUUID((string)LoginValues["session_id"]);
+ Client.Avatar.ID = new LLUUID((string)LoginValues["agent_id"]);
+ Client.Avatar.FirstName = (string)LoginValues["first_name"];
+ Client.Avatar.LastName = (string)LoginValues["last_name"];
+ Client.Avatar.LookAt = vector;
+ Client.Avatar.HomePosition = posVector;
+ Client.Avatar.HomeLookAt = lookatVector;
+ uint circuitCode = (uint)(int)LoginValues["circuit_code"];
// Connect to the sim given in the login reply
Circuit circuit = new Circuit(Protocol, this, circuitCode);
- if (!circuit.Open((string)values["sim_ip"], (int)values["sim_port"]))
+ if (!circuit.Open((string)LoginValues["sim_ip"], (int)LoginValues["sim_port"]))
{
return false;
}
diff --git a/libsecondlife-cs/Packet.cs b/libsecondlife-cs/Packet.cs
index d41618b6..324aee11 100644
--- a/libsecondlife-cs/Packet.cs
+++ b/libsecondlife-cs/Packet.cs
@@ -1059,7 +1059,7 @@ namespace libsecondlife
return packet;
}
- public static Packet ChatOut(ProtocolManager protocol, LLUUID myAgentID, LLUUID mySessionID, string message,
+ public static Packet Chat(ProtocolManager protocol, LLUUID myAgentID, LLUUID mySessionID, string message,
byte type, int channel, byte command, LLUUID commandID, float radius, LLVector3 position)
{
Hashtable blocks = new Hashtable();
diff --git a/libsecondlife-cs/Types.cs b/libsecondlife-cs/Types.cs
index bdebc787..735a243f 100644
--- a/libsecondlife-cs/Types.cs
+++ b/libsecondlife-cs/Types.cs
@@ -43,8 +43,17 @@ namespace libsecondlife
public U64(uint left, uint right)
{
Data = new uint[2];
- Data[0] = right; //left;
- Data[1] = left; //right;
+ // Backwards... don't ask me, it works
+ Data[0] = right;
+ Data[1] = left;
+ }
+
+ public U64(int left, int right)
+ {
+ Data = new uint[2];
+ // Backwards... don't ask me, it works
+ Data[0] = (uint)right;
+ Data[1] = (uint)left;
}
public U64(byte[] byteArray, int pos)
@@ -368,6 +377,13 @@ namespace libsecondlife
X = Y = Z = 0.0D;
}
+ public LLVector3d(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
public LLVector3d(byte[] byteArray, int pos)
{
X = BitConverter.ToDouble(byteArray, pos);
diff --git a/libsecondlife-cs/examples/name2key/name2key.cs b/libsecondlife-cs/examples/name2key/name2key.cs
index 0b2b5ece..4923ebd3 100644
--- a/libsecondlife-cs/examples/name2key/name2key.cs
+++ b/libsecondlife-cs/examples/name2key/name2key.cs
@@ -97,9 +97,8 @@ namespace name2key
Hashtable loginParams = NetworkManager.DefaultLoginValues(args[0], args[1], args[2], "00:00:00:00:00:00",
"last", 1, 10, 10, 10, "Win", "0", "name2key", "jhurliman@wsu.edu");
- Hashtable loginReply = new Hashtable();
- if (!client.Network.Login(loginParams, out loginReply))
+ if (!client.Network.Login(loginParams))
{
// Login failed
Console.WriteLine("ERROR: " + client.Network.LoginError);
diff --git a/libsecondlife-cs/examples/name2key/name2key.csproj b/libsecondlife-cs/examples/name2key/name2key.csproj
index 4ac978bf..ac11480d 100644
--- a/libsecondlife-cs/examples/name2key/name2key.csproj
+++ b/libsecondlife-cs/examples/name2key/name2key.csproj
@@ -83,6 +83,7 @@
Name = "libsecondlife"
Project = "{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ Private = "False"
/>
diff --git a/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs b/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs
index 995440bc..374695de 100644
--- a/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs
+++ b/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs
@@ -473,11 +473,11 @@ namespace SLAccountant
Hashtable loginParams = NetworkManager.DefaultLoginValues(txtFirstName.Text,
txtLastName.Text, txtPassword.Text, "00:00:00:00:00:00", "last", 1, 10, 10, 0,
"Win", "0", "accountant", "jhurliman@wsu.edu");
- Hashtable loginValues = new Hashtable();
- if (client.Network.Login(loginParams, out loginValues))
+ if (client.Network.Login(loginParams))
{
- lblName.Text = loginValues["first_name"] + " " + loginValues["last_name"];
+ lblName.Text = client.Network.LoginValues["first_name"] + " " +
+ client.Network.LoginValues["last_name"];
// AgentHeightWidth
Hashtable blocks = new Hashtable();
diff --git a/libsecondlife-cs/examples/slaccountant/slaccountant.csproj b/libsecondlife-cs/examples/slaccountant/slaccountant.csproj
index b9f5e3b3..f201319d 100644
--- a/libsecondlife-cs/examples/slaccountant/slaccountant.csproj
+++ b/libsecondlife-cs/examples/slaccountant/slaccountant.csproj
@@ -93,6 +93,7 @@
Name = "libsecondlife"
Project = "{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ Private = "False"
/>
diff --git a/libsecondlife-cs/examples/sldump/sldump.cs b/libsecondlife-cs/examples/sldump/sldump.cs
index 045ea39e..516f4976 100644
--- a/libsecondlife-cs/examples/sldump/sldump.cs
+++ b/libsecondlife-cs/examples/sldump/sldump.cs
@@ -168,9 +168,7 @@ namespace sldump
optionsArray.Add("inventory-skeleton");
loginParams["options"] = optionsArray;
- Hashtable loginReply = new Hashtable();
-
- if (!client.Network.Login(loginParams, out loginReply))
+ if (!client.Network.Login(loginParams))
{
// Login failed
Console.WriteLine("Error logging in: " + client.Network.LoginError);
@@ -178,7 +176,7 @@ namespace sldump
}
// Login was successful
- Console.WriteLine("Message of the day: " + loginReply["message"]);
+ Console.WriteLine("Message of the day: " + client.Network.LoginValues["message"]);
while (true)
{
diff --git a/libsecondlife-cs/examples/sldump/sldump.csproj b/libsecondlife-cs/examples/sldump/sldump.csproj
index 4b5c775e..02b5700f 100644
--- a/libsecondlife-cs/examples/sldump/sldump.csproj
+++ b/libsecondlife-cs/examples/sldump/sldump.csproj
@@ -83,6 +83,7 @@
Name = "libsecondlife"
Project = "{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ Private = "False"
/>
diff --git a/libsecondlife-cs/libsecondlife.csproj b/libsecondlife-cs/libsecondlife.csproj
index 923d31e7..1a1dffcb 100644
--- a/libsecondlife-cs/libsecondlife.csproj
+++ b/libsecondlife-cs/libsecondlife.csproj
@@ -84,6 +84,11 @@
Project = "{410F8877-F1E1-4696-ABC7-4339189EECC3}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
+
diff --git a/libsecondlife-cs/libsecondlife.sln b/libsecondlife-cs/libsecondlife.sln
index 22a8ad2a..44408737 100644
--- a/libsecondlife-cs/libsecondlife.sln
+++ b/libsecondlife-cs/libsecondlife.sln
@@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlRpcCS", "XmlRpcCS\XmlRpc
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nii.JSON", "JSONlib\Nii.JSON.csproj", "{C40EB7FD-F957-4659-A184-A1C28908D748}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "slaccountant", "examples\slaccountant\slaccountant.csproj", "{FC19D5F6-076E-4923-8456-9B0E00E22896}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
@@ -41,6 +45,10 @@ Global
{410F8877-F1E1-4696-ABC7-4339189EECC3}.Debug.Build.0 = Debug|.NET
{410F8877-F1E1-4696-ABC7-4339189EECC3}.Release.ActiveCfg = Release|.NET
{410F8877-F1E1-4696-ABC7-4339189EECC3}.Release.Build.0 = Release|.NET
+ {C40EB7FD-F957-4659-A184-A1C28908D748}.Debug.ActiveCfg = Debug|.NET
+ {C40EB7FD-F957-4659-A184-A1C28908D748}.Debug.Build.0 = Debug|.NET
+ {C40EB7FD-F957-4659-A184-A1C28908D748}.Release.ActiveCfg = Release|.NET
+ {C40EB7FD-F957-4659-A184-A1C28908D748}.Release.Build.0 = Release|.NET
{FC19D5F6-076E-4923-8456-9B0E00E22896}.Debug.ActiveCfg = Debug|.NET
{FC19D5F6-076E-4923-8456-9B0E00E22896}.Debug.Build.0 = Debug|.NET
{FC19D5F6-076E-4923-8456-9B0E00E22896}.Release.ActiveCfg = Release|.NET