mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 01:46:44 +08:00
933 lines
30 KiB
C#
933 lines
30 KiB
C#
//------------------------------------------------------------------------------
|
||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
// Github源代码仓库:https://github.com/RRQM
|
||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||
// 交流QQ群:234762506
|
||
// 感谢您的下载和使用
|
||
//------------------------------------------------------------------------------
|
||
//------------------------------------------------------------------------------
|
||
|
||
#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 License
|
||
|
||
using System;
|
||
|
||
#if HAVE_BIG_INTEGER
|
||
using System.Numerics;
|
||
#endif
|
||
|
||
using System.IO;
|
||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||
|
||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||
{
|
||
/// <summary>
|
||
/// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||
/// </summary>
|
||
public partial class JsonTextWriter : JsonWriter
|
||
{
|
||
private const int IndentCharBufferSize = 12;
|
||
private readonly TextWriter _writer;
|
||
private Base64Encoder _base64Encoder;
|
||
private char _indentChar;
|
||
private int _indentation;
|
||
private char _quoteChar;
|
||
private bool _quoteName;
|
||
private bool[] _charEscapeFlags;
|
||
private char[] _writeBuffer;
|
||
private IArrayPool<char> _arrayPool;
|
||
private char[] _indentChars;
|
||
|
||
private Base64Encoder Base64Encoder
|
||
{
|
||
get
|
||
{
|
||
if (this._base64Encoder == null)
|
||
{
|
||
this._base64Encoder = new Base64Encoder(this._writer);
|
||
}
|
||
|
||
return this._base64Encoder;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets the writer's character array pool.
|
||
/// </summary>
|
||
public IArrayPool<char> ArrayPool
|
||
{
|
||
get => this._arrayPool;
|
||
set
|
||
{
|
||
if (value == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(value));
|
||
}
|
||
|
||
this._arrayPool = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets how many <see cref="JsonTextWriter.IndentChar"/>s to write for each level in the hierarchy when <see cref="JsonWriter.Formatting"/> is set to <see cref="Formatting.Indented"/>.
|
||
/// </summary>
|
||
public int Indentation
|
||
{
|
||
get => this._indentation;
|
||
set
|
||
{
|
||
if (value < 0)
|
||
{
|
||
throw new ArgumentException("Indentation value must be greater than 0.");
|
||
}
|
||
|
||
this._indentation = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets which character to use to quote attribute values.
|
||
/// </summary>
|
||
public char QuoteChar
|
||
{
|
||
get => this._quoteChar;
|
||
set
|
||
{
|
||
if (value != '"' && value != '\'')
|
||
{
|
||
throw new ArgumentException(@"Invalid JavaScript string quote character. Valid quote characters are ' and "".");
|
||
}
|
||
|
||
this._quoteChar = value;
|
||
this.UpdateCharEscapeFlags();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets which character to use for indenting when <see cref="JsonWriter.Formatting"/> is set to <see cref="Formatting.Indented"/>.
|
||
/// </summary>
|
||
public char IndentChar
|
||
{
|
||
get => this._indentChar;
|
||
set
|
||
{
|
||
if (value != this._indentChar)
|
||
{
|
||
this._indentChar = value;
|
||
this._indentChars = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets a value indicating whether object names will be surrounded with quotes.
|
||
/// </summary>
|
||
public bool QuoteName
|
||
{
|
||
get => this._quoteName;
|
||
set => this._quoteName = value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Initializes a new instance of the <see cref="JsonTextWriter"/> class using the specified <see cref="TextWriter"/>.
|
||
/// </summary>
|
||
/// <param name="textWriter">The <see cref="TextWriter"/> to write to.</param>
|
||
public JsonTextWriter(TextWriter textWriter)
|
||
{
|
||
if (textWriter == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(textWriter));
|
||
}
|
||
|
||
this._writer = textWriter;
|
||
this._quoteChar = '"';
|
||
this._quoteName = true;
|
||
this._indentChar = ' ';
|
||
this._indentation = 2;
|
||
|
||
this.UpdateCharEscapeFlags();
|
||
|
||
#if HAVE_ASYNC
|
||
_safeAsync = GetType() == typeof(JsonTextWriter);
|
||
#endif
|
||
}
|
||
|
||
/// <summary>
|
||
/// Flushes whatever is in the buffer to the underlying <see cref="TextWriter"/> and also flushes the underlying <see cref="TextWriter"/>.
|
||
/// </summary>
|
||
public override void Flush()
|
||
{
|
||
this._writer.Flush();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Closes this writer.
|
||
/// If <see cref="JsonWriter.CloseOutput"/> is set to <c>true</c>, the underlying <see cref="TextWriter"/> is also closed.
|
||
/// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
|
||
/// </summary>
|
||
public override void Close()
|
||
{
|
||
base.Close();
|
||
|
||
this.CloseBufferAndWriter();
|
||
}
|
||
|
||
private void CloseBufferAndWriter()
|
||
{
|
||
if (this._writeBuffer != null)
|
||
{
|
||
BufferUtils.ReturnBuffer(this._arrayPool, this._writeBuffer);
|
||
this._writeBuffer = null;
|
||
}
|
||
|
||
if (this.CloseOutput)
|
||
{
|
||
#if HAVE_STREAM_READER_WRITER_CLOSE
|
||
_writer?.Close();
|
||
#else
|
||
this._writer?.Dispose();
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the beginning of a JSON object.
|
||
/// </summary>
|
||
public override void WriteStartObject()
|
||
{
|
||
this.InternalWriteStart(JsonToken.StartObject, JsonContainerType.Object);
|
||
|
||
this._writer.Write('{');
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the beginning of a JSON array.
|
||
/// </summary>
|
||
public override void WriteStartArray()
|
||
{
|
||
this.InternalWriteStart(JsonToken.StartArray, JsonContainerType.Array);
|
||
|
||
this._writer.Write('[');
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the start of a constructor with the given name.
|
||
/// </summary>
|
||
/// <param name="name">The name of the constructor.</param>
|
||
public override void WriteStartConstructor(string name)
|
||
{
|
||
this.InternalWriteStart(JsonToken.StartConstructor, JsonContainerType.Constructor);
|
||
|
||
this._writer.Write("new ");
|
||
this._writer.Write(name);
|
||
this._writer.Write('(');
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the specified end token.
|
||
/// </summary>
|
||
/// <param name="token">The end token to write.</param>
|
||
protected override void WriteEnd(JsonToken token)
|
||
{
|
||
switch (token)
|
||
{
|
||
case JsonToken.EndObject:
|
||
this._writer.Write('}');
|
||
break;
|
||
|
||
case JsonToken.EndArray:
|
||
this._writer.Write(']');
|
||
break;
|
||
|
||
case JsonToken.EndConstructor:
|
||
this._writer.Write(')');
|
||
break;
|
||
|
||
default:
|
||
throw JsonWriterException.Create(this, "Invalid JsonToken: " + token, null);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the property name of a name/value pair on a JSON object.
|
||
/// </summary>
|
||
/// <param name="name">The name of the property.</param>
|
||
public override void WritePropertyName(string name)
|
||
{
|
||
this.InternalWritePropertyName(name);
|
||
|
||
this.WriteEscapedString(name, this._quoteName);
|
||
|
||
this._writer.Write(':');
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the property name of a name/value pair on a JSON object.
|
||
/// </summary>
|
||
/// <param name="name">The name of the property.</param>
|
||
/// <param name="escape">A flag to indicate whether the text should be escaped when it is written as a JSON property name.</param>
|
||
public override void WritePropertyName(string name, bool escape)
|
||
{
|
||
this.InternalWritePropertyName(name);
|
||
|
||
if (escape)
|
||
{
|
||
this.WriteEscapedString(name, this._quoteName);
|
||
}
|
||
else
|
||
{
|
||
if (this._quoteName)
|
||
{
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
|
||
this._writer.Write(name);
|
||
|
||
if (this._quoteName)
|
||
{
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
}
|
||
|
||
this._writer.Write(':');
|
||
}
|
||
|
||
internal override void OnStringEscapeHandlingChanged()
|
||
{
|
||
this.UpdateCharEscapeFlags();
|
||
}
|
||
|
||
private void UpdateCharEscapeFlags()
|
||
{
|
||
this._charEscapeFlags = JavaScriptUtils.GetCharEscapeFlags(this.StringEscapeHandling, this._quoteChar);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes indent characters.
|
||
/// </summary>
|
||
protected override void WriteIndent()
|
||
{
|
||
// levels of indentation multiplied by the indent count
|
||
int currentIndentCount = this.Top * this._indentation;
|
||
|
||
int newLineLen = this.SetIndentChars();
|
||
|
||
this._writer.Write(this._indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize));
|
||
|
||
while ((currentIndentCount -= IndentCharBufferSize) > 0)
|
||
{
|
||
this._writer.Write(this._indentChars, newLineLen, Math.Min(currentIndentCount, IndentCharBufferSize));
|
||
}
|
||
}
|
||
|
||
private int SetIndentChars()
|
||
{
|
||
// Set _indentChars to be a newline followed by IndentCharBufferSize indent characters.
|
||
string writerNewLine = this._writer.NewLine;
|
||
int newLineLen = writerNewLine.Length;
|
||
bool match = this._indentChars != null && this._indentChars.Length == IndentCharBufferSize + newLineLen;
|
||
if (match)
|
||
{
|
||
for (int i = 0; i != newLineLen; ++i)
|
||
{
|
||
if (writerNewLine[i] != this._indentChars[i])
|
||
{
|
||
match = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!match)
|
||
{
|
||
// If we're here, either _indentChars hasn't been set yet, or _writer.NewLine
|
||
// has been changed, or _indentChar has been changed.
|
||
this._indentChars = (writerNewLine + new string(this._indentChar, IndentCharBufferSize)).ToCharArray();
|
||
}
|
||
|
||
return newLineLen;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the JSON value delimiter.
|
||
/// </summary>
|
||
protected override void WriteValueDelimiter()
|
||
{
|
||
this._writer.Write(',');
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes an indent space.
|
||
/// </summary>
|
||
protected override void WriteIndentSpace()
|
||
{
|
||
this._writer.Write(' ');
|
||
}
|
||
|
||
private void WriteValueInternal(string value, JsonToken token)
|
||
{
|
||
this._writer.Write(value);
|
||
}
|
||
|
||
#region WriteValue methods
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="Object"/> value.
|
||
/// An error will raised if the value cannot be written as a single JSON token.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||
public override void WriteValue(object value)
|
||
{
|
||
#if HAVE_BIG_INTEGER
|
||
if (value is BigInteger)
|
||
{
|
||
InternalWriteValue(JsonToken.Integer);
|
||
WriteValueInternal(((BigInteger)value).ToString(CultureInfo.InvariantCulture), JsonToken.String);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
base.WriteValue(value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes a null value.
|
||
/// </summary>
|
||
public override void WriteNull()
|
||
{
|
||
this.InternalWriteValue(JsonToken.Null);
|
||
this.WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes an undefined value.
|
||
/// </summary>
|
||
public override void WriteUndefined()
|
||
{
|
||
this.InternalWriteValue(JsonToken.Undefined);
|
||
this.WriteValueInternal(JsonConvert.Undefined, JsonToken.Undefined);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes raw JSON.
|
||
/// </summary>
|
||
/// <param name="json">The raw JSON to write.</param>
|
||
public override void WriteRaw(string json)
|
||
{
|
||
this.InternalWriteRaw();
|
||
|
||
this._writer.Write(json);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.String);
|
||
|
||
if (value == null)
|
||
{
|
||
this.WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||
}
|
||
else
|
||
{
|
||
this.WriteEscapedString(value, true);
|
||
}
|
||
}
|
||
|
||
private void WriteEscapedString(string value, bool quote)
|
||
{
|
||
this.EnsureWriteBuffer();
|
||
JavaScriptUtils.WriteEscapedJavaScriptString(this._writer, value, this._quoteChar, quote, this._charEscapeFlags, this.StringEscapeHandling, this._arrayPool, ref this._writeBuffer);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value, false);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Float);
|
||
this.WriteValueInternal(JsonConvert.ToString(value, this.FloatFormatHandling, this.QuoteChar, false), JsonToken.Float);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="Nullable{T}"/> of <see cref="Single"/> value.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Single"/> value to write.</param>
|
||
public override void WriteValue(float? value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
this.WriteNull();
|
||
}
|
||
else
|
||
{
|
||
this.InternalWriteValue(JsonToken.Float);
|
||
this.WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), this.FloatFormatHandling, this.QuoteChar, true), JsonToken.Float);
|
||
}
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Float);
|
||
this.WriteValueInternal(JsonConvert.ToString(value, this.FloatFormatHandling, this.QuoteChar, false), JsonToken.Float);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="Nullable{T}"/> of <see cref="Double"/> value.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Double"/> value to write.</param>
|
||
public override void WriteValue(double? value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
this.WriteNull();
|
||
}
|
||
else
|
||
{
|
||
this.InternalWriteValue(JsonToken.Float);
|
||
this.WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), this.FloatFormatHandling, this.QuoteChar, true), JsonToken.Float);
|
||
}
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Boolean);
|
||
this.WriteValueInternal(JsonConvert.ToString(value), JsonToken.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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.String);
|
||
this.WriteValueInternal(JsonConvert.ToString(value), JsonToken.String);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Integer);
|
||
this.WriteIntegerValue(value);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Float);
|
||
this.WriteValueInternal(JsonConvert.ToString(value), JsonToken.Float);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
this.InternalWriteValue(JsonToken.Date);
|
||
value = DateTimeUtils.EnsureDateTime(value, this.DateTimeZoneHandling);
|
||
|
||
if (string.IsNullOrEmpty(this.DateFormatString))
|
||
{
|
||
int length = this.WriteValueToBuffer(value);
|
||
|
||
this._writer.Write(this._writeBuffer, 0, length);
|
||
}
|
||
else
|
||
{
|
||
this._writer.Write(this._quoteChar);
|
||
this._writer.Write(value.ToString(this.DateFormatString, this.Culture));
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
}
|
||
|
||
private int WriteValueToBuffer(DateTime value)
|
||
{
|
||
this.EnsureWriteBuffer();
|
||
|
||
int pos = 0;
|
||
this._writeBuffer[pos++] = this._quoteChar;
|
||
pos = DateTimeUtils.WriteDateTimeString(this._writeBuffer, pos, value, null, value.Kind, this.DateFormatHandling);
|
||
this._writeBuffer[pos++] = this._quoteChar;
|
||
return pos;
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
if (value == null)
|
||
{
|
||
this.WriteNull();
|
||
}
|
||
else
|
||
{
|
||
this.InternalWriteValue(JsonToken.Bytes);
|
||
this._writer.Write(this._quoteChar);
|
||
this.Base64Encoder.Encode(value, 0, value.Length);
|
||
this.Base64Encoder.Flush();
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
}
|
||
|
||
#if HAVE_DATE_TIME_OFFSET
|
||
/// <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)
|
||
{
|
||
InternalWriteValue(JsonToken.Date);
|
||
|
||
if (string.IsNullOrEmpty(DateFormatString))
|
||
{
|
||
int length = WriteValueToBuffer(value);
|
||
|
||
_writer.Write(_writeBuffer, 0, length);
|
||
}
|
||
else
|
||
{
|
||
_writer.Write(_quoteChar);
|
||
_writer.Write(value.ToString(DateFormatString, Culture));
|
||
_writer.Write(_quoteChar);
|
||
}
|
||
}
|
||
|
||
private int WriteValueToBuffer(DateTimeOffset value)
|
||
{
|
||
EnsureWriteBuffer();
|
||
|
||
int pos = 0;
|
||
_writeBuffer[pos++] = _quoteChar;
|
||
pos = DateTimeUtils.WriteDateTimeString(_writeBuffer, pos, (DateFormatHandling == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, DateFormatHandling);
|
||
_writeBuffer[pos++] = _quoteChar;
|
||
return pos;
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="Guid"/> value.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||
public override void WriteValue(Guid value)
|
||
{
|
||
this.InternalWriteValue(JsonToken.String);
|
||
|
||
string text = null;
|
||
|
||
#if HAVE_CHAR_TO_STRING_WITH_CULTURE
|
||
text = value.ToString("D", CultureInfo.InvariantCulture);
|
||
#else
|
||
text = value.ToString("D");
|
||
#endif
|
||
|
||
this._writer.Write(this._quoteChar);
|
||
this._writer.Write(text);
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="TimeSpan"/> value.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||
public override void WriteValue(TimeSpan value)
|
||
{
|
||
this.InternalWriteValue(JsonToken.String);
|
||
|
||
string text;
|
||
#if !HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE
|
||
text = value.ToString();
|
||
#else
|
||
text = value.ToString(null, CultureInfo.InvariantCulture);
|
||
#endif
|
||
|
||
this._writer.Write(this._quoteChar);
|
||
this._writer.Write(text);
|
||
this._writer.Write(this._quoteChar);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes a <see cref="Uri"/> value.
|
||
/// </summary>
|
||
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||
public override void WriteValue(Uri value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
this.WriteNull();
|
||
}
|
||
else
|
||
{
|
||
this.InternalWriteValue(JsonToken.String);
|
||
this.WriteEscapedString(value.OriginalString, true);
|
||
}
|
||
}
|
||
|
||
#endregion WriteValue methods
|
||
|
||
/// <summary>
|
||
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||
/// </summary>
|
||
/// <param name="text">Text to place inside the comment.</param>
|
||
public override void WriteComment(string text)
|
||
{
|
||
this.InternalWriteComment();
|
||
|
||
this._writer.Write("/*");
|
||
this._writer.Write(text);
|
||
this._writer.Write("*/");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes the given white space.
|
||
/// </summary>
|
||
/// <param name="ws">The string of white space characters.</param>
|
||
public override void WriteWhitespace(string ws)
|
||
{
|
||
this.InternalWriteWhitespace(ws);
|
||
|
||
this._writer.Write(ws);
|
||
}
|
||
|
||
private void EnsureWriteBuffer()
|
||
{
|
||
if (this._writeBuffer == null)
|
||
{
|
||
// maximum buffer sized used when writing iso date
|
||
this._writeBuffer = BufferUtils.RentBuffer(this._arrayPool, 35);
|
||
}
|
||
}
|
||
|
||
private void WriteIntegerValue(long value)
|
||
{
|
||
if (value >= 0 && value <= 9)
|
||
{
|
||
this._writer.Write((char)('0' + value));
|
||
}
|
||
else
|
||
{
|
||
bool negative = value < 0;
|
||
this.WriteIntegerValue(negative ? (ulong)-value : (ulong)value, negative);
|
||
}
|
||
}
|
||
|
||
private void WriteIntegerValue(ulong value, bool negative)
|
||
{
|
||
if (!negative & value <= 9)
|
||
{
|
||
this._writer.Write((char)('0' + value));
|
||
}
|
||
else
|
||
{
|
||
int length = this.WriteNumberToBuffer(value, negative);
|
||
this._writer.Write(this._writeBuffer, 0, length);
|
||
}
|
||
}
|
||
|
||
private int WriteNumberToBuffer(ulong value, bool negative)
|
||
{
|
||
if (value <= uint.MaxValue)
|
||
{
|
||
// avoid the 64 bit division if possible
|
||
return this.WriteNumberToBuffer((uint)value, negative);
|
||
}
|
||
|
||
this.EnsureWriteBuffer();
|
||
|
||
int totalLength = MathUtils.IntLength(value);
|
||
|
||
if (negative)
|
||
{
|
||
totalLength++;
|
||
this._writeBuffer[0] = '-';
|
||
}
|
||
|
||
int index = totalLength;
|
||
|
||
do
|
||
{
|
||
ulong quotient = value / 10;
|
||
ulong digit = value - (quotient * 10);
|
||
this._writeBuffer[--index] = (char)('0' + digit);
|
||
value = quotient;
|
||
} while (value != 0);
|
||
|
||
return totalLength;
|
||
}
|
||
|
||
private void WriteIntegerValue(int value)
|
||
{
|
||
if (value >= 0 && value <= 9)
|
||
{
|
||
this._writer.Write((char)('0' + value));
|
||
}
|
||
else
|
||
{
|
||
bool negative = value < 0;
|
||
this.WriteIntegerValue(negative ? (uint)-value : (uint)value, negative);
|
||
}
|
||
}
|
||
|
||
private void WriteIntegerValue(uint value, bool negative)
|
||
{
|
||
if (!negative & value <= 9)
|
||
{
|
||
this._writer.Write((char)('0' + value));
|
||
}
|
||
else
|
||
{
|
||
int length = this.WriteNumberToBuffer(value, negative);
|
||
this._writer.Write(this._writeBuffer, 0, length);
|
||
}
|
||
}
|
||
|
||
private int WriteNumberToBuffer(uint value, bool negative)
|
||
{
|
||
this.EnsureWriteBuffer();
|
||
|
||
int totalLength = MathUtils.IntLength(value);
|
||
|
||
if (negative)
|
||
{
|
||
totalLength++;
|
||
this._writeBuffer[0] = '-';
|
||
}
|
||
|
||
int index = totalLength;
|
||
|
||
do
|
||
{
|
||
uint quotient = value / 10;
|
||
uint digit = value - (quotient * 10);
|
||
this._writeBuffer[--index] = (char)('0' + digit);
|
||
value = quotient;
|
||
} while (value != 0);
|
||
|
||
return totalLength;
|
||
}
|
||
}
|
||
} |