2021-03-29 14:54:12 +08:00
#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.Generic ;
using System.Globalization ;
#if HAVE_BIG_INTEGER
using System.Numerics ;
# endif
using System.Text ;
using System.IO ;
using System.Xml ;
using LC.Newtonsoft.Json.Utilities ;
namespace LC.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 ;
2021-03-30 10:54:25 +08:00
private Base64Encoder _base64Encoder ;
2021-03-29 14:54:12 +08:00
private char _indentChar ;
private int _indentation ;
private char _quoteChar ;
private bool _quoteName ;
2021-03-30 10:54:25 +08:00
private bool [ ] _charEscapeFlags ;
private char [ ] _writeBuffer ;
private IArrayPool < char > _arrayPool ;
private char [ ] _indentChars ;
2021-03-29 14:54:12 +08:00
private Base64Encoder Base64Encoder
{
get
{
if ( _base64Encoder = = null )
{
_base64Encoder = new Base64Encoder ( _writer ) ;
}
return _base64Encoder ;
}
}
/// <summary>
/// Gets or sets the writer's character array pool.
/// </summary>
2021-03-30 10:54:25 +08:00
public IArrayPool < char > ArrayPool
2021-03-29 14:54:12 +08:00
{
get = > _arrayPool ;
set
{
if ( value = = null )
{
throw new ArgumentNullException ( nameof ( value ) ) ;
}
_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 = > _indentation ;
set
{
if ( value < 0 )
{
throw new ArgumentException ( "Indentation value must be greater than 0." ) ;
}
_indentation = value ;
}
}
/// <summary>
/// Gets or sets which character to use to quote attribute values.
/// </summary>
public char QuoteChar
{
get = > _quoteChar ;
set
{
if ( value ! = '"' & & value ! = '\'' )
{
throw new ArgumentException ( @"Invalid JavaScript string quote character. Valid quote characters are ' and ""." ) ;
}
_quoteChar = value ;
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 = > _indentChar ;
set
{
if ( value ! = _indentChar )
{
_indentChar = value ;
_indentChars = null ;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether object names will be surrounded with quotes.
/// </summary>
public bool QuoteName
{
get = > _quoteName ;
set = > _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 ) ) ;
}
_writer = textWriter ;
_quoteChar = '"' ;
_quoteName = true ;
_indentChar = ' ' ;
_indentation = 2 ;
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 ( )
{
_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 ( ) ;
CloseBufferAndWriter ( ) ;
}
private void CloseBufferAndWriter ( )
{
if ( _writeBuffer ! = null )
{
BufferUtils . ReturnBuffer ( _arrayPool , _writeBuffer ) ;
_writeBuffer = null ;
}
if ( CloseOutput )
{
#if HAVE_STREAM_READER_WRITER_CLOSE
_writer ? . Close ( ) ;
# else
_writer ? . Dispose ( ) ;
# endif
}
}
/// <summary>
/// Writes the beginning of a JSON object.
/// </summary>
public override void WriteStartObject ( )
{
InternalWriteStart ( JsonToken . StartObject , JsonContainerType . Object ) ;
_writer . Write ( '{' ) ;
}
/// <summary>
/// Writes the beginning of a JSON array.
/// </summary>
public override void WriteStartArray ( )
{
InternalWriteStart ( JsonToken . StartArray , JsonContainerType . Array ) ;
_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 )
{
InternalWriteStart ( JsonToken . StartConstructor , JsonContainerType . Constructor ) ;
_writer . Write ( "new " ) ;
_writer . Write ( name ) ;
_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 :
_writer . Write ( '}' ) ;
break ;
case JsonToken . EndArray :
_writer . Write ( ']' ) ;
break ;
case JsonToken . EndConstructor :
_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 )
{
InternalWritePropertyName ( name ) ;
WriteEscapedString ( name , _quoteName ) ;
_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 )
{
InternalWritePropertyName ( name ) ;
if ( escape )
{
WriteEscapedString ( name , _quoteName ) ;
}
else
{
if ( _quoteName )
{
_writer . Write ( _quoteChar ) ;
}
_writer . Write ( name ) ;
if ( _quoteName )
{
_writer . Write ( _quoteChar ) ;
}
}
_writer . Write ( ':' ) ;
}
internal override void OnStringEscapeHandlingChanged ( )
{
UpdateCharEscapeFlags ( ) ;
}
private void UpdateCharEscapeFlags ( )
{
_charEscapeFlags = JavaScriptUtils . GetCharEscapeFlags ( StringEscapeHandling , _quoteChar ) ;
}
/// <summary>
/// Writes indent characters.
/// </summary>
protected override void WriteIndent ( )
{
// levels of indentation multiplied by the indent count
int currentIndentCount = Top * _indentation ;
int newLineLen = SetIndentChars ( ) ;
_writer . Write ( _indentChars , 0 , newLineLen + Math . Min ( currentIndentCount , IndentCharBufferSize ) ) ;
while ( ( currentIndentCount - = IndentCharBufferSize ) > 0 )
{
_writer . Write ( _indentChars , newLineLen , Math . Min ( currentIndentCount , IndentCharBufferSize ) ) ;
}
}
private int SetIndentChars ( )
{
// Set _indentChars to be a newline followed by IndentCharBufferSize indent characters.
string writerNewLine = _writer . NewLine ;
int newLineLen = writerNewLine . Length ;
bool match = _indentChars ! = null & & _indentChars . Length = = IndentCharBufferSize + newLineLen ;
if ( match )
{
for ( int i = 0 ; i ! = newLineLen ; + + i )
{
2021-03-30 10:54:25 +08:00
if ( writerNewLine [ i ] ! = _indentChars [ i ] )
2021-03-29 14:54:12 +08:00
{
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.
_indentChars = ( writerNewLine + new string ( _indentChar , IndentCharBufferSize ) ) . ToCharArray ( ) ;
}
return newLineLen ;
}
/// <summary>
/// Writes the JSON value delimiter.
/// </summary>
protected override void WriteValueDelimiter ( )
{
_writer . Write ( ',' ) ;
}
/// <summary>
/// Writes an indent space.
/// </summary>
protected override void WriteIndentSpace ( )
{
_writer . Write ( ' ' ) ;
}
private void WriteValueInternal ( string value , JsonToken token )
{
_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>
2021-03-30 10:54:25 +08:00
public override void WriteValue ( object value )
2021-03-29 14:54:12 +08:00
{
#if HAVE_BIG_INTEGER
if ( value is BigInteger i )
{
InternalWriteValue ( JsonToken . Integer ) ;
WriteValueInternal ( i . ToString ( CultureInfo . InvariantCulture ) , JsonToken . String ) ;
}
else
# endif
{
base . WriteValue ( value ) ;
}
}
/// <summary>
/// Writes a null value.
/// </summary>
public override void WriteNull ( )
{
InternalWriteValue ( JsonToken . Null ) ;
WriteValueInternal ( JsonConvert . Null , JsonToken . Null ) ;
}
/// <summary>
/// Writes an undefined value.
/// </summary>
public override void WriteUndefined ( )
{
InternalWriteValue ( JsonToken . Undefined ) ;
WriteValueInternal ( JsonConvert . Undefined , JsonToken . Undefined ) ;
}
/// <summary>
/// Writes raw JSON.
/// </summary>
/// <param name="json">The raw JSON to write.</param>
2021-03-30 10:54:25 +08:00
public override void WriteRaw ( string json )
2021-03-29 14:54:12 +08:00
{
InternalWriteRaw ( ) ;
_writer . Write ( json ) ;
}
/// <summary>
/// Writes a <see cref="String"/> value.
/// </summary>
/// <param name="value">The <see cref="String"/> value to write.</param>
2021-03-30 10:54:25 +08:00
public override void WriteValue ( string value )
2021-03-29 14:54:12 +08:00
{
InternalWriteValue ( JsonToken . String ) ;
if ( value = = null )
{
WriteValueInternal ( JsonConvert . Null , JsonToken . Null ) ;
}
else
{
WriteEscapedString ( value , true ) ;
}
}
private void WriteEscapedString ( string value , bool quote )
{
EnsureWriteBuffer ( ) ;
2021-03-30 10:54:25 +08:00
JavaScriptUtils . WriteEscapedJavaScriptString ( _writer , value , _quoteChar , quote , _charEscapeFlags , StringEscapeHandling , _arrayPool , ref _writeBuffer ) ;
2021-03-29 14:54:12 +08:00
}
/// <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 )
{
InternalWriteValue ( JsonToken . Integer ) ;
WriteIntegerValue ( value ) ;
}
/// <summary>
/// Writes a <see cref="UInt32"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue ( uint value )
{
InternalWriteValue ( JsonToken . Integer ) ;
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 )
{
InternalWriteValue ( JsonToken . Integer ) ;
WriteIntegerValue ( value ) ;
}
/// <summary>
/// Writes a <see cref="UInt64"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue ( ulong value )
{
InternalWriteValue ( JsonToken . Integer ) ;
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 )
{
InternalWriteValue ( JsonToken . Float ) ;
WriteValueInternal ( JsonConvert . ToString ( value , FloatFormatHandling , 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 )
{
WriteNull ( ) ;
}
else
{
InternalWriteValue ( JsonToken . Float ) ;
WriteValueInternal ( JsonConvert . ToString ( value . GetValueOrDefault ( ) , FloatFormatHandling , 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 )
{
InternalWriteValue ( JsonToken . Float ) ;
WriteValueInternal ( JsonConvert . ToString ( value , FloatFormatHandling , 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 )
{
WriteNull ( ) ;
}
else
{
InternalWriteValue ( JsonToken . Float ) ;
WriteValueInternal ( JsonConvert . ToString ( value . GetValueOrDefault ( ) , FloatFormatHandling , 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 )
{
InternalWriteValue ( JsonToken . Boolean ) ;
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 )
{
InternalWriteValue ( JsonToken . Integer ) ;
WriteIntegerValue ( value ) ;
}
/// <summary>
/// Writes a <see cref="UInt16"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue ( ushort value )
{
InternalWriteValue ( JsonToken . Integer ) ;
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 )
{
InternalWriteValue ( JsonToken . String ) ;
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 )
{
InternalWriteValue ( JsonToken . Integer ) ;
WriteIntegerValue ( value ) ;
}
/// <summary>
/// Writes a <see cref="SByte"/> value.
/// </summary>
/// <param name="value">The <see cref="SByte"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue ( sbyte value )
{
InternalWriteValue ( JsonToken . Integer ) ;
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 )
{
InternalWriteValue ( JsonToken . Float ) ;
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 )
{
InternalWriteValue ( JsonToken . Date ) ;
value = DateTimeUtils . EnsureDateTime ( value , DateTimeZoneHandling ) ;
2021-03-30 10:54:25 +08:00
if ( string . IsNullOrEmpty ( DateFormatString ) )
2021-03-29 14:54:12 +08:00
{
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 ( DateTime value )
{
EnsureWriteBuffer ( ) ;
int pos = 0 ;
_writeBuffer [ pos + + ] = _quoteChar ;
pos = DateTimeUtils . WriteDateTimeString ( _writeBuffer , pos , value , null , value . Kind , DateFormatHandling ) ;
_writeBuffer [ pos + + ] = _quoteChar ;
return pos ;
}
/// <summary>
/// Writes a <see cref="Byte"/>[] value.
/// </summary>
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
2021-03-30 10:54:25 +08:00
public override void WriteValue ( byte [ ] value )
2021-03-29 14:54:12 +08:00
{
if ( value = = null )
{
WriteNull ( ) ;
}
else
{
InternalWriteValue ( JsonToken . Bytes ) ;
_writer . Write ( _quoteChar ) ;
Base64Encoder . Encode ( value , 0 , value . Length ) ;
Base64Encoder . Flush ( ) ;
_writer . Write ( _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 ) ;
2021-03-30 10:54:25 +08:00
if ( string . IsNullOrEmpty ( DateFormatString ) )
2021-03-29 14:54:12 +08:00
{
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 )
{
InternalWriteValue ( JsonToken . String ) ;
2021-03-30 10:54:25 +08:00
string text = null ;
2021-03-29 14:54:12 +08:00
#if HAVE_CHAR_TO_STRING_WITH_CULTURE
text = value . ToString ( "D" , CultureInfo . InvariantCulture ) ;
# else
text = value . ToString ( "D" ) ;
# endif
_writer . Write ( _quoteChar ) ;
_writer . Write ( text ) ;
_writer . Write ( _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 )
{
InternalWriteValue ( JsonToken . String ) ;
string text ;
#if !HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE
text = value . ToString ( ) ;
# else
text = value . ToString ( null , CultureInfo . InvariantCulture ) ;
# endif
_writer . Write ( _quoteChar ) ;
_writer . Write ( text ) ;
_writer . Write ( _quoteChar ) ;
}
/// <summary>
/// Writes a <see cref="Uri"/> value.
/// </summary>
/// <param name="value">The <see cref="Uri"/> value to write.</param>
2021-03-30 10:54:25 +08:00
public override void WriteValue ( Uri value )
2021-03-29 14:54:12 +08:00
{
if ( value = = null )
{
WriteNull ( ) ;
}
else
{
InternalWriteValue ( JsonToken . String ) ;
WriteEscapedString ( value . OriginalString , true ) ;
}
}
# endregion
/// <summary>
/// Writes a comment <c>/*...*/</c> containing the specified text.
/// </summary>
/// <param name="text">Text to place inside the comment.</param>
2021-03-30 10:54:25 +08:00
public override void WriteComment ( string text )
2021-03-29 14:54:12 +08:00
{
InternalWriteComment ( ) ;
_writer . Write ( "/*" ) ;
_writer . Write ( text ) ;
_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 )
{
InternalWriteWhitespace ( ws ) ;
_writer . Write ( ws ) ;
}
private void EnsureWriteBuffer ( )
{
if ( _writeBuffer = = null )
{
// maximum buffer sized used when writing iso date
_writeBuffer = BufferUtils . RentBuffer ( _arrayPool , 35 ) ;
}
}
private void WriteIntegerValue ( long value )
{
if ( value > = 0 & & value < = 9 )
{
_writer . Write ( ( char ) ( '0' + value ) ) ;
}
else
{
bool negative = value < 0 ;
WriteIntegerValue ( negative ? ( ulong ) - value : ( ulong ) value , negative ) ;
}
}
private void WriteIntegerValue ( ulong value , bool negative )
{
if ( ! negative & value < = 9 )
{
_writer . Write ( ( char ) ( '0' + value ) ) ;
}
else
{
int length = WriteNumberToBuffer ( value , negative ) ;
_writer . Write ( _writeBuffer , 0 , length ) ;
}
}
private int WriteNumberToBuffer ( ulong value , bool negative )
{
if ( value < = uint . MaxValue )
{
// avoid the 64 bit division if possible
return WriteNumberToBuffer ( ( uint ) value , negative ) ;
}
EnsureWriteBuffer ( ) ;
int totalLength = MathUtils . IntLength ( value ) ;
if ( negative )
{
totalLength + + ;
_writeBuffer [ 0 ] = '-' ;
}
int index = totalLength ;
do
{
ulong quotient = value / 10 ;
ulong digit = value - ( quotient * 10 ) ;
_writeBuffer [ - - index ] = ( char ) ( '0' + digit ) ;
value = quotient ;
} while ( value ! = 0 ) ;
return totalLength ;
}
private void WriteIntegerValue ( int value )
{
if ( value > = 0 & & value < = 9 )
{
_writer . Write ( ( char ) ( '0' + value ) ) ;
}
else
{
bool negative = value < 0 ;
WriteIntegerValue ( negative ? ( uint ) - value : ( uint ) value , negative ) ;
}
}
private void WriteIntegerValue ( uint value , bool negative )
{
if ( ! negative & value < = 9 )
{
_writer . Write ( ( char ) ( '0' + value ) ) ;
}
else
{
int length = WriteNumberToBuffer ( value , negative ) ;
_writer . Write ( _writeBuffer , 0 , length ) ;
}
}
private int WriteNumberToBuffer ( uint value , bool negative )
{
EnsureWriteBuffer ( ) ;
int totalLength = MathUtils . IntLength ( value ) ;
if ( negative )
{
totalLength + + ;
_writeBuffer [ 0 ] = '-' ;
}
int index = totalLength ;
do
{
uint quotient = value / 10 ;
uint digit = value - ( quotient * 10 ) ;
_writeBuffer [ - - index ] = ( char ) ( '0' + digit ) ;
value = quotient ;
} while ( value ! = 0 ) ;
return totalLength ;
}
}
}