Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs89
-rw-r--r--Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs31
-rw-r--r--Src/Newtonsoft.Json.Tests/PerformanceTests.cs13
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs269
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonReader.cs16
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonWriter.cs569
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj1
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj1
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj1
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.csproj1
-rw-r--r--Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs7
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs13
-rw-r--r--Src/Newtonsoft.Json/Utilities/MathUtils.cs11
13 files changed, 794 insertions, 228 deletions
diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs
index 8c6a0b3..a648982 100644
--- a/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs
@@ -68,6 +68,95 @@ namespace Newtonsoft.Json.Tests.Bson
}
[Test]
+ public void WriteValues()
+ {
+ byte[] data = MiscellaneousUtils.HexToBytes("8C-00-00-00-12-30-00-FF-FF-FF-FF-FF-FF-FF-7F-12-31-00-FF-FF-FF-FF-FF-FF-FF-7F-10-32-00-FF-FF-FF-7F-10-33-00-FF-FF-FF-7F-10-34-00-FF-00-00-00-10-35-00-7F-00-00-00-02-36-00-02-00-00-00-61-00-01-37-00-00-00-00-00-00-00-F0-45-01-38-00-FF-FF-FF-FF-FF-FF-EF-7F-01-39-00-00-00-00-E0-FF-FF-EF-47-08-31-30-00-01-05-31-31-00-05-00-00-00-02-00-01-02-03-04-09-31-32-00-40-C5-E2-BA-E3-00-00-00-09-31-33-00-40-C5-E2-BA-E3-00-00-00-00");
+ MemoryStream ms = new MemoryStream(data);
+ BsonReader reader = new BsonReader(ms);
+ reader.ReadRootValueAsArray = true;
+ reader.DateTimeKindHandling = DateTimeKind.Utc;
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(long.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(long.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(int.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(int.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(byte.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Integer, reader.TokenType);
+ Assert.AreEqual(sbyte.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(long), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.String, reader.TokenType);
+ Assert.AreEqual("a", reader.Value);
+ Assert.AreEqual(typeof(string), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Float, reader.TokenType);
+ Assert.AreEqual(decimal.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(double), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Float, reader.TokenType);
+ Assert.AreEqual(double.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(double), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Float, reader.TokenType);
+ Assert.AreEqual(float.MaxValue, reader.Value);
+ Assert.AreEqual(typeof(double), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
+ Assert.AreEqual(true, reader.Value);
+ Assert.AreEqual(typeof(bool), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Bytes, reader.TokenType);
+ Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4 }, reader.Value);
+ Assert.AreEqual(typeof(byte[]), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Date, reader.TokenType);
+ Assert.AreEqual(new DateTime(2000, 12, 29, 12, 30, 0, DateTimeKind.Utc), reader.Value);
+ Assert.AreEqual(typeof(DateTime), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Date, reader.TokenType);
+ Assert.AreEqual(new DateTime(2000, 12, 29, 12, 30, 0, DateTimeKind.Utc), reader.Value);
+ Assert.AreEqual(typeof(DateTime), reader.ValueType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
+
+ Assert.IsFalse(reader.Read());
+ }
+
+
+ [Test]
public void ReadObjectBsonFromSite()
{
byte[] data = MiscellaneousUtils.HexToBytes("20-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-02-32-00-02-00-00-00-63-00-00");
diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
index 79307e2..e99595e 100644
--- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
@@ -48,11 +48,40 @@ namespace Newtonsoft.Json.Tests.Bson
writer.WritePropertyName("Blah");
writer.WriteValue(1);
writer.WriteEndObject();
-
+
string bson = MiscellaneousUtils.BytesToHex(ms.ToArray());
Assert.AreEqual("0F-00-00-00-10-42-6C-61-68-00-01-00-00-00-00", bson);
}
+#if !PocketPC && !NET20
+ [Test]
+ public void WriteValues()
+ {
+ MemoryStream ms = new MemoryStream();
+ BsonWriter writer = new BsonWriter(ms);
+
+ writer.WriteStartArray();
+ writer.WriteValue(long.MaxValue);
+ writer.WriteValue((ulong)long.MaxValue);
+ writer.WriteValue(int.MaxValue);
+ writer.WriteValue((uint)int.MaxValue);
+ writer.WriteValue(byte.MaxValue);
+ writer.WriteValue(sbyte.MaxValue);
+ writer.WriteValue('a');
+ writer.WriteValue(decimal.MaxValue);
+ writer.WriteValue(double.MaxValue);
+ writer.WriteValue(float.MaxValue);
+ writer.WriteValue(true);
+ writer.WriteValue(new byte[] { 0, 1, 2, 3, 4 });
+ writer.WriteValue(new DateTimeOffset(2000, 12, 29, 12, 30, 0, TimeSpan.Zero));
+ writer.WriteValue(new DateTime(2000, 12, 29, 12, 30, 0, DateTimeKind.Utc));
+ writer.WriteEnd();
+
+ string bson = MiscellaneousUtils.BytesToHex(ms.ToArray());
+ Assert.AreEqual("8C-00-00-00-12-30-00-FF-FF-FF-FF-FF-FF-FF-7F-12-31-00-FF-FF-FF-FF-FF-FF-FF-7F-10-32-00-FF-FF-FF-7F-10-33-00-FF-FF-FF-7F-10-34-00-FF-00-00-00-10-35-00-7F-00-00-00-02-36-00-02-00-00-00-61-00-01-37-00-00-00-00-00-00-00-F0-45-01-38-00-FF-FF-FF-FF-FF-FF-EF-7F-01-39-00-00-00-00-E0-FF-FF-EF-47-08-31-30-00-01-05-31-31-00-05-00-00-00-02-00-01-02-03-04-09-31-32-00-40-C5-E2-BA-E3-00-00-00-09-31-33-00-40-C5-E2-BA-E3-00-00-00-00", bson);
+ }
+#endif
+
[Test]
public void WriteArrayBsonFromSite()
{
diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
index 6772418..70e2e3d 100644
--- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
+++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
@@ -122,10 +122,13 @@ namespace Newtonsoft.Json.Tests
private void SerializeSize(object value)
{
+ // this is extremely slow with 5000 interations
+ int interations = 100;
+
byte[] jsonBytes = TimeOperation(() =>
{
string json = null;
- for (int i = 0; i < Iterations; i++)
+ for (int i = 0; i < interations; i++)
{
json = JsonConvert.SerializeObject(value, Formatting.None);
}
@@ -136,7 +139,7 @@ namespace Newtonsoft.Json.Tests
byte[] bsonBytes = TimeOperation(() =>
{
MemoryStream ms = null;
- for (int i = 0; i < Iterations; i++)
+ for (int i = 0; i < interations; i++)
{
ms = new MemoryStream();
JsonSerializer serializer = new JsonSerializer();
@@ -152,7 +155,7 @@ namespace Newtonsoft.Json.Tests
byte[] xmlBytes = TimeOperation(() =>
{
MemoryStream ms = null;
- for (int i = 0; i < Iterations; i++)
+ for (int i = 0; i < interations; i++)
{
ms = new MemoryStream();
DataContractSerializer dataContractSerializer = new DataContractSerializer(value.GetType());
@@ -165,7 +168,7 @@ namespace Newtonsoft.Json.Tests
byte[] wcfJsonBytes = TimeOperation(() =>
{
MemoryStream ms = null;
- for (int i = 0; i < Iterations; i++)
+ for (int i = 0; i < interations; i++)
{
ms = new MemoryStream();
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(value.GetType());
@@ -178,7 +181,7 @@ namespace Newtonsoft.Json.Tests
byte[] binaryFormatterBytes = TimeOperation(() =>
{
MemoryStream ms = null;
- for (int i = 0; i < Iterations; i++)
+ for (int i = 0; i < interations; i++)
{
ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
new file mode 100644
index 0000000..7ff6965
--- /dev/null
+++ b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Bson
+{
+ internal class BsonBinaryWriter
+ {
+ private static readonly Encoding Encoding = Encoding.UTF8;
+
+ private readonly BinaryWriter _writer;
+
+ private byte[] _largeByteBuffer;
+ private int _maxChars;
+
+ public BsonBinaryWriter(Stream stream)
+ {
+ _writer = new BinaryWriter(stream);
+ }
+
+ public void Flush()
+ {
+ _writer.Flush();
+ }
+
+ public void WriteToken(BsonToken t)
+ {
+ CalculateSize(t);
+ WriteTokenInternal(t);
+ }
+
+ private void WriteTokenInternal(BsonToken t)
+ {
+ switch (t.Type)
+ {
+ case BsonType.Object:
+ {
+ BsonObject value = (BsonObject) t;
+ _writer.Write(value.CalculatedSize);
+ foreach (BsonProperty property in value)
+ {
+ _writer.Write((sbyte)property.Value.Type);
+ WriteString((string)property.Name.Value, property.Name.ByteCount, null);
+ WriteTokenInternal(property.Value);
+ }
+ _writer.Write((byte)0);
+ }
+ break;
+ case BsonType.Array:
+ {
+ BsonArray value = (BsonArray) t;
+ _writer.Write(value.CalculatedSize);
+ int index = 0;
+ foreach (BsonToken c in value)
+ {
+ _writer.Write((sbyte)c.Type);
+ WriteString(index.ToString(CultureInfo.InvariantCulture), Encoding.GetByteCount(index.ToString(CultureInfo.InvariantCulture)), null);
+ WriteTokenInternal(c);
+ index++;
+ }
+ _writer.Write((byte)0);
+ }
+ break;
+ case BsonType.Integer:
+ {
+ BsonValue value = (BsonValue) t;
+ _writer.Write(Convert.ToInt32(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.Long:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write(Convert.ToInt64(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.Number:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write(Convert.ToDouble(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.String:
+ {
+ BsonString value = (BsonString)t;
+ WriteString((string)value.Value, value.ByteCount, value.CalculatedSize - 4);
+ }
+ break;
+ case BsonType.Boolean:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write((bool)value.Value);
+ }
+ break;
+ case BsonType.Null:
+ case BsonType.Undefined:
+ break;
+ case BsonType.Date:
+ {
+ BsonValue value = (BsonValue)t;
+
+ long ticks = 0;
+
+ if (value.Value is DateTime)
+ {
+ DateTime dateTime = (DateTime) value.Value;
+ dateTime = dateTime.ToUniversalTime();
+ ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
+ }
+#if !PocketPC && !NET20
+ else
+ {
+ DateTimeOffset dateTimeOffset = (DateTimeOffset) value.Value;
+ ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset);
+ }
+#endif
+
+ _writer.Write(ticks);
+ }
+ break;
+ case BsonType.Binary:
+ {
+ BsonValue value = (BsonValue)t;
+
+ byte[] data = (byte[])value.Value;
+ _writer.Write(data.Length);
+ _writer.Write((byte)BsonBinaryType.Data);
+ _writer.Write(data);
+ }
+ break;
+ case BsonType.Oid:
+ {
+ BsonValue value = (BsonValue)t;
+
+ byte[] data = (byte[])value.Value;
+ _writer.Write(data);
+ }
+ break;
+ default:
+ throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
+ }
+ }
+
+ private void WriteString(string s, int byteCount, int? calculatedlengthPrefix)
+ {
+ if (calculatedlengthPrefix != null)
+ _writer.Write(calculatedlengthPrefix.Value);
+
+ if (_largeByteBuffer == null)
+ {
+ _largeByteBuffer = new byte[256];
+ _maxChars = 256 / Encoding.GetMaxByteCount(1);
+ }
+ if (byteCount <= 256)
+ {
+ Encoding.GetBytes(s, 0, s.Length, _largeByteBuffer, 0);
+ _writer.Write(_largeByteBuffer, 0, byteCount);
+ }
+ else
+ {
+ int charCount;
+ int totalCharsWritten = 0;
+ for (int i = s.Length; i > 0; i -= charCount)
+ {
+ charCount = (i > _maxChars) ? _maxChars : i;
+ int count = Encoding.GetBytes(s, totalCharsWritten, charCount, _largeByteBuffer, 0);
+ _writer.Write(_largeByteBuffer, 0, count);
+ totalCharsWritten += charCount;
+ }
+ }
+
+ _writer.Write((byte)0);
+ }
+
+ private int CalculateSize(int stringByteCount)
+ {
+ return stringByteCount + 1;
+ }
+
+ private int CalculateSizeWithLength(int stringByteCount, bool includeSize)
+ {
+ int baseSize = (includeSize)
+ ? 5 // size bytes + terminator
+ : 1; // terminator
+
+ return baseSize + stringByteCount;
+ }
+
+ private int CalculateSize(BsonToken t)
+ {
+ switch (t.Type)
+ {
+ case BsonType.Object:
+ {
+ BsonObject value = (BsonObject) t;
+
+ int bases = 4;
+ foreach (BsonProperty p in value)
+ {
+ int size = 1;
+ size += CalculateSize(p.Name);
+ size += CalculateSize(p.Value);
+
+ bases += size;
+ }
+ bases += 1;
+ value.CalculatedSize = bases;
+ return bases;
+ }
+ case BsonType.Array:
+ {
+ BsonArray value = (BsonArray)t;
+
+ int size = 4;
+ int index = 0;
+ foreach (BsonToken c in value)
+ {
+ size += 1;
+ size += CalculateSize(MathUtils.IntLength(index));
+ size += CalculateSize(c);
+ index++;
+ }
+ size += 1;
+ value.CalculatedSize = size;
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Integer:
+ return 4;
+ case BsonType.Long:
+ return 8;
+ case BsonType.Number:
+ return 8;
+ case BsonType.String:
+ {
+ BsonString value = (BsonString)t;
+ string s = (string) value.Value;
+ value.ByteCount = Encoding.GetByteCount(s);
+ value.CalculatedSize = CalculateSizeWithLength(value.ByteCount, value.IncludeLength);
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Boolean:
+ return 1;
+ case BsonType.Null:
+ case BsonType.Undefined:
+ return 0;
+ case BsonType.Date:
+ return 8;
+ case BsonType.Binary:
+ {
+ BsonValue value = (BsonValue) t;
+
+ byte[] data = (byte[])value.Value;
+ value.CalculatedSize = 4 + 1 + data.Length;
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Oid:
+ return 12;
+ default:
+ throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs
index f7858d0..710fe96 100644
--- a/Src/Newtonsoft.Json/Bson/BsonReader.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs
@@ -72,11 +72,11 @@ namespace Newtonsoft.Json.Bson
private class ContainerContext
{
- public readonly JTokenType Type;
+ public readonly BsonType Type;
public int Length;
public int Position;
- public ContainerContext(JTokenType type)
+ public ContainerContext(BsonType type)
{
Type = type;
}
@@ -210,7 +210,7 @@ namespace Newtonsoft.Json.Bson
SetToken(JsonToken.StartObject);
_bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
- ContainerContext newContext = new ContainerContext(JTokenType.Object);
+ ContainerContext newContext = new ContainerContext(BsonType.Object);
PushContext(newContext);
newContext.Length = ReadInt32();
@@ -289,7 +289,7 @@ namespace Newtonsoft.Json.Bson
case State.Start:
{
JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
- JTokenType type = (!_readRootValueAsArray) ? JTokenType.Object : JTokenType.Array;
+ BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
SetToken(token);
ContainerContext newContext = new ContainerContext(type);
@@ -316,7 +316,7 @@ namespace Newtonsoft.Json.Bson
if (context.Position < lengthMinusEnd)
{
- if (context.Type == JTokenType.Array)
+ if (context.Type == BsonType.Array)
{
ReadElement();
ReadType(_currentElementType);
@@ -337,7 +337,7 @@ namespace Newtonsoft.Json.Bson
if (_currentContext != null)
MovePosition(context.Length);
- JsonToken endToken = (context.Type == JTokenType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
+ JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
SetToken(endToken);
return true;
}
@@ -396,7 +396,7 @@ namespace Newtonsoft.Json.Bson
{
SetToken(JsonToken.StartObject);
- ContainerContext newContext = new ContainerContext(JTokenType.Object);
+ ContainerContext newContext = new ContainerContext(BsonType.Object);
PushContext(newContext);
newContext.Length = ReadInt32();
break;
@@ -405,7 +405,7 @@ namespace Newtonsoft.Json.Bson
{
SetToken(JsonToken.StartArray);
- ContainerContext newContext = new ContainerContext(JTokenType.Array);
+ ContainerContext newContext = new ContainerContext(BsonType.Array);
PushContext(newContext);
newContext.Length = ReadInt32();
break;
diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs
index 7fa0808..82940a6 100644
--- a/Src/Newtonsoft.Json/Bson/BsonWriter.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs
@@ -24,6 +24,8 @@
#endregion
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json.Utilities;
@@ -32,246 +34,132 @@ using System.Globalization;
namespace Newtonsoft.Json.Bson
{
- /// <summary>
- /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data.
- /// </summary>
- public class BsonWriter : JTokenWriter
+ internal abstract class BsonToken
{
- private static readonly Encoding Encoding = Encoding.UTF8;
+ public abstract BsonType Type { get; }
+ public BsonToken Parent { get; set; }
+ public int CalculatedSize { get; set; }
+ }
- private readonly BinaryWriter _writer;
+ internal class BsonObject : BsonToken, IEnumerable<BsonProperty>
+ {
+ private readonly List<BsonProperty> _children = new List<BsonProperty>();
- private byte[] _largeByteBuffer;
- private int _maxChars;
+ public void Add(string name, BsonToken token)
+ {
+ _children.Add(new BsonProperty { Name = new BsonString(name, false), Value = token });
+ token.Parent = this;
+ }
- /// <summary>
- /// Initializes a new instance of the <see cref="BsonWriter"/> class.
- /// </summary>
- /// <param name="stream">The stream.</param>
- public BsonWriter(Stream stream)
+ public override BsonType Type
{
- ValidationUtils.ArgumentNotNull(stream, "stream");
- _writer = new BinaryWriter(stream);
+ get { return BsonType.Object; }
}
- /// <summary>
- /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream.
- /// </summary>
- public override void Flush()
+ public IEnumerator<BsonProperty> GetEnumerator()
{
- _writer.Flush();
+ return _children.GetEnumerator();
}
- private void WriteToken(JToken t)
+ IEnumerator IEnumerable.GetEnumerator()
{
- switch (t.Type)
- {
- case JTokenType.Object:
- {
- int size = CalculateSize(t);
- _writer.Write(size);
- foreach (JProperty property in t)
- {
- _writer.Write((sbyte)GetTypeNumber(property.Value));
- WriteString(property.Name, false);
- WriteToken(property.Value);
- }
- _writer.Write((byte)0);
- }
- break;
- case JTokenType.Array:
- {
- int size = CalculateSize(t);
- _writer.Write(size);
- int index = 0;
- foreach (JToken c in t)
- {
- _writer.Write((sbyte)GetTypeNumber(c));
- WriteString(index.ToString(CultureInfo.InvariantCulture), false);
- WriteToken(c);
- index++;
- }
- _writer.Write((byte)0);
- }
- break;
- case JTokenType.Integer:
- _writer.Write(Convert.ToInt32(((JValue)t).Value, CultureInfo.InvariantCulture));
- break;
- case JTokenType.Float:
- _writer.Write(Convert.ToDouble(((JValue)t).Value, CultureInfo.InvariantCulture));
- break;
- case JTokenType.String:
- WriteString((string)t, true);
- break;
- case JTokenType.Boolean:
- _writer.Write((bool)t);
- break;
- case JTokenType.Null:
- case JTokenType.Undefined:
- break;
- case JTokenType.Date:
- DateTime dateTime = (DateTime)t;
- dateTime = dateTime.ToUniversalTime();
- long ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
- _writer.Write(ticks);
- break;
- case JTokenType.Bytes:
- byte[] data = (byte[])t;
- _writer.Write(data.Length);
- _writer.Write((byte)BsonBinaryType.Data);
- _writer.Write(data);
- break;
- case JTokenType.Raw:
- // hacky
- JRaw r = (JRaw)t;
- _writer.Write((byte[])r.Value);
- break;
- default:
- throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
- }
+ return GetEnumerator();
}
+ }
+
+ internal class BsonArray : BsonToken, IEnumerable<BsonToken>
+ {
+ private readonly List<BsonToken> _children = new List<BsonToken>();
- private void WriteString(string s, bool includeLength)
+ public void Add(BsonToken token)
{
- int byteCount = Encoding.GetByteCount(s);
+ _children.Add(token);
+ token.Parent = this;
+ }
- if (includeLength)
- _writer.Write(CalculateSizeWithLength(byteCount, false));
+ public override BsonType Type
+ {
+ get { return BsonType.Array; }
+ }
- if (_largeByteBuffer == null)
- {
- _largeByteBuffer = new byte[256];
- _maxChars = 256 / Encoding.GetMaxByteCount(1);
- }
- if (byteCount <= 256)
- {
- Encoding.GetBytes(s, 0, s.Length, _largeByteBuffer, 0);
- _writer.Write(_largeByteBuffer, 0, byteCount);
- }
- else
- {
- int charCount;
- int totalCharsWritten = 0;
- for (int i = s.Length; i > 0; i -= charCount)
- {
- charCount = (i > _maxChars) ? _maxChars : i;
- int count = Encoding.GetBytes(s, totalCharsWritten, charCount, _largeByteBuffer, 0);
- _writer.Write(_largeByteBuffer, 0, count);
- totalCharsWritten += charCount;
- }
- }
+ public IEnumerator<BsonToken> GetEnumerator()
+ {
+ return _children.GetEnumerator();
+ }
- _writer.Write((byte)0);
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
}
+ }
- private BsonType GetTypeNumber(JToken t)
+ internal class BsonValue : BsonToken
+ {
+ private object _value;
+ private BsonType _type;
+
+ public BsonValue(object value, BsonType type)
{
- switch (t.Type)
- {
- case JTokenType.Object:
- return BsonType.Object;
- case JTokenType.Array:
- return BsonType.Array;
- case JTokenType.Integer:
- return BsonType.Integer;
- case JTokenType.Float:
- return BsonType.Number;
- case JTokenType.String:
- return BsonType.String;
- case JTokenType.Boolean:
- return BsonType.Boolean;
- case JTokenType.Null:
- case JTokenType.Undefined:
- return BsonType.Null;
- case JTokenType.Date:
- return BsonType.Date;
- case JTokenType.Bytes:
- return BsonType.Binary;
- case JTokenType.Raw:
- // hacky
- return BsonType.Oid;
- default:
- throw new ArgumentOutOfRangeException("t", "Unexpected token when resolving JSON type to BSON type: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
- }
+ _value = value;
+ _type = type;
}
- private int CalculateSize(string s)
+ public object Value
{
- return Encoding.GetByteCount(s) + 1;
+ get { return _value; }
}
- private int CalculateSizeWithLength(string s, bool includeSize)
+ public override BsonType Type
{
- return CalculateSizeWithLength(Encoding.GetByteCount(s), includeSize);
+ get { return _type; }
}
+ }
+
+ internal class BsonString : BsonValue
+ {
+ public int ByteCount { get; set; }
+ public bool IncludeLength { get; set; }
- private int CalculateSizeWithLength(int stringByteCount, bool includeSize)
+ public BsonString(object value, bool includeLength)
+ : base(value, BsonType.String)
{
- int baseSize = (includeSize)
- ? 5 // size bytes + terminator
- : 1; // terminator
+ IncludeLength = includeLength;
+ }
+ }
+
+ internal class BsonProperty
+ {
+ public BsonString Name { get; set; }
+ public BsonToken Value { get; set; }
+ }
- return baseSize + stringByteCount;
+ /// <summary>
+ /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data.
+ /// </summary>
+ public class BsonWriter : JsonWriter
+ {
+ private readonly BsonBinaryWriter _writer;
+
+ private BsonToken _root;
+ private BsonToken _parent;
+ private string _propertyName;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BsonWriter"/> class.
+ /// </summary>
+ /// <param name="stream">The stream.</param>
+ public BsonWriter(Stream stream)
+ {
+ ValidationUtils.ArgumentNotNull(stream, "stream");
+ _writer = new BsonBinaryWriter(stream);
}
- private int CalculateSize(JToken t)
+ /// <summary>
+ /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream.
+ /// </summary>
+ public override void Flush()
{
- switch (t.Type)
- {
- case JTokenType.Object:
- {
- int bases = 4;
- foreach (JProperty p in t)
- {
- bases += CalculateSize(p);
- }
- bases += 1;
- return bases;
- }
- case JTokenType.Array:
- {
- int bases = 4;
- int index = 0;
- foreach (JToken c in t)
- {
- bases += 1;
- bases += CalculateSize(index.ToString(CultureInfo.InvariantCulture));
- bases += CalculateSize(c);
- index++;
- }
- bases += 1;
- return bases;
- }
- case JTokenType.Property:
- JProperty property = (JProperty)t;
- int ss = 1;
- ss += CalculateSize(property.Name);
- ss += CalculateSize(property.Value);
- return ss;
- case JTokenType.Integer:
- return 4;
- case JTokenType.Float:
- return 8;
- case JTokenType.String:
- string s = (string)t;
-
- return CalculateSizeWithLength(s, true);
- case JTokenType.Boolean:
- return 1;
- case JTokenType.Null:
- case JTokenType.Undefined:
- return 0;
- case JTokenType.Date:
- return 8;
- case JTokenType.Bytes:
- byte[] data = (byte[])t;
- return 4 + 1 + data.Length;
- case JTokenType.Raw:
- // hacky
- return 12;
- default:
- throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
- }
+ _writer.Flush();
}
/// <summary>
@@ -281,10 +169,11 @@ namespace Newtonsoft.Json.Bson
protected override void WriteEnd(JsonToken token)
{
base.WriteEnd(token);
+ RemoveParent();
if (Top == 0)
{
- WriteToken(Token);
+ _writer.WriteToken(_root);
}
}
@@ -337,7 +226,269 @@ namespace Newtonsoft.Json.Bson
// hack to update the writer state
AutoComplete(JsonToken.Undefined);
- AddValue(new JRaw(value), JsonToken.Raw);
+ AddValue(value, BsonType.Oid);
+ }
+
+ /// <summary>
+ /// Writes the beginning of a Json array.
+ /// </summary>
+ public override void WriteStartArray()
+ {
+ base.WriteStartArray();
+
+ AddParent(new BsonArray());
+ }
+
+ /// <summary>
+ /// Writes the beginning of a Json object.
+ /// </summary>
+ public override void WriteStartObject()
+ {
+ base.WriteStartObject();
+
+ AddParent(new BsonObject());
+ }
+
+ public override void WritePropertyName(string name)
+ {
+ base.WritePropertyName(name);
+
+ _propertyName = name;
+ }
+
+ private void AddParent(BsonToken container)
+ {
+ AddToken(container);
+ _parent = container;
+ }
+
+ private void RemoveParent()
+ {
+ _parent = _parent.Parent;
+ }
+
+ private void AddValue(object value, BsonType type)
+ {
+ AddToken(new BsonValue(value, type));
+ }
+
+ internal void AddToken(BsonToken token)
+ {
+ if (_parent != null)
+ {
+ if (_parent is BsonObject)
+ {
+ ((BsonObject)_parent).Add(_propertyName, token);
+ _propertyName = null;
+ }
+ else
+ {
+ ((BsonArray)_parent).Add(token);
+ }
+ }
+ else
+ {
+ _parent = token;
+ _root = token;
+ }
+ }
+
+ #region WriteValue methods
+ /// <summary>
+ /// Writes a null value.
+ /// </summary>
+ public override void WriteNull()
+ {
+ base.WriteNull();
+ AddValue(null, BsonType.Null);
+ }
+
+ /// <summary>
+ /// Writes an undefined value.
+ /// </summary>
+ public override void WriteUndefined()
+ {
+ base.WriteUndefined();
+ AddValue(null, BsonType.Undefined);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="String"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="String"/> value to write.</param>
+ public override void WriteValue(string value)
+ {
+ base.WriteValue(value);
+ AddToken(new BsonString(value ?? string.Empty, true));
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int32"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int32"/> value to write.</param>
+ public override void WriteValue(int value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt32"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt32"/> value to write.</param>
+ public override void WriteValue(uint value)
+ {
+ if (value > int.MaxValue)
+ throw new JsonWriterException("Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values.");
+
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int64"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int64"/> value to write.</param>
+ public override void WriteValue(long value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Long);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt64"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt64"/> value to write.</param>
+ public override void WriteValue(ulong value)
+ {
+ if (value > long.MaxValue)
+ throw new JsonWriterException("Value is too large to fit in a signed 64 bit integer. BSON does not support unsigned values.");
+
+ base.WriteValue(value);
+ AddValue(value, BsonType.Long);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Single"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Single"/> value to write.</param>
+ public override void WriteValue(float value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Double"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Double"/> value to write.</param>
+ public override void WriteValue(double value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Boolean"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Boolean"/> value to write.</param>
+ public override void WriteValue(bool value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Boolean);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int16"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int16"/> value to write.</param>
+ public override void WriteValue(short value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt16"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt16"/> value to write.</param>
+ public override void WriteValue(ushort value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Char"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Char"/> value to write.</param>
+ public override void WriteValue(char value)
+ {
+ base.WriteValue(value);
+ AddToken(new BsonString(value.ToString(), true));
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Byte"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Byte"/> value to write.</param>
+ public override void WriteValue(byte value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="SByte"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="SByte"/> value to write.</param>
+ public override void WriteValue(sbyte value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Decimal"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Decimal"/> value to write.</param>
+ public override void WriteValue(decimal value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="DateTime"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="DateTime"/> value to write.</param>
+ public override void WriteValue(DateTime value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Date);
+ }
+
+#if !PocketPC && !NET20
+ /// <summary>
+ /// Writes a <see cref="DateTimeOffset"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
+ public override void WriteValue(DateTimeOffset value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Date);
+ }
+#endif
+
+ /// <summary>
+ /// Writes a <see cref="T:Byte[]"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="T:Byte[]"/> value to write.</param>
+ public override void WriteValue(byte[] value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Binary);
}
+ #endregion
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
index fa2ebc7..04581ed 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
@@ -58,6 +58,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bson\BsonBinaryType.cs" />
+ <Compile Include="Bson\BsonBinaryWriter.cs" />
<Compile Include="Bson\BsonObjectId.cs" />
<Compile Include="Bson\BsonReader.cs" />
<Compile Include="Bson\BsonType.cs" />
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
index 204dadd..0021f90 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
@@ -78,6 +78,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bson\BsonBinaryType.cs" />
+ <Compile Include="Bson\BsonBinaryWriter.cs" />
<Compile Include="Bson\BsonObjectId.cs" />
<Compile Include="Bson\BsonReader.cs" />
<Compile Include="Bson\BsonType.cs" />
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
index 2b11fe3..4745f60 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
@@ -55,6 +55,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bson\BsonBinaryType.cs" />
+ <Compile Include="Bson\BsonBinaryWriter.cs" />
<Compile Include="Bson\BsonObjectId.cs" />
<Compile Include="Bson\BsonReader.cs" />
<Compile Include="Bson\BsonType.cs" />
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index 7b27b53..79acf22 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -81,6 +81,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bson\BsonBinaryType.cs" />
+ <Compile Include="Bson\BsonBinaryWriter.cs" />
<Compile Include="Bson\BsonReader.cs" />
<Compile Include="Bson\BsonType.cs" />
<Compile Include="Bson\BsonWriter.cs" />
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
index db8c47a..cd226ff 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Text;
using Newtonsoft.Json.Utilities;
using System.Globalization;
@@ -43,7 +44,13 @@ namespace Newtonsoft.Json.Serialization
int IEqualityComparer<object>.GetHashCode(object obj)
{
+#if !PocketPC
+ // put objects in a bucket based on their reference
+ return RuntimeHelpers.GetHashCode(obj);
+#else
+ // put all objects in the same bucket so ReferenceEquals is called on all
return -1;
+#endif
}
}
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
index 94353a4..43bafd8 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
@@ -199,15 +199,18 @@ namespace Newtonsoft.Json.Serialization
return;
}
- if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling))
+ if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling, contract))
return;
writer.WritePropertyName(propertyName);
SerializeValue(writer, memberValue, memberConverter, contract);
}
- private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling)
+ private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling, JsonContract contract)
{
+ if (value == null || contract is JsonPrimitiveContract)
+ return true;
+
if (SerializeStack.IndexOf(value) != -1)
{
switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling))
@@ -358,7 +361,7 @@ namespace Newtonsoft.Json.Serialization
}
else
{
- if (!CheckForCircularReference(value, null))
+ if (!CheckForCircularReference(value, null, contract))
return;
SerializeStack.Add(value);
@@ -416,7 +419,7 @@ namespace Newtonsoft.Json.Serialization
}
else
{
- if (!CheckForCircularReference(value, null))
+ if (!CheckForCircularReference(value, null, contract))
continue;
SerializeValue(writer, value, null, valueContract);
@@ -503,7 +506,7 @@ namespace Newtonsoft.Json.Serialization
}
else
{
- if (!CheckForCircularReference(value, null))
+ if (!CheckForCircularReference(value, null, contract))
continue;
writer.WritePropertyName(propertyName);
diff --git a/Src/Newtonsoft.Json/Utilities/MathUtils.cs b/Src/Newtonsoft.Json/Utilities/MathUtils.cs
index 0752083..db489eb 100644
--- a/Src/Newtonsoft.Json/Utilities/MathUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/MathUtils.cs
@@ -31,6 +31,17 @@ namespace Newtonsoft.Json.Utilities
{
internal class MathUtils
{
+ public static int IntLength(int i)
+ {
+ if (i < 0)
+ throw new ArgumentOutOfRangeException();
+
+ if (i == 0)
+ return 1;
+
+ return (int)Math.Floor(Math.Log10(i)) + 1;
+ }
+
public static int HexToInt(char h)
{
if ((h >= '0') && (h <= '9'))