* Moved OpenMetaverse.StructuredData to a separate library
* Added experimental JSON serialization/deserialization to OSD using LitJSON (works, but subject to change soon) * Moved packet handling code out of Simian.cs git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2361 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
60
OpenMetaverse.StructuredData/JSON/IJsonWrapper.cs
Normal file
60
OpenMetaverse.StructuredData/JSON/IJsonWrapper.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
#region Header
|
||||
/**
|
||||
* IJsonWrapper.cs
|
||||
* Interface that represents a type capable of handling all kinds of JSON
|
||||
* data. This is mainly used when mapping objects through JsonMapper, and
|
||||
* it's implemented by JsonData.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
public enum JsonType
|
||||
{
|
||||
None,
|
||||
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
Boolean
|
||||
}
|
||||
|
||||
public interface IJsonWrapper : IList, IOrderedDictionary
|
||||
{
|
||||
bool IsArray { get; }
|
||||
bool IsBoolean { get; }
|
||||
bool IsDouble { get; }
|
||||
bool IsInt { get; }
|
||||
bool IsLong { get; }
|
||||
bool IsObject { get; }
|
||||
bool IsString { get; }
|
||||
|
||||
bool GetBoolean ();
|
||||
double GetDouble ();
|
||||
int GetInt ();
|
||||
JsonType GetJsonType ();
|
||||
long GetLong ();
|
||||
string GetString ();
|
||||
|
||||
void SetBoolean (bool val);
|
||||
void SetDouble (double val);
|
||||
void SetInt (int val);
|
||||
void SetJsonType (JsonType type);
|
||||
void SetLong (long val);
|
||||
void SetString (string val);
|
||||
|
||||
string ToJson ();
|
||||
void ToJson (JsonWriter writer);
|
||||
}
|
||||
}
|
||||
993
OpenMetaverse.StructuredData/JSON/JsonData.cs
Normal file
993
OpenMetaverse.StructuredData/JSON/JsonData.cs
Normal file
@@ -0,0 +1,993 @@
|
||||
#region Header
|
||||
/**
|
||||
* JsonData.cs
|
||||
* Generic type to hold JSON data (objects, arrays, and so on). This is
|
||||
* the default type returned by JsonMapper.ToObject().
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
public class JsonData : IJsonWrapper, IEquatable<JsonData>
|
||||
{
|
||||
#region Fields
|
||||
private IList<JsonData> inst_array;
|
||||
private bool inst_boolean;
|
||||
private double inst_double;
|
||||
private int inst_int;
|
||||
private long inst_long;
|
||||
private IDictionary<string, JsonData> inst_object;
|
||||
private string inst_string;
|
||||
private string json;
|
||||
private JsonType type;
|
||||
|
||||
// Used to implement the IOrderedDictionary interface
|
||||
private IList<KeyValuePair<string, JsonData>> object_list;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
public int Count {
|
||||
get { return EnsureCollection ().Count; }
|
||||
}
|
||||
|
||||
public bool IsArray {
|
||||
get { return type == JsonType.Array; }
|
||||
}
|
||||
|
||||
public bool IsBoolean {
|
||||
get { return type == JsonType.Boolean; }
|
||||
}
|
||||
|
||||
public bool IsDouble {
|
||||
get { return type == JsonType.Double; }
|
||||
}
|
||||
|
||||
public bool IsInt {
|
||||
get { return type == JsonType.Int; }
|
||||
}
|
||||
|
||||
public bool IsLong {
|
||||
get { return type == JsonType.Long; }
|
||||
}
|
||||
|
||||
public bool IsObject {
|
||||
get { return type == JsonType.Object; }
|
||||
}
|
||||
|
||||
public bool IsString {
|
||||
get { return type == JsonType.String; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region ICollection Properties
|
||||
int ICollection.Count {
|
||||
get {
|
||||
return Count;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized {
|
||||
get {
|
||||
return EnsureCollection ().IsSynchronized;
|
||||
}
|
||||
}
|
||||
|
||||
object ICollection.SyncRoot {
|
||||
get {
|
||||
return EnsureCollection ().SyncRoot;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IDictionary Properties
|
||||
bool IDictionary.IsFixedSize {
|
||||
get {
|
||||
return EnsureDictionary ().IsFixedSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDictionary.IsReadOnly {
|
||||
get {
|
||||
return EnsureDictionary ().IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
ICollection IDictionary.Keys {
|
||||
get {
|
||||
EnsureDictionary ();
|
||||
IList<string> keys = new List<string> ();
|
||||
|
||||
foreach (KeyValuePair<string, JsonData> entry in
|
||||
object_list) {
|
||||
keys.Add (entry.Key);
|
||||
}
|
||||
|
||||
return (ICollection) keys;
|
||||
}
|
||||
}
|
||||
|
||||
ICollection IDictionary.Values {
|
||||
get {
|
||||
EnsureDictionary ();
|
||||
IList<JsonData> values = new List<JsonData> ();
|
||||
|
||||
foreach (KeyValuePair<string, JsonData> entry in
|
||||
object_list) {
|
||||
values.Add (entry.Value);
|
||||
}
|
||||
|
||||
return (ICollection) values;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IJsonWrapper Properties
|
||||
bool IJsonWrapper.IsArray {
|
||||
get { return IsArray; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsBoolean {
|
||||
get { return IsBoolean; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsDouble {
|
||||
get { return IsDouble; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsInt {
|
||||
get { return IsInt; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsLong {
|
||||
get { return IsLong; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsObject {
|
||||
get { return IsObject; }
|
||||
}
|
||||
|
||||
bool IJsonWrapper.IsString {
|
||||
get { return IsString; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IList Properties
|
||||
bool IList.IsFixedSize {
|
||||
get {
|
||||
return EnsureList ().IsFixedSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool IList.IsReadOnly {
|
||||
get {
|
||||
return EnsureList ().IsReadOnly;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IDictionary Indexer
|
||||
object IDictionary.this[object key] {
|
||||
get {
|
||||
return EnsureDictionary ()[key];
|
||||
}
|
||||
|
||||
set {
|
||||
if (! (key is String))
|
||||
throw new ArgumentException (
|
||||
"The key has to be a string");
|
||||
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
this[(string) key] = data;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IOrderedDictionary Indexer
|
||||
object IOrderedDictionary.this[int idx] {
|
||||
get {
|
||||
EnsureDictionary ();
|
||||
return object_list[idx].Value;
|
||||
}
|
||||
|
||||
set {
|
||||
EnsureDictionary ();
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
KeyValuePair<string, JsonData> old_entry = object_list[idx];
|
||||
|
||||
inst_object[old_entry.Key] = data;
|
||||
|
||||
KeyValuePair<string, JsonData> entry =
|
||||
new KeyValuePair<string, JsonData> (old_entry.Key, data);
|
||||
|
||||
object_list[idx] = entry;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IList Indexer
|
||||
object IList.this[int index] {
|
||||
get {
|
||||
return EnsureList ()[index];
|
||||
}
|
||||
|
||||
set {
|
||||
EnsureList ();
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
this[index] = data;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Indexers
|
||||
public JsonData this[string prop_name] {
|
||||
get {
|
||||
EnsureDictionary ();
|
||||
return inst_object[prop_name];
|
||||
}
|
||||
|
||||
set {
|
||||
EnsureDictionary ();
|
||||
|
||||
KeyValuePair<string, JsonData> entry =
|
||||
new KeyValuePair<string, JsonData> (prop_name, value);
|
||||
|
||||
if (inst_object.ContainsKey (prop_name)) {
|
||||
for (int i = 0; i < object_list.Count; i++) {
|
||||
if (object_list[i].Key == prop_name) {
|
||||
object_list[i] = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
object_list.Add (entry);
|
||||
|
||||
inst_object[prop_name] = value;
|
||||
|
||||
json = null;
|
||||
}
|
||||
}
|
||||
|
||||
public JsonData this[int index] {
|
||||
get {
|
||||
EnsureCollection ();
|
||||
|
||||
if (type == JsonType.Array)
|
||||
return inst_array[index];
|
||||
|
||||
return object_list[index].Value;
|
||||
}
|
||||
|
||||
set {
|
||||
EnsureCollection ();
|
||||
|
||||
if (type == JsonType.Array)
|
||||
inst_array[index] = value;
|
||||
else {
|
||||
KeyValuePair<string, JsonData> entry = object_list[index];
|
||||
KeyValuePair<string, JsonData> new_entry =
|
||||
new KeyValuePair<string, JsonData> (entry.Key, value);
|
||||
|
||||
object_list[index] = new_entry;
|
||||
inst_object[entry.Key] = value;
|
||||
}
|
||||
|
||||
json = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
public JsonData ()
|
||||
{
|
||||
}
|
||||
|
||||
public JsonData (bool boolean)
|
||||
{
|
||||
type = JsonType.Boolean;
|
||||
inst_boolean = boolean;
|
||||
}
|
||||
|
||||
public JsonData (double number)
|
||||
{
|
||||
type = JsonType.Double;
|
||||
inst_double = number;
|
||||
}
|
||||
|
||||
public JsonData (int number)
|
||||
{
|
||||
type = JsonType.Int;
|
||||
inst_int = number;
|
||||
}
|
||||
|
||||
public JsonData (long number)
|
||||
{
|
||||
type = JsonType.Long;
|
||||
inst_long = number;
|
||||
}
|
||||
|
||||
public JsonData (object obj)
|
||||
{
|
||||
if (obj is Boolean) {
|
||||
type = JsonType.Boolean;
|
||||
inst_boolean = (bool) obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Double) {
|
||||
type = JsonType.Double;
|
||||
inst_double = (double) obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Int32) {
|
||||
type = JsonType.Int;
|
||||
inst_int = (int) obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Int64) {
|
||||
type = JsonType.Long;
|
||||
inst_long = (long) obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is String) {
|
||||
type = JsonType.String;
|
||||
inst_string = (string) obj;
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ArgumentException (
|
||||
"Unable to wrap the given object with JsonData");
|
||||
}
|
||||
|
||||
public JsonData (string str)
|
||||
{
|
||||
type = JsonType.String;
|
||||
inst_string = str;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implicit Conversions
|
||||
public static implicit operator JsonData (Boolean data)
|
||||
{
|
||||
return new JsonData (data);
|
||||
}
|
||||
|
||||
public static implicit operator JsonData (Double data)
|
||||
{
|
||||
return new JsonData (data);
|
||||
}
|
||||
|
||||
public static implicit operator JsonData (Int32 data)
|
||||
{
|
||||
return new JsonData (data);
|
||||
}
|
||||
|
||||
public static implicit operator JsonData (Int64 data)
|
||||
{
|
||||
return new JsonData (data);
|
||||
}
|
||||
|
||||
public static implicit operator JsonData (String data)
|
||||
{
|
||||
return new JsonData (data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Explicit Conversions
|
||||
public static explicit operator Boolean (JsonData data)
|
||||
{
|
||||
if (data.type != JsonType.Boolean)
|
||||
throw new InvalidCastException (
|
||||
"Instance of JsonData doesn't hold a double");
|
||||
|
||||
return data.inst_boolean;
|
||||
}
|
||||
|
||||
public static explicit operator Double (JsonData data)
|
||||
{
|
||||
if (data.type != JsonType.Double)
|
||||
throw new InvalidCastException (
|
||||
"Instance of JsonData doesn't hold a double");
|
||||
|
||||
return data.inst_double;
|
||||
}
|
||||
|
||||
public static explicit operator Int32 (JsonData data)
|
||||
{
|
||||
if (data.type != JsonType.Int)
|
||||
throw new InvalidCastException (
|
||||
"Instance of JsonData doesn't hold an int");
|
||||
|
||||
return data.inst_int;
|
||||
}
|
||||
|
||||
public static explicit operator Int64 (JsonData data)
|
||||
{
|
||||
if (data.type != JsonType.Long)
|
||||
throw new InvalidCastException (
|
||||
"Instance of JsonData doesn't hold an int");
|
||||
|
||||
return data.inst_long;
|
||||
}
|
||||
|
||||
public static explicit operator String (JsonData data)
|
||||
{
|
||||
if (data.type != JsonType.String)
|
||||
throw new InvalidCastException (
|
||||
"Instance of JsonData doesn't hold a string");
|
||||
|
||||
return data.inst_string;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region ICollection Methods
|
||||
void ICollection.CopyTo (Array array, int index)
|
||||
{
|
||||
EnsureCollection ().CopyTo (array, index);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IDictionary Methods
|
||||
void IDictionary.Add (object key, object value)
|
||||
{
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
EnsureDictionary ().Add (key, data);
|
||||
|
||||
KeyValuePair<string, JsonData> entry =
|
||||
new KeyValuePair<string, JsonData> ((string) key, data);
|
||||
object_list.Add (entry);
|
||||
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IDictionary.Clear ()
|
||||
{
|
||||
EnsureDictionary ().Clear ();
|
||||
object_list.Clear ();
|
||||
json = null;
|
||||
}
|
||||
|
||||
bool IDictionary.Contains (object key)
|
||||
{
|
||||
return EnsureDictionary ().Contains (key);
|
||||
}
|
||||
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator ()
|
||||
{
|
||||
return ((IOrderedDictionary) this).GetEnumerator ();
|
||||
}
|
||||
|
||||
void IDictionary.Remove (object key)
|
||||
{
|
||||
EnsureDictionary ().Remove (key);
|
||||
|
||||
for (int i = 0; i < object_list.Count; i++) {
|
||||
if (object_list[i].Key == (string) key) {
|
||||
object_list.RemoveAt (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IEnumerable Methods
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return EnsureCollection ().GetEnumerator ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IJsonWrapper Methods
|
||||
bool IJsonWrapper.GetBoolean ()
|
||||
{
|
||||
if (type != JsonType.Boolean)
|
||||
throw new InvalidOperationException (
|
||||
"JsonData instance doesn't hold a boolean");
|
||||
|
||||
return inst_boolean;
|
||||
}
|
||||
|
||||
double IJsonWrapper.GetDouble ()
|
||||
{
|
||||
if (type != JsonType.Double)
|
||||
throw new InvalidOperationException (
|
||||
"JsonData instance doesn't hold a double");
|
||||
|
||||
return inst_double;
|
||||
}
|
||||
|
||||
int IJsonWrapper.GetInt ()
|
||||
{
|
||||
if (type != JsonType.Int)
|
||||
throw new InvalidOperationException (
|
||||
"JsonData instance doesn't hold an int");
|
||||
|
||||
return inst_int;
|
||||
}
|
||||
|
||||
long IJsonWrapper.GetLong ()
|
||||
{
|
||||
if (type != JsonType.Long)
|
||||
throw new InvalidOperationException (
|
||||
"JsonData instance doesn't hold a long");
|
||||
|
||||
return inst_long;
|
||||
}
|
||||
|
||||
string IJsonWrapper.GetString ()
|
||||
{
|
||||
if (type != JsonType.String)
|
||||
throw new InvalidOperationException (
|
||||
"JsonData instance doesn't hold a string");
|
||||
|
||||
return inst_string;
|
||||
}
|
||||
|
||||
void IJsonWrapper.SetBoolean (bool val)
|
||||
{
|
||||
type = JsonType.Boolean;
|
||||
inst_boolean = val;
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IJsonWrapper.SetDouble (double val)
|
||||
{
|
||||
type = JsonType.Double;
|
||||
inst_double = val;
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IJsonWrapper.SetInt (int val)
|
||||
{
|
||||
type = JsonType.Int;
|
||||
inst_int = val;
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IJsonWrapper.SetLong (long val)
|
||||
{
|
||||
type = JsonType.Long;
|
||||
inst_long = val;
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IJsonWrapper.SetString (string val)
|
||||
{
|
||||
type = JsonType.String;
|
||||
inst_string = val;
|
||||
json = null;
|
||||
}
|
||||
|
||||
string IJsonWrapper.ToJson ()
|
||||
{
|
||||
return ToJson ();
|
||||
}
|
||||
|
||||
void IJsonWrapper.ToJson (JsonWriter writer)
|
||||
{
|
||||
ToJson (writer);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IList Methods
|
||||
int IList.Add (object value)
|
||||
{
|
||||
return Add (value);
|
||||
}
|
||||
|
||||
void IList.Clear ()
|
||||
{
|
||||
EnsureList ().Clear ();
|
||||
json = null;
|
||||
}
|
||||
|
||||
bool IList.Contains (object value)
|
||||
{
|
||||
return EnsureList ().Contains (value);
|
||||
}
|
||||
|
||||
int IList.IndexOf (object value)
|
||||
{
|
||||
return EnsureList ().IndexOf (value);
|
||||
}
|
||||
|
||||
void IList.Insert (int index, object value)
|
||||
{
|
||||
EnsureList ().Insert (index, value);
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IList.Remove (object value)
|
||||
{
|
||||
EnsureList ().Remove (value);
|
||||
json = null;
|
||||
}
|
||||
|
||||
void IList.RemoveAt (int index)
|
||||
{
|
||||
EnsureList ().RemoveAt (index);
|
||||
json = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region IOrderedDictionary Methods
|
||||
IDictionaryEnumerator IOrderedDictionary.GetEnumerator ()
|
||||
{
|
||||
EnsureDictionary ();
|
||||
|
||||
return new OrderedDictionaryEnumerator (
|
||||
object_list.GetEnumerator ());
|
||||
}
|
||||
|
||||
void IOrderedDictionary.Insert (int idx, object key, object value)
|
||||
{
|
||||
string property = (string) key;
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
this[property] = data;
|
||||
|
||||
KeyValuePair<string, JsonData> entry =
|
||||
new KeyValuePair<string, JsonData> (property, data);
|
||||
|
||||
object_list.Insert (idx, entry);
|
||||
}
|
||||
|
||||
void IOrderedDictionary.RemoveAt (int idx)
|
||||
{
|
||||
EnsureDictionary ();
|
||||
|
||||
inst_object.Remove (object_list[idx].Key);
|
||||
object_list.RemoveAt (idx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
private ICollection EnsureCollection ()
|
||||
{
|
||||
if (type == JsonType.Array)
|
||||
return (ICollection) inst_array;
|
||||
|
||||
if (type == JsonType.Object)
|
||||
return (ICollection) inst_object;
|
||||
|
||||
throw new InvalidOperationException (
|
||||
"The JsonData instance has to be initialized first");
|
||||
}
|
||||
|
||||
private IDictionary EnsureDictionary ()
|
||||
{
|
||||
if (type == JsonType.Object)
|
||||
return (IDictionary) inst_object;
|
||||
|
||||
if (type != JsonType.None)
|
||||
throw new InvalidOperationException (
|
||||
"Instance of JsonData is not a dictionary");
|
||||
|
||||
type = JsonType.Object;
|
||||
inst_object = new Dictionary<string, JsonData> ();
|
||||
object_list = new List<KeyValuePair<string, JsonData>> ();
|
||||
|
||||
return (IDictionary) inst_object;
|
||||
}
|
||||
|
||||
private IList EnsureList ()
|
||||
{
|
||||
if (type == JsonType.Array)
|
||||
return (IList) inst_array;
|
||||
|
||||
if (type != JsonType.None)
|
||||
throw new InvalidOperationException (
|
||||
"Instance of JsonData is not a list");
|
||||
|
||||
type = JsonType.Array;
|
||||
inst_array = new List<JsonData> ();
|
||||
|
||||
return (IList) inst_array;
|
||||
}
|
||||
|
||||
private JsonData ToJsonData (object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
||||
if (obj is JsonData)
|
||||
return (JsonData) obj;
|
||||
|
||||
return new JsonData (obj);
|
||||
}
|
||||
|
||||
private static void WriteJson (IJsonWrapper obj, JsonWriter writer)
|
||||
{
|
||||
if (obj.IsString) {
|
||||
writer.Write (obj.GetString ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsBoolean) {
|
||||
writer.Write (obj.GetBoolean ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsDouble) {
|
||||
writer.Write (obj.GetDouble ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsInt) {
|
||||
writer.Write (obj.GetInt ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsLong) {
|
||||
writer.Write (obj.GetLong ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsArray) {
|
||||
writer.WriteArrayStart ();
|
||||
foreach (object elem in (IList) obj)
|
||||
WriteJson ((JsonData) elem, writer);
|
||||
writer.WriteArrayEnd ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.IsObject) {
|
||||
writer.WriteObjectStart ();
|
||||
|
||||
foreach (DictionaryEntry entry in ((IDictionary) obj)) {
|
||||
writer.WritePropertyName ((string) entry.Key);
|
||||
WriteJson ((JsonData) entry.Value, writer);
|
||||
}
|
||||
writer.WriteObjectEnd ();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public int Add (object value)
|
||||
{
|
||||
JsonData data = ToJsonData (value);
|
||||
|
||||
json = null;
|
||||
|
||||
return EnsureList ().Add (data);
|
||||
}
|
||||
|
||||
public void Clear ()
|
||||
{
|
||||
if (IsObject) {
|
||||
((IDictionary) this).Clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsArray) {
|
||||
((IList) this).Clear ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals (JsonData x)
|
||||
{
|
||||
if (x == null)
|
||||
return false;
|
||||
|
||||
if (x.type != this.type)
|
||||
return false;
|
||||
|
||||
switch (this.type) {
|
||||
case JsonType.None:
|
||||
return true;
|
||||
|
||||
case JsonType.Object:
|
||||
return this.inst_object.Equals (x.inst_object);
|
||||
|
||||
case JsonType.Array:
|
||||
return this.inst_array.Equals (x.inst_array);
|
||||
|
||||
case JsonType.String:
|
||||
return this.inst_string.Equals (x.inst_string);
|
||||
|
||||
case JsonType.Int:
|
||||
return this.inst_int.Equals (x.inst_int);
|
||||
|
||||
case JsonType.Long:
|
||||
return this.inst_long.Equals (x.inst_long);
|
||||
|
||||
case JsonType.Double:
|
||||
return this.inst_double.Equals (x.inst_double);
|
||||
|
||||
case JsonType.Boolean:
|
||||
return this.inst_boolean.Equals (x.inst_boolean);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonType GetJsonType ()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void SetJsonType (JsonType type)
|
||||
{
|
||||
if (this.type == type)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case JsonType.None:
|
||||
break;
|
||||
|
||||
case JsonType.Object:
|
||||
inst_object = new Dictionary<string, JsonData> ();
|
||||
object_list = new List<KeyValuePair<string, JsonData>> ();
|
||||
break;
|
||||
|
||||
case JsonType.Array:
|
||||
inst_array = new List<JsonData> ();
|
||||
break;
|
||||
|
||||
case JsonType.String:
|
||||
inst_string = default (String);
|
||||
break;
|
||||
|
||||
case JsonType.Int:
|
||||
inst_int = default (Int32);
|
||||
break;
|
||||
|
||||
case JsonType.Long:
|
||||
inst_long = default (Int64);
|
||||
break;
|
||||
|
||||
case JsonType.Double:
|
||||
inst_double = default (Double);
|
||||
break;
|
||||
|
||||
case JsonType.Boolean:
|
||||
inst_boolean = default (Boolean);
|
||||
break;
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public string ToJson ()
|
||||
{
|
||||
if (json != null)
|
||||
return json;
|
||||
|
||||
StringWriter sw = new StringWriter ();
|
||||
JsonWriter writer = new JsonWriter (sw);
|
||||
writer.Validate = false;
|
||||
|
||||
WriteJson (this, writer);
|
||||
json = sw.ToString ();
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public void ToJson (JsonWriter writer)
|
||||
{
|
||||
bool old_validate = writer.Validate;
|
||||
|
||||
writer.Validate = false;
|
||||
|
||||
WriteJson (this, writer);
|
||||
|
||||
writer.Validate = old_validate;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
switch (type) {
|
||||
case JsonType.Array:
|
||||
return "JsonData array";
|
||||
|
||||
case JsonType.Boolean:
|
||||
return inst_boolean.ToString ();
|
||||
|
||||
case JsonType.Double:
|
||||
return inst_double.ToString ();
|
||||
|
||||
case JsonType.Int:
|
||||
return inst_int.ToString ();
|
||||
|
||||
case JsonType.Long:
|
||||
return inst_long.ToString ();
|
||||
|
||||
case JsonType.Object:
|
||||
return "JsonData object";
|
||||
|
||||
case JsonType.String:
|
||||
return inst_string;
|
||||
}
|
||||
|
||||
return "Uninitialized JsonData";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class OrderedDictionaryEnumerator : IDictionaryEnumerator
|
||||
{
|
||||
IEnumerator<KeyValuePair<string, JsonData>> list_enumerator;
|
||||
|
||||
|
||||
public object Current {
|
||||
get { return Entry; }
|
||||
}
|
||||
|
||||
public DictionaryEntry Entry {
|
||||
get {
|
||||
KeyValuePair<string, JsonData> curr = list_enumerator.Current;
|
||||
return new DictionaryEntry (curr.Key, curr.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public object Key {
|
||||
get { return list_enumerator.Current.Key; }
|
||||
}
|
||||
|
||||
public object Value {
|
||||
get { return list_enumerator.Current.Value; }
|
||||
}
|
||||
|
||||
|
||||
public OrderedDictionaryEnumerator (
|
||||
IEnumerator<KeyValuePair<string, JsonData>> enumerator)
|
||||
{
|
||||
list_enumerator = enumerator;
|
||||
}
|
||||
|
||||
|
||||
public bool MoveNext ()
|
||||
{
|
||||
return list_enumerator.MoveNext ();
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
list_enumerator.Reset ();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
OpenMetaverse.StructuredData/JSON/JsonException.cs
Normal file
60
OpenMetaverse.StructuredData/JSON/JsonException.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
#region Header
|
||||
/**
|
||||
* JsonException.cs
|
||||
* Base class throwed by LitJSON when a parsing error occurs.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
public class JsonException : ApplicationException
|
||||
{
|
||||
public JsonException () : base ()
|
||||
{
|
||||
}
|
||||
|
||||
internal JsonException (ParserToken token) :
|
||||
base (String.Format (
|
||||
"Invalid token '{0}' in input string", token))
|
||||
{
|
||||
}
|
||||
|
||||
internal JsonException (ParserToken token,
|
||||
Exception inner_exception) :
|
||||
base (String.Format (
|
||||
"Invalid token '{0}' in input string", token),
|
||||
inner_exception)
|
||||
{
|
||||
}
|
||||
|
||||
internal JsonException (int c) :
|
||||
base (String.Format (
|
||||
"Invalid character '{0}' in input string", (char) c))
|
||||
{
|
||||
}
|
||||
|
||||
internal JsonException (int c, Exception inner_exception) :
|
||||
base (String.Format (
|
||||
"Invalid character '{0}' in input string", (char) c),
|
||||
inner_exception)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public JsonException (string message) : base (message)
|
||||
{
|
||||
}
|
||||
|
||||
public JsonException (string message, Exception inner_exception) :
|
||||
base (message, inner_exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
911
OpenMetaverse.StructuredData/JSON/JsonMapper.cs
Normal file
911
OpenMetaverse.StructuredData/JSON/JsonMapper.cs
Normal file
@@ -0,0 +1,911 @@
|
||||
#region Header
|
||||
/**
|
||||
* JsonMapper.cs
|
||||
* JSON to .Net object and object to JSON conversions.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
internal struct PropertyMetadata
|
||||
{
|
||||
public MemberInfo Info;
|
||||
public bool IsField;
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
|
||||
internal struct ArrayMetadata
|
||||
{
|
||||
private Type element_type;
|
||||
private bool is_array;
|
||||
private bool is_list;
|
||||
|
||||
|
||||
public Type ElementType {
|
||||
get {
|
||||
if (element_type == null)
|
||||
return typeof (JsonData);
|
||||
|
||||
return element_type;
|
||||
}
|
||||
|
||||
set { element_type = value; }
|
||||
}
|
||||
|
||||
public bool IsArray {
|
||||
get { return is_array; }
|
||||
set { is_array = value; }
|
||||
}
|
||||
|
||||
public bool IsList {
|
||||
get { return is_list; }
|
||||
set { is_list = value; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal struct ObjectMetadata
|
||||
{
|
||||
private Type element_type;
|
||||
private bool is_dictionary;
|
||||
|
||||
private IDictionary<string, PropertyMetadata> properties;
|
||||
|
||||
|
||||
public Type ElementType {
|
||||
get {
|
||||
if (element_type == null)
|
||||
return typeof (JsonData);
|
||||
|
||||
return element_type;
|
||||
}
|
||||
|
||||
set { element_type = value; }
|
||||
}
|
||||
|
||||
public bool IsDictionary {
|
||||
get { return is_dictionary; }
|
||||
set { is_dictionary = value; }
|
||||
}
|
||||
|
||||
public IDictionary<string, PropertyMetadata> Properties {
|
||||
get { return properties; }
|
||||
set { properties = value; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal delegate void ExporterFunc (object obj, JsonWriter writer);
|
||||
public delegate void ExporterFunc<T> (T obj, JsonWriter writer);
|
||||
|
||||
internal delegate object ImporterFunc (object input);
|
||||
public delegate TValue ImporterFunc<TJson, TValue> (TJson input);
|
||||
|
||||
public delegate IJsonWrapper WrapperFactory ();
|
||||
|
||||
|
||||
public class JsonMapper
|
||||
{
|
||||
#region Fields
|
||||
private static int max_nesting_depth;
|
||||
|
||||
private static IFormatProvider datetime_format;
|
||||
|
||||
private static IDictionary<Type, ExporterFunc> base_exporters_table;
|
||||
private static IDictionary<Type, ExporterFunc> custom_exporters_table;
|
||||
|
||||
private static IDictionary<Type,
|
||||
IDictionary<Type, ImporterFunc>> base_importers_table;
|
||||
private static IDictionary<Type,
|
||||
IDictionary<Type, ImporterFunc>> custom_importers_table;
|
||||
|
||||
private static IDictionary<Type, ArrayMetadata> array_metadata;
|
||||
private static readonly object array_metadata_lock = new Object ();
|
||||
|
||||
private static IDictionary<Type,
|
||||
IDictionary<Type, MethodInfo>> conv_ops;
|
||||
private static readonly object conv_ops_lock = new Object ();
|
||||
|
||||
private static IDictionary<Type, ObjectMetadata> object_metadata;
|
||||
private static readonly object object_metadata_lock = new Object ();
|
||||
|
||||
private static IDictionary<Type,
|
||||
IList<PropertyMetadata>> type_properties;
|
||||
private static readonly object type_properties_lock = new Object ();
|
||||
|
||||
private static JsonWriter static_writer;
|
||||
private static readonly object static_writer_lock = new Object ();
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
static JsonMapper ()
|
||||
{
|
||||
max_nesting_depth = 100;
|
||||
|
||||
array_metadata = new Dictionary<Type, ArrayMetadata> ();
|
||||
conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
|
||||
object_metadata = new Dictionary<Type, ObjectMetadata> ();
|
||||
type_properties = new Dictionary<Type,
|
||||
IList<PropertyMetadata>> ();
|
||||
|
||||
static_writer = new JsonWriter ();
|
||||
|
||||
datetime_format = DateTimeFormatInfo.InvariantInfo;
|
||||
|
||||
base_exporters_table = new Dictionary<Type, ExporterFunc> ();
|
||||
custom_exporters_table = new Dictionary<Type, ExporterFunc> ();
|
||||
|
||||
base_importers_table = new Dictionary<Type,
|
||||
IDictionary<Type, ImporterFunc>> ();
|
||||
custom_importers_table = new Dictionary<Type,
|
||||
IDictionary<Type, ImporterFunc>> ();
|
||||
|
||||
RegisterBaseExporters ();
|
||||
RegisterBaseImporters ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
private static void AddArrayMetadata (Type type)
|
||||
{
|
||||
if (array_metadata.ContainsKey (type))
|
||||
return;
|
||||
|
||||
ArrayMetadata data = new ArrayMetadata ();
|
||||
|
||||
data.IsArray = type.IsArray;
|
||||
|
||||
if (type.GetInterface ("System.Collections.IList") != null)
|
||||
data.IsList = true;
|
||||
|
||||
foreach (PropertyInfo p_info in type.GetProperties ()) {
|
||||
if (p_info.Name != "Item")
|
||||
continue;
|
||||
|
||||
ParameterInfo[] parameters = p_info.GetIndexParameters ();
|
||||
|
||||
if (parameters.Length != 1)
|
||||
continue;
|
||||
|
||||
if (parameters[0].ParameterType == typeof (int))
|
||||
data.ElementType = p_info.PropertyType;
|
||||
}
|
||||
|
||||
lock (array_metadata_lock) {
|
||||
try {
|
||||
array_metadata.Add (type, data);
|
||||
} catch (ArgumentException) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddObjectMetadata (Type type)
|
||||
{
|
||||
if (object_metadata.ContainsKey (type))
|
||||
return;
|
||||
|
||||
ObjectMetadata data = new ObjectMetadata ();
|
||||
|
||||
if (type.GetInterface ("System.Collections.IDictionary") != null)
|
||||
data.IsDictionary = true;
|
||||
|
||||
data.Properties = new Dictionary<string, PropertyMetadata> ();
|
||||
|
||||
foreach (PropertyInfo p_info in type.GetProperties ()) {
|
||||
if (p_info.Name == "Item") {
|
||||
ParameterInfo[] parameters = p_info.GetIndexParameters ();
|
||||
|
||||
if (parameters.Length != 1)
|
||||
continue;
|
||||
|
||||
if (parameters[0].ParameterType == typeof (string))
|
||||
data.ElementType = p_info.PropertyType;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyMetadata p_data = new PropertyMetadata ();
|
||||
p_data.Info = p_info;
|
||||
p_data.Type = p_info.PropertyType;
|
||||
|
||||
data.Properties.Add (p_info.Name, p_data);
|
||||
}
|
||||
|
||||
foreach (FieldInfo f_info in type.GetFields ()) {
|
||||
PropertyMetadata p_data = new PropertyMetadata ();
|
||||
p_data.Info = f_info;
|
||||
p_data.IsField = true;
|
||||
p_data.Type = f_info.FieldType;
|
||||
|
||||
data.Properties.Add (f_info.Name, p_data);
|
||||
}
|
||||
|
||||
lock (object_metadata_lock) {
|
||||
try {
|
||||
object_metadata.Add (type, data);
|
||||
} catch (ArgumentException) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTypeProperties (Type type)
|
||||
{
|
||||
if (type_properties.ContainsKey (type))
|
||||
return;
|
||||
|
||||
IList<PropertyMetadata> props = new List<PropertyMetadata> ();
|
||||
|
||||
foreach (PropertyInfo p_info in type.GetProperties ()) {
|
||||
if (p_info.Name == "Item")
|
||||
continue;
|
||||
|
||||
PropertyMetadata p_data = new PropertyMetadata ();
|
||||
p_data.Info = p_info;
|
||||
p_data.IsField = false;
|
||||
props.Add (p_data);
|
||||
}
|
||||
|
||||
foreach (FieldInfo f_info in type.GetFields ()) {
|
||||
PropertyMetadata p_data = new PropertyMetadata ();
|
||||
p_data.Info = f_info;
|
||||
p_data.IsField = true;
|
||||
|
||||
props.Add (p_data);
|
||||
}
|
||||
|
||||
lock (type_properties_lock) {
|
||||
try {
|
||||
type_properties.Add (type, props);
|
||||
} catch (ArgumentException) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodInfo GetConvOp (Type t1, Type t2)
|
||||
{
|
||||
lock (conv_ops_lock) {
|
||||
if (! conv_ops.ContainsKey (t1))
|
||||
conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
|
||||
}
|
||||
|
||||
if (conv_ops[t1].ContainsKey (t2))
|
||||
return conv_ops[t1][t2];
|
||||
|
||||
MethodInfo op = t1.GetMethod (
|
||||
"op_Implicit", new Type[] { t2 });
|
||||
|
||||
lock (conv_ops_lock) {
|
||||
try {
|
||||
conv_ops[t1].Add (t2, op);
|
||||
} catch (ArgumentException) {
|
||||
return conv_ops[t1][t2];
|
||||
}
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static object ReadValue (Type inst_type, JsonReader reader)
|
||||
{
|
||||
reader.Read ();
|
||||
|
||||
if (reader.Token == JsonToken.ArrayEnd)
|
||||
return null;
|
||||
|
||||
if (reader.Token == JsonToken.Null) {
|
||||
|
||||
if (! inst_type.IsClass)
|
||||
throw new JsonException (String.Format (
|
||||
"Can't assign null to an instance of type {0}",
|
||||
inst_type));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.Double ||
|
||||
reader.Token == JsonToken.Int ||
|
||||
reader.Token == JsonToken.Long ||
|
||||
reader.Token == JsonToken.String ||
|
||||
reader.Token == JsonToken.Boolean) {
|
||||
|
||||
Type json_type = reader.Value.GetType ();
|
||||
|
||||
if (inst_type.IsAssignableFrom (json_type))
|
||||
return reader.Value;
|
||||
|
||||
// If there's a custom importer that fits, use it
|
||||
if (custom_importers_table.ContainsKey (json_type) &&
|
||||
custom_importers_table[json_type].ContainsKey (
|
||||
inst_type)) {
|
||||
|
||||
ImporterFunc importer =
|
||||
custom_importers_table[json_type][inst_type];
|
||||
|
||||
return importer (reader.Value);
|
||||
}
|
||||
|
||||
// Maybe there's a base importer that works
|
||||
if (base_importers_table.ContainsKey (json_type) &&
|
||||
base_importers_table[json_type].ContainsKey (
|
||||
inst_type)) {
|
||||
|
||||
ImporterFunc importer =
|
||||
base_importers_table[json_type][inst_type];
|
||||
|
||||
return importer (reader.Value);
|
||||
}
|
||||
|
||||
// Maybe it's an enum
|
||||
if (inst_type.IsEnum)
|
||||
return Enum.ToObject (inst_type, reader.Value);
|
||||
|
||||
// Try using an implicit conversion operator
|
||||
MethodInfo conv_op = GetConvOp (inst_type, json_type);
|
||||
|
||||
if (conv_op != null)
|
||||
return conv_op.Invoke (null,
|
||||
new object[] { reader.Value });
|
||||
|
||||
// No luck
|
||||
throw new JsonException (String.Format (
|
||||
"Can't assign value '{0}' (type {1}) to type {2}",
|
||||
reader.Value, json_type, inst_type));
|
||||
}
|
||||
|
||||
object instance = null;
|
||||
|
||||
if (reader.Token == JsonToken.ArrayStart) {
|
||||
|
||||
AddArrayMetadata (inst_type);
|
||||
ArrayMetadata t_data = array_metadata[inst_type];
|
||||
|
||||
if (! t_data.IsArray && ! t_data.IsList)
|
||||
throw new JsonException (String.Format (
|
||||
"Type {0} can't act as an array",
|
||||
inst_type));
|
||||
|
||||
IList list;
|
||||
Type elem_type;
|
||||
|
||||
if (! t_data.IsArray) {
|
||||
list = (IList) Activator.CreateInstance (inst_type);
|
||||
elem_type = t_data.ElementType;
|
||||
} else {
|
||||
list = new ArrayList ();
|
||||
elem_type = inst_type.GetElementType ();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
object item = ReadValue (elem_type, reader);
|
||||
if (reader.Token == JsonToken.ArrayEnd)
|
||||
break;
|
||||
|
||||
list.Add (item);
|
||||
}
|
||||
|
||||
if (t_data.IsArray) {
|
||||
int n = list.Count;
|
||||
instance = Array.CreateInstance (elem_type, n);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
((Array) instance).SetValue (list[i], i);
|
||||
} else
|
||||
instance = list;
|
||||
|
||||
} else if (reader.Token == JsonToken.ObjectStart) {
|
||||
|
||||
AddObjectMetadata (inst_type);
|
||||
ObjectMetadata t_data = object_metadata[inst_type];
|
||||
|
||||
instance = Activator.CreateInstance (inst_type);
|
||||
|
||||
while (true) {
|
||||
reader.Read ();
|
||||
|
||||
if (reader.Token == JsonToken.ObjectEnd)
|
||||
break;
|
||||
|
||||
string property = (string) reader.Value;
|
||||
|
||||
if (t_data.Properties.ContainsKey (property)) {
|
||||
PropertyMetadata prop_data =
|
||||
t_data.Properties[property];
|
||||
|
||||
if (prop_data.IsField) {
|
||||
((FieldInfo) prop_data.Info).SetValue (
|
||||
instance, ReadValue (prop_data.Type, reader));
|
||||
} else {
|
||||
PropertyInfo p_info =
|
||||
(PropertyInfo) prop_data.Info;
|
||||
|
||||
if (p_info.CanWrite)
|
||||
p_info.SetValue (
|
||||
instance,
|
||||
ReadValue (prop_data.Type, reader),
|
||||
null);
|
||||
else
|
||||
ReadValue (prop_data.Type, reader);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (! t_data.IsDictionary)
|
||||
throw new JsonException (String.Format (
|
||||
"The type {0} doesn't have the " +
|
||||
"property '{1}'", inst_type, property));
|
||||
|
||||
((IDictionary) instance).Add (
|
||||
property, ReadValue (
|
||||
t_data.ElementType, reader));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static IJsonWrapper ReadValue (WrapperFactory factory,
|
||||
JsonReader reader)
|
||||
{
|
||||
reader.Read ();
|
||||
|
||||
if (reader.Token == JsonToken.ArrayEnd ||
|
||||
reader.Token == JsonToken.Null)
|
||||
return null;
|
||||
|
||||
IJsonWrapper instance = factory ();
|
||||
|
||||
if (reader.Token == JsonToken.String) {
|
||||
instance.SetString ((string) reader.Value);
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.Double) {
|
||||
instance.SetDouble ((double) reader.Value);
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.Int) {
|
||||
instance.SetInt ((int) reader.Value);
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.Long) {
|
||||
instance.SetLong ((long) reader.Value);
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.Boolean) {
|
||||
instance.SetBoolean ((bool) reader.Value);
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (reader.Token == JsonToken.ArrayStart) {
|
||||
instance.SetJsonType (JsonType.Array);
|
||||
|
||||
while (true) {
|
||||
IJsonWrapper item = ReadValue (factory, reader);
|
||||
if (reader.Token == JsonToken.ArrayEnd)
|
||||
break;
|
||||
|
||||
((IList) instance).Add (item);
|
||||
}
|
||||
}
|
||||
else if (reader.Token == JsonToken.ObjectStart) {
|
||||
instance.SetJsonType (JsonType.Object);
|
||||
|
||||
while (true) {
|
||||
reader.Read ();
|
||||
|
||||
if (reader.Token == JsonToken.ObjectEnd)
|
||||
break;
|
||||
|
||||
string property = (string) reader.Value;
|
||||
|
||||
((IDictionary) instance)[property] = ReadValue (
|
||||
factory, reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void RegisterBaseExporters ()
|
||||
{
|
||||
base_exporters_table[typeof (byte)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToInt32 ((byte) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (char)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToString ((char) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (DateTime)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToString ((DateTime) obj,
|
||||
datetime_format));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (decimal)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write ((decimal) obj);
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (sbyte)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToInt32 ((sbyte) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (short)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToInt32 ((short) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (ushort)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToInt32 ((ushort) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (uint)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write (Convert.ToUInt64 ((uint) obj));
|
||||
};
|
||||
|
||||
base_exporters_table[typeof (ulong)] =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
writer.Write ((ulong) obj);
|
||||
};
|
||||
}
|
||||
|
||||
private static void RegisterBaseImporters ()
|
||||
{
|
||||
ImporterFunc importer;
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToByte ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (byte), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToUInt64 ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (ulong), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToSByte ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (sbyte), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToInt16 ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (short), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToUInt16 ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (ushort), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToUInt32 ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (uint), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToSingle ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (float), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToDouble ((int) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (int),
|
||||
typeof (double), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToDecimal ((double) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (double),
|
||||
typeof (decimal), importer);
|
||||
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToUInt32 ((long) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (long),
|
||||
typeof (uint), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToChar ((string) input);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (string),
|
||||
typeof (char), importer);
|
||||
|
||||
importer = delegate (object input) {
|
||||
return Convert.ToDateTime ((string) input, datetime_format);
|
||||
};
|
||||
RegisterImporter (base_importers_table, typeof (string),
|
||||
typeof (DateTime), importer);
|
||||
}
|
||||
|
||||
private static void RegisterImporter (
|
||||
IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
|
||||
Type json_type, Type value_type, ImporterFunc importer)
|
||||
{
|
||||
if (! table.ContainsKey (json_type))
|
||||
table.Add (json_type, new Dictionary<Type, ImporterFunc> ());
|
||||
|
||||
table[json_type][value_type] = importer;
|
||||
}
|
||||
|
||||
private static void WriteValue (object obj, JsonWriter writer,
|
||||
bool writer_is_private,
|
||||
int depth)
|
||||
{
|
||||
if (depth > max_nesting_depth)
|
||||
throw new JsonException (
|
||||
String.Format ("Max allowed object depth reached while " +
|
||||
"trying to export from type {0}",
|
||||
obj.GetType ()));
|
||||
|
||||
if (obj == null) {
|
||||
writer.Write (null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is IJsonWrapper) {
|
||||
if (writer_is_private)
|
||||
writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
|
||||
else
|
||||
((IJsonWrapper) obj).ToJson (writer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is String) {
|
||||
writer.Write ((string) obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Double) {
|
||||
writer.Write ((double) obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Int32) {
|
||||
writer.Write ((int) obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Boolean) {
|
||||
writer.Write ((bool) obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Int64) {
|
||||
writer.Write ((long) obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Array) {
|
||||
writer.WriteArrayStart ();
|
||||
|
||||
foreach (object elem in (Array) obj)
|
||||
WriteValue (elem, writer, writer_is_private, depth + 1);
|
||||
|
||||
writer.WriteArrayEnd ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is IList) {
|
||||
writer.WriteArrayStart ();
|
||||
foreach (object elem in (IList) obj)
|
||||
WriteValue (elem, writer, writer_is_private, depth + 1);
|
||||
writer.WriteArrayEnd ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is IDictionary) {
|
||||
writer.WriteObjectStart ();
|
||||
foreach (DictionaryEntry entry in (IDictionary) obj) {
|
||||
writer.WritePropertyName ((string) entry.Key);
|
||||
WriteValue (entry.Value, writer, writer_is_private,
|
||||
depth + 1);
|
||||
}
|
||||
writer.WriteObjectEnd ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Type obj_type = obj.GetType ();
|
||||
|
||||
// See if there's a custom exporter for the object
|
||||
if (custom_exporters_table.ContainsKey (obj_type)) {
|
||||
ExporterFunc exporter = custom_exporters_table[obj_type];
|
||||
exporter (obj, writer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If not, maybe there's a base exporter
|
||||
if (base_exporters_table.ContainsKey (obj_type)) {
|
||||
ExporterFunc exporter = base_exporters_table[obj_type];
|
||||
exporter (obj, writer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Last option, let's see if it's an enum
|
||||
if (obj is Enum) {
|
||||
Type e_type = Enum.GetUnderlyingType (obj_type);
|
||||
|
||||
if (e_type == typeof (long)
|
||||
|| e_type == typeof (uint)
|
||||
|| e_type == typeof (ulong))
|
||||
writer.Write ((ulong) obj);
|
||||
else
|
||||
writer.Write ((int) obj);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Okay, so it looks like the input should be exported as an
|
||||
// object
|
||||
AddTypeProperties (obj_type);
|
||||
IList<PropertyMetadata> props = type_properties[obj_type];
|
||||
|
||||
writer.WriteObjectStart ();
|
||||
foreach (PropertyMetadata p_data in props) {
|
||||
if (p_data.IsField) {
|
||||
writer.WritePropertyName (p_data.Info.Name);
|
||||
WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
|
||||
writer, writer_is_private, depth + 1);
|
||||
}
|
||||
else {
|
||||
PropertyInfo p_info = (PropertyInfo) p_data.Info;
|
||||
|
||||
if (p_info.CanRead) {
|
||||
writer.WritePropertyName (p_data.Info.Name);
|
||||
WriteValue (p_info.GetValue (obj, null),
|
||||
writer, writer_is_private, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.WriteObjectEnd ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static string ToJson (object obj)
|
||||
{
|
||||
lock (static_writer_lock) {
|
||||
static_writer.Reset ();
|
||||
|
||||
WriteValue (obj, static_writer, true, 0);
|
||||
|
||||
return static_writer.ToString ();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ToJson (object obj, JsonWriter writer)
|
||||
{
|
||||
WriteValue (obj, writer, false, 0);
|
||||
}
|
||||
|
||||
public static JsonData ToObject (JsonReader reader)
|
||||
{
|
||||
return (JsonData) ToWrapper (
|
||||
delegate { return new JsonData (); }, reader);
|
||||
}
|
||||
|
||||
public static JsonData ToObject (TextReader reader)
|
||||
{
|
||||
JsonReader json_reader = new JsonReader (reader);
|
||||
|
||||
return (JsonData) ToWrapper (
|
||||
delegate { return new JsonData (); }, json_reader);
|
||||
}
|
||||
|
||||
public static JsonData ToObject (string json)
|
||||
{
|
||||
return (JsonData) ToWrapper (
|
||||
delegate { return new JsonData (); }, json);
|
||||
}
|
||||
|
||||
public static T ToObject<T> (JsonReader reader)
|
||||
{
|
||||
return (T) ReadValue (typeof (T), reader);
|
||||
}
|
||||
|
||||
public static T ToObject<T> (TextReader reader)
|
||||
{
|
||||
JsonReader json_reader = new JsonReader (reader);
|
||||
|
||||
return (T) ReadValue (typeof (T), json_reader);
|
||||
}
|
||||
|
||||
public static T ToObject<T> (string json)
|
||||
{
|
||||
JsonReader reader = new JsonReader (json);
|
||||
|
||||
return (T) ReadValue (typeof (T), reader);
|
||||
}
|
||||
|
||||
public static IJsonWrapper ToWrapper (WrapperFactory factory,
|
||||
JsonReader reader)
|
||||
{
|
||||
return ReadValue (factory, reader);
|
||||
}
|
||||
|
||||
public static IJsonWrapper ToWrapper (WrapperFactory factory,
|
||||
string json)
|
||||
{
|
||||
JsonReader reader = new JsonReader (json);
|
||||
|
||||
return ReadValue (factory, reader);
|
||||
}
|
||||
|
||||
public static void RegisterExporter<T> (ExporterFunc<T> exporter)
|
||||
{
|
||||
ExporterFunc exporter_wrapper =
|
||||
delegate (object obj, JsonWriter writer) {
|
||||
exporter ((T) obj, writer);
|
||||
};
|
||||
|
||||
custom_exporters_table[typeof (T)] = exporter_wrapper;
|
||||
}
|
||||
|
||||
public static void RegisterImporter<TJson, TValue> (
|
||||
ImporterFunc<TJson, TValue> importer)
|
||||
{
|
||||
ImporterFunc importer_wrapper =
|
||||
delegate (object input) {
|
||||
return importer ((TJson) input);
|
||||
};
|
||||
|
||||
RegisterImporter (custom_importers_table, typeof (TJson),
|
||||
typeof (TValue), importer_wrapper);
|
||||
}
|
||||
|
||||
public static void UnregisterExporters ()
|
||||
{
|
||||
custom_exporters_table.Clear ();
|
||||
}
|
||||
|
||||
public static void UnregisterImporters ()
|
||||
{
|
||||
custom_importers_table.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
455
OpenMetaverse.StructuredData/JSON/JsonReader.cs
Normal file
455
OpenMetaverse.StructuredData/JSON/JsonReader.cs
Normal file
@@ -0,0 +1,455 @@
|
||||
#region Header
|
||||
/**
|
||||
* JsonReader.cs
|
||||
* Stream-like access to JSON text.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
public enum JsonToken
|
||||
{
|
||||
None,
|
||||
|
||||
ObjectStart,
|
||||
PropertyName,
|
||||
ObjectEnd,
|
||||
|
||||
ArrayStart,
|
||||
ArrayEnd,
|
||||
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
|
||||
String,
|
||||
|
||||
Boolean,
|
||||
Null
|
||||
}
|
||||
|
||||
|
||||
public class JsonReader
|
||||
{
|
||||
#region Fields
|
||||
private static IDictionary<int, IDictionary<int, int[]>> parse_table;
|
||||
|
||||
private Stack<int> automaton_stack;
|
||||
private int current_input;
|
||||
private int current_symbol;
|
||||
private bool end_of_json;
|
||||
private bool end_of_input;
|
||||
private Lexer lexer;
|
||||
private bool parser_in_string;
|
||||
private bool parser_return;
|
||||
private bool read_started;
|
||||
private TextReader reader;
|
||||
private bool reader_is_owned;
|
||||
private object token_value;
|
||||
private JsonToken token;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Properties
|
||||
public bool AllowComments {
|
||||
get { return lexer.AllowComments; }
|
||||
set { lexer.AllowComments = value; }
|
||||
}
|
||||
|
||||
public bool AllowSingleQuotedStrings {
|
||||
get { return lexer.AllowSingleQuotedStrings; }
|
||||
set { lexer.AllowSingleQuotedStrings = value; }
|
||||
}
|
||||
|
||||
public bool EndOfInput {
|
||||
get { return end_of_input; }
|
||||
}
|
||||
|
||||
public bool EndOfJson {
|
||||
get { return end_of_json; }
|
||||
}
|
||||
|
||||
public JsonToken Token {
|
||||
get { return token; }
|
||||
}
|
||||
|
||||
public object Value {
|
||||
get { return token_value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
static JsonReader ()
|
||||
{
|
||||
PopulateParseTable ();
|
||||
}
|
||||
|
||||
public JsonReader (string json_text) :
|
||||
this (new StringReader (json_text), true)
|
||||
{
|
||||
}
|
||||
|
||||
public JsonReader (TextReader reader) :
|
||||
this (reader, false)
|
||||
{
|
||||
}
|
||||
|
||||
private JsonReader (TextReader reader, bool owned)
|
||||
{
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException ("reader");
|
||||
|
||||
parser_in_string = false;
|
||||
parser_return = false;
|
||||
|
||||
read_started = false;
|
||||
automaton_stack = new Stack<int> ();
|
||||
automaton_stack.Push ((int) ParserToken.End);
|
||||
automaton_stack.Push ((int) ParserToken.Text);
|
||||
|
||||
lexer = new Lexer (reader);
|
||||
|
||||
end_of_input = false;
|
||||
end_of_json = false;
|
||||
|
||||
this.reader = reader;
|
||||
reader_is_owned = owned;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Static Methods
|
||||
private static void PopulateParseTable ()
|
||||
{
|
||||
parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
|
||||
|
||||
TableAddRow (ParserToken.Array);
|
||||
TableAddCol (ParserToken.Array, '[',
|
||||
'[',
|
||||
(int) ParserToken.ArrayPrime);
|
||||
|
||||
TableAddRow (ParserToken.ArrayPrime);
|
||||
TableAddCol (ParserToken.ArrayPrime, '"',
|
||||
(int) ParserToken.Value,
|
||||
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, '[',
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, ']',
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, '{',
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest,
|
||||
']');
|
||||
|
||||
TableAddRow (ParserToken.Object);
|
||||
TableAddCol (ParserToken.Object, '{',
|
||||
'{',
|
||||
(int) ParserToken.ObjectPrime);
|
||||
|
||||
TableAddRow (ParserToken.ObjectPrime);
|
||||
TableAddCol (ParserToken.ObjectPrime, '"',
|
||||
(int) ParserToken.Pair,
|
||||
(int) ParserToken.PairRest,
|
||||
'}');
|
||||
TableAddCol (ParserToken.ObjectPrime, '}',
|
||||
'}');
|
||||
|
||||
TableAddRow (ParserToken.Pair);
|
||||
TableAddCol (ParserToken.Pair, '"',
|
||||
(int) ParserToken.String,
|
||||
':',
|
||||
(int) ParserToken.Value);
|
||||
|
||||
TableAddRow (ParserToken.PairRest);
|
||||
TableAddCol (ParserToken.PairRest, ',',
|
||||
',',
|
||||
(int) ParserToken.Pair,
|
||||
(int) ParserToken.PairRest);
|
||||
TableAddCol (ParserToken.PairRest, '}',
|
||||
(int) ParserToken.Epsilon);
|
||||
|
||||
TableAddRow (ParserToken.String);
|
||||
TableAddCol (ParserToken.String, '"',
|
||||
'"',
|
||||
(int) ParserToken.CharSeq,
|
||||
'"');
|
||||
|
||||
TableAddRow (ParserToken.Text);
|
||||
TableAddCol (ParserToken.Text, '[',
|
||||
(int) ParserToken.Array);
|
||||
TableAddCol (ParserToken.Text, '{',
|
||||
(int) ParserToken.Object);
|
||||
|
||||
TableAddRow (ParserToken.Value);
|
||||
TableAddCol (ParserToken.Value, '"',
|
||||
(int) ParserToken.String);
|
||||
TableAddCol (ParserToken.Value, '[',
|
||||
(int) ParserToken.Array);
|
||||
TableAddCol (ParserToken.Value, '{',
|
||||
(int) ParserToken.Object);
|
||||
TableAddCol (ParserToken.Value, (int) ParserToken.Number,
|
||||
(int) ParserToken.Number);
|
||||
TableAddCol (ParserToken.Value, (int) ParserToken.True,
|
||||
(int) ParserToken.True);
|
||||
TableAddCol (ParserToken.Value, (int) ParserToken.False,
|
||||
(int) ParserToken.False);
|
||||
TableAddCol (ParserToken.Value, (int) ParserToken.Null,
|
||||
(int) ParserToken.Null);
|
||||
|
||||
TableAddRow (ParserToken.ValueRest);
|
||||
TableAddCol (ParserToken.ValueRest, ',',
|
||||
',',
|
||||
(int) ParserToken.Value,
|
||||
(int) ParserToken.ValueRest);
|
||||
TableAddCol (ParserToken.ValueRest, ']',
|
||||
(int) ParserToken.Epsilon);
|
||||
}
|
||||
|
||||
private static void TableAddCol (ParserToken row, int col,
|
||||
params int[] symbols)
|
||||
{
|
||||
parse_table[(int) row].Add (col, symbols);
|
||||
}
|
||||
|
||||
private static void TableAddRow (ParserToken rule)
|
||||
{
|
||||
parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
private void ProcessNumber (string number)
|
||||
{
|
||||
if (number.IndexOf ('.') != -1 ||
|
||||
number.IndexOf ('e') != -1 ||
|
||||
number.IndexOf ('E') != -1) {
|
||||
|
||||
double n_double;
|
||||
if (Double.TryParse (number, out n_double)) {
|
||||
token = JsonToken.Double;
|
||||
token_value = n_double;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int n_int32;
|
||||
if (Int32.TryParse (number, out n_int32)) {
|
||||
token = JsonToken.Int;
|
||||
token_value = n_int32;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long n_int64;
|
||||
if (Int64.TryParse (number, out n_int64)) {
|
||||
token = JsonToken.Long;
|
||||
token_value = n_int64;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Shouldn't happen, but just in case, return something
|
||||
token = JsonToken.Int;
|
||||
token_value = 0;
|
||||
}
|
||||
|
||||
private void ProcessSymbol ()
|
||||
{
|
||||
if (current_symbol == '[') {
|
||||
token = JsonToken.ArrayStart;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == ']') {
|
||||
token = JsonToken.ArrayEnd;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == '{') {
|
||||
token = JsonToken.ObjectStart;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == '}') {
|
||||
token = JsonToken.ObjectEnd;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == '"') {
|
||||
if (parser_in_string) {
|
||||
parser_in_string = false;
|
||||
|
||||
parser_return = true;
|
||||
|
||||
} else {
|
||||
if (token == JsonToken.None)
|
||||
token = JsonToken.String;
|
||||
|
||||
parser_in_string = true;
|
||||
}
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.CharSeq) {
|
||||
token_value = lexer.StringValue;
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.False) {
|
||||
token = JsonToken.Boolean;
|
||||
token_value = false;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.Null) {
|
||||
token = JsonToken.Null;
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.Number) {
|
||||
ProcessNumber (lexer.StringValue);
|
||||
|
||||
parser_return = true;
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.Pair) {
|
||||
token = JsonToken.PropertyName;
|
||||
|
||||
} else if (current_symbol == (int) ParserToken.True) {
|
||||
token = JsonToken.Boolean;
|
||||
token_value = true;
|
||||
parser_return = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadToken ()
|
||||
{
|
||||
if (end_of_input)
|
||||
return false;
|
||||
|
||||
lexer.NextToken ();
|
||||
|
||||
if (lexer.EndOfInput) {
|
||||
Close ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
current_input = lexer.Token;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public void Close ()
|
||||
{
|
||||
if (end_of_input)
|
||||
return;
|
||||
|
||||
end_of_input = true;
|
||||
end_of_json = true;
|
||||
|
||||
if (reader_is_owned)
|
||||
reader.Close ();
|
||||
|
||||
reader = null;
|
||||
}
|
||||
|
||||
public bool Read ()
|
||||
{
|
||||
if (end_of_input)
|
||||
return false;
|
||||
|
||||
if (end_of_json) {
|
||||
end_of_json = false;
|
||||
automaton_stack.Clear ();
|
||||
automaton_stack.Push ((int) ParserToken.End);
|
||||
automaton_stack.Push ((int) ParserToken.Text);
|
||||
}
|
||||
|
||||
parser_in_string = false;
|
||||
parser_return = false;
|
||||
|
||||
token = JsonToken.None;
|
||||
token_value = null;
|
||||
|
||||
if (! read_started) {
|
||||
read_started = true;
|
||||
|
||||
if (! ReadToken ())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int[] entry_symbols;
|
||||
|
||||
while (true) {
|
||||
if (parser_return) {
|
||||
if (automaton_stack.Peek () == (int) ParserToken.End)
|
||||
end_of_json = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
current_symbol = automaton_stack.Pop ();
|
||||
|
||||
ProcessSymbol ();
|
||||
|
||||
if (current_symbol == current_input) {
|
||||
if (! ReadToken ()) {
|
||||
if (automaton_stack.Peek () != (int) ParserToken.End)
|
||||
throw new JsonException (
|
||||
"Input doesn't evaluate to proper JSON text");
|
||||
|
||||
if (parser_return)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
entry_symbols =
|
||||
parse_table[current_symbol][current_input];
|
||||
|
||||
} catch (KeyNotFoundException e) {
|
||||
throw new JsonException ((ParserToken) current_input, e);
|
||||
}
|
||||
|
||||
if (entry_symbols[0] == (int) ParserToken.Epsilon)
|
||||
continue;
|
||||
|
||||
for (int i = entry_symbols.Length - 1; i >= 0; i--)
|
||||
automaton_stack.Push (entry_symbols[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
462
OpenMetaverse.StructuredData/JSON/JsonWriter.cs
Normal file
462
OpenMetaverse.StructuredData/JSON/JsonWriter.cs
Normal file
@@ -0,0 +1,462 @@
|
||||
#region Header
|
||||
/**
|
||||
* JsonWriter.cs
|
||||
* Stream-like facility to output JSON text.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
internal enum Condition
|
||||
{
|
||||
InArray,
|
||||
InObject,
|
||||
NotAProperty,
|
||||
Property,
|
||||
Value
|
||||
}
|
||||
|
||||
internal class WriterContext
|
||||
{
|
||||
public int Count;
|
||||
public bool InArray;
|
||||
public bool InObject;
|
||||
public bool ExpectingValue;
|
||||
public int Padding;
|
||||
}
|
||||
|
||||
public class JsonWriter
|
||||
{
|
||||
#region Fields
|
||||
private static NumberFormatInfo number_format;
|
||||
|
||||
private WriterContext context;
|
||||
private Stack<WriterContext> ctx_stack;
|
||||
private bool has_reached_end;
|
||||
private char[] hex_seq;
|
||||
private int indentation;
|
||||
private int indent_value;
|
||||
private StringBuilder inst_string_builder;
|
||||
private bool pretty_print;
|
||||
private bool validate;
|
||||
private TextWriter writer;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
public int IndentValue {
|
||||
get { return indent_value; }
|
||||
set {
|
||||
indentation = (indentation / indent_value) * value;
|
||||
indent_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool PrettyPrint {
|
||||
get { return pretty_print; }
|
||||
set { pretty_print = value; }
|
||||
}
|
||||
|
||||
public TextWriter TextWriter {
|
||||
get { return writer; }
|
||||
}
|
||||
|
||||
public bool Validate {
|
||||
get { return validate; }
|
||||
set { validate = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
static JsonWriter ()
|
||||
{
|
||||
number_format = NumberFormatInfo.InvariantInfo;
|
||||
}
|
||||
|
||||
public JsonWriter ()
|
||||
{
|
||||
inst_string_builder = new StringBuilder ();
|
||||
writer = new StringWriter (inst_string_builder);
|
||||
|
||||
Init ();
|
||||
}
|
||||
|
||||
public JsonWriter (StringBuilder sb) :
|
||||
this (new StringWriter (sb))
|
||||
{
|
||||
}
|
||||
|
||||
public JsonWriter (TextWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException ("writer");
|
||||
|
||||
this.writer = writer;
|
||||
|
||||
Init ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
private void DoValidation (Condition cond)
|
||||
{
|
||||
if (! context.ExpectingValue)
|
||||
context.Count++;
|
||||
|
||||
if (! validate)
|
||||
return;
|
||||
|
||||
if (has_reached_end)
|
||||
throw new JsonException (
|
||||
"A complete JSON symbol has already been written");
|
||||
|
||||
switch (cond) {
|
||||
case Condition.InArray:
|
||||
if (! context.InArray)
|
||||
throw new JsonException (
|
||||
"Can't close an array here");
|
||||
break;
|
||||
|
||||
case Condition.InObject:
|
||||
if (! context.InObject || context.ExpectingValue)
|
||||
throw new JsonException (
|
||||
"Can't close an object here");
|
||||
break;
|
||||
|
||||
case Condition.NotAProperty:
|
||||
if (context.InObject && ! context.ExpectingValue)
|
||||
throw new JsonException (
|
||||
"Expected a property");
|
||||
break;
|
||||
|
||||
case Condition.Property:
|
||||
if (! context.InObject || context.ExpectingValue)
|
||||
throw new JsonException (
|
||||
"Can't add a property here");
|
||||
break;
|
||||
|
||||
case Condition.Value:
|
||||
if (! context.InArray &&
|
||||
(! context.InObject || ! context.ExpectingValue))
|
||||
throw new JsonException (
|
||||
"Can't add a value here");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Init ()
|
||||
{
|
||||
has_reached_end = false;
|
||||
hex_seq = new char[4];
|
||||
indentation = 0;
|
||||
indent_value = 4;
|
||||
pretty_print = false;
|
||||
validate = true;
|
||||
|
||||
ctx_stack = new Stack<WriterContext> ();
|
||||
context = new WriterContext ();
|
||||
ctx_stack.Push (context);
|
||||
}
|
||||
|
||||
private static void IntToHex (int n, char[] hex)
|
||||
{
|
||||
int num;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
num = n % 16;
|
||||
|
||||
if (num < 10)
|
||||
hex[3 - i] = (char) ('0' + num);
|
||||
else
|
||||
hex[3 - i] = (char) ('A' + (num - 10));
|
||||
|
||||
n >>= 4;
|
||||
}
|
||||
}
|
||||
|
||||
private void Indent ()
|
||||
{
|
||||
if (pretty_print)
|
||||
indentation += indent_value;
|
||||
}
|
||||
|
||||
|
||||
private void Put (string str)
|
||||
{
|
||||
if (pretty_print && ! context.ExpectingValue)
|
||||
for (int i = 0; i < indentation; i++)
|
||||
writer.Write (' ');
|
||||
|
||||
writer.Write (str);
|
||||
}
|
||||
|
||||
private void PutNewline ()
|
||||
{
|
||||
PutNewline (true);
|
||||
}
|
||||
|
||||
private void PutNewline (bool add_comma)
|
||||
{
|
||||
if (add_comma && ! context.ExpectingValue &&
|
||||
context.Count > 1)
|
||||
writer.Write (',');
|
||||
|
||||
if (pretty_print && ! context.ExpectingValue)
|
||||
writer.Write ('\n');
|
||||
}
|
||||
|
||||
private void PutString (string str)
|
||||
{
|
||||
Put (String.Empty);
|
||||
|
||||
writer.Write ('"');
|
||||
|
||||
int n = str.Length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
switch (str[i]) {
|
||||
case '\n':
|
||||
writer.Write ("\\n");
|
||||
continue;
|
||||
|
||||
case '\r':
|
||||
writer.Write ("\\r");
|
||||
continue;
|
||||
|
||||
case '\t':
|
||||
writer.Write ("\\t");
|
||||
continue;
|
||||
|
||||
case '"':
|
||||
case '\\':
|
||||
writer.Write ('\\');
|
||||
writer.Write (str[i]);
|
||||
continue;
|
||||
|
||||
case '\f':
|
||||
writer.Write ("\\f");
|
||||
continue;
|
||||
|
||||
case '\b':
|
||||
writer.Write ("\\b");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int) str[i] >= 32 && (int) str[i] <= 126) {
|
||||
writer.Write (str[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Default, turn into a \uXXXX sequence
|
||||
IntToHex ((int) str[i], hex_seq);
|
||||
writer.Write ("\\u");
|
||||
writer.Write (hex_seq);
|
||||
}
|
||||
|
||||
writer.Write ('"');
|
||||
}
|
||||
|
||||
private void Unindent ()
|
||||
{
|
||||
if (pretty_print)
|
||||
indentation -= indent_value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
if (inst_string_builder == null)
|
||||
return String.Empty;
|
||||
|
||||
return inst_string_builder.ToString ();
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
has_reached_end = false;
|
||||
|
||||
ctx_stack.Clear ();
|
||||
context = new WriterContext ();
|
||||
ctx_stack.Push (context);
|
||||
|
||||
if (inst_string_builder != null)
|
||||
inst_string_builder.Remove (0, inst_string_builder.Length);
|
||||
}
|
||||
|
||||
public void Write (bool boolean)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
Put (boolean ? "true" : "false");
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (decimal number)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
Put (Convert.ToString (number, number_format));
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (double number)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
string str = Convert.ToString (number, number_format);
|
||||
Put (str);
|
||||
|
||||
if (str.IndexOf ('.') == -1 &&
|
||||
str.IndexOf ('E') == -1)
|
||||
writer.Write (".0");
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (int number)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
Put (Convert.ToString (number, number_format));
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (long number)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
Put (Convert.ToString (number, number_format));
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (string str)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
if (str == null)
|
||||
Put ("null");
|
||||
else
|
||||
PutString (str);
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void Write (ulong number)
|
||||
{
|
||||
DoValidation (Condition.Value);
|
||||
PutNewline ();
|
||||
|
||||
Put (Convert.ToString (number, number_format));
|
||||
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
public void WriteArrayEnd ()
|
||||
{
|
||||
DoValidation (Condition.InArray);
|
||||
PutNewline (false);
|
||||
|
||||
ctx_stack.Pop ();
|
||||
if (ctx_stack.Count == 1)
|
||||
has_reached_end = true;
|
||||
else {
|
||||
context = ctx_stack.Peek ();
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
Unindent ();
|
||||
Put ("]");
|
||||
}
|
||||
|
||||
public void WriteArrayStart ()
|
||||
{
|
||||
DoValidation (Condition.NotAProperty);
|
||||
PutNewline ();
|
||||
|
||||
Put ("[");
|
||||
|
||||
context = new WriterContext ();
|
||||
context.InArray = true;
|
||||
ctx_stack.Push (context);
|
||||
|
||||
Indent ();
|
||||
}
|
||||
|
||||
public void WriteObjectEnd ()
|
||||
{
|
||||
DoValidation (Condition.InObject);
|
||||
PutNewline (false);
|
||||
|
||||
ctx_stack.Pop ();
|
||||
if (ctx_stack.Count == 1)
|
||||
has_reached_end = true;
|
||||
else {
|
||||
context = ctx_stack.Peek ();
|
||||
context.ExpectingValue = false;
|
||||
}
|
||||
|
||||
Unindent ();
|
||||
Put ("}");
|
||||
}
|
||||
|
||||
public void WriteObjectStart ()
|
||||
{
|
||||
DoValidation (Condition.NotAProperty);
|
||||
PutNewline ();
|
||||
|
||||
Put ("{");
|
||||
|
||||
context = new WriterContext ();
|
||||
context.InObject = true;
|
||||
ctx_stack.Push (context);
|
||||
|
||||
Indent ();
|
||||
}
|
||||
|
||||
public void WritePropertyName (string property_name)
|
||||
{
|
||||
DoValidation (Condition.Property);
|
||||
PutNewline ();
|
||||
|
||||
PutString (property_name);
|
||||
|
||||
if (pretty_print) {
|
||||
if (property_name.Length > context.Padding)
|
||||
context.Padding = property_name.Length;
|
||||
|
||||
for (int i = context.Padding - property_name.Length;
|
||||
i >= 0; i--)
|
||||
writer.Write (' ');
|
||||
|
||||
writer.Write (": ");
|
||||
} else
|
||||
writer.Write (':');
|
||||
|
||||
context.ExpectingValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
910
OpenMetaverse.StructuredData/JSON/Lexer.cs
Normal file
910
OpenMetaverse.StructuredData/JSON/Lexer.cs
Normal file
@@ -0,0 +1,910 @@
|
||||
#region Header
|
||||
/**
|
||||
* Lexer.cs
|
||||
* JSON lexer implementation based on a finite state machine.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
internal class FsmContext
|
||||
{
|
||||
public bool Return;
|
||||
public int NextState;
|
||||
public Lexer L;
|
||||
public int StateStack;
|
||||
}
|
||||
|
||||
|
||||
internal class Lexer
|
||||
{
|
||||
#region Fields
|
||||
private delegate bool StateHandler (FsmContext ctx);
|
||||
|
||||
private static int[] fsm_return_table;
|
||||
private static StateHandler[] fsm_handler_table;
|
||||
|
||||
private bool allow_comments;
|
||||
private bool allow_single_quoted_strings;
|
||||
private bool end_of_input;
|
||||
private FsmContext fsm_context;
|
||||
private int input_buffer;
|
||||
private int input_char;
|
||||
private TextReader reader;
|
||||
private int state;
|
||||
private StringBuilder string_buffer;
|
||||
private string string_value;
|
||||
private int token;
|
||||
private int unichar;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
public bool AllowComments {
|
||||
get { return allow_comments; }
|
||||
set { allow_comments = value; }
|
||||
}
|
||||
|
||||
public bool AllowSingleQuotedStrings {
|
||||
get { return allow_single_quoted_strings; }
|
||||
set { allow_single_quoted_strings = value; }
|
||||
}
|
||||
|
||||
public bool EndOfInput {
|
||||
get { return end_of_input; }
|
||||
}
|
||||
|
||||
public int Token {
|
||||
get { return token; }
|
||||
}
|
||||
|
||||
public string StringValue {
|
||||
get { return string_value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
static Lexer ()
|
||||
{
|
||||
PopulateFsmTables ();
|
||||
}
|
||||
|
||||
public Lexer (TextReader reader)
|
||||
{
|
||||
allow_comments = true;
|
||||
allow_single_quoted_strings = true;
|
||||
|
||||
input_buffer = 0;
|
||||
string_buffer = new StringBuilder (128);
|
||||
state = 1;
|
||||
end_of_input = false;
|
||||
this.reader = reader;
|
||||
|
||||
fsm_context = new FsmContext ();
|
||||
fsm_context.L = this;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Static Methods
|
||||
private static int HexValue (int digit)
|
||||
{
|
||||
switch (digit) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
return 10;
|
||||
|
||||
case 'b':
|
||||
case 'B':
|
||||
return 11;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
return 12;
|
||||
|
||||
case 'd':
|
||||
case 'D':
|
||||
return 13;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
return 14;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
return 15;
|
||||
|
||||
default:
|
||||
return digit - '0';
|
||||
}
|
||||
}
|
||||
|
||||
private static void PopulateFsmTables ()
|
||||
{
|
||||
fsm_handler_table = new StateHandler[28] {
|
||||
State1,
|
||||
State2,
|
||||
State3,
|
||||
State4,
|
||||
State5,
|
||||
State6,
|
||||
State7,
|
||||
State8,
|
||||
State9,
|
||||
State10,
|
||||
State11,
|
||||
State12,
|
||||
State13,
|
||||
State14,
|
||||
State15,
|
||||
State16,
|
||||
State17,
|
||||
State18,
|
||||
State19,
|
||||
State20,
|
||||
State21,
|
||||
State22,
|
||||
State23,
|
||||
State24,
|
||||
State25,
|
||||
State26,
|
||||
State27,
|
||||
State28
|
||||
};
|
||||
|
||||
fsm_return_table = new int[28] {
|
||||
(int) ParserToken.Char,
|
||||
0,
|
||||
(int) ParserToken.Number,
|
||||
(int) ParserToken.Number,
|
||||
0,
|
||||
(int) ParserToken.Number,
|
||||
0,
|
||||
(int) ParserToken.Number,
|
||||
0,
|
||||
0,
|
||||
(int) ParserToken.True,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(int) ParserToken.False,
|
||||
0,
|
||||
0,
|
||||
(int) ParserToken.Null,
|
||||
(int) ParserToken.CharSeq,
|
||||
(int) ParserToken.Char,
|
||||
0,
|
||||
0,
|
||||
(int) ParserToken.CharSeq,
|
||||
(int) ParserToken.Char,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
private static char ProcessEscChar (int esc_char)
|
||||
{
|
||||
switch (esc_char) {
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
return Convert.ToChar (esc_char);
|
||||
|
||||
case 'n':
|
||||
return '\n';
|
||||
|
||||
case 't':
|
||||
return '\t';
|
||||
|
||||
case 'r':
|
||||
return '\r';
|
||||
|
||||
case 'b':
|
||||
return '\b';
|
||||
|
||||
case 'f':
|
||||
return '\f';
|
||||
|
||||
default:
|
||||
// Unreachable
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State1 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char == ' ' ||
|
||||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
|
||||
continue;
|
||||
|
||||
if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '"':
|
||||
ctx.NextState = 19;
|
||||
ctx.Return = true;
|
||||
return true;
|
||||
|
||||
case ',':
|
||||
case ':':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
ctx.NextState = 1;
|
||||
ctx.Return = true;
|
||||
return true;
|
||||
|
||||
case '-':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 2;
|
||||
return true;
|
||||
|
||||
case '0':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 4;
|
||||
return true;
|
||||
|
||||
case 'f':
|
||||
ctx.NextState = 12;
|
||||
return true;
|
||||
|
||||
case 'n':
|
||||
ctx.NextState = 16;
|
||||
return true;
|
||||
|
||||
case 't':
|
||||
ctx.NextState = 9;
|
||||
return true;
|
||||
|
||||
case '\'':
|
||||
if (! ctx.L.allow_single_quoted_strings)
|
||||
return false;
|
||||
|
||||
ctx.L.input_char = '"';
|
||||
ctx.NextState = 23;
|
||||
ctx.Return = true;
|
||||
return true;
|
||||
|
||||
case '/':
|
||||
if (! ctx.L.allow_comments)
|
||||
return false;
|
||||
|
||||
ctx.NextState = 25;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State2 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '0':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 4;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State3 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx.L.input_char == ' ' ||
|
||||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case ',':
|
||||
case ']':
|
||||
case '}':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
case '.':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 5;
|
||||
return true;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 7;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State4 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
if (ctx.L.input_char == ' ' ||
|
||||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case ',':
|
||||
case ']':
|
||||
case '}':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
case '.':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 5;
|
||||
return true;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 7;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State5 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 6;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool State6 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx.L.input_char == ' ' ||
|
||||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case ',':
|
||||
case ']':
|
||||
case '}':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 7;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State7 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '+':
|
||||
case '-':
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
ctx.NextState = 8;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State8 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx.L.input_char == ' ' ||
|
||||
ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case ',':
|
||||
case ']':
|
||||
case '}':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State9 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'r':
|
||||
ctx.NextState = 10;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State10 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'u':
|
||||
ctx.NextState = 11;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State11 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'e':
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State12 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'a':
|
||||
ctx.NextState = 13;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State13 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'l':
|
||||
ctx.NextState = 14;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State14 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 's':
|
||||
ctx.NextState = 15;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State15 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'e':
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State16 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'u':
|
||||
ctx.NextState = 17;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State17 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'l':
|
||||
ctx.NextState = 18;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State18 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'l':
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State19 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
switch (ctx.L.input_char) {
|
||||
case '"':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 20;
|
||||
return true;
|
||||
|
||||
case '\\':
|
||||
ctx.StateStack = 19;
|
||||
ctx.NextState = 21;
|
||||
return true;
|
||||
|
||||
default:
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State20 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '"':
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State21 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case 'u':
|
||||
ctx.NextState = 22;
|
||||
return true;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
case '/':
|
||||
case '\\':
|
||||
case 'b':
|
||||
case 'f':
|
||||
case 'n':
|
||||
case 'r':
|
||||
case 't':
|
||||
ctx.L.string_buffer.Append (
|
||||
ProcessEscChar (ctx.L.input_char));
|
||||
ctx.NextState = ctx.StateStack;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State22 (FsmContext ctx)
|
||||
{
|
||||
int counter = 0;
|
||||
int mult = 4096;
|
||||
|
||||
ctx.L.unichar = 0;
|
||||
|
||||
while (ctx.L.GetChar ()) {
|
||||
|
||||
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
|
||||
ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
|
||||
ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
|
||||
|
||||
ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
|
||||
|
||||
counter++;
|
||||
mult /= 16;
|
||||
|
||||
if (counter == 4) {
|
||||
ctx.L.string_buffer.Append (
|
||||
Convert.ToChar (ctx.L.unichar));
|
||||
ctx.NextState = ctx.StateStack;
|
||||
return true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State23 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
switch (ctx.L.input_char) {
|
||||
case '\'':
|
||||
ctx.L.UngetChar ();
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 24;
|
||||
return true;
|
||||
|
||||
case '\\':
|
||||
ctx.StateStack = 23;
|
||||
ctx.NextState = 21;
|
||||
return true;
|
||||
|
||||
default:
|
||||
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State24 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '\'':
|
||||
ctx.L.input_char = '"';
|
||||
ctx.Return = true;
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State25 (FsmContext ctx)
|
||||
{
|
||||
ctx.L.GetChar ();
|
||||
|
||||
switch (ctx.L.input_char) {
|
||||
case '*':
|
||||
ctx.NextState = 27;
|
||||
return true;
|
||||
|
||||
case '/':
|
||||
ctx.NextState = 26;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool State26 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char == '\n') {
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State27 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char == '*') {
|
||||
ctx.NextState = 28;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool State28 (FsmContext ctx)
|
||||
{
|
||||
while (ctx.L.GetChar ()) {
|
||||
if (ctx.L.input_char == '*')
|
||||
continue;
|
||||
|
||||
if (ctx.L.input_char == '/') {
|
||||
ctx.NextState = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
ctx.NextState = 27;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private bool GetChar ()
|
||||
{
|
||||
if ((input_char = NextChar ()) != -1)
|
||||
return true;
|
||||
|
||||
end_of_input = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private int NextChar ()
|
||||
{
|
||||
if (input_buffer != 0) {
|
||||
int tmp = input_buffer;
|
||||
input_buffer = 0;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return reader.Read ();
|
||||
}
|
||||
|
||||
public bool NextToken ()
|
||||
{
|
||||
StateHandler handler;
|
||||
fsm_context.Return = false;
|
||||
|
||||
while (true) {
|
||||
handler = fsm_handler_table[state - 1];
|
||||
|
||||
if (! handler (fsm_context))
|
||||
throw new JsonException (input_char);
|
||||
|
||||
if (end_of_input)
|
||||
return false;
|
||||
|
||||
if (fsm_context.Return) {
|
||||
string_value = string_buffer.ToString ();
|
||||
string_buffer.Remove (0, string_buffer.Length);
|
||||
token = fsm_return_table[state - 1];
|
||||
|
||||
if (token == (int) ParserToken.Char)
|
||||
token = input_char;
|
||||
|
||||
state = fsm_context.NextState;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
state = fsm_context.NextState;
|
||||
}
|
||||
}
|
||||
|
||||
private void UngetChar ()
|
||||
{
|
||||
input_buffer = input_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
OpenMetaverse.StructuredData/JSON/OSDJson.cs
Normal file
128
OpenMetaverse.StructuredData/JSON/OSDJson.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LitJson;
|
||||
|
||||
namespace OpenMetaverse.StructuredData
|
||||
{
|
||||
public static partial class OSDParser
|
||||
{
|
||||
public static OSD DeserializeJson(string json)
|
||||
{
|
||||
return DeserializeJson(JsonMapper.ToObject(json));
|
||||
}
|
||||
|
||||
public static OSD DeserializeJson(JsonData json)
|
||||
{
|
||||
switch (json.GetJsonType())
|
||||
{
|
||||
case JsonType.Boolean:
|
||||
return OSD.FromBoolean((bool)json);
|
||||
case JsonType.Int:
|
||||
return OSD.FromInteger((int)json);
|
||||
case JsonType.Long:
|
||||
return OSD.FromLong((long)json);
|
||||
case JsonType.Double:
|
||||
return OSD.FromReal((double)json);
|
||||
case JsonType.String:
|
||||
string str = (string)json;
|
||||
switch (str[0])
|
||||
{
|
||||
case 'd':
|
||||
if (str.StartsWith("date::"))
|
||||
{
|
||||
DateTime dt;
|
||||
if (DateTime.TryParse(str.Substring(6), out dt))
|
||||
return OSD.FromDate(dt);
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
if (str.StartsWith("uuid::"))
|
||||
{
|
||||
UUID id;
|
||||
if (UUID.TryParse(str.Substring(6), out id))
|
||||
return OSD.FromUUID(id);
|
||||
}
|
||||
else if (str.StartsWith("uri::"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(str.Substring(5));
|
||||
return OSD.FromUri(uri);
|
||||
}
|
||||
catch (UriFormatException) { }
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (str.StartsWith("b64::"))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] data = Convert.FromBase64String(str.Substring(5));
|
||||
return OSD.FromBinary(data);
|
||||
}
|
||||
catch (FormatException) { }
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return OSD.FromString((string)json);
|
||||
case JsonType.Array:
|
||||
OSDArray array = new OSDArray(json.Count);
|
||||
for (int i = 0; i < json.Count; i++)
|
||||
array.Add(DeserializeJson(json[i]));
|
||||
return array;
|
||||
case JsonType.Object:
|
||||
OSDMap map = new OSDMap(json.Count);
|
||||
foreach (KeyValuePair<string, JsonData> kvp in json)
|
||||
map.Add(kvp.Key, DeserializeJson(kvp.Value));
|
||||
return map;
|
||||
case JsonType.None:
|
||||
default:
|
||||
return new OSD();
|
||||
}
|
||||
}
|
||||
|
||||
public static string SerializeJsonString(OSD osd)
|
||||
{
|
||||
return SerializeJson(osd).ToJson();
|
||||
}
|
||||
|
||||
public static JsonData SerializeJson(OSD osd)
|
||||
{
|
||||
switch (osd.Type)
|
||||
{
|
||||
case OSDType.Boolean:
|
||||
return new JsonData(osd.AsBoolean());
|
||||
case OSDType.Integer:
|
||||
return new JsonData(osd.AsInteger());
|
||||
case OSDType.Real:
|
||||
return new JsonData(osd.AsReal());
|
||||
case OSDType.String:
|
||||
return new JsonData(osd.AsString());
|
||||
case OSDType.Date:
|
||||
return new JsonData("date::" + osd.AsString());
|
||||
case OSDType.URI:
|
||||
return new JsonData("uri::" + osd.AsString());
|
||||
case OSDType.UUID:
|
||||
return new JsonData("uuid::" + osd.AsString());
|
||||
case OSDType.Binary:
|
||||
return new JsonData("b64::" + Convert.ToBase64String(osd.AsBinary()));
|
||||
case OSDType.Array:
|
||||
JsonData jsonarray = new JsonData();
|
||||
OSDArray array = (OSDArray)osd;
|
||||
for (int i = 0; i < array.Count; i++)
|
||||
jsonarray.Add(SerializeJson(array[i]));
|
||||
return jsonarray;
|
||||
case OSDType.Map:
|
||||
JsonData jsonmap = new JsonData();
|
||||
OSDMap map = (OSDMap)osd;
|
||||
foreach (KeyValuePair<string, OSD> kvp in map)
|
||||
jsonmap[kvp.Key] = SerializeJson(kvp.Value);
|
||||
return jsonmap;
|
||||
case OSDType.Unknown:
|
||||
default:
|
||||
return new JsonData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
OpenMetaverse.StructuredData/JSON/ParserToken.cs
Normal file
44
OpenMetaverse.StructuredData/JSON/ParserToken.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#region Header
|
||||
/**
|
||||
* ParserToken.cs
|
||||
* Internal representation of the tokens used by the lexer and the parser.
|
||||
*
|
||||
* The authors disclaim copyright to this source code. For more details, see
|
||||
* the COPYING file included with this distribution.
|
||||
**/
|
||||
#endregion
|
||||
|
||||
|
||||
namespace LitJson
|
||||
{
|
||||
internal enum ParserToken
|
||||
{
|
||||
// Lexer tokens
|
||||
None = System.Char.MaxValue + 1,
|
||||
Number,
|
||||
True,
|
||||
False,
|
||||
Null,
|
||||
CharSeq,
|
||||
// Single char
|
||||
Char,
|
||||
|
||||
// Parser Rules
|
||||
Text,
|
||||
Object,
|
||||
ObjectPrime,
|
||||
Pair,
|
||||
PairRest,
|
||||
Array,
|
||||
ArrayPrime,
|
||||
Value,
|
||||
ValueRest,
|
||||
String,
|
||||
|
||||
// End of input
|
||||
End,
|
||||
|
||||
// The empty rule
|
||||
Epsilon
|
||||
}
|
||||
}
|
||||
470
OpenMetaverse.StructuredData/LLSD/BinaryLLSD.cs
Normal file
470
OpenMetaverse.StructuredData/LLSD/BinaryLLSD.cs
Normal file
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* This implementation is based upon the description at
|
||||
*
|
||||
* http://wiki.secondlife.com/wiki/LLSD
|
||||
*
|
||||
* and (partially) tested against the (supposed) reference implementation at
|
||||
*
|
||||
* http://svn.secondlife.com/svn/linden/release/indra/lib/python/indra/base/osd.py
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenMetaverse.StructuredData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static partial class OSDParser
|
||||
{
|
||||
private const int initialBufferSize = 128;
|
||||
private const int int32Length = 4;
|
||||
private const int doubleLength = 8;
|
||||
|
||||
private static byte[] llsdBinaryHead = Encoding.ASCII.GetBytes("<?llsd/binary?>\n");
|
||||
private const byte undefBinaryValue = (byte)'!';
|
||||
private const byte trueBinaryValue = (byte)'1';
|
||||
private const byte falseBinaryValue = (byte)'0';
|
||||
private const byte integerBinaryMarker = (byte)'i';
|
||||
private const byte realBinaryMarker = (byte)'r';
|
||||
private const byte uuidBinaryMarker = (byte)'u';
|
||||
private const byte binaryBinaryMarker = (byte)'b';
|
||||
private const byte stringBinaryMarker = (byte)'s';
|
||||
private const byte uriBinaryMarker = (byte)'l';
|
||||
private const byte dateBinaryMarker = (byte)'d';
|
||||
private const byte arrayBeginBinaryMarker = (byte)'[';
|
||||
private const byte arrayEndBinaryMarker = (byte)']';
|
||||
private const byte mapBeginBinaryMarker = (byte)'{';
|
||||
private const byte mapEndBinaryMarker = (byte)'}';
|
||||
private const byte keyBinaryMarker = (byte)'k';
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="binaryData"></param>
|
||||
/// <returns></returns>
|
||||
public static OSD DeserializeLLSDBinary(byte[] binaryData)
|
||||
{
|
||||
|
||||
MemoryStream stream = new MemoryStream(binaryData);
|
||||
OSD osd = DeserializeLLSDBinary(stream);
|
||||
stream.Close();
|
||||
return osd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static OSD DeserializeLLSDBinary(Stream stream)
|
||||
{
|
||||
if (!stream.CanSeek)
|
||||
throw new OSDException("Cannot deserialize binary LLSD from unseekable streams");
|
||||
|
||||
SkipWhiteSpace(stream);
|
||||
|
||||
bool result = FindByteArray(stream, llsdBinaryHead);
|
||||
if (!result)
|
||||
throw new OSDException("Failed to decode binary LLSD");
|
||||
|
||||
return ParseLLSDBinaryElement(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="osd"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] SerializeLLSDBinary(OSD osd)
|
||||
{
|
||||
MemoryStream stream = SerializeLLSDBinaryStream(osd);
|
||||
byte[] binaryData = stream.ToArray();
|
||||
stream.Close();
|
||||
|
||||
return binaryData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryStream SerializeLLSDBinaryStream(OSD data)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream(initialBufferSize);
|
||||
|
||||
stream.Write(llsdBinaryHead, 0, llsdBinaryHead.Length);
|
||||
SerializeLLSDBinaryElement(stream, data);
|
||||
return stream;
|
||||
}
|
||||
|
||||
private static void SerializeLLSDBinaryElement(MemoryStream stream, OSD osd)
|
||||
{
|
||||
switch (osd.Type)
|
||||
{
|
||||
case OSDType.Unknown:
|
||||
stream.WriteByte(undefBinaryValue);
|
||||
break;
|
||||
case OSDType.Boolean:
|
||||
stream.Write(osd.AsBinary(), 0, 1);
|
||||
break;
|
||||
case OSDType.Integer:
|
||||
stream.WriteByte(integerBinaryMarker);
|
||||
stream.Write(osd.AsBinary(), 0, int32Length);
|
||||
break;
|
||||
case OSDType.Real:
|
||||
stream.WriteByte(realBinaryMarker);
|
||||
stream.Write(osd.AsBinary(), 0, doubleLength);
|
||||
break;
|
||||
case OSDType.UUID:
|
||||
stream.WriteByte(uuidBinaryMarker);
|
||||
stream.Write(osd.AsBinary(), 0, 16);
|
||||
break;
|
||||
case OSDType.String:
|
||||
stream.WriteByte(stringBinaryMarker);
|
||||
byte[] rawString = osd.AsBinary();
|
||||
byte[] stringLengthNetEnd = HostToNetworkIntBytes(rawString.Length);
|
||||
stream.Write(stringLengthNetEnd, 0, int32Length);
|
||||
stream.Write(rawString, 0, rawString.Length);
|
||||
break;
|
||||
case OSDType.Binary:
|
||||
stream.WriteByte(binaryBinaryMarker);
|
||||
byte[] rawBinary = osd.AsBinary();
|
||||
byte[] binaryLengthNetEnd = HostToNetworkIntBytes(rawBinary.Length);
|
||||
stream.Write(binaryLengthNetEnd, 0, int32Length);
|
||||
stream.Write(rawBinary, 0, rawBinary.Length);
|
||||
break;
|
||||
case OSDType.Date:
|
||||
stream.WriteByte(dateBinaryMarker);
|
||||
stream.Write(osd.AsBinary(), 0, doubleLength);
|
||||
break;
|
||||
case OSDType.URI:
|
||||
stream.WriteByte(uriBinaryMarker);
|
||||
byte[] rawURI = osd.AsBinary();
|
||||
byte[] uriLengthNetEnd = HostToNetworkIntBytes(rawURI.Length);
|
||||
stream.Write(uriLengthNetEnd, 0, int32Length);
|
||||
stream.Write(rawURI, 0, rawURI.Length);
|
||||
break;
|
||||
case OSDType.Array:
|
||||
SerializeLLSDBinaryArray(stream, (OSDArray)osd);
|
||||
break;
|
||||
case OSDType.Map:
|
||||
SerializeLLSDBinaryMap(stream, (OSDMap)osd);
|
||||
break;
|
||||
default:
|
||||
throw new OSDException("Binary serialization: Not existing element discovered.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void SerializeLLSDBinaryArray(MemoryStream stream, OSDArray osdArray)
|
||||
{
|
||||
stream.WriteByte(arrayBeginBinaryMarker);
|
||||
byte[] binaryNumElementsHostEnd = HostToNetworkIntBytes(osdArray.Count);
|
||||
stream.Write(binaryNumElementsHostEnd, 0, int32Length);
|
||||
|
||||
foreach (OSD osd in osdArray)
|
||||
{
|
||||
SerializeLLSDBinaryElement(stream, osd);
|
||||
}
|
||||
stream.WriteByte(arrayEndBinaryMarker);
|
||||
}
|
||||
|
||||
private static void SerializeLLSDBinaryMap(MemoryStream stream, OSDMap osdMap)
|
||||
{
|
||||
stream.WriteByte(mapBeginBinaryMarker);
|
||||
byte[] binaryNumElementsNetEnd = HostToNetworkIntBytes(osdMap.Count);
|
||||
stream.Write(binaryNumElementsNetEnd, 0, int32Length);
|
||||
|
||||
foreach (KeyValuePair<string, OSD> kvp in osdMap)
|
||||
{
|
||||
stream.WriteByte(keyBinaryMarker);
|
||||
byte[] binaryKey = Encoding.UTF8.GetBytes(kvp.Key);
|
||||
byte[] binaryKeyLength = HostToNetworkIntBytes(binaryKey.Length);
|
||||
stream.Write(binaryKeyLength, 0, int32Length);
|
||||
stream.Write(binaryKey, 0, binaryKey.Length);
|
||||
SerializeLLSDBinaryElement(stream, kvp.Value);
|
||||
}
|
||||
stream.WriteByte(mapEndBinaryMarker);
|
||||
}
|
||||
|
||||
private static OSD ParseLLSDBinaryElement(Stream stream)
|
||||
{
|
||||
SkipWhiteSpace(stream);
|
||||
OSD osd;
|
||||
|
||||
int marker = stream.ReadByte();
|
||||
if (marker < 0)
|
||||
throw new OSDException("Binary LLSD parsing: Unexpected end of stream.");
|
||||
|
||||
switch ((byte)marker)
|
||||
{
|
||||
case undefBinaryValue:
|
||||
osd = new OSD();
|
||||
break;
|
||||
case trueBinaryValue:
|
||||
osd = OSD.FromBoolean(true);
|
||||
break;
|
||||
case falseBinaryValue:
|
||||
osd = OSD.FromBoolean(false);
|
||||
break;
|
||||
case integerBinaryMarker:
|
||||
int integer = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
osd = OSD.FromInteger(integer);
|
||||
break;
|
||||
case realBinaryMarker:
|
||||
double dbl = NetworkToHostDouble(ConsumeBytes(stream, doubleLength));
|
||||
osd = OSD.FromReal(dbl);
|
||||
break;
|
||||
case uuidBinaryMarker:
|
||||
osd = OSD.FromUUID(new UUID(ConsumeBytes(stream, 16), 0));
|
||||
break;
|
||||
case binaryBinaryMarker:
|
||||
int binaryLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
osd = OSD.FromBinary(ConsumeBytes(stream, binaryLength));
|
||||
break;
|
||||
case stringBinaryMarker:
|
||||
int stringLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
string ss = Encoding.UTF8.GetString(ConsumeBytes(stream, stringLength));
|
||||
osd = OSD.FromString(ss);
|
||||
break;
|
||||
case uriBinaryMarker:
|
||||
int uriLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
string sUri = Encoding.UTF8.GetString(ConsumeBytes(stream, uriLength));
|
||||
Uri uri;
|
||||
try
|
||||
{
|
||||
uri = new Uri(sUri, UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new OSDException("Binary LLSD parsing: Invalid Uri format detected.");
|
||||
}
|
||||
osd = OSD.FromUri(uri);
|
||||
break;
|
||||
case dateBinaryMarker:
|
||||
double timestamp = NetworkToHostDouble(ConsumeBytes(stream, doubleLength));
|
||||
DateTime dateTime = DateTime.SpecifyKind(Utils.Epoch, DateTimeKind.Utc);
|
||||
dateTime = dateTime.AddSeconds(timestamp);
|
||||
osd = OSD.FromDate(dateTime.ToLocalTime());
|
||||
break;
|
||||
case arrayBeginBinaryMarker:
|
||||
osd = ParseLLSDBinaryArray(stream);
|
||||
break;
|
||||
case mapBeginBinaryMarker:
|
||||
osd = ParseLLSDBinaryMap(stream);
|
||||
break;
|
||||
default:
|
||||
throw new OSDException("Binary LLSD parsing: Unknown type marker.");
|
||||
|
||||
}
|
||||
return osd;
|
||||
}
|
||||
|
||||
private static OSD ParseLLSDBinaryArray(Stream stream)
|
||||
{
|
||||
int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
int crrElement = 0;
|
||||
OSDArray osdArray = new OSDArray();
|
||||
while (crrElement < numElements)
|
||||
{
|
||||
osdArray.Add(ParseLLSDBinaryElement(stream));
|
||||
crrElement++;
|
||||
}
|
||||
|
||||
if (!FindByte(stream, arrayEndBinaryMarker))
|
||||
throw new OSDException("Binary LLSD parsing: Missing end marker in array.");
|
||||
|
||||
return (OSD)osdArray;
|
||||
}
|
||||
|
||||
private static OSD ParseLLSDBinaryMap(Stream stream)
|
||||
{
|
||||
int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
int crrElement = 0;
|
||||
OSDMap osdMap = new OSDMap();
|
||||
while (crrElement < numElements)
|
||||
{
|
||||
if (!FindByte(stream, keyBinaryMarker))
|
||||
throw new OSDException("Binary LLSD parsing: Missing key marker in map.");
|
||||
int keyLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
|
||||
string key = Encoding.UTF8.GetString(ConsumeBytes(stream, keyLength));
|
||||
osdMap[key] = ParseLLSDBinaryElement(stream);
|
||||
crrElement++;
|
||||
}
|
||||
|
||||
if (!FindByte(stream, mapEndBinaryMarker))
|
||||
throw new OSDException("Binary LLSD parsing: Missing end marker in map.");
|
||||
|
||||
return (OSD)osdMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public static void SkipWhiteSpace(Stream stream)
|
||||
{
|
||||
int bt;
|
||||
|
||||
while (((bt = stream.ReadByte()) > 0) &&
|
||||
((byte)bt == ' ' || (byte)bt == '\t' ||
|
||||
(byte)bt == '\n' || (byte)bt == '\r')
|
||||
)
|
||||
{
|
||||
}
|
||||
stream.Seek(-1, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="toFind"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FindByte(Stream stream, byte toFind)
|
||||
{
|
||||
int bt = stream.ReadByte();
|
||||
if (bt < 0)
|
||||
return false;
|
||||
if ((byte)bt == toFind)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
stream.Seek(-1L, SeekOrigin.Current);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="toFind"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FindByteArray(Stream stream, byte[] toFind)
|
||||
{
|
||||
int lastIndexToFind = toFind.Length - 1;
|
||||
int crrIndex = 0;
|
||||
bool found = true;
|
||||
int bt;
|
||||
long lastPosition = stream.Position;
|
||||
|
||||
while (found &&
|
||||
((bt = stream.ReadByte()) > 0) &&
|
||||
(crrIndex <= lastIndexToFind)
|
||||
)
|
||||
{
|
||||
if (toFind[crrIndex] == (byte)bt)
|
||||
{
|
||||
found = true;
|
||||
crrIndex++;
|
||||
}
|
||||
else
|
||||
found = false;
|
||||
}
|
||||
|
||||
if (found && crrIndex > lastIndexToFind)
|
||||
{
|
||||
stream.Seek(-1L, SeekOrigin.Current);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Position = lastPosition;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="consumeBytes"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ConsumeBytes(Stream stream, int consumeBytes)
|
||||
{
|
||||
byte[] bytes = new byte[consumeBytes];
|
||||
if (stream.Read(bytes, 0, consumeBytes) < consumeBytes)
|
||||
throw new OSDException("Binary LLSD parsing: Unexpected end of stream.");
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="binaryNetEnd"></param>
|
||||
/// <returns></returns>
|
||||
public static int NetworkToHostInt(byte[] binaryNetEnd)
|
||||
{
|
||||
if (binaryNetEnd == null)
|
||||
return -1;
|
||||
|
||||
int intNetEnd = BitConverter.ToInt32(binaryNetEnd, 0);
|
||||
int intHostEnd = System.Net.IPAddress.NetworkToHostOrder(intNetEnd);
|
||||
return intHostEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="binaryNetEnd"></param>
|
||||
/// <returns></returns>
|
||||
public static double NetworkToHostDouble(byte[] binaryNetEnd)
|
||||
{
|
||||
if (binaryNetEnd == null)
|
||||
return -1d;
|
||||
long longNetEnd = BitConverter.ToInt64(binaryNetEnd, 0);
|
||||
long longHostEnd = System.Net.IPAddress.NetworkToHostOrder(longNetEnd);
|
||||
byte[] binaryHostEnd = BitConverter.GetBytes(longHostEnd);
|
||||
double doubleHostEnd = BitConverter.ToDouble(binaryHostEnd, 0);
|
||||
return doubleHostEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="intHostEnd"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] HostToNetworkIntBytes(int intHostEnd)
|
||||
{
|
||||
int intNetEnd = System.Net.IPAddress.HostToNetworkOrder(intHostEnd);
|
||||
byte[] bytesNetEnd = BitConverter.GetBytes(intNetEnd);
|
||||
return bytesNetEnd;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
774
OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs
Normal file
774
OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenMetaverse.StructuredData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static partial class OSDParser
|
||||
{
|
||||
private const string baseIndent = " ";
|
||||
|
||||
private const char undefNotationValue = '!';
|
||||
|
||||
private const char trueNotationValueOne = '1';
|
||||
private const char trueNotationValueTwo = 't';
|
||||
private static readonly char[] trueNotationValueTwoFull = { 't', 'r', 'u', 'e' };
|
||||
private const char trueNotationValueThree = 'T';
|
||||
private static readonly char[] trueNotationValueThreeFull = { 'T', 'R', 'U', 'E' };
|
||||
|
||||
private const char falseNotationValueOne = '0';
|
||||
private const char falseNotationValueTwo = 'f';
|
||||
private static readonly char[] falseNotationValueTwoFull = { 'f', 'a', 'l', 's', 'e' };
|
||||
private const char falseNotationValueThree = 'F';
|
||||
private static readonly char[] falseNotationValueThreeFull = { 'F', 'A', 'L', 'S', 'E' };
|
||||
|
||||
private const char integerNotationMarker = 'i';
|
||||
private const char realNotationMarker = 'r';
|
||||
private const char uuidNotationMarker = 'u';
|
||||
private const char binaryNotationMarker = 'b';
|
||||
private const char stringNotationMarker = 's';
|
||||
private const char uriNotationMarker = 'l';
|
||||
private const char dateNotationMarker = 'd';
|
||||
|
||||
private const char arrayBeginNotationMarker = '[';
|
||||
private const char arrayEndNotationMarker = ']';
|
||||
|
||||
private const char mapBeginNotationMarker = '{';
|
||||
private const char mapEndNotationMarker = '}';
|
||||
private const char kommaNotationDelimiter = ',';
|
||||
private const char keyNotationDelimiter = ':';
|
||||
|
||||
private const char sizeBeginNotationMarker = '(';
|
||||
private const char sizeEndNotationMarker = ')';
|
||||
private const char doubleQuotesNotationMarker = '"';
|
||||
private const char singleQuotesNotationMarker = '\'';
|
||||
|
||||
public static OSD DeserializeLLSDNotation(string notationData)
|
||||
{
|
||||
StringReader reader = new StringReader(notationData);
|
||||
OSD osd = DeserializeLLSDNotation(reader);
|
||||
reader.Close();
|
||||
return osd;
|
||||
}
|
||||
|
||||
public static OSD DeserializeLLSDNotation(StringReader reader)
|
||||
{
|
||||
OSD osd = DeserializeLLSDNotationElement(reader);
|
||||
return osd;
|
||||
}
|
||||
|
||||
public static string SerializeLLSDNotation(OSD osd)
|
||||
{
|
||||
StringWriter writer = SerializeLLSDNotationStream(osd);
|
||||
string s = writer.ToString();
|
||||
writer.Close();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static StringWriter SerializeLLSDNotationStream(OSD osd)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
SerializeLLSDNotationElement(writer, osd);
|
||||
return writer;
|
||||
}
|
||||
|
||||
public static string SerializeLLSDNotationFormatted(OSD osd)
|
||||
{
|
||||
StringWriter writer = SerializeLLSDNotationStreamFormatted(osd);
|
||||
string s = writer.ToString();
|
||||
writer.Close();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static StringWriter SerializeLLSDNotationStreamFormatted(OSD osd)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
string indent = String.Empty;
|
||||
SerializeLLSDNotationElementFormatted(writer, indent, osd);
|
||||
return writer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
private static OSD DeserializeLLSDNotationElement(StringReader reader)
|
||||
{
|
||||
int character = ReadAndSkipWhitespace(reader);
|
||||
if (character < 0)
|
||||
return new OSD(); // server returned an empty file, so we're going to pass along a null LLSD object
|
||||
|
||||
OSD osd;
|
||||
int matching;
|
||||
switch ((char)character)
|
||||
{
|
||||
case undefNotationValue:
|
||||
osd = new OSD();
|
||||
break;
|
||||
case trueNotationValueOne:
|
||||
osd = OSD.FromBoolean(true);
|
||||
break;
|
||||
case trueNotationValueTwo:
|
||||
matching = BufferCharactersEqual(reader, trueNotationValueTwoFull, 1);
|
||||
if (matching > 1 && matching < trueNotationValueTwoFull.Length)
|
||||
throw new OSDException("Notation LLSD parsing: True value parsing error:");
|
||||
osd = OSD.FromBoolean(true);
|
||||
break;
|
||||
case trueNotationValueThree:
|
||||
matching = BufferCharactersEqual(reader, trueNotationValueThreeFull, 1);
|
||||
if (matching > 1 && matching < trueNotationValueThreeFull.Length)
|
||||
throw new OSDException("Notation LLSD parsing: True value parsing error:");
|
||||
osd = OSD.FromBoolean(true);
|
||||
break;
|
||||
case falseNotationValueOne:
|
||||
osd = OSD.FromBoolean(false);
|
||||
break;
|
||||
case falseNotationValueTwo:
|
||||
matching = BufferCharactersEqual(reader, falseNotationValueTwoFull, 1);
|
||||
if (matching > 1 && matching < falseNotationValueTwoFull.Length)
|
||||
throw new OSDException("Notation LLSD parsing: True value parsing error:");
|
||||
osd = OSD.FromBoolean(false);
|
||||
break;
|
||||
case falseNotationValueThree:
|
||||
matching = BufferCharactersEqual(reader, falseNotationValueThreeFull, 1);
|
||||
if (matching > 1 && matching < falseNotationValueThreeFull.Length)
|
||||
throw new OSDException("Notation LLSD parsing: True value parsing error:");
|
||||
osd = OSD.FromBoolean(false);
|
||||
break;
|
||||
case integerNotationMarker:
|
||||
osd = DeserializeLLSDNotationInteger(reader);
|
||||
break;
|
||||
case realNotationMarker:
|
||||
osd = DeserializeLLSDNotationReal(reader);
|
||||
break;
|
||||
case uuidNotationMarker:
|
||||
char[] uuidBuf = new char[36];
|
||||
if (reader.Read(uuidBuf, 0, 36) < 36)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in UUID.");
|
||||
UUID lluuid;
|
||||
if (!UUID.TryParse(new String(uuidBuf), out lluuid))
|
||||
throw new OSDException("Notation LLSD parsing: Invalid UUID discovered.");
|
||||
osd = OSD.FromUUID(lluuid);
|
||||
break;
|
||||
case binaryNotationMarker:
|
||||
byte[] bytes = new byte[0];
|
||||
int bChar = reader.Peek();
|
||||
if (bChar < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary.");
|
||||
if ((char)bChar == sizeBeginNotationMarker)
|
||||
{
|
||||
throw new OSDException("Notation LLSD parsing: Raw binary encoding not supported.");
|
||||
}
|
||||
else if (Char.IsDigit((char)bChar))
|
||||
{
|
||||
char[] charsBaseEncoding = new char[2];
|
||||
if (reader.Read(charsBaseEncoding, 0, 2) < 2)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary.");
|
||||
int baseEncoding;
|
||||
if (!Int32.TryParse(new String(charsBaseEncoding), out baseEncoding))
|
||||
throw new OSDException("Notation LLSD parsing: Invalid binary encoding base.");
|
||||
if (baseEncoding == 64)
|
||||
{
|
||||
if (reader.Read() < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary.");
|
||||
string bytes64 = GetStringDelimitedBy(reader, doubleQuotesNotationMarker);
|
||||
bytes = Convert.FromBase64String(bytes64);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new OSDException("Notation LLSD parsing: Encoding base" + baseEncoding + " + not supported.");
|
||||
}
|
||||
}
|
||||
osd = OSD.FromBinary(bytes);
|
||||
break;
|
||||
case stringNotationMarker:
|
||||
int numChars = GetLengthInBrackets(reader);
|
||||
if (reader.Read() < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string.");
|
||||
char[] chars = new char[numChars];
|
||||
if (reader.Read(chars, 0, numChars) < numChars)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string.");
|
||||
if (reader.Read() < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string.");
|
||||
osd = OSD.FromString(new String(chars));
|
||||
break;
|
||||
case singleQuotesNotationMarker:
|
||||
string sOne = GetStringDelimitedBy(reader, singleQuotesNotationMarker);
|
||||
osd = OSD.FromString(sOne);
|
||||
break;
|
||||
case doubleQuotesNotationMarker:
|
||||
string sTwo = GetStringDelimitedBy(reader, doubleQuotesNotationMarker);
|
||||
osd = OSD.FromString(sTwo);
|
||||
break;
|
||||
case uriNotationMarker:
|
||||
if (reader.Read() < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string.");
|
||||
string sUri = GetStringDelimitedBy(reader, doubleQuotesNotationMarker);
|
||||
|
||||
Uri uri;
|
||||
try
|
||||
{
|
||||
uri = new Uri(sUri, UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new OSDException("Notation LLSD parsing: Invalid Uri format detected.");
|
||||
}
|
||||
osd = OSD.FromUri(uri);
|
||||
break;
|
||||
case dateNotationMarker:
|
||||
if (reader.Read() < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in date.");
|
||||
string date = GetStringDelimitedBy(reader, doubleQuotesNotationMarker);
|
||||
DateTime dt;
|
||||
if (!DateTime.TryParse(date, out dt))
|
||||
throw new OSDException("Notation LLSD parsing: Invalid date discovered.");
|
||||
osd = OSD.FromDate(dt);
|
||||
break;
|
||||
case arrayBeginNotationMarker:
|
||||
osd = DeserializeLLSDNotationArray(reader);
|
||||
break;
|
||||
case mapBeginNotationMarker:
|
||||
osd = DeserializeLLSDNotationMap(reader);
|
||||
break;
|
||||
default:
|
||||
throw new OSDException("Notation LLSD parsing: Unknown type marker '" + (char)character + "'.");
|
||||
}
|
||||
return osd;
|
||||
}
|
||||
|
||||
private static OSD DeserializeLLSDNotationInteger(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
StringBuilder s = new StringBuilder();
|
||||
if (((character = reader.Peek()) > 0) && ((char)character == '-'))
|
||||
{
|
||||
s.Append((char)character);
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
while ((character = reader.Peek()) > 0 &&
|
||||
Char.IsDigit((char)character))
|
||||
{
|
||||
s.Append((char)character);
|
||||
reader.Read();
|
||||
}
|
||||
int integer;
|
||||
if (!Int32.TryParse(s.ToString(), out integer))
|
||||
throw new OSDException("Notation LLSD parsing: Can't parse integer value." + s.ToString());
|
||||
|
||||
return OSD.FromInteger(integer);
|
||||
}
|
||||
|
||||
private static OSD DeserializeLLSDNotationReal(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
StringBuilder s = new StringBuilder();
|
||||
if (((character = reader.Peek()) > 0) &&
|
||||
((char)character == '-' && (char)character == '+'))
|
||||
{
|
||||
s.Append((char)character);
|
||||
reader.Read();
|
||||
}
|
||||
while (((character = reader.Peek()) > 0) &&
|
||||
(Char.IsDigit((char)character) || (char)character == '.' ||
|
||||
(char)character == 'e' || (char)character == 'E' ||
|
||||
(char)character == '+' || (char)character == '-'))
|
||||
{
|
||||
s.Append((char)character);
|
||||
reader.Read();
|
||||
}
|
||||
double dbl;
|
||||
if (!Utils.TryParseDouble(s.ToString(), out dbl))
|
||||
throw new OSDException("Notation LLSD parsing: Can't parse real value: " + s.ToString());
|
||||
|
||||
return OSD.FromReal(dbl);
|
||||
}
|
||||
|
||||
private static OSD DeserializeLLSDNotationArray(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
OSDArray osdArray = new OSDArray();
|
||||
while (((character = PeekAndSkipWhitespace(reader)) > 0) &&
|
||||
((char)character != arrayEndNotationMarker))
|
||||
{
|
||||
osdArray.Add(DeserializeLLSDNotationElement(reader));
|
||||
|
||||
character = ReadAndSkipWhitespace(reader);
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of array discovered.");
|
||||
else if ((char)character == kommaNotationDelimiter)
|
||||
continue;
|
||||
else if ((char)character == arrayEndNotationMarker)
|
||||
break;
|
||||
}
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of array discovered.");
|
||||
|
||||
return (OSD)osdArray;
|
||||
}
|
||||
|
||||
private static OSD DeserializeLLSDNotationMap(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
OSDMap osdMap = new OSDMap();
|
||||
while (((character = PeekAndSkipWhitespace(reader)) > 0) &&
|
||||
((char)character != mapEndNotationMarker))
|
||||
{
|
||||
OSD osdKey = DeserializeLLSDNotationElement(reader);
|
||||
if (osdKey.Type != OSDType.String)
|
||||
throw new OSDException("Notation LLSD parsing: Invalid key in map");
|
||||
string key = osdKey.AsString();
|
||||
|
||||
character = ReadAndSkipWhitespace(reader);
|
||||
if ((char)character != keyNotationDelimiter)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of stream in map.");
|
||||
if ((char)character != keyNotationDelimiter)
|
||||
throw new OSDException("Notation LLSD parsing: Invalid delimiter in map.");
|
||||
|
||||
osdMap[key] = DeserializeLLSDNotationElement(reader);
|
||||
character = ReadAndSkipWhitespace(reader);
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of map discovered.");
|
||||
else if ((char)character == kommaNotationDelimiter)
|
||||
continue;
|
||||
else if ((char)character == mapEndNotationMarker)
|
||||
break;
|
||||
}
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Unexpected end of map discovered.");
|
||||
|
||||
return (OSD)osdMap;
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationElement(StringWriter writer, OSD osd)
|
||||
{
|
||||
|
||||
switch (osd.Type)
|
||||
{
|
||||
case OSDType.Unknown:
|
||||
writer.Write(undefNotationValue);
|
||||
break;
|
||||
case OSDType.Boolean:
|
||||
if (osd.AsBoolean())
|
||||
writer.Write(trueNotationValueTwo);
|
||||
else
|
||||
writer.Write(falseNotationValueTwo);
|
||||
break;
|
||||
case OSDType.Integer:
|
||||
writer.Write(integerNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.Real:
|
||||
writer.Write(realNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.UUID:
|
||||
writer.Write(uuidNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.String:
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(osd.AsString(), singleQuotesNotationMarker));
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Binary:
|
||||
writer.Write(binaryNotationMarker);
|
||||
writer.Write("64");
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Date:
|
||||
writer.Write(dateNotationMarker);
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.URI:
|
||||
writer.Write(uriNotationMarker);
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(osd.AsString(), doubleQuotesNotationMarker));
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Array:
|
||||
SerializeLLSDNotationArray(writer, (OSDArray)osd);
|
||||
break;
|
||||
case OSDType.Map:
|
||||
SerializeLLSDNotationMap(writer, (OSDMap)osd);
|
||||
break;
|
||||
default:
|
||||
throw new OSDException("Notation serialization: Not existing element discovered.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationArray(StringWriter writer, OSDArray osdArray)
|
||||
{
|
||||
writer.Write(arrayBeginNotationMarker);
|
||||
int lastIndex = osdArray.Count - 1;
|
||||
|
||||
for (int idx = 0; idx <= lastIndex; idx++)
|
||||
{
|
||||
SerializeLLSDNotationElement(writer, osdArray[idx]);
|
||||
if (idx < lastIndex)
|
||||
writer.Write(kommaNotationDelimiter);
|
||||
}
|
||||
writer.Write(arrayEndNotationMarker);
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationMap(StringWriter writer, OSDMap osdMap)
|
||||
{
|
||||
writer.Write(mapBeginNotationMarker);
|
||||
int lastIndex = osdMap.Count - 1;
|
||||
int idx = 0;
|
||||
|
||||
foreach (KeyValuePair<string, OSD> kvp in osdMap)
|
||||
{
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(kvp.Key, singleQuotesNotationMarker));
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(keyNotationDelimiter);
|
||||
SerializeLLSDNotationElement(writer, kvp.Value);
|
||||
if (idx < lastIndex)
|
||||
writer.Write(kommaNotationDelimiter);
|
||||
|
||||
idx++;
|
||||
}
|
||||
writer.Write(mapEndNotationMarker);
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationElementFormatted(StringWriter writer, string indent, OSD osd)
|
||||
{
|
||||
switch (osd.Type)
|
||||
{
|
||||
case OSDType.Unknown:
|
||||
writer.Write(undefNotationValue);
|
||||
break;
|
||||
case OSDType.Boolean:
|
||||
if (osd.AsBoolean())
|
||||
writer.Write(trueNotationValueTwo);
|
||||
else
|
||||
writer.Write(falseNotationValueTwo);
|
||||
break;
|
||||
case OSDType.Integer:
|
||||
writer.Write(integerNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.Real:
|
||||
writer.Write(realNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.UUID:
|
||||
writer.Write(uuidNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
break;
|
||||
case OSDType.String:
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(osd.AsString(), singleQuotesNotationMarker));
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Binary:
|
||||
writer.Write(binaryNotationMarker);
|
||||
writer.Write("64");
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Date:
|
||||
writer.Write(dateNotationMarker);
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(osd.AsString());
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.URI:
|
||||
writer.Write(uriNotationMarker);
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(osd.AsString(), doubleQuotesNotationMarker));
|
||||
writer.Write(doubleQuotesNotationMarker);
|
||||
break;
|
||||
case OSDType.Array:
|
||||
SerializeLLSDNotationArrayFormatted(writer, indent + baseIndent, (OSDArray)osd);
|
||||
break;
|
||||
case OSDType.Map:
|
||||
SerializeLLSDNotationMapFormatted(writer, indent + baseIndent, (OSDMap)osd);
|
||||
break;
|
||||
default:
|
||||
throw new OSDException("Notation serialization: Not existing element discovered.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationArrayFormatted(StringWriter writer, string intend, OSDArray osdArray)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.Write(intend);
|
||||
writer.Write(arrayBeginNotationMarker);
|
||||
int lastIndex = osdArray.Count - 1;
|
||||
|
||||
for (int idx = 0; idx <= lastIndex; idx++)
|
||||
{
|
||||
if (osdArray[idx].Type != OSDType.Array && osdArray[idx].Type != OSDType.Map)
|
||||
writer.WriteLine();
|
||||
writer.Write(intend + baseIndent);
|
||||
SerializeLLSDNotationElementFormatted(writer, intend, osdArray[idx]);
|
||||
if (idx < lastIndex)
|
||||
{
|
||||
writer.Write(kommaNotationDelimiter);
|
||||
}
|
||||
}
|
||||
writer.WriteLine();
|
||||
writer.Write(intend);
|
||||
writer.Write(arrayEndNotationMarker);
|
||||
}
|
||||
|
||||
private static void SerializeLLSDNotationMapFormatted(StringWriter writer, string intend, OSDMap osdMap)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.Write(intend);
|
||||
writer.WriteLine(mapBeginNotationMarker);
|
||||
int lastIndex = osdMap.Count - 1;
|
||||
int idx = 0;
|
||||
|
||||
foreach (KeyValuePair<string, OSD> kvp in osdMap)
|
||||
{
|
||||
writer.Write(intend + baseIndent);
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(EscapeCharacter(kvp.Key, singleQuotesNotationMarker));
|
||||
writer.Write(singleQuotesNotationMarker);
|
||||
writer.Write(keyNotationDelimiter);
|
||||
SerializeLLSDNotationElementFormatted(writer, intend, kvp.Value);
|
||||
if (idx < lastIndex)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.Write(intend + baseIndent);
|
||||
writer.WriteLine(kommaNotationDelimiter);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
writer.WriteLine();
|
||||
writer.Write(intend);
|
||||
writer.Write(mapEndNotationMarker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static int PeekAndSkipWhitespace(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
while ((character = reader.Peek()) > 0)
|
||||
{
|
||||
char c = (char)character;
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
{
|
||||
reader.Read();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static int ReadAndSkipWhitespace(StringReader reader)
|
||||
{
|
||||
int character = PeekAndSkipWhitespace(reader);
|
||||
reader.Read();
|
||||
return character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetLengthInBrackets(StringReader reader)
|
||||
{
|
||||
int character;
|
||||
StringBuilder s = new StringBuilder();
|
||||
if (((character = PeekAndSkipWhitespace(reader)) > 0) &&
|
||||
((char)character == sizeBeginNotationMarker))
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
while (((character = reader.Read()) > 0) &&
|
||||
Char.IsDigit((char)character) &&
|
||||
((char)character != sizeEndNotationMarker))
|
||||
{
|
||||
s.Append((char)character);
|
||||
}
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Can't parse length value cause unexpected end of stream.");
|
||||
int length;
|
||||
if (!Int32.TryParse(s.ToString(), out length))
|
||||
throw new OSDException("Notation LLSD parsing: Can't parse length value.");
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="delimiter"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetStringDelimitedBy(StringReader reader, char delimiter)
|
||||
{
|
||||
int character;
|
||||
bool foundEscape = false;
|
||||
StringBuilder s = new StringBuilder();
|
||||
while (((character = reader.Read()) > 0) &&
|
||||
(((char)character != delimiter) ||
|
||||
((char)character == delimiter && foundEscape)))
|
||||
{
|
||||
|
||||
if (foundEscape)
|
||||
{
|
||||
foundEscape = false;
|
||||
switch ((char)character)
|
||||
{
|
||||
case 'a':
|
||||
s.Append('\a');
|
||||
break;
|
||||
case 'b':
|
||||
s.Append('\b');
|
||||
break;
|
||||
case 'f':
|
||||
s.Append('\f');
|
||||
break;
|
||||
case 'n':
|
||||
s.Append('\n');
|
||||
break;
|
||||
case 'r':
|
||||
s.Append('\r');
|
||||
break;
|
||||
case 't':
|
||||
s.Append('\t');
|
||||
break;
|
||||
case 'v':
|
||||
s.Append('\v');
|
||||
break;
|
||||
default:
|
||||
s.Append((char)character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((char)character == '\\')
|
||||
foundEscape = true;
|
||||
else
|
||||
s.Append((char)character);
|
||||
|
||||
}
|
||||
if (character < 0)
|
||||
throw new OSDException("Notation LLSD parsing: Can't parse text because unexpected end of stream while expecting a '"
|
||||
+ delimiter + "' character.");
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static int BufferCharactersEqual(StringReader reader, char[] buffer, int offset)
|
||||
{
|
||||
|
||||
int character;
|
||||
int lastIndex = buffer.Length - 1;
|
||||
int crrIndex = offset;
|
||||
bool charactersEqual = true;
|
||||
|
||||
while ((character = reader.Peek()) > 0 &&
|
||||
crrIndex <= lastIndex &&
|
||||
charactersEqual)
|
||||
{
|
||||
if (((char)character) != buffer[crrIndex])
|
||||
{
|
||||
charactersEqual = false;
|
||||
break;
|
||||
}
|
||||
crrIndex++;
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
return crrIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="c"></param>
|
||||
/// <returns></returns>
|
||||
public static string UnescapeCharacter(String s, char c)
|
||||
{
|
||||
string oldOne = "\\" + c;
|
||||
string newOne = new String(c, 1);
|
||||
|
||||
String sOne = s.Replace("\\\\", "\\").Replace(oldOne, newOne);
|
||||
return sOne;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="c"></param>
|
||||
/// <returns></returns>
|
||||
public static string EscapeCharacter(String s, char c)
|
||||
{
|
||||
string oldOne = new String(c, 1);
|
||||
string newOne = "\\" + c;
|
||||
|
||||
String sOne = s.Replace("\\", "\\\\").Replace(oldOne, newOne);
|
||||
return sOne;
|
||||
}
|
||||
}
|
||||
}
|
||||
640
OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs
Normal file
640
OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs
Normal file
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenMetaverse.StructuredData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static partial class OSDParser
|
||||
{
|
||||
private static XmlSchema XmlSchema;
|
||||
private static XmlTextReader XmlTextReader;
|
||||
private static string LastXmlErrors = String.Empty;
|
||||
private static object XmlValidationLock = new object();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="xmlData"></param>
|
||||
/// <returns></returns>
|
||||
public static OSD DeserializeLLSDXml(byte[] xmlData)
|
||||
{
|
||||
return DeserializeLLSDXml(new XmlTextReader(new MemoryStream(xmlData, false)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="xmlData"></param>
|
||||
/// <returns></returns>
|
||||
public static OSD DeserializeLLSDXml(string xmlData)
|
||||
{
|
||||
byte[] bytes = Utils.StringToBytes(xmlData);
|
||||
return DeserializeLLSDXml(new XmlTextReader(new MemoryStream(bytes, false)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="xmlData"></param>
|
||||
/// <returns></returns>
|
||||
public static OSD DeserializeLLSDXml(XmlTextReader xmlData)
|
||||
{
|
||||
xmlData.Read();
|
||||
SkipWhitespace(xmlData);
|
||||
|
||||
xmlData.Read();
|
||||
OSD ret = ParseLLSDXmlElement(xmlData);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] SerializeLLSDXmlBytes(OSD data)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(SerializeLLSDXmlString(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static string SerializeLLSDXmlString(OSD data)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
XmlTextWriter writer = new XmlTextWriter(sw);
|
||||
writer.Formatting = Formatting.None;
|
||||
|
||||
writer.WriteStartElement(String.Empty, "llsd", String.Empty);
|
||||
SerializeLLSDXmlElement(writer, data);
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.Close();
|
||||
|
||||
return sw.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="data"></param>
|
||||
public static void SerializeLLSDXmlElement(XmlTextWriter writer, OSD data)
|
||||
{
|
||||
switch (data.Type)
|
||||
{
|
||||
case OSDType.Unknown:
|
||||
writer.WriteStartElement(String.Empty, "undef", String.Empty);
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Boolean:
|
||||
writer.WriteStartElement(String.Empty, "boolean", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Integer:
|
||||
writer.WriteStartElement(String.Empty, "integer", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Real:
|
||||
writer.WriteStartElement(String.Empty, "real", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.String:
|
||||
writer.WriteStartElement(String.Empty, "string", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.UUID:
|
||||
writer.WriteStartElement(String.Empty, "uuid", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Date:
|
||||
writer.WriteStartElement(String.Empty, "date", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.URI:
|
||||
writer.WriteStartElement(String.Empty, "uri", String.Empty);
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Binary:
|
||||
writer.WriteStartElement(String.Empty, "binary", String.Empty);
|
||||
writer.WriteStartAttribute(String.Empty, "encoding", String.Empty);
|
||||
writer.WriteString("base64");
|
||||
writer.WriteEndAttribute();
|
||||
writer.WriteString(data.AsString());
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Map:
|
||||
OSDMap map = (OSDMap)data;
|
||||
writer.WriteStartElement(String.Empty, "map", String.Empty);
|
||||
foreach (KeyValuePair<string, OSD> kvp in map)
|
||||
{
|
||||
writer.WriteStartElement(String.Empty, "key", String.Empty);
|
||||
writer.WriteString(kvp.Key);
|
||||
writer.WriteEndElement();
|
||||
|
||||
SerializeLLSDXmlElement(writer, kvp.Value);
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
case OSDType.Array:
|
||||
OSDArray array = (OSDArray)data;
|
||||
writer.WriteStartElement(String.Empty, "array", String.Empty);
|
||||
for (int i = 0; i < array.Count; i++)
|
||||
{
|
||||
SerializeLLSDXmlElement(writer, array[i]);
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="xmlData"></param>
|
||||
/// <param name="error"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryValidateLLSDXml(XmlTextReader xmlData, out string error)
|
||||
{
|
||||
lock (XmlValidationLock)
|
||||
{
|
||||
LastXmlErrors = String.Empty;
|
||||
XmlTextReader = xmlData;
|
||||
|
||||
CreateLLSDXmlSchema();
|
||||
|
||||
XmlReaderSettings readerSettings = new XmlReaderSettings();
|
||||
readerSettings.ValidationType = ValidationType.Schema;
|
||||
readerSettings.Schemas.Add(XmlSchema);
|
||||
readerSettings.ValidationEventHandler += new ValidationEventHandler(LLSDXmlSchemaValidationHandler);
|
||||
|
||||
XmlReader reader = XmlReader.Create(xmlData, readerSettings);
|
||||
|
||||
try
|
||||
{
|
||||
while (reader.Read()) { }
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
error = LastXmlErrors;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LastXmlErrors == String.Empty)
|
||||
{
|
||||
error = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = LastXmlErrors;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
private static OSD ParseLLSDXmlElement(XmlTextReader reader)
|
||||
{
|
||||
SkipWhitespace(reader);
|
||||
|
||||
if (reader.NodeType != XmlNodeType.Element)
|
||||
throw new OSDException("Expected an element");
|
||||
|
||||
string type = reader.LocalName;
|
||||
OSD ret;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "undef":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return new OSD();
|
||||
}
|
||||
|
||||
reader.Read();
|
||||
SkipWhitespace(reader);
|
||||
ret = new OSD();
|
||||
break;
|
||||
case "boolean":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromBoolean(false);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
string s = reader.ReadString().Trim();
|
||||
|
||||
if (!String.IsNullOrEmpty(s) && (s == "true" || s == "1"))
|
||||
{
|
||||
ret = OSD.FromBoolean(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = OSD.FromBoolean(false);
|
||||
break;
|
||||
case "integer":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromInteger(0);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
int value = 0;
|
||||
Int32.TryParse(reader.ReadString().Trim(), out value);
|
||||
ret = OSD.FromInteger(value);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromInteger(0);
|
||||
break;
|
||||
case "real":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromReal(0d);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
double value = 0d;
|
||||
string str = reader.ReadString().Trim().ToLower();
|
||||
|
||||
if (str == "nan")
|
||||
value = Double.NaN;
|
||||
else
|
||||
Utils.TryParseDouble(str, out value);
|
||||
|
||||
ret = OSD.FromReal(value);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromReal(0d);
|
||||
break;
|
||||
case "uuid":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromUUID(UUID.Zero);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
UUID value = UUID.Zero;
|
||||
UUID.TryParse(reader.ReadString().Trim(), out value);
|
||||
ret = OSD.FromUUID(value);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromUUID(UUID.Zero);
|
||||
break;
|
||||
case "date":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromDate(Utils.Epoch);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
DateTime value = Utils.Epoch;
|
||||
DateTime.TryParse(reader.ReadString().Trim(), out value);
|
||||
ret = OSD.FromDate(value);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromDate(Utils.Epoch);
|
||||
break;
|
||||
case "string":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromString(String.Empty);
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
ret = OSD.FromString(reader.ReadString());
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromString(String.Empty);
|
||||
break;
|
||||
case "binary":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromBinary(new byte[0]);
|
||||
}
|
||||
|
||||
if (reader.GetAttribute("encoding") != null && reader.GetAttribute("encoding") != "base64")
|
||||
throw new OSDException("Unsupported binary encoding: " + reader.GetAttribute("encoding"));
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = OSD.FromBinary(Convert.FromBase64String(reader.ReadString().Trim()));
|
||||
break;
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
throw new OSDException("Binary decoding exception: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
ret = OSD.FromBinary(new byte[0]);
|
||||
break;
|
||||
case "uri":
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return OSD.FromUri(new Uri(String.Empty, UriKind.RelativeOrAbsolute));
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
ret = OSD.FromUri(new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute));
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OSD.FromUri(new Uri(String.Empty, UriKind.RelativeOrAbsolute));
|
||||
break;
|
||||
case "map":
|
||||
return ParseLLSDXmlMap(reader);
|
||||
case "array":
|
||||
return ParseLLSDXmlArray(reader);
|
||||
default:
|
||||
reader.Read();
|
||||
ret = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != type)
|
||||
{
|
||||
throw new OSDException("Expected </" + type + ">");
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private static OSDMap ParseLLSDXmlMap(XmlTextReader reader)
|
||||
{
|
||||
if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map")
|
||||
throw new NotImplementedException("Expected <map>");
|
||||
|
||||
OSDMap map = new OSDMap();
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return map;
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
SkipWhitespace(reader);
|
||||
|
||||
if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "map")
|
||||
{
|
||||
reader.Read();
|
||||
break;
|
||||
}
|
||||
|
||||
if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "key")
|
||||
throw new OSDException("Expected <key>");
|
||||
|
||||
string key = reader.ReadString();
|
||||
|
||||
if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "key")
|
||||
throw new OSDException("Expected </key>");
|
||||
|
||||
if (reader.Read())
|
||||
map[key] = ParseLLSDXmlElement(reader);
|
||||
else
|
||||
throw new OSDException("Failed to parse a value for key " + key);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static OSDArray ParseLLSDXmlArray(XmlTextReader reader)
|
||||
{
|
||||
if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array")
|
||||
throw new OSDException("Expected <array>");
|
||||
|
||||
OSDArray array = new OSDArray();
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return array;
|
||||
}
|
||||
|
||||
if (reader.Read())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
SkipWhitespace(reader);
|
||||
|
||||
if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "array")
|
||||
{
|
||||
reader.Read();
|
||||
break;
|
||||
}
|
||||
|
||||
array.Add(ParseLLSDXmlElement(reader));
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private static void SkipWhitespace(XmlTextReader reader)
|
||||
{
|
||||
while (
|
||||
reader.NodeType == XmlNodeType.Comment ||
|
||||
reader.NodeType == XmlNodeType.Whitespace ||
|
||||
reader.NodeType == XmlNodeType.SignificantWhitespace ||
|
||||
reader.NodeType == XmlNodeType.XmlDeclaration)
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateLLSDXmlSchema()
|
||||
{
|
||||
if (XmlSchema == null)
|
||||
{
|
||||
#region XSD
|
||||
string schemaText = @"
|
||||
<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<xs:schema elementFormDefault=""qualified"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
|
||||
<xs:import schemaLocation=""xml.xsd"" namespace=""http://www.w3.org/XML/1998/namespace"" />
|
||||
<xs:element name=""uri"" type=""xs:string"" />
|
||||
<xs:element name=""uuid"" type=""xs:string"" />
|
||||
<xs:element name=""KEYDATA"">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref=""key"" />
|
||||
<xs:element ref=""DATA"" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""date"" type=""xs:string"" />
|
||||
<xs:element name=""key"" type=""xs:string"" />
|
||||
<xs:element name=""boolean"" type=""xs:string"" />
|
||||
<xs:element name=""undef"">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref=""EMPTY"" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""map"">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs=""0"" maxOccurs=""unbounded"" ref=""KEYDATA"" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""real"" type=""xs:string"" />
|
||||
<xs:element name=""ATOMIC"">
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
<xs:element ref=""undef"" />
|
||||
<xs:element ref=""boolean"" />
|
||||
<xs:element ref=""integer"" />
|
||||
<xs:element ref=""real"" />
|
||||
<xs:element ref=""uuid"" />
|
||||
<xs:element ref=""string"" />
|
||||
<xs:element ref=""date"" />
|
||||
<xs:element ref=""uri"" />
|
||||
<xs:element ref=""binary"" />
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""DATA"">
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
<xs:element ref=""ATOMIC"" />
|
||||
<xs:element ref=""map"" />
|
||||
<xs:element ref=""array"" />
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""llsd"">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref=""DATA"" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""binary"">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base=""xs:string"">
|
||||
<xs:attribute default=""base64"" name=""encoding"" type=""xs:string"" />
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""array"">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs=""0"" maxOccurs=""unbounded"" ref=""DATA"" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name=""integer"" type=""xs:string"" />
|
||||
<xs:element name=""string"">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base=""xs:string"">
|
||||
<xs:attribute ref=""xml:space"" />
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
";
|
||||
#endregion XSD
|
||||
|
||||
MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(schemaText));
|
||||
|
||||
XmlSchema = new XmlSchema();
|
||||
XmlSchema = XmlSchema.Read(stream, new ValidationEventHandler(LLSDXmlSchemaValidationHandler));
|
||||
}
|
||||
}
|
||||
|
||||
private static void LLSDXmlSchemaValidationHandler(object sender, ValidationEventArgs args)
|
||||
{
|
||||
string error = String.Format("Line: {0} - Position: {1} - {2}", XmlTextReader.LineNumber, XmlTextReader.LinePosition,
|
||||
args.Message);
|
||||
|
||||
if (LastXmlErrors == String.Empty)
|
||||
LastXmlErrors = error;
|
||||
else
|
||||
LastXmlErrors += Environment.NewLine + error;
|
||||
}
|
||||
}
|
||||
}
|
||||
919
OpenMetaverse.StructuredData/StructuredData.cs
Normal file
919
OpenMetaverse.StructuredData/StructuredData.cs
Normal file
@@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (c) 2008, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenMetaverse.StructuredData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum OSDType
|
||||
{
|
||||
/// <summary></summary>
|
||||
Unknown,
|
||||
/// <summary></summary>
|
||||
Boolean,
|
||||
/// <summary></summary>
|
||||
Integer,
|
||||
/// <summary></summary>
|
||||
Real,
|
||||
/// <summary></summary>
|
||||
String,
|
||||
/// <summary></summary>
|
||||
UUID,
|
||||
/// <summary></summary>
|
||||
Date,
|
||||
/// <summary></summary>
|
||||
URI,
|
||||
/// <summary></summary>
|
||||
Binary,
|
||||
/// <summary></summary>
|
||||
Map,
|
||||
/// <summary></summary>
|
||||
Array
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDException : Exception
|
||||
{
|
||||
public OSDException(string message) : base(message) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class OSD
|
||||
{
|
||||
public virtual OSDType Type { get { return OSDType.Unknown; } }
|
||||
|
||||
public virtual bool AsBoolean() { return false; }
|
||||
public virtual int AsInteger() { return 0; }
|
||||
public virtual double AsReal() { return 0d; }
|
||||
public virtual string AsString() { return String.Empty; }
|
||||
public virtual UUID AsUUID() { return UUID.Zero; }
|
||||
public virtual DateTime AsDate() { return Utils.Epoch; }
|
||||
public virtual Uri AsUri() { return new Uri(String.Empty); }
|
||||
public virtual byte[] AsBinary() { return new byte[0]; }
|
||||
|
||||
public override string ToString() { return "undef"; }
|
||||
|
||||
public static OSD FromBoolean(bool value) { return new OSDBoolean(value); }
|
||||
public static OSD FromInteger(int value) { return new OSDInteger(value); }
|
||||
public static OSD FromInteger(uint value) { return new OSDInteger((int)value); }
|
||||
public static OSD FromInteger(short value) { return new OSDInteger((int)value); }
|
||||
public static OSD FromInteger(ushort value) { return new OSDInteger((int)value); }
|
||||
public static OSD FromInteger(sbyte value) { return new OSDInteger((int)value); }
|
||||
public static OSD FromInteger(byte value) { return new OSDInteger((int)value); }
|
||||
public static OSD FromUInteger(uint value) { return new OSDBinary(value); }
|
||||
public static OSD FromLong(long value) { return new OSDBinary(value); }
|
||||
public static OSD FromULong(ulong value) { return new OSDBinary(value); }
|
||||
public static OSD FromReal(double value) { return new OSDReal(value); }
|
||||
public static OSD FromReal(float value) { return new OSDReal((double)value); }
|
||||
public static OSD FromString(string value) { return new OSDString(value); }
|
||||
public static OSD FromUUID(UUID value) { return new OSDUUID(value); }
|
||||
public static OSD FromDate(DateTime value) { return new OSDDate(value); }
|
||||
public static OSD FromUri(Uri value) { return new OSDURI(value); }
|
||||
public static OSD FromBinary(byte[] value) { return new OSDBinary(value); }
|
||||
public static OSD FromBinary(long value) { return new OSDBinary(value); }
|
||||
public static OSD FromBinary(ulong value) { return new OSDBinary(value); }
|
||||
|
||||
public static OSD FromVector2(Vector2 value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.X));
|
||||
array.Add(OSD.FromReal(value.Y));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromVector3(Vector3 value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.X));
|
||||
array.Add(OSD.FromReal(value.Y));
|
||||
array.Add(OSD.FromReal(value.Z));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromVector3d(Vector3d value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.X));
|
||||
array.Add(OSD.FromReal(value.Y));
|
||||
array.Add(OSD.FromReal(value.Z));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromVector4(Vector4 value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.X));
|
||||
array.Add(OSD.FromReal(value.Y));
|
||||
array.Add(OSD.FromReal(value.Z));
|
||||
array.Add(OSD.FromReal(value.W));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromQuaternion(Quaternion value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.X));
|
||||
array.Add(OSD.FromReal(value.Y));
|
||||
array.Add(OSD.FromReal(value.Z));
|
||||
array.Add(OSD.FromReal(value.W));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromColor4(Color4 value)
|
||||
{
|
||||
OSDArray array = new OSDArray();
|
||||
array.Add(OSD.FromReal(value.R));
|
||||
array.Add(OSD.FromReal(value.G));
|
||||
array.Add(OSD.FromReal(value.B));
|
||||
array.Add(OSD.FromReal(value.A));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static OSD FromObject(object value)
|
||||
{
|
||||
if (value == null) { return new OSD(); }
|
||||
else if (value is bool) { return new OSDBoolean((bool)value); }
|
||||
else if (value is int) { return new OSDInteger((int)value); }
|
||||
else if (value is uint) { return new OSDBinary((uint)value); }
|
||||
else if (value is short) { return new OSDInteger((int)(short)value); }
|
||||
else if (value is ushort) { return new OSDInteger((int)(ushort)value); }
|
||||
else if (value is sbyte) { return new OSDInteger((int)(sbyte)value); }
|
||||
else if (value is byte) { return new OSDInteger((int)(byte)value); }
|
||||
else if (value is double) { return new OSDReal((double)value); }
|
||||
else if (value is float) { return new OSDReal((double)(float)value); }
|
||||
else if (value is string) { return new OSDString((string)value); }
|
||||
else if (value is UUID) { return new OSDUUID((UUID)value); }
|
||||
else if (value is DateTime) { return new OSDDate((DateTime)value); }
|
||||
else if (value is Uri) { return new OSDURI((Uri)value); }
|
||||
else if (value is byte[]) { return new OSDBinary((byte[])value); }
|
||||
else if (value is long) { return new OSDBinary((long)value); }
|
||||
else if (value is ulong) { return new OSDBinary((ulong)value); }
|
||||
else if (value is Vector2) { return FromVector2((Vector2)value); }
|
||||
else if (value is Vector3) { return FromVector3((Vector3)value); }
|
||||
else if (value is Vector3d) { return FromVector3d((Vector3d)value); }
|
||||
else if (value is Vector4) { return FromVector4((Vector4)value); }
|
||||
else if (value is Quaternion) { return FromQuaternion((Quaternion)value); }
|
||||
else if (value is Color4) { return FromColor4((Color4)value); }
|
||||
else return new OSD();
|
||||
}
|
||||
|
||||
public static object ToObject(Type type, OSD value)
|
||||
{
|
||||
if (type == typeof(ulong))
|
||||
{
|
||||
if (value.Type == OSDType.Binary)
|
||||
{
|
||||
byte[] bytes = value.AsBinary();
|
||||
return Utils.BytesToUInt64(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ulong)value.AsInteger();
|
||||
}
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
if (value.Type == OSDType.Binary)
|
||||
{
|
||||
byte[] bytes = value.AsBinary();
|
||||
return Utils.BytesToUInt(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint)value.AsInteger();
|
||||
}
|
||||
}
|
||||
else if (type == typeof(ushort))
|
||||
{
|
||||
return (ushort)value.AsInteger();
|
||||
}
|
||||
else if (type == typeof(byte))
|
||||
{
|
||||
return (byte)value.AsInteger();
|
||||
}
|
||||
else if (type == typeof(short))
|
||||
{
|
||||
return (short)value.AsInteger();
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
return value.AsString();
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
return value.AsBoolean();
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
return (float)value.AsReal();
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
return value.AsReal();
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
{
|
||||
return value.AsInteger();
|
||||
}
|
||||
else if (type == typeof(UUID))
|
||||
{
|
||||
return value.AsUUID();
|
||||
}
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
if (value.Type == OSDType.Array)
|
||||
return ((OSDArray)value).AsVector3();
|
||||
else
|
||||
return Vector3.Zero;
|
||||
}
|
||||
else if (type == typeof(Vector4))
|
||||
{
|
||||
if (value.Type == OSDType.Array)
|
||||
return ((OSDArray)value).AsVector4();
|
||||
else
|
||||
return Vector4.Zero;
|
||||
}
|
||||
else if (type == typeof(Quaternion))
|
||||
{
|
||||
if (value.Type == OSDType.Array)
|
||||
return ((OSDArray)value).AsQuaternion();
|
||||
else
|
||||
return Quaternion.Identity;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to create an SDMap from all of the SD
|
||||
/// serializable types in an object
|
||||
/// </summary>
|
||||
/// <param name="obj">Class or struct containing serializable types</param>
|
||||
/// <returns>An SDMap holding the serialized values from the
|
||||
/// container object</returns>
|
||||
public static OSDMap SerializeMembers(object obj)
|
||||
{
|
||||
Type t = obj.GetType();
|
||||
FieldInfo[] fields = t.GetFields();
|
||||
|
||||
OSDMap map = new OSDMap(fields.Length);
|
||||
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
FieldInfo field = fields[i];
|
||||
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
|
||||
{
|
||||
OSD serializedField = OSD.FromObject(field.GetValue(obj));
|
||||
|
||||
if (serializedField.Type != OSDType.Unknown || field.FieldType == typeof(string) || field.FieldType == typeof(byte[]))
|
||||
map.Add(field.Name, serializedField);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to deserialize member variables in an object from
|
||||
/// an SDMap
|
||||
/// </summary>
|
||||
/// <param name="obj">Reference to an object to fill with deserialized
|
||||
/// values</param>
|
||||
/// <param name="serialized">Serialized values to put in the target
|
||||
/// object</param>
|
||||
public static void DeserializeMembers(ref object obj, OSDMap serialized)
|
||||
{
|
||||
Type t = obj.GetType();
|
||||
FieldInfo[] fields = t.GetFields();
|
||||
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
FieldInfo field = fields[i];
|
||||
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
|
||||
{
|
||||
OSD serializedField;
|
||||
if (serialized.TryGetValue(field.Name, out serializedField))
|
||||
field.SetValue(obj, ToObject(field.FieldType, serializedField));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDBoolean : OSD
|
||||
{
|
||||
private bool value;
|
||||
|
||||
private static byte[] trueBinary = { 0x31 };
|
||||
private static byte[] falseBinary = { 0x30 };
|
||||
|
||||
public override OSDType Type { get { return OSDType.Boolean; } }
|
||||
|
||||
public OSDBoolean(bool value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return value; }
|
||||
public override int AsInteger() { return value ? 1 : 0; }
|
||||
public override double AsReal() { return value ? 1d : 0d; }
|
||||
public override string AsString() { return value ? "1" : "0"; }
|
||||
public override byte[] AsBinary() { return value ? trueBinary : falseBinary; }
|
||||
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDInteger : OSD
|
||||
{
|
||||
private int value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Integer; } }
|
||||
|
||||
public OSDInteger(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return value != 0; }
|
||||
public override int AsInteger() { return value; }
|
||||
public override double AsReal() { return (double)value; }
|
||||
public override string AsString() { return value.ToString(); }
|
||||
public override byte[] AsBinary() { return Utils.IntToBytes(value); }
|
||||
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDReal : OSD
|
||||
{
|
||||
private double value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Real; } }
|
||||
|
||||
public OSDReal(double value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return (!Double.IsNaN(value) && value != 0d); }
|
||||
public override int AsInteger() {
|
||||
if ( Double.IsNaN( value ) )
|
||||
return 0;
|
||||
if ( value > (double)Int32.MaxValue )
|
||||
return Int32.MaxValue;
|
||||
if ( value < (double)Int32.MinValue )
|
||||
return Int32.MinValue;
|
||||
return (int)Math.Round( value );
|
||||
}
|
||||
|
||||
public override double AsReal() { return value; }
|
||||
public override string AsString() { return value.ToString(Utils.EnUsCulture); }
|
||||
public override byte[] AsBinary() { return Utils.DoubleToBytes(value); }
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDString : OSD
|
||||
{
|
||||
private string value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.String; } }
|
||||
|
||||
public OSDString(string value)
|
||||
{
|
||||
// Refuse to hold null pointers
|
||||
if (value != null)
|
||||
this.value = value;
|
||||
else
|
||||
this.value = String.Empty;
|
||||
}
|
||||
|
||||
public override bool AsBoolean()
|
||||
{
|
||||
if (String.IsNullOrEmpty(value))
|
||||
return false;
|
||||
|
||||
if (value == "0" || value.ToLower() == "false")
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int AsInteger()
|
||||
{
|
||||
double dbl;
|
||||
if (Double.TryParse(value, out dbl))
|
||||
return (int)Math.Floor( dbl );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
public override double AsReal()
|
||||
{
|
||||
double dbl;
|
||||
if (Double.TryParse(value, out dbl))
|
||||
return dbl;
|
||||
else
|
||||
return 0d;
|
||||
}
|
||||
public override string AsString() { return value; }
|
||||
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes( value ); }
|
||||
public override UUID AsUUID()
|
||||
{
|
||||
UUID uuid;
|
||||
if (UUID.TryParse(value, out uuid))
|
||||
return uuid;
|
||||
else
|
||||
return UUID.Zero;
|
||||
}
|
||||
public override DateTime AsDate()
|
||||
{
|
||||
DateTime dt;
|
||||
if (DateTime.TryParse(value, out dt))
|
||||
return dt;
|
||||
else
|
||||
return Utils.Epoch;
|
||||
}
|
||||
public override Uri AsUri() { return new Uri(value); }
|
||||
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDUUID : OSD
|
||||
{
|
||||
private UUID value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.UUID; } }
|
||||
|
||||
public OSDUUID(UUID value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return (value == UUID.Zero) ? false : true; }
|
||||
public override string AsString() { return value.ToString(); }
|
||||
public override UUID AsUUID() { return value; }
|
||||
public override byte[] AsBinary() { return value.GetBytes(); }
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDDate : OSD
|
||||
{
|
||||
private DateTime value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Date; } }
|
||||
|
||||
public OSDDate(DateTime value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string AsString()
|
||||
{
|
||||
string format;
|
||||
if ( value.Millisecond > 0 )
|
||||
format = "yyyy-MM-ddTHH:mm:ss.ffZ";
|
||||
else
|
||||
format = "yyyy-MM-ddTHH:mm:ssZ";
|
||||
return value.ToUniversalTime().ToString( format );
|
||||
}
|
||||
|
||||
public override byte[] AsBinary()
|
||||
{
|
||||
TimeSpan ts = value.ToUniversalTime() - new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
||||
return Utils.DoubleToBytes(ts.TotalSeconds);
|
||||
}
|
||||
|
||||
public override DateTime AsDate() { return value; }
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDURI : OSD
|
||||
{
|
||||
private Uri value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.URI; } }
|
||||
|
||||
public OSDURI(Uri value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string AsString() { return value.ToString(); }
|
||||
public override Uri AsUri() { return value; }
|
||||
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(value.ToString()); }
|
||||
public override string ToString() { return AsString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDBinary : OSD
|
||||
{
|
||||
private byte[] value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Binary; } }
|
||||
|
||||
public OSDBinary(byte[] value)
|
||||
{
|
||||
if (value != null)
|
||||
this.value = value;
|
||||
else
|
||||
this.value = new byte[0];
|
||||
}
|
||||
|
||||
public OSDBinary(uint value)
|
||||
{
|
||||
this.value = Utils.UIntToBytes(value);
|
||||
}
|
||||
|
||||
public OSDBinary(long value)
|
||||
{
|
||||
this.value = Utils.Int64ToBytes(value);
|
||||
}
|
||||
|
||||
public OSDBinary(ulong value)
|
||||
{
|
||||
this.value = Utils.UInt64ToBytes(value);
|
||||
}
|
||||
|
||||
public override string AsString() { return Convert.ToBase64String(value); }
|
||||
public override byte[] AsBinary() { return value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Utils.BytesToHexString(value, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDMap : OSD, IDictionary<string, OSD>
|
||||
{
|
||||
private Dictionary<string, OSD> value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Map; } }
|
||||
|
||||
public OSDMap()
|
||||
{
|
||||
value = new Dictionary<string, OSD>();
|
||||
}
|
||||
|
||||
public OSDMap(int capacity)
|
||||
{
|
||||
value = new Dictionary<string, OSD>(capacity);
|
||||
}
|
||||
|
||||
public OSDMap(Dictionary<string, OSD> value)
|
||||
{
|
||||
if (value != null)
|
||||
this.value = value;
|
||||
else
|
||||
this.value = new Dictionary<string, OSD>();
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return value.Count > 0; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return OSDParser.SerializeLLSDNotationFormatted(this);
|
||||
}
|
||||
|
||||
#region IDictionary Implementation
|
||||
|
||||
public int Count { get { return value.Count; } }
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
public ICollection<string> Keys { get { return value.Keys; } }
|
||||
public ICollection<OSD> Values { get { return value.Values; } }
|
||||
public OSD this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
OSD llsd;
|
||||
if (this.value.TryGetValue(key, out llsd))
|
||||
return llsd;
|
||||
else
|
||||
return new OSD();
|
||||
}
|
||||
set { this.value[key] = value; }
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return value.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void Add(string key, OSD llsd)
|
||||
{
|
||||
value.Add(key, llsd);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, OSD> kvp)
|
||||
{
|
||||
value.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
return value.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out OSD llsd)
|
||||
{
|
||||
return value.TryGetValue(key, out llsd);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
value.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, OSD> kvp)
|
||||
{
|
||||
// This is a bizarre function... we don't really implement it
|
||||
// properly, hopefully no one wants to use it
|
||||
return value.ContainsKey(kvp.Key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, OSD>[] array, int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, OSD> kvp)
|
||||
{
|
||||
return this.value.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
public System.Collections.IDictionaryEnumerator GetEnumerator()
|
||||
{
|
||||
return value.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<string, OSD>> IEnumerable<KeyValuePair<string, OSD>>.GetEnumerator()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return value.GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion IDictionary Implementation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OSDArray : OSD, IList<OSD>
|
||||
{
|
||||
private List<OSD> value;
|
||||
|
||||
public override OSDType Type { get { return OSDType.Array; } }
|
||||
|
||||
public OSDArray()
|
||||
{
|
||||
value = new List<OSD>();
|
||||
}
|
||||
|
||||
public OSDArray(int capacity)
|
||||
{
|
||||
value = new List<OSD>(capacity);
|
||||
}
|
||||
|
||||
public OSDArray(List<OSD> value)
|
||||
{
|
||||
if (value != null)
|
||||
this.value = value;
|
||||
else
|
||||
this.value = new List<OSD>();
|
||||
}
|
||||
|
||||
public Vector2 AsVector2()
|
||||
{
|
||||
Vector2 vector = Vector2.Zero;
|
||||
|
||||
if (this.Count == 2)
|
||||
{
|
||||
vector.X = (float)this[0].AsReal();
|
||||
vector.Y = (float)this[1].AsReal();
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public Vector3 AsVector3()
|
||||
{
|
||||
Vector3 vector = Vector3.Zero;
|
||||
|
||||
if (this.Count == 3)
|
||||
{
|
||||
vector.X = (float)this[0].AsReal();
|
||||
vector.Y = (float)this[1].AsReal();
|
||||
vector.Z = (float)this[2].AsReal();
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public Vector3d AsVector3d()
|
||||
{
|
||||
Vector3d vector = Vector3d.Zero;
|
||||
|
||||
if (this.Count == 3)
|
||||
{
|
||||
vector.X = this[0].AsReal();
|
||||
vector.Y = this[1].AsReal();
|
||||
vector.Z = this[2].AsReal();
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public Vector4 AsVector4()
|
||||
{
|
||||
Vector4 vector = Vector4.Zero;
|
||||
|
||||
if (this.Count == 4)
|
||||
{
|
||||
vector.X = (float)this[0].AsReal();
|
||||
vector.Y = (float)this[1].AsReal();
|
||||
vector.Z = (float)this[2].AsReal();
|
||||
vector.W = (float)this[3].AsReal();
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public Quaternion AsQuaternion()
|
||||
{
|
||||
Quaternion quaternion = Quaternion.Identity;
|
||||
|
||||
if (this.Count == 4)
|
||||
{
|
||||
quaternion.X = (float)this[0].AsReal();
|
||||
quaternion.Y = (float)this[1].AsReal();
|
||||
quaternion.Z = (float)this[2].AsReal();
|
||||
quaternion.W = (float)this[3].AsReal();
|
||||
}
|
||||
|
||||
return quaternion;
|
||||
}
|
||||
|
||||
public Color4 AsColor4()
|
||||
{
|
||||
Color4 color = Color4.Black;
|
||||
|
||||
if (this.Count == 4)
|
||||
{
|
||||
color.R = (float)this[0].AsReal();
|
||||
color.G = (float)this[1].AsReal();
|
||||
color.B = (float)this[2].AsReal();
|
||||
color.A = (float)this[3].AsReal();
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
public override bool AsBoolean() { return value.Count > 0; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return OSDParser.SerializeLLSDNotationFormatted(this);
|
||||
}
|
||||
|
||||
#region IList Implementation
|
||||
|
||||
public int Count { get { return value.Count; } }
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
public OSD this[int index]
|
||||
{
|
||||
get { return value[index]; }
|
||||
set { this.value[index] = value; }
|
||||
}
|
||||
|
||||
public int IndexOf(OSD llsd)
|
||||
{
|
||||
return value.IndexOf(llsd);
|
||||
}
|
||||
|
||||
public void Insert(int index, OSD llsd)
|
||||
{
|
||||
value.Insert(index, llsd);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
value.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void Add(OSD llsd)
|
||||
{
|
||||
value.Add(llsd);
|
||||
}
|
||||
|
||||
public void Add(string str)
|
||||
{
|
||||
// This is so common that we throw a little helper in here
|
||||
value.Add(OSD.FromString(str));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
value.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(OSD llsd)
|
||||
{
|
||||
return value.Contains(llsd);
|
||||
}
|
||||
|
||||
public bool Contains(string element)
|
||||
{
|
||||
for (int i = 0; i < value.Count; i++)
|
||||
{
|
||||
if (value[i].Type == OSDType.String && value[i].AsString() == element)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(OSD[] array, int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(OSD llsd)
|
||||
{
|
||||
return value.Remove(llsd);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return value.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator<OSD> IEnumerable<OSD>.GetEnumerator()
|
||||
{
|
||||
return value.GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion IList Implementation
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user