/// <summary> /// Returns a character array to the pool. /// </summary> /// <param name="bufferPool">The character pool.</param> /// <param name="buffer">The character array should be returned.</param> public static void ReturnToBuffer(ICharArrayPool bufferPool, char[] buffer) { if (bufferPool != null) { bufferPool.Return(buffer); } }
/// <summary> /// Writes the string value with special characters escaped. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputString">Input string value.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="bufferPool">Array pool for renting a buffer.</param> internal static void WriteEscapedJsonStringValue( TextWriter writer, string inputString, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool bufferPool) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(inputString != null, "The string value must not be null."); int firstIndex; if (!JsonValueUtils.CheckIfStringHasSpecialChars(inputString, stringEscapeOption, out firstIndex)) { writer.Write(inputString); } else { int inputStringLength = inputString.Length; Debug.Assert(firstIndex < inputStringLength, "First index of the special character should be within the string"); buffer.Value = BufferUtils.InitializeBufferIfRequired(bufferPool, buffer.Value); int bufferLength = buffer.Value.Length; int bufferIndex = 0; int currentIndex = 0; // Let's copy and flush strings up to the first index of the special char while (currentIndex < firstIndex) { int subStrLength = firstIndex - currentIndex; Debug.Assert(subStrLength > 0, "SubStrLength should be greater than 0 always"); // If the first index of the special character is larger than the buffer length, // flush everything to the buffer first and reset the buffer to the next chunk. // Otherwise copy to the buffer and go on from there. if (subStrLength >= bufferLength) { inputString.CopyTo(currentIndex, buffer.Value, 0, bufferLength); writer.Write(buffer.Value, 0, bufferLength); currentIndex += bufferLength; } else { WriteSubstringToBuffer(inputString, ref currentIndex, buffer.Value, ref bufferIndex, subStrLength); } } // start writing escaped strings WriteEscapedStringToBuffer(writer, inputString, ref currentIndex, buffer.Value, ref bufferIndex, stringEscapeOption); // write any remaining chars to the writer if (bufferIndex > 0) { writer.Write(buffer.Value, 0, bufferIndex); } } }
/// <summary> /// Checks if the buffer is not initialized and if initialized returns the same buffer or creates a new one. /// </summary> /// <param name="bufferPool">The character pool.</param> /// <param name="buffer">The buffer to verify</param> /// <returns>The initialized buffer.</returns> public static char[] InitializeBufferIfRequired(ICharArrayPool bufferPool, char[] buffer) { if (buffer != null) { return(buffer); } return(RentFromBuffer(bufferPool, BufferLength)); }
/// <summary> /// A TextWriter for writing properly escaped JSON text. /// </summary> /// <param name="textWriter">The underlying TextWriter used when writing JSON</param> /// <param name="buffer">Buffer used when converting binary values.</param> /// <param name="bufferPool">Buffer pool used for renting a buffer.</param> internal ODataJsonTextWriter(TextWriter textWriter, Ref <char[]> wrappedBuffer, ICharArrayPool bufferPool) : base(System.Globalization.CultureInfo.InvariantCulture) { ExceptionUtils.CheckArgumentNotNull(textWriter, "textWriter"); this.textWriter = textWriter; this.wrappedBuffer = wrappedBuffer; this.bufferPool = bufferPool; }
/// <summary> /// Dispose the writer /// </summary> public void Dispose() { if (this.ArrayPool != null && this.buffer != null) { BufferUtils.ReturnToBuffer(this.ArrayPool, this.buffer); this.ArrayPool = null; this.buffer = null; } }
/// <summary> /// Rents a character array from the pool. /// </summary> /// <param name="bufferPool">The character pool.</param> /// <param name="minSize">The min required size of the character array.</param> /// <returns>The character array from the pool.</returns> public static char[] RentFromBuffer(ICharArrayPool bufferPool, int minSize) { if (bufferPool == null) { return(new char[minSize]); } char[] buffer = bufferPool.Rent(minSize); return(buffer); }
/// <summary> /// Returns the string value with special characters escaped. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputString">Input string value.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data</param> /// <param name="bufferPool">Array pool for renting a buffer.</param> internal static void WriteEscapedJsonString( TextWriter writer, string inputString, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool bufferPool = null) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(inputString != null, "The string value must not be null."); writer.Write(JsonConstants.QuoteCharacter); WriteEscapedJsonStringValue(writer, inputString, stringEscapeOption, buffer, bufferPool); writer.Write(JsonConstants.QuoteCharacter); }
/// <summary> /// Rents a character array from the pool. /// </summary> /// <param name="bufferPool">The character pool.</param> /// <param name="minSize">The min required size of the character array.</param> /// <returns>The character array from the pool.</returns> public static char[] RentFromBuffer(ICharArrayPool bufferPool, int minSize) { if (bufferPool == null) { return(new char[minSize]); } char[] buffer = bufferPool.Rent(minSize); if (buffer == null || buffer.Length < minSize) { throw new ODataException(Strings.BufferUtils_InvalidBufferOrSize(minSize)); } return(buffer); }
/// <summary> /// Returns the string value with special characters escaped. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputString">Input string value.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="bufferPool">Array pool for renting a buffer.</param> internal static async Task WriteEscapedJsonStringAsync( this TextWriter writer, string inputString, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool bufferPool = null) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(inputString != null, "The string value must not be null."); await writer.WriteAsync(JsonConstants.QuoteCharacter).ConfigureAwait(false); await writer.WriteEscapedJsonStringValueAsync(inputString, stringEscapeOption, buffer, bufferPool).ConfigureAwait(false); await writer.WriteAsync(JsonConstants.QuoteCharacter).ConfigureAwait(false); }
/// <summary> /// Write a string value. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">String value to be written.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="arrayPool">Array pool for renting a buffer.</param> internal static Task WriteValueAsync( this TextWriter writer, string value, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool arrayPool = null) { Debug.Assert(writer != null, "writer != null"); if (value == null) { return(writer.WriteAsync(JsonConstants.JsonNullLiteral)); } else { return(writer.WriteEscapedJsonStringAsync(value, stringEscapeOption, buffer, arrayPool)); } }
/// <summary> /// Write a string value. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">String value to be written.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="arrayPool">Array pool for renting a buffer.</param> internal static void WriteValue( TextWriter writer, string value, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool arrayPool = null) { Debug.Assert(writer != null, "writer != null"); if (value == null) { writer.Write(JsonConstants.JsonNullLiteral); } else { JsonValueUtils.WriteEscapedJsonString(writer, value, stringEscapeOption, buffer, arrayPool); } }
/// <summary> /// Escapes and writes a character array to a writer. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputArray">Character array to write.</param> /// <param name="inputArrayOffset">How many characters to skip in the input array.</param> /// <param name="inputArrayCount">How many characters to write from the input array.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="bufferPool">Character buffer pool.</param> internal static void WriteEscapedCharArray( TextWriter writer, char[] inputArray, int inputArrayOffset, int inputArrayCount, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool bufferPool) { int bufferIndex = 0; buffer.Value = BufferUtils.InitializeBufferIfRequired(bufferPool, buffer.Value); WriteEscapedCharArrayToBuffer(writer, inputArray, ref inputArrayOffset, inputArrayCount, buffer.Value, ref bufferIndex, stringEscapeOption); // write remaining bytes in buffer if (bufferIndex > 0) { writer.Write(buffer.Value, 0, bufferIndex); } }
/// <summary> /// Escapes and writes a character array to a writer. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputArray">Character array to write.</param> /// <param name="inputArrayOffset">How many characters to skip in the input array.</param> /// <param name="inputArrayCount">How many characters to write from the input array.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="bufferPool">Character buffer pool.</param> internal static async Task WriteEscapedCharArrayAsync( this TextWriter writer, char[] inputArray, int inputArrayOffset, int inputArrayCount, ODataStringEscapeOption stringEscapeOption, Ref <char[]> buffer, ICharArrayPool bufferPool) { int bufferIndex = 0; buffer.Value = BufferUtils.InitializeBufferIfRequired(bufferPool, buffer.Value); WriteEscapedCharArrayToBuffer(writer, inputArray, ref inputArrayOffset, inputArrayCount, buffer.Value, ref bufferIndex, stringEscapeOption); // write remaining bytes in buffer if (bufferIndex > 0) { await writer.WriteAsync(buffer.Value, 0, bufferIndex).ConfigureAwait(false); } }
/// <summary> /// Constructor. /// </summary> /// <param name="writer">A Textwriter for writing to the stream.</param> /// <param name="streamingBuffer">A temporary buffer to use when converting binary values.</param> /// <param name="bufferPool">Array pool for renting a buffer.</param> public ODataBinaryStreamWriter(TextWriter writer, Ref <char[]> wrappedBuffer, ICharArrayPool bufferPool) { this.Writer = writer; this.wrappedBuffer = wrappedBuffer; this.bufferPool = bufferPool; }
/// <summary> /// Write a byte array. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Byte array to be written.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="arrayPool">Array pool for renting a buffer.</param> internal static async Task WriteBinaryStringAsync(this TextWriter writer, byte[] value, Ref <char[]> buffer, ICharArrayPool arrayPool) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(value != null, "The value must not be null."); buffer.Value = BufferUtils.InitializeBufferIfRequired(arrayPool, buffer.Value); Debug.Assert(buffer.Value != null); int bufferLength = buffer.Value.Length; // Try to hold base64 string as much as possible in one converting. int bufferByteSize = bufferLength * 3 / 4; for (int offsetIn = 0; offsetIn < value.Length; offsetIn += bufferByteSize) { int count = WriteByteArrayToBuffer(value, offsetIn, buffer.Value, bufferByteSize); await writer.WriteAsync(buffer.Value, 0, count).ConfigureAwait(false); } }
/// <summary> /// Escapes and writes a character array to a writer. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputArray">Character array to write.</param> /// <param name="inputArrayOffset">How many characters to skip in the input array.</param> /// <param name="inputArrayCount">How many characters to write from the input array.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="bufferPool">Character buffer pool.</param> internal static void WriteEscapedCharArray(TextWriter writer, char[] inputArray, int inputArrayOffset, int inputArrayCount, ODataStringEscapeOption stringEscapeOption, ref char[] buffer, ICharArrayPool bufferPool) { int bufferIndex = 0; buffer = BufferUtils.InitializeBufferIfRequired(bufferPool, buffer); for (; inputArrayOffset < inputArrayCount; inputArrayOffset++) { bufferIndex = EscapeAndWriteCharToBuffer(writer, inputArray[inputArrayOffset], buffer, bufferIndex, stringEscapeOption); } // write remaining bytes in buffer if (bufferIndex > 0) { writer.Write(buffer, 0, bufferIndex); } }
/// <summary> /// Write a byte array. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Byte array to be written.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> /// <param name="arrayPool">Array pool for renting a buffer.</param> internal static async Task WriteValueAsync(this TextWriter writer, byte[] value, Ref <char[]> buffer, ICharArrayPool arrayPool = null) { Debug.Assert(writer != null, "writer != null"); if (value == null) { await writer.WriteAsync(JsonConstants.JsonNullLiteral).ConfigureAwait(false); } else { await writer.WriteAsync(JsonConstants.QuoteCharacter).ConfigureAwait(false); await writer.WriteBinaryStringAsync(value, buffer, arrayPool).ConfigureAwait(false); await writer.WriteAsync(JsonConstants.QuoteCharacter).ConfigureAwait(false); } }
/// <summary> /// Write a byte array. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Byte array to be written.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> internal static void WriteValue(TextWriter writer, byte[] value, ref char[] buffer, ICharArrayPool arrayPool = null) { Debug.Assert(writer != null, "writer != null"); if (value == null) { writer.Write(JsonConstants.JsonNullLiteral); } else { writer.Write(JsonConstants.QuoteCharacter); WriteBinaryString(writer, value, ref buffer, arrayPool); writer.Write(JsonConstants.QuoteCharacter); } }
/// <summary> /// Constructor. /// </summary> /// <param name="writer">A Textwriter for writing to the stream.</param> /// <param name="streamingBuffer">A temporary buffer to use when converting binary values.</param> /// <param name="bufferPool">Array pool for renting a buffer.</param> public ODataBinaryStreamWriter(TextWriter writer, ref char[] streamingBuffer, ICharArrayPool bufferPool) { this.Writer = writer; this.streamingBuffer = streamingBuffer; this.bufferPool = bufferPool; }
/// <summary> /// Write a byte array. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Byte array to be written.</param> /// <param name="buffer">Char buffer to use for streaming data.</param> internal static void WriteBinaryString(TextWriter writer, byte[] value, ref char[] buffer, ICharArrayPool arrayPool) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(value != null, "The value must not be null."); buffer = BufferUtils.InitializeBufferIfRequired(arrayPool, buffer); Debug.Assert(buffer != null); int bufferLength = buffer.Length; // Try to hold base64 string as much as possible in one converting. int bufferByteSize = bufferLength * 3 / 4; for (int offsetIn = 0; offsetIn < value.Length; offsetIn += bufferByteSize) { int length = bufferByteSize; if (offsetIn + length > value.Length) { length = value.Length - offsetIn; } int output = Convert.ToBase64CharArray(value, offsetIn, length, buffer, 0); writer.Write(buffer, 0, output); } }
/// <summary> /// Returns the string value with special characters escaped. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="inputString">Input string value.</param> /// <param name="stringEscapeOption">The string escape option.</param> /// <param name="buffer">Char buffer to use for streaming data</param> internal static void WriteEscapedJsonString(TextWriter writer, string inputString, ODataStringEscapeOption stringEscapeOption, ref char[] buffer, ICharArrayPool bufferPool = null) { Debug.Assert(writer != null, "writer != null"); Debug.Assert(inputString != null, "The string value must not be null."); writer.Write(JsonConstants.QuoteCharacter); int firstIndex; if (!JsonValueUtils.CheckIfStringHasSpecialChars(inputString, stringEscapeOption, out firstIndex)) { writer.Write(inputString); } else { int inputStringLength = inputString.Length; Debug.Assert(firstIndex < inputStringLength, "First index of the special character should be within the string"); buffer = BufferUtils.InitializeBufferIfRequired(bufferPool, buffer); int bufferLength = buffer.Length; int bufferIndex = 0; int currentIndex = 0; // Let's copy and flush strings up to the first index of the special char while (currentIndex < firstIndex) { int subStrLength = firstIndex - currentIndex; Debug.Assert(subStrLength > 0, "SubStrLength should be greater than 0 always"); // If the first index of the special character is larger than the buffer length, // flush everything to the buffer first and reset the buffer to the next chunk. // Otherwise copy to the buffer and go on from there. if (subStrLength >= bufferLength) { inputString.CopyTo(currentIndex, buffer, 0, bufferLength); writer.Write(buffer, 0, bufferLength); currentIndex += bufferLength; } else { inputString.CopyTo(currentIndex, buffer, 0, subStrLength); bufferIndex = subStrLength; currentIndex += subStrLength; } } for (; currentIndex < inputStringLength; currentIndex++) { char c = inputString[currentIndex]; string escapedString = null; if (stringEscapeOption == ODataStringEscapeOption.EscapeNonAscii || c <= 0x7F) { escapedString = JsonValueUtils.SpecialCharToEscapedStringMap[c]; } // Append the unhandled characters (that do not require special treament) // to the buffer. if (escapedString == null) { buffer[bufferIndex] = c; bufferIndex++; } else { // Okay, an unhandled character was deteced. // First lets check if we can fit it in the existing buffer, if not, // flush the current buffer and reset. Add the escaped string to the buffer // and continue. int escapedStringLength = escapedString.Length; Debug.Assert(escapedStringLength <= bufferLength, "Buffer should be larger than the escaped string"); if ((bufferIndex + escapedStringLength) > bufferLength) { writer.Write(buffer, 0, bufferIndex); bufferIndex = 0; } escapedString.CopyTo(0, buffer, bufferIndex, escapedStringLength); bufferIndex += escapedStringLength; } if (bufferIndex >= bufferLength) { Debug.Assert(bufferIndex == bufferLength, "We should never encounter a situation where the buffer index is greater than the buffer length"); writer.Write(buffer, 0, bufferIndex); bufferIndex = 0; } } if (bufferIndex > 0) { writer.Write(buffer, 0, bufferIndex); } } writer.Write(JsonConstants.QuoteCharacter); }