Browse Source

Added support for escapable strings

voice-allocs
RogueException 7 years ago
parent
commit
a4dbef6725
2 changed files with 101 additions and 13 deletions
  1. +1
    -1
      src/Discord.Net.Serialization/_corefxlab/System.Text.Json/System/Text/Json/JsonReader.cs
  2. +100
    -12
      src/Discord.Net.Serialization/_corefxlab/System.Text.Json/System/Text/Json/JsonWriter.cs

+ 1
- 1
src/Discord.Net.Serialization/_corefxlab/System.Text.Json/System/Text/Json/JsonReader.cs View File

@@ -720,7 +720,7 @@ namespace System.Text.Json
int doubleSize = _working.Free.Count * 2;
int minNewSize = _working.Capacity + segmentLength;
int newSize = minNewSize > doubleSize ? minNewSize : doubleSize;
var newArray = ArrayPool<byte>.Shared.Rent(minNewSize + _working.Count);
var newArray = ArrayPool<byte>.Shared.Rent(newSize);
var oldArray = _working.Resize(newArray);
ArrayPool<byte>.Shared.Return(oldArray);
}


+ 100
- 12
src/Discord.Net.Serialization/_corefxlab/System.Text.Json/System/Text/Json/JsonWriter.cs View File

@@ -1,6 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Buffers;
using System.Collections.Sequences;
using System.Runtime.CompilerServices;
using System.Text.Formatting;

@@ -14,6 +16,7 @@ namespace System.Text.Json

int _indent;
bool _firstItem;
ResizableArray<byte> _working;

// These next 2 properties are used to check for whether we can take the fast path
// for invariant UTF-8 or UTF-16 processing. Otherwise, we need to go through the
@@ -33,6 +36,7 @@ namespace System.Text.Json

_indent = -1;
_firstItem = true;
_working = default;

var symbolTable = output.SymbolTable;
if (symbolTable == SymbolTable.InvariantUtf8)
@@ -356,7 +360,6 @@ namespace System.Text.Json
private void WriteQuotedString(string value)
{
WriteControl(JsonConstants.Quote);
// TODO: We need to handle escaping.
Write(value.AsSpan());
WriteControl(JsonConstants.Quote);
}
@@ -423,25 +426,110 @@ namespace System.Text.Json

if (UseFastUtf8)
{
Span<byte> destination = _output.Buffer;
bool hasBackslashes = false;
for (int i = 0; i < value.Length; i++)
{
char c = value[i];
if (c == '\\' || c == '"')
{
hasBackslashes = true;
break;
}
}

while (true)
if (!hasBackslashes) //Fast path
{
var status = Encoders.Utf16.ToUtf8(source, destination, out int consumed, out int written);
if (status == Buffers.TransformationStatus.Done)
Span<byte> destination = _output.Buffer;

while (true)
{
_output.Advance(written);
return;
var status = Encoders.Utf16.ToUtf8(source, destination, out int consumed, out int written);
if (status == Buffers.TransformationStatus.Done)
{
_output.Advance(written);
return;
}
if (status == Buffers.TransformationStatus.DestinationTooSmall)
{
destination = EnsureBuffer();
continue;
}

// This is a failure due to bad input. This shouldn't happen under normal circumstances.
throw new FormatException();
}
}
else //Slow path
{
if (_working.Items == null)
_working = new ResizableArray<byte>(ArrayPool<byte>.Shared.Rent(128));
else
_working.Clear();

if (status == Buffers.TransformationStatus.DestinationTooSmall)
while (true)
{
destination = EnsureBuffer();
continue;
int outputWritten = 0;
var workingBuffer = _working.Free.AsSpan();
var status = Encoders.Utf16.ToUtf8(source, _working.Free, out int consumed, out int workingWritten);
_working.Count += workingWritten;
if (status == Buffers.TransformationStatus.Done)
{
int start = 0;
int workingLength = _output.Buffer.Length;
for (int i = 0; i <= workingWritten; i++)
{
byte c = i != workingWritten ? _working[i] : (byte)0;

//Search for next backslash/quote or end of string
bool isEscapable = c == JsonConstants.Backslash || c == JsonConstants.Quote;
if (isEscapable || i == workingWritten)
{
int segmentLength = i - start;

//Ensure buffer length
var destination = _output.Buffer;
if (destination.Length <= segmentLength)
{
workingLength += segmentLength;
_output.Enlarge(workingLength);
destination = _output.Buffer;
}

//Write data before escapable char
if (segmentLength != 0)
{
workingBuffer.Slice(start, segmentLength).CopyTo(destination); //TODO: Optimize w/ ref ptrs
start = i;
outputWritten += segmentLength;
_output.Advance(segmentLength);
}

//Write backslash
if (isEscapable)
{
destination[segmentLength] = JsonConstants.Backslash;
outputWritten++;
_output.Advance(1);
}
}
}
return;
}
if (status == Buffers.TransformationStatus.DestinationTooSmall)
{
int newSize = _working.Free.Count * 2;
var newArray = ArrayPool<byte>.Shared.Rent(newSize);
var oldArray = _working.Resize(newArray);
ArrayPool<byte>.Shared.Return(oldArray);

workingBuffer = _working.Free.AsSpan();
continue;
}

// This is a failure due to bad input. This shouldn't happen under normal circumstances.
throw new FormatException();
}

// This is a failure due to bad input. This shouldn't happen under normal circumstances.
throw new FormatException();
}
}
else if (UseFastUtf16)


Loading…
Cancel
Save