* 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:
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user