#region License // Copyright (c) 2007 James Newton-King // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #endregion using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; using System.Globalization; namespace Newtonsoft.Json.Bson { /// /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. /// public class BsonWriter : JsonWriter { private readonly BsonBinaryWriter _writer; private BsonToken _root; private BsonToken _parent; private string _propertyName; /// /// Gets or sets the used when writing values to BSON. /// When set to no conversion will occur. /// /// The used when writing values to BSON. public DateTimeKind DateTimeKindHandling { get { return _writer.DateTimeKindHandling; } set { _writer.DateTimeKindHandling = value; } } /// /// Initializes a new instance of the class. /// /// The stream. public BsonWriter(Stream stream) { ValidationUtils.ArgumentNotNull(stream, "stream"); _writer = new BsonBinaryWriter(stream); } /// /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. /// public override void Flush() { _writer.Flush(); } /// /// Writes the end. /// /// The token. protected override void WriteEnd(JsonToken token) { base.WriteEnd(token); RemoveParent(); if (Top == 0) { _writer.WriteToken(_root); } } /// /// Writes out a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. public override void WriteComment(string text) { throw new JsonWriterException("Cannot write JSON comment as BSON."); } /// /// Writes the start of a constructor with the given name. /// /// The name of the constructor. public override void WriteStartConstructor(string name) { throw new JsonWriterException("Cannot write JSON constructor as BSON."); } /// /// Writes raw JSON. /// /// The raw JSON to write. public override void WriteRaw(string json) { throw new JsonWriterException("Cannot write raw JSON as BSON."); } /// /// Writes raw JSON where a value is expected and updates the writer's state. /// /// The raw JSON to write. public override void WriteRawValue(string json) { throw new JsonWriterException("Cannot write raw JSON as BSON."); } /// /// Writes the beginning of a Json array. /// public override void WriteStartArray() { base.WriteStartArray(); AddParent(new BsonArray()); } /// /// Writes the beginning of a Json object. /// public override void WriteStartObject() { base.WriteStartObject(); AddParent(new BsonObject()); } /// /// Writes the property name of a name/value pair on a Json object. /// /// The name of the property. public override void WritePropertyName(string name) { base.WritePropertyName(name); _propertyName = name; } /// /// Closes this stream and the underlying stream. /// public override void Close() { base.Close(); if (CloseOutput && _writer != null) _writer.Close(); } 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 { if (token.Type != BsonType.Object && token.Type != BsonType.Array) throw new JsonWriterException("Error writing {0} value. BSON must start with an Object or Array.".FormatWith(CultureInfo.InvariantCulture, token.Type)); _parent = token; _root = token; } } #region WriteValue methods /// /// Writes a null value. /// public override void WriteNull() { base.WriteNull(); AddValue(null, BsonType.Null); } /// /// Writes an undefined value. /// public override void WriteUndefined() { base.WriteUndefined(); AddValue(null, BsonType.Undefined); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(string value) { base.WriteValue(value); if (value == null) AddValue(null, BsonType.Null); else AddToken(new BsonString(value, true)); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(int value) { base.WriteValue(value); AddValue(value, BsonType.Integer); } /// /// Writes a value. /// /// The value to write. [CLSCompliant(false)] 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); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(long value) { base.WriteValue(value); AddValue(value, BsonType.Long); } /// /// Writes a value. /// /// The value to write. [CLSCompliant(false)] 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); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(float value) { base.WriteValue(value); AddValue(value, BsonType.Number); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(double value) { base.WriteValue(value); AddValue(value, BsonType.Number); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(bool value) { base.WriteValue(value); AddValue(value, BsonType.Boolean); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(short value) { base.WriteValue(value); AddValue(value, BsonType.Integer); } /// /// Writes a value. /// /// The value to write. [CLSCompliant(false)] public override void WriteValue(ushort value) { base.WriteValue(value); AddValue(value, BsonType.Integer); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(char value) { base.WriteValue(value); AddToken(new BsonString(value.ToString(), true)); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(byte value) { base.WriteValue(value); AddValue(value, BsonType.Integer); } /// /// Writes a value. /// /// The value to write. [CLSCompliant(false)] public override void WriteValue(sbyte value) { base.WriteValue(value); AddValue(value, BsonType.Integer); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(decimal value) { base.WriteValue(value); AddValue(value, BsonType.Number); } /// /// Writes a value. /// /// The value to write. public override void WriteValue(DateTime value) { base.WriteValue(value); AddValue(value, BsonType.Date); } #if !PocketPC && !NET20 /// /// Writes a value. /// /// The value to write. public override void WriteValue(DateTimeOffset value) { base.WriteValue(value); AddValue(value, BsonType.Date); } #endif /// /// Writes a value. /// /// The value to write. public override void WriteValue(byte[] value) { base.WriteValue(value); AddValue(value, BsonType.Binary); } #endregion /// /// Writes a value that represents a BSON object id. /// /// public void WriteObjectId(byte[] value) { ValidationUtils.ArgumentNotNull(value, "value"); if (value.Length != 12) throw new Exception("An object id must be 12 bytes"); // hack to update the writer state AutoComplete(JsonToken.Undefined); AddValue(value, BsonType.Oid); } /// /// Writes a BSON regex. /// /// The regex pattern. /// The regex options. public void WriteRegex(string pattern, string options) { ValidationUtils.ArgumentNotNull(pattern, "pattern"); // hack to update the writer state AutoComplete(JsonToken.Undefined); AddToken(new BsonRegex(pattern, options)); } } }