/*
* Copyright (c) 2006-2016, openmetaverse.co
* Copyright (c) 2021-2025, Sjofn LLC.
* 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.co 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.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace OpenMetaverse.StructuredData
{
public enum OSDType : byte
{
Unknown,
Boolean,
Integer,
Real,
String,
UUID,
Date,
URI,
Binary,
Map,
Array,
LlsdXml
}
public enum OSDFormat
{
Xml = 0,
Json,
Binary
}
///
///
/// OSD Exception
///
[Serializable]
public class OSDException : Exception
{
public OSDException(string message) : base(message) { }
public OSDException() { }
public OSDException(string message, Exception innerException) : base(message, innerException) { }
}
///
/// OSD element base class
///
public partial class OSD
{
public virtual OSDType Type => OSDType.Unknown;
public virtual bool AsBoolean() { return false; }
public virtual int AsInteger() { return 0; }
public virtual uint AsUInteger() { return 0; }
public virtual long AsLong() { return 0; }
public virtual ulong AsULong() { 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 null; }
public virtual byte[] AsBinary() { return Utils.EmptyBytes; }
public virtual Vector2 AsVector2() { return Vector2.Zero; }
public virtual Vector3 AsVector3() { return Vector3.Zero; }
public virtual Vector3d AsVector3d() { return Vector3d.Zero; }
public virtual Vector4 AsVector4() { return Vector4.Zero; }
public virtual Quaternion AsQuaternion() { return Quaternion.Identity; }
public virtual Color4 AsColor4() { return Color4.Black; }
public virtual OSD Copy() { return new OSD(); }
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(value); }
public static OSD FromInteger(ushort value) { return new OSDInteger(value); }
public static OSD FromInteger(sbyte value) { return new OSDInteger(value); }
public static OSD FromInteger(byte value) { return new OSDInteger(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(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 FromVector2(Vector2 value)
{
OSDArray array = new OSDArray
{
FromReal(value.X),
FromReal(value.Y)
};
return array;
}
public static OSD FromVector3(Vector3 value)
{
OSDArray array = new OSDArray
{
FromReal(value.X),
FromReal(value.Y),
FromReal(value.Z)
};
return array;
}
public static OSD FromVector3d(Vector3d value)
{
OSDArray array = new OSDArray
{
FromReal(value.X),
FromReal(value.Y),
FromReal(value.Z)
};
return array;
}
public static OSD FromVector4(Vector4 value)
{
OSDArray array = new OSDArray
{
FromReal(value.X),
FromReal(value.Y),
FromReal(value.Z),
FromReal(value.W)
};
return array;
}
public static OSD FromQuaternion(Quaternion value)
{
OSDArray array = new OSDArray
{
FromReal(value.X),
FromReal(value.Y),
FromReal(value.Z),
FromReal(value.W)
};
return array;
}
public static OSD FromColor4(Color4 value)
{
OSDArray array = new OSDArray
{
FromReal(value.R),
FromReal(value.G),
FromReal(value.B),
FromReal(value.A)
};
return array;
}
public static OSD FromObject(object value)
{
switch (value)
{
case null:
return new OSD();
case bool b:
return new OSDBoolean(b);
case int i:
return new OSDInteger(i);
case uint u:
return new OSDBinary(u);
case short s:
return new OSDInteger(s);
case ushort us:
return new OSDInteger(us);
case sbyte sb:
return new OSDInteger(sb);
case byte by:
return new OSDInteger(by);
case double d:
return new OSDReal(d);
case float f:
return new OSDReal(f);
case string str:
return new OSDString(str);
case UUID uuid:
return new OSDUUID(uuid);
case DateTime time:
return new OSDDate(time);
case Uri uri:
return new OSDUri(uri);
case byte[] bytes:
return new OSDBinary(bytes);
case long l:
return new OSDBinary(l);
case ulong ul:
return new OSDBinary(ul);
case Vector2 vector2:
return FromVector2(vector2);
case Vector3 vector3:
return FromVector3(vector3);
case Vector3d vector3D:
return FromVector3d(vector3D);
case Vector4 vector4:
return FromVector4(vector4);
case Quaternion quaternion:
return FromQuaternion(quaternion);
case Color4 color4:
return FromColor4(color4);
}
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);
}
return (ulong)value.AsInteger();
}
if (type == typeof(uint))
{
if (value.Type == OSDType.Binary)
{
byte[] bytes = value.AsBinary();
return Utils.BytesToUInt(bytes);
}
return (uint)value.AsInteger();
}
if (type == typeof(ushort))
{
return (ushort)value.AsInteger();
}
if (type == typeof(byte))
{
return (byte)value.AsInteger();
}
if (type == typeof(short))
{
return (short)value.AsInteger();
}
if (type == typeof(string))
{
return value.AsString();
}
if (type == typeof(bool))
{
return value.AsBoolean();
}
if (type == typeof(float))
{
return (float)value.AsReal();
}
if (type == typeof(double))
{
return value.AsReal();
}
if (type == typeof(int))
{
return value.AsInteger();
}
if (type == typeof(UUID))
{
return value.AsUUID();
}
if (type == typeof(Vector3))
{
return value.Type == OSDType.Array ? ((OSDArray)value).AsVector3() : Vector3.Zero;
}
if (type == typeof(Vector4))
{
return value.Type == OSDType.Array ? ((OSDArray)value).AsVector4() : Vector4.Zero;
}
if (type == typeof(Quaternion))
{
return value.Type == OSDType.Array ? ((OSDArray)value).AsQuaternion() : Quaternion.Identity;
}
if (type == typeof(OSDArray))
{
OSDArray newArray = new OSDArray();
foreach (OSD o in (OSDArray)value)
newArray.Add(o);
return newArray;
}
if (type == typeof(OSDMap))
{
OSDMap newMap = new OSDMap();
foreach (KeyValuePair o in (OSDMap)value)
newMap.Add(o);
return newMap;
}
return null;
}
#region Implicit Conversions
public static implicit operator OSD(bool value) { return new OSDBoolean(value); }
public static implicit operator OSD(int value) { return new OSDInteger(value); }
public static implicit operator OSD(uint value) { return new OSDInteger((int)value); }
public static implicit operator OSD(short value) { return new OSDInteger(value); }
public static implicit operator OSD(ushort value) { return new OSDInteger(value); }
public static implicit operator OSD(sbyte value) { return new OSDInteger(value); }
public static implicit operator OSD(byte value) { return new OSDInteger(value); }
public static implicit operator OSD(long value) { return new OSDBinary(value); }
public static implicit operator OSD(ulong value) { return new OSDBinary(value); }
public static implicit operator OSD(double value) { return new OSDReal(value); }
public static implicit operator OSD(float value) { return new OSDReal(value); }
public static implicit operator OSD(string value) { return new OSDString(value); }
public static implicit operator OSD(UUID value) { return new OSDUUID(value); }
public static implicit operator OSD(DateTime value) { return new OSDDate(value); }
public static implicit operator OSD(Uri value) { return new OSDUri(value); }
public static implicit operator OSD(byte[] value) { return new OSDBinary(value); }
public static implicit operator OSD(Vector2 value) { return FromVector2(value); }
public static implicit operator OSD(Vector3 value) { return FromVector3(value); }
public static implicit operator OSD(Vector3d value) { return FromVector3d(value); }
public static implicit operator OSD(Vector4 value) { return FromVector4(value); }
public static implicit operator OSD(Quaternion value) { return FromQuaternion(value); }
public static implicit operator OSD(Color4 value) { return FromColor4(value); }
public static implicit operator bool(OSD value) { return value.AsBoolean(); }
public static implicit operator int(OSD value) { return value.AsInteger(); }
public static implicit operator uint(OSD value) { return value.AsUInteger(); }
public static implicit operator long(OSD value) { return value.AsLong(); }
public static implicit operator ulong(OSD value) { return value.AsULong(); }
public static implicit operator double(OSD value) { return value.AsReal(); }
public static implicit operator float(OSD value) { return (float)value.AsReal(); }
public static implicit operator string(OSD value) { return value.AsString(); }
public static implicit operator UUID(OSD value) { return value.AsUUID(); }
public static implicit operator DateTime(OSD value) { return value.AsDate(); }
public static implicit operator Uri(OSD value) { return value.AsUri(); }
public static implicit operator byte[](OSD value) { return value.AsBinary(); }
public static implicit operator Vector2(OSD value) { return value.AsVector2(); }
public static implicit operator Vector3(OSD value) { return value.AsVector3(); }
public static implicit operator Vector3d(OSD value) { return value.AsVector3d(); }
public static implicit operator Vector4(OSD value) { return value.AsVector4(); }
public static implicit operator Quaternion(OSD value) { return value.AsQuaternion(); }
public static implicit operator Color4(OSD value) { return value.AsColor4(); }
#endregion Implicit Conversions
///
/// Uses reflection to create an SDMap from all SD
/// serializable types in an object
///
/// Class or struct containing serializable types
/// An SDMap holding the serialized values from the
/// container object
public static OSDMap SerializeMembers(object obj)
{
Type t = obj.GetType();
FieldInfo[] fields = t.GetFields();
OSDMap map = new OSDMap(fields.Length);
foreach (FieldInfo field in fields)
{
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
{
OSD serializedField = FromObject(field.GetValue(obj));
if (serializedField.Type != OSDType.Unknown
|| field.FieldType == typeof(string)
|| field.FieldType == typeof(byte[]))
{
map.Add(field.Name, serializedField);
}
}
}
return map;
}
///
/// Uses reflection to deserialize member variables in an object from
/// an SDMap
///
/// Reference to an object to fill with deserialized
/// values
/// Serialized values to put in the target
/// object
public static void DeserializeMembers(ref object obj, OSDMap serialized)
{
Type t = obj.GetType();
FieldInfo[] fields = t.GetFields();
foreach (FieldInfo field in fields)
{
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
{
if (serialized.TryGetValue(field.Name, out var serializedField))
field.SetValue(obj, ToObject(field.FieldType, serializedField));
}
}
}
}
///
/// OSD Boolean Element
///
public sealed class OSDBoolean : OSD
{
private readonly bool _mBool;
private static readonly byte[] TrueBinary = { 0x31 };
private static readonly byte[] FalseBinary = { 0x30 };
public override OSDType Type => OSDType.Boolean;
public OSDBoolean(bool value)
{
this._mBool = value;
}
public override bool AsBoolean() { return _mBool; }
public override int AsInteger() { return _mBool ? 1 : 0; }
public override double AsReal() { return _mBool ? 1d : 0d; }
public override string AsString() { return _mBool ? "1" : "0"; }
public override byte[] AsBinary() { return _mBool ? TrueBinary : FalseBinary; }
public override OSD Copy() { return new OSDBoolean(_mBool); }
public override string ToString() { return AsString(); }
}
///
/// OSD Integer Element
///
public sealed class OSDInteger : OSD
{
private readonly int _mInt;
public override OSDType Type => OSDType.Integer;
public OSDInteger(int value)
{
this._mInt = value;
}
public override bool AsBoolean() { return _mInt != 0; }
public override int AsInteger() { return _mInt; }
public override uint AsUInteger() { return (uint)_mInt; }
public override long AsLong() { return _mInt; }
public override ulong AsULong() { return (ulong)_mInt; }
public override double AsReal() { return _mInt; }
public override string AsString() { return _mInt.ToString(); }
public override byte[] AsBinary() { return Utils.IntToBytesBig(_mInt); }
public override OSD Copy() { return new OSDInteger(_mInt); }
public override string ToString() { return AsString(); }
}
///
/// OSD Floating point Element
///
public sealed class OSDReal : OSD
{
private readonly double _mReal;
public override OSDType Type => OSDType.Real;
public OSDReal(double value)
{
this._mReal = value;
}
public override bool AsBoolean() { return (!double.IsNaN(_mReal) && _mReal != 0d); }
public override OSD Copy() { return new OSDReal(_mReal); }
public override int AsInteger()
{
if (double.IsNaN(_mReal))
return 0;
if (_mReal > int.MaxValue)
return int.MaxValue;
if (_mReal < int.MinValue)
return int.MinValue;
return (int)Math.Round(_mReal);
}
public override uint AsUInteger()
{
if (double.IsNaN(_mReal))
return 0;
if (_mReal > uint.MaxValue)
return uint.MaxValue;
if (_mReal < uint.MinValue)
return uint.MinValue;
return (uint)Math.Round(_mReal);
}
public override long AsLong()
{
if (double.IsNaN(_mReal))
return 0;
if (_mReal > long.MaxValue)
return long.MaxValue;
if (_mReal < long.MinValue)
return long.MinValue;
return (long)Math.Round(_mReal);
}
public override ulong AsULong()
{
if (double.IsNaN(_mReal))
return 0;
if (_mReal > ulong.MaxValue)
return int.MaxValue;
if (_mReal < ulong.MinValue)
return ulong.MinValue;
return (ulong)Math.Round(_mReal);
}
public override double AsReal() { return _mReal; }
// "r" ensures the dt will correctly round-trip back through Double.TryParse
public override string AsString() { return _mReal.ToString("r", Utils.EnUsCulture); }
public override byte[] AsBinary() { return Utils.DoubleToBytesBig(_mReal); }
public override string ToString() { return AsString(); }
}
///
/// OSD LLSD-XML Element
///
public sealed class OSDLlsdXml : OSD
{
public readonly string value;
public override OSDType Type => OSDType.LlsdXml;
public override OSD Copy() { return new OSDLlsdXml(value); }
public OSDLlsdXml(string value)
{
// Refuse to hold null pointers
this.value = value ?? string.Empty;
}
public override string AsString() { return value; }
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(value); }
public override string ToString() { return AsString(); }
}
///
/// OSD String Element
///
public sealed class OSDString : OSD
{
private readonly string _mString;
public override OSDType Type => OSDType.String;
public override OSD Copy() { return new OSDString(_mString); }
public OSDString(string value)
{
// Refuse to hold null pointers
this._mString = value ?? string.Empty;
}
public override bool AsBoolean()
{
if (string.IsNullOrEmpty(_mString))
return false;
return _mString != "0" && !string.Equals(_mString, "false", StringComparison.OrdinalIgnoreCase);
}
public override int AsInteger()
{
if (double.TryParse(_mString, out var dbl))
return (int)Math.Floor(dbl);
return 0;
}
public override uint AsUInteger()
{
if (double.TryParse(_mString, out var dbl))
return (uint)Math.Floor(dbl);
return 0;
}
public override long AsLong()
{
if (double.TryParse(_mString, out var dbl))
return (long)Math.Floor(dbl);
return 0;
}
public override ulong AsULong()
{
if (double.TryParse(_mString, out var dbl))
return (ulong)Math.Floor(dbl);
return 0;
}
public override double AsReal()
{
return double.TryParse(_mString, out var dbl) ? dbl : 0d;
}
public override string AsString() { return _mString; }
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(_mString); }
public override UUID AsUUID()
{
return UUID.TryParse(_mString, out var uuid) ? uuid : UUID.Zero;
}
public override DateTime AsDate()
{
return DateTime.TryParse(_mString, out var dt) ? dt : Utils.Epoch;
}
public override Uri AsUri()
{
return Uri.TryCreate(_mString, UriKind.RelativeOrAbsolute, out var uri) ? uri : null;
}
public override string ToString() { return AsString(); }
}
///
/// OSD UUID Element
///
public sealed class OSDUUID : OSD
{
private UUID _id;
public override OSDType Type => OSDType.UUID;
public OSDUUID(UUID value)
{
_id = value;
}
public override OSD Copy() { return new OSDUUID(_id); }
public override bool AsBoolean() { return (_id != UUID.Zero); }
public override string AsString() { return _id.ToString(); }
public override UUID AsUUID() { return _id; }
public override byte[] AsBinary() { return _id.GetBytes(); }
public override string ToString() { return AsString(); }
}
///
/// OSD DateTime Element
///
public sealed class OSDDate : OSD
{
private DateTime _dateTime;
public override OSDType Type => OSDType.Date;
public OSDDate(DateTime dt)
{
_dateTime = dt;
}
public override string AsString()
{
var format = _dateTime.Millisecond > 0 ? "yyyy-MM-ddTHH:mm:ss.ffZ" : "yyyy-MM-ddTHH:mm:ssZ";
return _dateTime.ToUniversalTime().ToString(format);
}
public override int AsInteger()
{
return (int)Utils.DateTimeToUnixTime(_dateTime);
}
public override uint AsUInteger()
{
return Utils.DateTimeToUnixTime(_dateTime);
}
public override long AsLong()
{
return Utils.DateTimeToUnixTime(_dateTime);
}
public override ulong AsULong()
{
return Utils.DateTimeToUnixTime(_dateTime);
}
public override byte[] AsBinary()
{
TimeSpan ts = _dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return Utils.DoubleToBytes(ts.TotalSeconds);
}
public override OSD Copy() { return new OSDDate(_dateTime); }
public override DateTime AsDate() { return _dateTime; }
public override string ToString() { return AsString(); }
}
///
/// OSD Uri Element
///
public sealed class OSDUri : OSD
{
private readonly Uri _mUri;
public override OSDType Type => OSDType.URI;
public OSDUri(Uri uri)
{
_mUri = uri;
}
public override string AsString()
{
if (_mUri == null) return string.Empty;
return _mUri.IsAbsoluteUri ? _mUri.AbsoluteUri : _mUri.ToString();
}
public override OSD Copy() { return new OSDUri(_mUri); }
public override Uri AsUri() { return _mUri; }
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(AsString()); }
public override string ToString() { return AsString(); }
}
///
/// OSD Binary Element
///
public sealed class OSDBinary : OSD
{
private readonly byte[] _mBytes;
public override OSDType Type => OSDType.Binary;
public OSDBinary(byte[] value)
{
this._mBytes = value ?? Utils.EmptyBytes;
}
public OSDBinary(uint value)
{
this._mBytes = new[]
{
(byte)((value >> 24) % 256),
(byte)((value >> 16) % 256),
(byte)((value >> 8) % 256),
(byte)(value % 256)
};
}
public OSDBinary(long value)
{
this._mBytes = new[]
{
(byte)((value >> 56) % 256),
(byte)((value >> 48) % 256),
(byte)((value >> 40) % 256),
(byte)((value >> 32) % 256),
(byte)((value >> 24) % 256),
(byte)((value >> 16) % 256),
(byte)((value >> 8) % 256),
(byte)(value % 256)
};
}
public OSDBinary(ulong value)
{
this._mBytes = new[]
{
(byte)((value >> 56) % 256),
(byte)((value >> 48) % 256),
(byte)((value >> 40) % 256),
(byte)((value >> 32) % 256),
(byte)((value >> 24) % 256),
(byte)((value >> 16) % 256),
(byte)((value >> 8) % 256),
(byte)(value % 256)
};
}
public override OSD Copy() { return new OSDBinary(_mBytes); }
public override string AsString() { return Convert.ToBase64String(_mBytes); }
public override byte[] AsBinary() { return _mBytes; }
public override uint AsUInteger()
{
return (uint)(
(_mBytes[0] << 24) +
(_mBytes[1] << 16) +
(_mBytes[2] << 8) +
(_mBytes[3] << 0));
}
public override long AsLong()
{
return ((long)_mBytes[0] << 56) +
((long)_mBytes[1] << 48) +
((long)_mBytes[2] << 40) +
((long)_mBytes[3] << 32) +
((long)_mBytes[4] << 24) +
((long)_mBytes[5] << 16) +
((long)_mBytes[6] << 8) +
((long)_mBytes[7] << 0);
}
public override ulong AsULong()
{
return ((ulong)_mBytes[0] << 56) +
((ulong)_mBytes[1] << 48) +
((ulong)_mBytes[2] << 40) +
((ulong)_mBytes[3] << 32) +
((ulong)_mBytes[4] << 24) +
((ulong)_mBytes[5] << 16) +
((ulong)_mBytes[6] << 8) +
((ulong)_mBytes[7] << 0);
}
public override string ToString()
{
return Utils.BytesToHexString(_mBytes, null);
}
}
///
/// OSD Map Element
///
public sealed class OSDMap : OSD, IDictionary
{
private readonly Dictionary _mMap;
public override OSDType Type => OSDType.Map;
public OSDMap()
{
_mMap = new Dictionary();
}
public OSDMap(int capacity)
{
_mMap = new Dictionary(capacity);
}
public OSDMap(Dictionary value)
{
this._mMap = value ?? new Dictionary();
}
public override bool AsBoolean() { return _mMap.Count > 0; }
public override string ToString()
{
return OSDParser.SerializeJsonString(this, true);
}
public override OSD Copy()
{
return new OSDMap(new Dictionary(_mMap));
}
public Hashtable ToHashtable()
{
return new Hashtable(_mMap);
}
#region IDictionary Implementation
public int Count => _mMap.Count;
public bool IsReadOnly => false;
public ICollection Keys => _mMap.Keys;
public ICollection Values => _mMap.Values;
public OSD this[string key]
{
get => _mMap.TryGetValue(key, out var llsd) ? llsd : new OSD();
set => _mMap[key] = value;
}
public bool ContainsKey(string key)
{
return _mMap.ContainsKey(key);
}
public void Add(string key, OSD llsd)
{
_mMap.Add(key, llsd);
}
public void Add(KeyValuePair kvp)
{
_mMap.Add(kvp.Key, kvp.Value);
}
public bool Remove(string key)
{
return _mMap.Remove(key);
}
public bool TryGetValue(string key, out OSD llsd)
{
return _mMap.TryGetValue(key, out llsd);
}
public void Clear()
{
_mMap.Clear();
}
public bool Contains(KeyValuePair kvp)
{
return _mMap.Contains(kvp);
}
public void CopyTo(KeyValuePair[] array, int index)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair kvp)
{
return _mMap.Remove(kvp.Key);
}
public IDictionaryEnumerator GetEnumerator()
{
return _mMap.GetEnumerator();
}
IEnumerator> IEnumerable>.GetEnumerator()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator()
{
return _mMap.GetEnumerator();
}
#endregion IDictionary Implementation
}
///
/// OSD Array Element
///
public sealed class OSDArray : OSD, IList
{
private readonly List _mArray;
public override OSDType Type => OSDType.Array;
public OSDArray()
{
_mArray = new List();
}
public OSDArray(int capacity)
{
_mArray = new List(capacity);
}
public OSDArray(List value)
{
this._mArray = value ?? new List();
}
public override byte[] AsBinary()
{
byte[] binary = new byte[_mArray.Count];
for (int i = 0; i < _mArray.Count; i++)
binary[i] = (byte)_mArray[i].AsInteger();
return binary;
}
public override long AsLong()
{
OSDBinary binary = new OSDBinary(AsBinary());
return binary.AsLong();
}
public override ulong AsULong()
{
OSDBinary binary = new OSDBinary(AsBinary());
return binary.AsULong();
}
public override uint AsUInteger()
{
OSDBinary binary = new OSDBinary(AsBinary());
return binary.AsUInteger();
}
public override Vector2 AsVector2()
{
Vector2 vector = Vector2.Zero;
if (Count == 2)
{
vector.X = (float)this[0].AsReal();
vector.Y = (float)this[1].AsReal();
}
return vector;
}
public override Vector3 AsVector3()
{
Vector3 vector = Vector3.Zero;
if (Count == 3)
{
vector.X = (float)this[0].AsReal();
vector.Y = (float)this[1].AsReal();
vector.Z = (float)this[2].AsReal();
}
return vector;
}
public override Vector3d AsVector3d()
{
Vector3d vector = Vector3d.Zero;
if (Count == 3)
{
vector.X = this[0].AsReal();
vector.Y = this[1].AsReal();
vector.Z = this[2].AsReal();
}
return vector;
}
public override Vector4 AsVector4()
{
Vector4 vector = Vector4.Zero;
if (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 override Quaternion AsQuaternion()
{
Quaternion quaternion = Quaternion.Identity;
if (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 override Color4 AsColor4()
{
Color4 color = Color4.Black;
if (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 OSD Copy()
{
return new OSDArray(new List(_mArray));
}
public override bool AsBoolean() { return _mArray.Count > 0; }
public override string ToString()
{
return OSDParser.SerializeJsonString(this, true);
}
public ArrayList ToArrayList()
{
return new ArrayList(_mArray);
}
#region IList Implementation
public int Count => _mArray.Count;
public bool IsReadOnly => false;
public OSD this[int index]
{
get => _mArray[index];
set => _mArray[index] = value;
}
public int IndexOf(OSD item)
{
return _mArray.IndexOf(item);
}
public void Insert(int index, OSD item)
{
_mArray.Insert(index, item);
}
public void RemoveAt(int index)
{
_mArray.RemoveAt(index);
}
public void Add(OSD llsd)
{
_mArray.Add(llsd);
}
public void Clear()
{
_mArray.Clear();
}
public bool Contains(OSD llsd)
{
return _mArray.Contains(llsd);
}
public bool Contains(string element)
{
return _mArray.Any(t => t.Type == OSDType.String && t.AsString() == element);
}
public void CopyTo(OSD[] array, int index)
{
throw new NotImplementedException();
}
public bool Remove(OSD llsd)
{
return _mArray.Remove(llsd);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _mArray.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _mArray.GetEnumerator();
}
#endregion IList Implementation
}
public partial class OSDParser
{
private const string LLSD_BINARY_HEADER = " llsd/binary ?>";
private const string LLSD_XML_HEADER = "";
private const string LLSD_XML_ALT_HEADER = "";
public static OSD Deserialize(byte[] data)
{
string header = Encoding.ASCII.GetString(data, 0, data.Length >= 17 ? 17 : data.Length);
try
{
string uHeader = Encoding.UTF8.GetString(data, 0, data.Length >= 17 ? 17 : data.Length).TrimStart();
if (uHeader.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
uHeader.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
uHeader.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase))
{
return DeserializeLLSDXml(data);
}
}
catch { }
if (header.StartsWith(LLSD_BINARY_HEADER, StringComparison.InvariantCultureIgnoreCase))
{
return DeserializeLLSDBinary(data);
}
if (header.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
header.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
header.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase))
{
return DeserializeLLSDXml(data);
}
return DeserializeJson(Encoding.UTF8.GetString(data));
}
public static OSD Deserialize(string data)
{
if (data.StartsWith(LLSD_BINARY_HEADER, StringComparison.InvariantCultureIgnoreCase))
{
return DeserializeLLSDBinary(Encoding.UTF8.GetBytes(data));
}
if (data.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
data.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) ||
data.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase))
{
return DeserializeLLSDXml(data);
}
return DeserializeJson(data);
}
public static OSD Deserialize(Stream stream)
{
if (!stream.CanSeek) { throw new OSDException("Cannot deserialize structured data from unseekable streams"); }
byte[] headerData = new byte[14];
int read = stream.Read(headerData, 0, 14);
if (read == 0) { throw new System.IO.EndOfStreamException(); }
stream.Seek(0, SeekOrigin.Begin);
string header = Encoding.ASCII.GetString(headerData);
if (header.StartsWith(LLSD_BINARY_HEADER))
return DeserializeLLSDBinary(stream);
if (header.StartsWith(LLSD_XML_HEADER) || header.StartsWith(LLSD_XML_ALT_HEADER) || header.StartsWith(LLSD_XML_ALT2_HEADER))
return DeserializeLLSDXml(stream);
return DeserializeJson(stream);
}
}
}