751 lines
38 KiB
C#
751 lines
38 KiB
C#
/*
|
||
* Copyright (c) 2006-2016, openmetaverse.co
|
||
* Copyright (c) 2021-2024, 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.
|
||
*/
|
||
|
||
/*
|
||
*
|
||
* These tests are based upon the description at
|
||
*
|
||
* http://wiki.secondlife.com/wiki/LLSD
|
||
*
|
||
* and (partially) generated by the (supposed) reference implementation at
|
||
*
|
||
* http://svn.secondlife.com/svn/linden/release/indra/lib/python/indra/base/llsd.py
|
||
*
|
||
*/
|
||
|
||
using System;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Xml;
|
||
using NUnit.Framework;
|
||
using OpenMetaverse;
|
||
using OpenMetaverse.StructuredData;
|
||
|
||
namespace LibreMetaverse.Tests
|
||
{
|
||
|
||
[TestFixture]
|
||
public class BinarySdTests
|
||
{
|
||
private static readonly byte[] BinaryHead = Encoding.ASCII.GetBytes("<?llsd/binary?>\n");
|
||
|
||
[Test]
|
||
public void HelperFunctions()
|
||
{
|
||
string s = "this is a teststring so that we can find something from the beginning";
|
||
byte[] sBinary = Encoding.ASCII.GetBytes(s);
|
||
MemoryStream stream = new MemoryStream(sBinary);
|
||
|
||
stream.Position = 0L;
|
||
bool result = OSDParser.FindString(stream, "this");
|
||
Assert.That(result, Is.True);
|
||
Assert.That(stream.Position, Is.EqualTo(4L));
|
||
|
||
stream.Position = 10L;
|
||
result = OSDParser.FindString(stream, "teststring");
|
||
Assert.That(result, Is.True);
|
||
Assert.That(stream.Position, Is.EqualTo((20L)));
|
||
|
||
stream.Position = 25L;
|
||
result = OSDParser.FindString(stream, "notfound");
|
||
Assert.That(result, Is.False);
|
||
Assert.That(stream.Position, Is.EqualTo(25L));
|
||
|
||
stream.Position = 60L;
|
||
result = OSDParser.FindString(stream, "beginningAndMore");
|
||
Assert.That(result, Is.False);
|
||
Assert.That(stream.Position, Is.EqualTo(60L));
|
||
|
||
byte[] sFrontWhiteSpace = Encoding.ASCII.GetBytes(" \t\t\n\rtest");
|
||
MemoryStream streamTwo = new MemoryStream(sFrontWhiteSpace);
|
||
OSDParser.SkipWhiteSpace(streamTwo);
|
||
Assert.That(streamTwo.Position, Is.EqualTo(7L));
|
||
|
||
byte[] sMiddleWhiteSpace = Encoding.ASCII.GetBytes("test \t\t\n\rtest");
|
||
MemoryStream streamThree = new MemoryStream(sMiddleWhiteSpace);
|
||
streamThree.Position = 4L;
|
||
OSDParser.SkipWhiteSpace(streamThree);
|
||
Assert.That(streamThree, Is.EqualTo(9L));
|
||
|
||
byte[] sNoWhiteSpace = Encoding.ASCII.GetBytes("testtesttest");
|
||
MemoryStream streamFour = new MemoryStream(sNoWhiteSpace);
|
||
OSDParser.SkipWhiteSpace(streamFour);
|
||
Assert.That(streamFour, Is.EqualTo(0L));
|
||
}
|
||
|
||
// Testvalues for Undef:
|
||
private static readonly byte[] BinaryUndefValue = { 0x21 };
|
||
private static readonly byte[] BinaryUndef = (byte[])ConcatenateArrays(BinaryHead, BinaryUndefValue);
|
||
|
||
[Test]
|
||
public void DeserializeUndef()
|
||
{
|
||
OSD llsdUndef = OSDParser.DeserializeLLSDBinary(BinaryUndef);
|
||
Assert.That(llsdUndef, Is.EqualTo(OSDType.Unknown));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeUndef()
|
||
{
|
||
OSD llsdUndef = new OSD();
|
||
byte[] binaryUndefSerialized = OSDParser.SerializeLLSDBinary(llsdUndef);
|
||
Assert.That(binaryUndefSerialized, Is.EqualTo(BinaryUndef));
|
||
}
|
||
|
||
private static readonly byte[] BinaryTrueValue = { 0x31 };
|
||
private static readonly byte[] BinaryTrue = (byte[])ConcatenateArrays(BinaryHead, BinaryTrueValue);
|
||
|
||
|
||
private static readonly byte[] BinaryFalseValue = { 0x30 };
|
||
private static readonly byte[] BinaryFalse = (byte[])ConcatenateArrays(BinaryHead, BinaryFalseValue);
|
||
|
||
[Test]
|
||
public void DeserializeBool()
|
||
{
|
||
OSD llsdTrue = OSDParser.DeserializeLLSDBinary(BinaryTrue);
|
||
Assert.That(llsdTrue.Type, Is.EqualTo(OSDType.Boolean));
|
||
Assert.That(llsdTrue.AsBoolean(), Is.True);
|
||
|
||
OSD llsdFalse = OSDParser.DeserializeLLSDBinary(BinaryFalse);
|
||
Assert.That(llsdFalse.Type, Is.EqualTo(OSDType.Boolean));
|
||
Assert.That(llsdFalse.AsBoolean(), Is.False);
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeBool()
|
||
{
|
||
OSD llsdTrue = OSD.FromBoolean(true);
|
||
byte[] binaryTrueSerialized = OSDParser.SerializeLLSDBinary(llsdTrue);
|
||
Assert.That(binaryTrueSerialized, Is.EqualTo(BinaryTrue));
|
||
|
||
OSD llsdFalse = OSD.FromBoolean(false);
|
||
byte[] binaryFalseSerialized = OSDParser.SerializeLLSDBinary(llsdFalse);
|
||
Assert.That(binaryFalseSerialized, Is.EqualTo(BinaryFalse));
|
||
}
|
||
|
||
private static readonly byte[] BinaryZeroIntValue = { 0x69, 0x0, 0x0, 0x0, 0x0 };
|
||
private static readonly byte[] BinaryZeroInt = (byte[])ConcatenateArrays(BinaryHead, BinaryZeroIntValue);
|
||
|
||
private static readonly byte[] BinaryAnIntValue = { 0x69, 0x0, 0x12, 0xd7, 0x9b };
|
||
private static readonly byte[] BinaryAnInt = (byte[])ConcatenateArrays(BinaryHead, BinaryAnIntValue);
|
||
|
||
[Test]
|
||
public void DeserializeInteger()
|
||
{
|
||
OSD llsdZeroInteger = OSDParser.DeserializeLLSDBinary(BinaryZeroInt);
|
||
Assert.That(llsdZeroInteger.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdZeroInteger.AsInteger(), Is.Zero);
|
||
|
||
OSD llsdAnInteger = OSDParser.DeserializeLLSDBinary(BinaryAnInt);
|
||
Assert.That(llsdAnInteger.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdAnInteger.AsInteger(), Is.EqualTo(1234843));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeInteger()
|
||
{
|
||
OSD llsdZeroInt = OSD.FromInteger(0);
|
||
byte[] binaryZeroIntSerialized = OSDParser.SerializeLLSDBinary(llsdZeroInt);
|
||
Assert.That(binaryZeroIntSerialized, Is.EqualTo(BinaryZeroInt));
|
||
|
||
binaryZeroIntSerialized = OSDParser.SerializeLLSDBinary(llsdZeroInt, false);
|
||
Assert.That(binaryZeroIntSerialized, Is.EqualTo(BinaryZeroIntValue));
|
||
|
||
OSD llsdAnInt = OSD.FromInteger(1234843);
|
||
byte[] binaryAnIntSerialized = OSDParser.SerializeLLSDBinary(llsdAnInt);
|
||
Assert.That(binaryAnIntSerialized, Is.EqualTo(BinaryAnInt));
|
||
|
||
binaryAnIntSerialized = OSDParser.SerializeLLSDBinary(llsdAnInt, false);
|
||
Assert.That(binaryAnIntSerialized, Is.EqualTo(BinaryAnIntValue));
|
||
}
|
||
|
||
private static readonly byte[] BinaryRealValue = { 0x72, 0x41, 0x2c, 0xec, 0xf6, 0x77, 0xce, 0xd9, 0x17 };
|
||
private static readonly byte[] BinaryReal = (byte[])ConcatenateArrays(BinaryHead, BinaryRealValue);
|
||
|
||
[Test]
|
||
public void DeserializeReal()
|
||
{
|
||
OSD llsdReal = OSDParser.DeserializeLLSDBinary(BinaryReal);
|
||
Assert.That(llsdReal.Type, Is.EqualTo(OSDType.Real));
|
||
Assert.That(llsdReal.AsReal(), Is.EqualTo(947835.234d));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeReal()
|
||
{
|
||
OSD llsdReal = OSD.FromReal(947835.234d);
|
||
byte[] binaryRealSerialized = OSDParser.SerializeLLSDBinary(llsdReal);
|
||
Assert.That(binaryRealSerialized, Is.EqualTo(BinaryReal));
|
||
|
||
binaryRealSerialized = OSDParser.SerializeLLSDBinary(llsdReal);
|
||
Assert.That(binaryRealSerialized, Is.EqualTo(BinaryReal));
|
||
}
|
||
|
||
private static readonly byte[] BinaryAuuidValue = { 0x75, 0x97, 0xf4, 0xae, 0xca, 0x88, 0xa1, 0x42, 0xa1,
|
||
0xb3, 0x85, 0xb9, 0x7b, 0x18, 0xab, 0xb2, 0x55 };
|
||
private static readonly byte[] BinaryAuuid = (byte[])ConcatenateArrays(BinaryHead, BinaryAuuidValue);
|
||
|
||
private static readonly byte[] BinaryZeroUuidValue = { 0x75, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||
private static readonly byte[] BinaryZeroUuid = (byte[])ConcatenateArrays(BinaryHead, BinaryZeroUuidValue);
|
||
|
||
|
||
[Test]
|
||
public void DeserializeUuid()
|
||
{
|
||
Assert.That(UUID.Zero.ToString(), Is.EqualTo("00000000-0000-0000-0000-000000000000"));
|
||
|
||
OSD llsdAuuid = OSDParser.DeserializeLLSDBinary(BinaryAuuid);
|
||
Assert.That(llsdAuuid.Type, Is.EqualTo(OSDType.UUID));
|
||
Assert.That(llsdAuuid.AsString(), Is.EqualTo("97f4aeca-88a1-42a1-b385-b97b18abb255"));
|
||
|
||
OSD llsdZeroUuid = OSDParser.DeserializeLLSDBinary(BinaryZeroUuid);
|
||
Assert.That(llsdZeroUuid.Type, Is.EqualTo(OSDType.UUID));
|
||
Assert.That(llsdZeroUuid.ToString(), Is.EqualTo(UUID.Zero.ToString()));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeUuid()
|
||
{
|
||
OSD llsdAuuid = OSD.FromUUID(new UUID("97f4aeca-88a1-42a1-b385-b97b18abb255"));
|
||
byte[] binaryAuuidSerialized = OSDParser.SerializeLLSDBinary(llsdAuuid);
|
||
Assert.That(binaryAuuidSerialized, Is.EqualTo(BinaryAuuid));
|
||
|
||
binaryAuuidSerialized = OSDParser.SerializeLLSDBinary(llsdAuuid);
|
||
Assert.That(binaryAuuidSerialized, Is.EqualTo(BinaryAuuid));
|
||
|
||
OSD llsdZeroUuid = OSD.FromUUID(UUID.Zero);
|
||
byte[] binaryZeroUuidSerialized = OSDParser.SerializeLLSDBinary(llsdZeroUuid);
|
||
Assert.That(binaryZeroUuidSerialized, Is.EqualTo(BinaryZeroUuid));
|
||
|
||
binaryZeroUuidSerialized = OSDParser.SerializeLLSDBinary(llsdZeroUuid);
|
||
Assert.That(binaryZeroUuidSerialized, Is.EqualTo(BinaryZeroUuid));
|
||
}
|
||
|
||
private static readonly byte[] BinaryBinStringValue = { 0x62, 0x0, 0x0, 0x0, 0x34, // this line is the encoding header
|
||
0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73,
|
||
0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
|
||
0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
|
||
0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
|
||
private static readonly byte[] BinaryBinString = (byte[])ConcatenateArrays(BinaryHead, BinaryBinStringValue);
|
||
|
||
[Test]
|
||
public void DeserializeLlsdBinary()
|
||
{
|
||
OSD llsdBytes = OSDParser.DeserializeLLSDBinary(BinaryBinString);
|
||
Assert.That(llsdBytes.Type, Is.EqualTo(OSDType.Binary));
|
||
byte[] contentBinString = { 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73,
|
||
0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
|
||
0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
|
||
0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
|
||
Assert.That(llsdBytes.AsBinary(), Is.EqualTo(contentBinString));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeLlsdBinary()
|
||
{
|
||
byte[] contentBinString = { 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73,
|
||
0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
|
||
0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
|
||
0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
|
||
OSD llsdBinary = OSD.FromBinary(contentBinString);
|
||
byte[] binaryBinarySerialized = OSDParser.SerializeLLSDBinary(llsdBinary);
|
||
Assert.That(binaryBinarySerialized, Is.EqualTo(BinaryBinString));
|
||
}
|
||
|
||
private static readonly byte[] BinaryEmptyStringValue = { 0x73, 0x0, 0x0, 0x0, 0x0 };
|
||
private static readonly byte[] BinaryEmptyString = (byte[])ConcatenateArrays(BinaryHead, BinaryEmptyStringValue);
|
||
private static readonly byte[] BinaryLongStringValue = { 0x73, 0x0, 0x0, 0x0, 0x25,
|
||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
|
||
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
|
||
0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||
0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
|
||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 };
|
||
private static readonly byte[] BinaryLongString = (byte[])ConcatenateArrays(BinaryHead, BinaryLongStringValue);
|
||
|
||
[Test]
|
||
public void DeserializeString()
|
||
{
|
||
OSD llsdEmptyString = OSDParser.DeserializeLLSDBinary(BinaryEmptyString);
|
||
Assert.That(llsdEmptyString.Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdEmptyString, Is.Empty);
|
||
|
||
OSD llsdLongString = OSDParser.DeserializeLLSDBinary(BinaryLongString);
|
||
Assert.That(llsdLongString.Type, Is.EqualTo(OSDType.String));
|
||
string contentLongString = "abcdefghijklmnopqrstuvwxyz01234567890";
|
||
Assert.That(llsdLongString, Is.EqualTo(contentLongString));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeString()
|
||
{
|
||
OSD llsdString = OSD.FromString("abcdefghijklmnopqrstuvwxyz01234567890");
|
||
byte[] binaryLongStringSerialized = OSDParser.SerializeLLSDBinary(llsdString);
|
||
Assert.That(binaryLongStringSerialized, Is.EqualTo(BinaryLongString));
|
||
|
||
// A test with some utf8 characters
|
||
string contentAStringXml = "<x>ƖȔȠȨɆɒ</x>";
|
||
byte[] bytes = Encoding.UTF8.GetBytes(contentAStringXml);
|
||
XmlTextReader xtr = new XmlTextReader(new MemoryStream(bytes, false));
|
||
xtr.Read();
|
||
xtr.Read();
|
||
|
||
string contentAString = xtr.ReadString();
|
||
OSD llsdAString = OSD.FromString(contentAString);
|
||
byte[] binaryAString = OSDParser.SerializeLLSDBinary(llsdAString);
|
||
OSD llsdAStringDs = OSDParser.DeserializeLLSDBinary(binaryAString);
|
||
Assert.That(llsdAStringDs.Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdAStringDs, Is.EqualTo(contentAString));
|
||
|
||
// we also test for a 4byte character.
|
||
string xml = "<x>𐄷</x>";
|
||
byte[] bytesTwo = Encoding.UTF8.GetBytes(xml);
|
||
XmlTextReader xtrTwo = new XmlTextReader(new MemoryStream(bytesTwo, false));
|
||
xtrTwo.Read();
|
||
xtrTwo.Read();
|
||
string content = xtrTwo.ReadString();
|
||
|
||
OSD llsdStringOne = OSD.FromString(content);
|
||
byte[] binaryAStringOneSerialized = OSDParser.SerializeLLSDBinary(llsdStringOne);
|
||
OSD llsdStringOneDs = OSDParser.DeserializeLLSDBinary(binaryAStringOneSerialized);
|
||
Assert.That(llsdStringOneDs.Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdStringOneDs, Is.EqualTo(content));
|
||
}
|
||
|
||
// Be careful. The current and above-mentioned reference implementation has a bug that
|
||
// doesn't allow proper binary Uri encoding.
|
||
// We compare here to a fixed version of Uri encoding
|
||
private static readonly byte[] BinaryUriValue = { 0x6c, 0x0, 0x0, 0x0, 0x18, // this line is the encoding header
|
||
0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74,
|
||
0x65, 0x73, 0x74, 0x75, 0x72, 0x6c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2f };
|
||
private static readonly byte[] BinaryUri = (byte[])ConcatenateArrays(BinaryHead, BinaryUriValue);
|
||
|
||
[Test]
|
||
public void DeserializeUri()
|
||
{
|
||
OSD llsdUri = OSDParser.DeserializeLLSDBinary(BinaryUri);
|
||
Assert.That(llsdUri.Type, Is.EqualTo(OSDType.URI));
|
||
Uri uri = new Uri("http://www.testurl.test/");
|
||
Assert.That(llsdUri.AsUri(), Is.EqualTo(uri));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeUri()
|
||
{
|
||
OSD llsdUri = OSD.FromUri(new Uri("http://www.testurl.test/"));
|
||
byte[] binaryUriSerialized = OSDParser.SerializeLLSDBinary(llsdUri);
|
||
Assert.That(binaryUriSerialized, Is.EqualTo(BinaryUri));
|
||
}
|
||
|
||
// Here is a problem.
|
||
// The reference implementation does serialize to a local timestamp and not to a universal timestamp,
|
||
// which means, this implementation and the reference implementation only work the same in the universal
|
||
// timezone. Therefore, this binaryDateTimeValue is generated in the UTC timezone by the reference
|
||
// implementation.
|
||
private static readonly byte[] BinaryDateTimeValue = { 100, 0, 0, 192, 141, 167, 222, 209, 65 };
|
||
private static readonly byte[] BinaryDateTime = (byte[])ConcatenateArrays(BinaryHead, BinaryDateTimeValue);
|
||
|
||
[Test]
|
||
public void DeserializeDateTime()
|
||
{
|
||
OSD llsdDateTime = OSDParser.DeserializeLLSDBinary(BinaryDateTime);
|
||
Assert.That(llsdDateTime.Type, Is.EqualTo(OSDType.Date));
|
||
DateTime dt = new DateTime(2008, 1, 1, 20, 10, 31, 0, DateTimeKind.Utc);
|
||
DateTime dateLocal = llsdDateTime.AsDate();
|
||
Assert.That(dt, Is.EqualTo(dateLocal.ToUniversalTime()));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeDateTime()
|
||
{
|
||
DateTime dt = new DateTime(2008, 1, 1, 20, 10, 31, 0, DateTimeKind.Utc);
|
||
OSD llsdDate = OSD.FromDate(dt);
|
||
byte[] binaryDateSerialized = OSDParser.SerializeLLSDBinary(llsdDate);
|
||
Assert.That(binaryDateSerialized, Is.EqualTo(BinaryDateTime));
|
||
|
||
// check if a *local* time can be serialized and deserialized
|
||
DateTime dtOne = new DateTime(2009, 12, 30, 8, 25, 10, DateTimeKind.Local);
|
||
OSD llsdDateOne = OSD.FromDate(dtOne);
|
||
byte[] binaryDateOneSerialized = OSDParser.SerializeLLSDBinary(llsdDateOne);
|
||
OSD llsdDateOneDs = OSDParser.DeserializeLLSDBinary(binaryDateOneSerialized);
|
||
Assert.That(llsdDateOneDs, Is.EqualTo(OSDType.Date));
|
||
Assert.That(llsdDateOneDs.AsDate(), Is.EqualTo(dtOne));
|
||
|
||
DateTime dtTwo = new DateTime(2010, 11, 11, 10, 8, 20, DateTimeKind.Utc);
|
||
OSD llsdDateTwo = OSD.FromDate(dtTwo);
|
||
byte[] binaryDateTwoSerialized = OSDParser.SerializeLLSDBinary(llsdDateTwo);
|
||
OSD llsdDateTwoDs = OSDParser.DeserializeLLSDBinary(binaryDateTwoSerialized);
|
||
Assert.That(llsdDateTwoDs, Is.EqualTo(OSDType.Date));
|
||
Assert.That(llsdDateTwoDs.AsDate(), Is.EqualTo(dtTwo));
|
||
}
|
||
|
||
// Data for empty array { }
|
||
private static readonly byte[] BinaryEmptyArrayValue = { 0x5b, 0x0, 0x0, 0x0, 0x0, 0x5d };
|
||
// Encoding header + num of elements + tail
|
||
private static readonly byte[] BinaryEmptyArray = (byte[])ConcatenateArrays(BinaryHead, BinaryEmptyArrayValue);
|
||
// Data for simple array { 0 }
|
||
private static readonly byte[] BinarySimpleArrayValue = { 0x5b, 0x0, 0x0, 0x0, 0x1, // Encoding header + num of elements
|
||
0x69, 0x0, 0x0, 0x0, 0x0, 0x5d };
|
||
private static readonly byte[] BinarySimpleArray = (byte[])ConcatenateArrays(BinaryHead, BinarySimpleArrayValue);
|
||
|
||
// Data for simple array { 0, 0 }
|
||
private static readonly byte[] BinarySimpleArrayTwoValue = { 0x5b, 0x0, 0x0, 0x0, 0x2, // Encoding header + num of elements
|
||
0x69, 0x0, 0x0, 0x0, 0x0,
|
||
0x69, 0x0, 0x0, 0x0, 0x0, 0x5d };
|
||
private static readonly byte[] BinarySimpleArrayTwo = (byte[])ConcatenateArrays(BinaryHead, BinarySimpleArrayTwoValue);
|
||
|
||
[Test]
|
||
public void DeserializeArray()
|
||
{
|
||
OSD llsdEmptyArray = OSDParser.DeserializeLLSDBinary(BinaryEmptyArray);
|
||
Assert.That(llsdEmptyArray.Type, Is.EqualTo(OSDType.Array));
|
||
OSDArray llsdEmptyArrayArray = (OSDArray)llsdEmptyArray;
|
||
Assert.That(llsdEmptyArrayArray, Is.Empty);
|
||
|
||
|
||
OSD llsdSimpleArray = OSDParser.DeserializeLLSDBinary(BinarySimpleArray);
|
||
Assert.That(llsdSimpleArray.Type, Is.EqualTo(OSDType.Array));
|
||
OSDArray llsdArray = (OSDArray)llsdSimpleArray;
|
||
Assert.That(llsdArray[0].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdArray[0].AsInteger(), Is.Zero);
|
||
|
||
|
||
OSD llsdSimpleArrayTwo = OSDParser.DeserializeLLSDBinary(BinarySimpleArrayTwo);
|
||
Assert.That(llsdSimpleArrayTwo.Type, Is.EqualTo(OSDType.Array));
|
||
OSDArray llsdArrayTwo = (OSDArray)llsdSimpleArrayTwo;
|
||
Assert.That(llsdArrayTwo.Count, Is.EqualTo(2));
|
||
|
||
Assert.That(llsdArrayTwo[0].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdArrayTwo[0].AsInteger(), Is.Zero);
|
||
Assert.That(llsdArrayTwo[1].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdArrayTwo[1].AsInteger(), Is.Zero);
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeArray()
|
||
{
|
||
OSDArray llsdEmptyArray = new OSDArray();
|
||
byte[] binaryEmptyArraySerialized = OSDParser.SerializeLLSDBinary(llsdEmptyArray);
|
||
Assert.That(binaryEmptyArraySerialized, Is.EqualTo(BinaryEmptyArray));
|
||
|
||
binaryEmptyArraySerialized = OSDParser.SerializeLLSDBinary(llsdEmptyArray, false);
|
||
Assert.That(binaryEmptyArraySerialized, Is.EqualTo(BinaryEmptyArrayValue));
|
||
|
||
OSDArray llsdSimpleArray = new OSDArray { OSD.FromInteger(0) };
|
||
byte[] binarySimpleArraySerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArray);
|
||
Assert.That(binarySimpleArraySerialized, Is.EqualTo(BinarySimpleArray));
|
||
|
||
binarySimpleArraySerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArray, false);
|
||
Assert.That(binarySimpleArraySerialized, Is.EqualTo(BinarySimpleArrayValue));
|
||
|
||
OSDArray llsdSimpleArrayTwo = new OSDArray
|
||
{
|
||
OSD.FromInteger(0),
|
||
OSD.FromInteger(0)
|
||
};
|
||
byte[] binarySimpleArrayTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArrayTwo);
|
||
Assert.That(binarySimpleArrayTwoSerialized, Is.EqualTo(BinarySimpleArrayTwo));
|
||
|
||
binarySimpleArrayTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArrayTwo, false);
|
||
Assert.That(binarySimpleArrayTwoSerialized, Is.EqualTo(BinarySimpleArrayTwoValue));
|
||
}
|
||
|
||
// Data for empty dictionary { }
|
||
private static readonly byte[] BinaryEmptyMapValue = { 0x7b, 0x0, 0x0, 0x0, 0x0, 0x7d };
|
||
private static readonly byte[] BinaryEmptyMap = (byte[])ConcatenateArrays(BinaryHead, BinaryEmptyMapValue);
|
||
|
||
// Data for simple dictionary { test = 0 }
|
||
private static readonly byte[] BinarySimpleMapValue = { 0x7b, 0x0, 0x0, 0x0, 0x1, // Encoding header + num of elements
|
||
0x6b, 0x0, 0x0, 0x0, 0x4, // 'k' + keylength
|
||
0x74, 0x65, 0x73, 0x74, // key 'test'
|
||
0x69, 0x0, 0x0, 0x0, 0x0, // i + '0'
|
||
0x7d };
|
||
private static readonly byte[] BinarySimpleMap = (byte[])ConcatenateArrays(BinaryHead, BinarySimpleMapValue);
|
||
|
||
// Data for simple dictionary { t0st = 241, tes1 = "aha", test = undef }
|
||
private static readonly byte[] BinarySimpleMapTwoValue = { 0x7b, 0x0, 0x0, 0x0, 0x3, // Encoding header + num of elements
|
||
0x6b, 0x0, 0x0, 0x0, 0x4, // 'k' + keylength
|
||
0x74, 0x65, 0x73, 0x74, // key 'test'
|
||
0x21, // undef
|
||
0x6b, 0x0, 0x0, 0x0, 0x4, // k + keylength
|
||
0x74, 0x65, 0x73, 0x31, // key 'tes1'
|
||
0x73, 0x0, 0x0, 0x0, 0x3, // string head + length
|
||
0x61, 0x68, 0x61, // 'aha'
|
||
0x6b, 0x0, 0x0, 0x0, 0x4, // k + keylength
|
||
0x74, 0x30, 0x73, 0x74, // key 't0st'
|
||
0x69, 0x0, 0x0, 0x0, 0xf1, // integer 241
|
||
0x7d };
|
||
private static readonly byte[] BinarySimpleMapTwo = (byte[])ConcatenateArrays(BinaryHead, BinarySimpleMapTwoValue);
|
||
|
||
[Test]
|
||
public void DeserializeDictionary()
|
||
{
|
||
OSDMap llsdEmptyMap = (OSDMap)OSDParser.DeserializeLLSDBinary(BinaryEmptyMap);
|
||
Assert.That(llsdEmptyMap.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdEmptyMap, Is.Empty);
|
||
|
||
OSDMap llsdSimpleMap = (OSDMap)OSDParser.DeserializeLLSDBinary(BinarySimpleMap);
|
||
Assert.That(llsdSimpleMap.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdSimpleMap.Count, Is.EqualTo(1));
|
||
Assert.That(llsdSimpleMap["test"].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdSimpleMap["test"].AsInteger(), Is.Zero);
|
||
|
||
OSDMap llsdSimpleMapTwo = (OSDMap)OSDParser.DeserializeLLSDBinary(BinarySimpleMapTwo);
|
||
Assert.That(llsdSimpleMapTwo.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdSimpleMapTwo.Count, Is.EqualTo(3));
|
||
Assert.That(llsdSimpleMapTwo["test"].Type, Is.EqualTo(OSDType.Unknown));
|
||
Assert.That(llsdSimpleMapTwo["tes1"].Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdSimpleMapTwo["tes1"].AsString(), Is.EqualTo("aha"));
|
||
Assert.That(llsdSimpleMapTwo["t0st"].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdSimpleMapTwo["t0st"].AsInteger(), Is.EqualTo(241));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeDictionary()
|
||
{
|
||
OSDMap llsdEmptyMap = new OSDMap();
|
||
byte[] binaryEmptyMapSerialized = OSDParser.SerializeLLSDBinary(llsdEmptyMap);
|
||
Assert.That(binaryEmptyMapSerialized, Is.EqualTo(BinaryEmptyMap));
|
||
|
||
OSDMap llsdSimpleMap = new OSDMap
|
||
{
|
||
["test"] = OSD.FromInteger(0)
|
||
};
|
||
byte[] binarySimpleMapSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleMap);
|
||
Assert.That(binarySimpleMapSerialized, Is.EqualTo(BinarySimpleMap));
|
||
|
||
OSDMap llsdSimpleMapTwo = new OSDMap
|
||
{
|
||
["t0st"] = OSD.FromInteger(241),
|
||
["tes1"] = OSD.FromString("aha"),
|
||
["test"] = new OSD()
|
||
};
|
||
byte[] binarySimpleMapTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleMapTwo);
|
||
|
||
// We dont compare here to the original serialized value, because, as maps don't preserve order,
|
||
// the original serialized value is not *exactly* the same. Instead we compare to a deserialized
|
||
// version created by this deserializer.
|
||
OSDMap llsdSimpleMapDeserialized = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMapTwoSerialized);
|
||
Assert.That(llsdSimpleMapDeserialized.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdSimpleMapDeserialized.Count, Is.EqualTo(3));
|
||
Assert.That(llsdSimpleMapDeserialized["t0st"].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdSimpleMapDeserialized["t0st"].AsInteger(), Is.EqualTo(241));
|
||
Assert.That(llsdSimpleMapDeserialized["tes1"].Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdSimpleMapDeserialized["tes1"].AsString(), Is.EqualTo("aha"));
|
||
Assert.That(llsdSimpleMapDeserialized["test"].Type, Is.EqualTo(OSDType.Unknown));
|
||
|
||
// we also test for a 4byte key character.
|
||
string xml = "<x>𐄷</x>";
|
||
byte[] bytes = Encoding.UTF8.GetBytes(xml);
|
||
XmlTextReader xtr = new XmlTextReader(new MemoryStream(bytes, false));
|
||
xtr.Read();
|
||
xtr.Read();
|
||
string content = xtr.ReadString();
|
||
|
||
OSDMap llsdSimpleMapThree = new OSDMap();
|
||
OSD llsdSimpleValue = OSD.FromString(content);
|
||
llsdSimpleMapThree[content] = llsdSimpleValue;
|
||
Assert.That(llsdSimpleMapThree[content].AsString(), Is.EqualTo(content));
|
||
|
||
byte[] binarySimpleMapThree = OSDParser.SerializeLLSDBinary(llsdSimpleMapThree);
|
||
OSDMap llsdSimpleMapThreeDs = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMapThree);
|
||
Assert.That(llsdSimpleMapThreeDs.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdSimpleMapThreeDs.Count, Is.EqualTo(1));
|
||
Assert.That(llsdSimpleMapThreeDs[content].AsString(), Is.EqualTo(content));
|
||
}
|
||
|
||
private static readonly byte[] BinaryNestedValue = { 0x5b, 0x0, 0x0, 0x0, 0x3,
|
||
0x7b, 0x0, 0x0, 0x0, 0x2,
|
||
0x6b, 0x0, 0x0, 0x0, 0x4,
|
||
0x74, 0x65, 0x73, 0x74,
|
||
0x73, 0x0, 0x0, 0x0, 0x4,
|
||
0x77, 0x68, 0x61, 0x74,
|
||
0x6b, 0x0, 0x0, 0x0, 0x4,
|
||
0x74, 0x30, 0x73,
|
||
0x74, 0x5b, 0x0, 0x0, 0x0, 0x2,
|
||
0x69, 0x0, 0x0, 0x0, 0x1,
|
||
0x69, 0x0, 0x0, 0x0, 0x2,
|
||
0x5d, 0x7d, 0x69, 0x0, 0x0, 0x0,
|
||
0x7c, 0x69, 0x0, 0x0, 0x3, 0xdb,
|
||
0x5d };
|
||
private static readonly byte[] BinaryNested = (byte[])ConcatenateArrays(BinaryHead, BinaryNestedValue);
|
||
|
||
[Test]
|
||
public void DeserializeNestedComposite()
|
||
{
|
||
OSD llsdNested = OSDParser.DeserializeLLSDBinary(BinaryNested);
|
||
Assert.That(llsdNested.Type, Is.EqualTo(OSDType.Array));
|
||
OSDArray llsdArray = (OSDArray)llsdNested;
|
||
Assert.That(llsdArray.Count, Is.EqualTo(3));
|
||
|
||
OSDMap llsdMap = (OSDMap)llsdArray[0];
|
||
Assert.That(llsdMap.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdMap.Count, Is.EqualTo(2));
|
||
|
||
OSDArray llsdNestedArray = (OSDArray)llsdMap["t0st"];
|
||
Assert.That(llsdNestedArray.Type, Is.EqualTo(OSDType.Array));
|
||
OSDInteger llsdNestedIntOne = (OSDInteger)llsdNestedArray[0];
|
||
Assert.That(llsdNestedIntOne.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedIntOne.AsInteger(), Is.EqualTo(1));
|
||
OSDInteger llsdNestedIntTwo = (OSDInteger)llsdNestedArray[1];
|
||
Assert.That(llsdNestedIntTwo.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedIntTwo.AsInteger(), Is.EqualTo(2));
|
||
|
||
OSDString llsdString = (OSDString)llsdMap["test"];
|
||
Assert.That(llsdString.Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdString.AsString(), Is.EqualTo("what"));
|
||
|
||
OSDInteger llsdIntOne = (OSDInteger)llsdArray[1];
|
||
Assert.That(llsdIntOne.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdIntOne.AsInteger(), Is.EqualTo(124));
|
||
OSDInteger llsdIntTwo = (OSDInteger)llsdArray[2];
|
||
Assert.That(llsdIntTwo.Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdIntTwo.AsInteger(), Is.EqualTo(987));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeNestedComposite()
|
||
{
|
||
OSDArray llsdNested = new OSDArray();
|
||
OSDMap llsdMap = new OSDMap();
|
||
OSDArray llsdArray = new OSDArray
|
||
{
|
||
OSD.FromInteger(1),
|
||
OSD.FromInteger(2)
|
||
};
|
||
llsdMap["t0st"] = llsdArray;
|
||
llsdMap["test"] = OSD.FromString("what");
|
||
llsdNested.Add(llsdMap);
|
||
llsdNested.Add(OSD.FromInteger(124));
|
||
llsdNested.Add(OSD.FromInteger(987));
|
||
|
||
byte[] binaryNestedSerialized = OSDParser.SerializeLLSDBinary(llsdNested);
|
||
// Because maps don't preserve order, we compare here to a deserialized value.
|
||
OSDArray llsdNestedDeserialized = (OSDArray)OSDParser.DeserializeLLSDBinary(binaryNestedSerialized);
|
||
Assert.That(llsdNestedDeserialized.Type, Is.EqualTo(OSDType.Array));
|
||
Assert.That(llsdNestedDeserialized.Count, Is.EqualTo(3));
|
||
|
||
OSDMap llsdMapDeserialized = (OSDMap)llsdNestedDeserialized[0];
|
||
Assert.That(llsdMapDeserialized.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdMapDeserialized.Count, Is.EqualTo(2));
|
||
Assert.That(llsdMapDeserialized["t0st"].Type, Is.EqualTo(OSDType.Array));
|
||
|
||
OSDArray llsdNestedArray = (OSDArray)llsdMapDeserialized["t0st"];
|
||
Assert.That(llsdNestedArray.Type, Is.EqualTo(OSDType.Array));
|
||
Assert.That(llsdNestedArray.Count, Is.EqualTo(2));
|
||
Assert.That(llsdNestedArray[0].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedArray[0].AsInteger(), Is.EqualTo(1));
|
||
Assert.That(llsdNestedArray[1].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedArray[1].AsInteger(), Is.EqualTo(2));
|
||
|
||
Assert.That(llsdMapDeserialized["test"].Type, Is.EqualTo(OSDType.String));
|
||
Assert.That(llsdMapDeserialized["test"].AsString(), Is.EqualTo("what"));
|
||
|
||
Assert.That(llsdNestedDeserialized[1].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedDeserialized[1].AsInteger(), Is.EqualTo(124));
|
||
|
||
Assert.That(llsdNestedDeserialized[2].Type, Is.EqualTo(OSDType.Integer));
|
||
Assert.That(llsdNestedDeserialized[2].AsInteger(), Is.EqualTo(987));
|
||
}
|
||
|
||
[Test]
|
||
public void SerializeLongMessage()
|
||
{
|
||
// each 80 chars
|
||
string sOne = "asdklfjasadlfkjaerotiudfgjkhsdklgjhsdklfghasdfklhjasdfkjhasdfkljahsdfjklaasdfkj8";
|
||
string sTwo = "asdfkjlaaweoiugsdfjkhsdfg,.mnasdgfkljhrtuiohfgl<67>kajsdfoiwghjkdlaaaaseldkfjgheus9";
|
||
|
||
OSD stringOne = OSD.FromString( sOne );
|
||
OSD stringTwo = OSD.FromString(sTwo);
|
||
|
||
OSDMap llsdMap = new OSDMap
|
||
{
|
||
["testOne"] = stringOne,
|
||
["testTwo"] = stringTwo,
|
||
["testThree"] = stringOne,
|
||
["testFour"] = stringTwo,
|
||
["testFive"] = stringOne,
|
||
["testSix"] = stringTwo,
|
||
["testSeven"] = stringOne,
|
||
["testEight"] = stringTwo,
|
||
["testNine"] = stringOne,
|
||
["testTen"] = stringTwo
|
||
};
|
||
|
||
|
||
byte[] binaryData = OSDParser.SerializeLLSDBinary( llsdMap );
|
||
|
||
OSDMap llsdMapDs = (OSDMap)OSDParser.DeserializeLLSDBinary( binaryData );
|
||
Assert.That(llsdMapDs.Type, Is.EqualTo(OSDType.Map));
|
||
Assert.That(llsdMapDs.Count, Is.EqualTo(10));
|
||
Assert.That(llsdMapDs["testOne"].AsString(), Is.EqualTo(sOne));
|
||
Assert.That(llsdMapDs["testTwo"].AsString(), Is.EqualTo(sTwo));
|
||
Assert.That(llsdMapDs["testThree"].AsString(), Is.EqualTo(sOne));
|
||
Assert.That(llsdMapDs["testFour"].AsString(), Is.EqualTo(sTwo));
|
||
Assert.That(llsdMapDs["testFive"].AsString(), Is.EqualTo(sOne));
|
||
Assert.That(llsdMapDs["testSix"].AsString(), Is.EqualTo(sTwo));
|
||
Assert.That(llsdMapDs["testSeven"].AsString(), Is.EqualTo(sOne));
|
||
Assert.That(llsdMapDs["testEight"].AsString(), Is.EqualTo(sTwo));
|
||
Assert.That(llsdMapDs["testNine"].AsString(), Is.EqualTo(sOne));
|
||
Assert.That(llsdMapDs["testTen"].AsString(), Is.EqualTo(sTwo));
|
||
}
|
||
|
||
|
||
static Array ConcatenateArrays(params Array[] arrays)
|
||
{
|
||
if (arrays == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(arrays));
|
||
}
|
||
if (arrays.Length == 0)
|
||
{
|
||
throw new ArgumentException("No arrays specified");
|
||
}
|
||
|
||
Type type = arrays[0].GetType().GetElementType();
|
||
int totalLength = arrays[0].Length;
|
||
for (int i = 1; i < arrays.Length; i++)
|
||
{
|
||
if (arrays[i].GetType().GetElementType() != type)
|
||
{
|
||
throw new ArgumentException("Arrays must all be of the same type");
|
||
}
|
||
totalLength += arrays[i].Length;
|
||
}
|
||
|
||
Array ret = Array.CreateInstance(type, totalLength);
|
||
int index = 0;
|
||
foreach (Array array in arrays)
|
||
{
|
||
Array.Copy(array, 0, ret, index, array.Length);
|
||
index += array.Length;
|
||
}
|
||
return ret;
|
||
}
|
||
}
|
||
}
|