private void ValidatePropertyNameAndDepth(ref ReadOnlySpan <byte> propertyName) { // TODO: Use throw helper with proper error messages if (propertyName.Length > JsonConstants.MaxTokenSize || CurrentDepth >= JsonConstants.MaxWriterDepth) { JsonThrowHelper.ThrowJsonWriterOrArgumentException(propertyName, _currentDepth); } }
public static void ValidateValue(ref ReadOnlySpan <char> value) { // TODO: Use throw helper with proper error messages if (value.Length > JsonConstants.MaxCharacterTokenSize) { JsonThrowHelper.ThrowArgumentException("Argument too large."); } }
public static void ValidatePropertyAndValue(ReadOnlySpan <char> propertyName, ReadOnlySpan <byte> value) { // TODO: Use throw helper with proper error messages if (propertyName.Length > JsonConstants.MaxCharacterTokenSize || value.Length > JsonConstants.MaxTokenSize) { JsonThrowHelper.ThrowArgumentException(propertyName, value); } }
public static void ValidateProperty(ref ReadOnlySpan <byte> propertyName) { // TODO: Use throw helper with proper error messages if (propertyName.Length > JsonConstants.MaxTokenSize) { JsonThrowHelper.ThrowArgumentException("Argument too large."); } }
public StackRow Peek() { if (_topOfStack > _stackSpace.Length - StackRow.Size) { JsonThrowHelper.ThrowInvalidOperationException(); } return(MemoryMarshal.Read <StackRow>(_stackSpace.Slice(_topOfStack))); }
private bool TryWriteAttributeUtf8(ReadOnlySpan <byte> nameSpanByte, ReadOnlySpan <byte> valueSpanByte) { int idx = 0; try { Span <byte> byteBuffer = _bufferWriter.Buffer; if (_indent < 0) { byteBuffer[idx++] = JsonConstants.ListSeperator; } byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpanByte, byteBuffer.Slice(idx), out int consumed, out int written); if (status == OperationStatus.DestinationTooSmall) { return(false); } if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } Debug.Assert(consumed == nameSpanByte.Length); idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; byteBuffer[idx++] = JsonConstants.Quote; status = Encodings.Utf16.ToUtf8(valueSpanByte, byteBuffer.Slice(idx), out consumed, out written); if (status == OperationStatus.DestinationTooSmall) { return(false); } if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } Debug.Assert(consumed == valueSpanByte.Length); idx += written; byteBuffer[idx++] = JsonConstants.Quote; } catch (IndexOutOfRangeException) { return(false); } _bufferWriter.Advance(idx); _indent |= 1 << 31; return(true); }
public void Flush(bool isFinalBlock = true) { //TODO: Fix exception message and check other potential conditions for invalid end. if (isFinalBlock && !_writerOptions.SkipValidation && CurrentDepth != 0) { JsonThrowHelper.ThrowJsonWriterException("Invalid end of JSON."); } Flush(); }
public void Dispose() { if (_pool == null) { JsonThrowHelper.ThrowInvalidOperationException("Only root object can (and should) be disposed."); } _pool.Return(_rentedBuffer); Span = Span <byte> .Empty; Index = 0; }
public JsonObject this[Utf8Span name] { get { if (TryGetValue(name, out JsonObject value)) { return(value); } JsonThrowHelper.ThrowKeyNotFoundException(); return(default);
public bool TryGetValue(Utf8Span propertyName, out JsonObject value) { DbRow record = _database.Get(); if (record.JsonType != JsonType.StartObject) { JsonThrowHelper.ThrowInvalidOperationException(); } for (int i = DbRow.Size; i < _database.Length; i += DbRow.Size) { record = _database.Get(i); if (!record.IsSimpleValue) { if (record.SizeOrLength != 0) { i += DbRow.Size * record.NumberOfRows; } continue; } Debug.Assert(record.JsonType == JsonType.String); int startIndex = i + DbRow.Size; DbRow nextRecord = _database.Get(startIndex); if (_jsonData.Slice(record.Location, record.SizeOrLength).SequenceEqual(propertyName.Bytes)) { int length = DbRow.Size; if (!nextRecord.IsSimpleValue) { if (nextRecord.SizeOrLength != 0) { length += DbRow.Size * nextRecord.NumberOfRows; } } value = CreateJsonObject(startIndex, length); return(true); } // Skip primitive value since we are looking for keys if (nextRecord.IsSimpleValue) { i += DbRow.Size; } } value = default; return(false); }
private void WriteAttributeUtf8(ReadOnlySpan <byte> nameSpanByte, ReadOnlySpan <byte> valueSpanByte, int bytesNeeded) { Span <byte> byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) { byteBuffer[idx++] = JsonConstants.ListSeperator; } if (_prettyPrint) { idx += AddNewLineAndIndentation(byteBuffer.Slice(idx)); } byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpanByte, byteBuffer.Slice(idx), out int consumed, out int written); Debug.Assert(consumed == nameSpanByte.Length); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; if (_prettyPrint) { byteBuffer[idx++] = JsonConstants.Space; } byteBuffer[idx++] = JsonConstants.Quote; status = Encodings.Utf16.ToUtf8(valueSpanByte, byteBuffer.Slice(idx), out consumed, out written); Debug.Assert(consumed == valueSpanByte.Length); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } idx += written; byteBuffer[idx++] = JsonConstants.Quote; _bufferWriter.Advance(idx); _firstItem = false; }
private void ValidateStart(ref ReadOnlySpan <byte> propertyName, byte token) { if (JsonWriterHelper.IndexOfAnyEscape(propertyName) != -1) { JsonThrowHelper.ThrowJsonWriterException("Property name must be properly escaped."); //TODO: Fix message } if (!_inObject) { Debug.Assert(_tokenType != JsonTokenType.StartObject); JsonThrowHelper.ThrowJsonWriterException(token); //TODO: Add resouce message } UpdateBitStackOnStart(token); }
public Utf8JsonReaderStream(Stream jsonStream) { if (!jsonStream.CanRead || !jsonStream.CanSeek) JsonThrowHelper.ThrowArgumentException("Stream must be readable and seekable."); _pooledArray = ArrayPool<byte>.Shared.Rent(FirstSegmentSize); int numberOfBytes = jsonStream.Read(_pooledArray, 0, FirstSegmentSize); _buffer = _pooledArray.AsSpan(0, numberOfBytes); _stream = jsonStream; _isFinalBlock = numberOfBytes == 0; _jsonReader = new Utf8JsonReader(_buffer, _isFinalBlock); _consumed = 0; }
public bool TryGetValue(string propertyName, out JsonObject value) { var record = GetRecord(0); if (record.Length == 0) { JsonThrowHelper.ThrowKeyNotFoundException(); } if (record.Type != JsonValueType.Object) { JsonThrowHelper.ThrowInvalidOperationException(); } for (int i = DbRow.Size; i < _database.Length; i += DbRow.Size) { record = MemoryMarshal.Read <DbRow>(_database.Slice(i)); if (!record.IsSimpleValue) { i += record.Length * DbRow.Size; continue; } if (new Utf8Span(_jsonData.Slice(record.Location, record.Length)) == propertyName) { int newStart = i + DbRow.Size; int newEnd = newStart + DbRow.Size; record = MemoryMarshal.Read <DbRow>(_database.Slice(newStart)); if (!record.IsSimpleValue) { newEnd = newEnd + DbRow.Size * record.Length; } value = new JsonObject(_jsonData, _database.Slice(newStart, newEnd - newStart)); return(true); } var valueType = MemoryMarshal.Read <JsonValueType>(_database.Slice(i + DbRow.Size + 8)); if (valueType != JsonValueType.Object && valueType != JsonValueType.Array) { i += DbRow.Size; } } value = default; return(false); }
private bool TryWriteAttributeUtf8(ReadOnlySpan <byte> nameSpanByte, long value) { int idx = 0; try { Span <byte> byteBuffer = _bufferWriter.Buffer; if (_indent < 0) { byteBuffer[idx++] = JsonConstants.ListSeperator; } byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpanByte, byteBuffer.Slice(idx), out int consumed, out int written); if (status == OperationStatus.DestinationTooSmall) { return(false); } if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } Debug.Assert(consumed == nameSpanByte.Length); idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; if (!JsonWriterHelper.TryFormatInt64Default(value, byteBuffer.Slice(idx), out int bytesWritten)) { return(false); } // Using Utf8Formatter with default StandardFormat is roughly 30% slower (17 ns versus 12 ns) // See: https://github.com/dotnet/corefx/issues/25425 //if (!Utf8Formatter.TryFormat(value, byteBuffer.Slice(idx), out int bytesWritten)) return false; idx += bytesWritten; } catch (IndexOutOfRangeException) { return(false); } _bufferWriter.Advance(idx); _indent |= 1 << 31; return(true); }
private void ValidateWritingValue() { if (_inObject) { Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray); JsonThrowHelper.ThrowJsonWriterException(_tokenType); //TODO: Add resource message } else { if (!_isNotPrimitive && _tokenType != JsonTokenType.None) { JsonThrowHelper.ThrowJsonWriterException(_tokenType); //TODO: Add resource message } } }
private void WriteCommentFormattedWithEncodingValue(ref ReadOnlySpan <byte> escapedValue) { int indent = Indentation; // This is guaranteed not to overflow. Debug.Assert(int.MaxValue - escapedValue.Length / 2 * 3 - 4 - JsonWriterHelper.NewLineUtf8.Length - indent >= 0); // Calculated based on the following: '\r\n /*encoded value*/' int bytesNeeded = escapedValue.Length / 2 * 3 + 4 + JsonWriterHelper.NewLineUtf8.Length + indent; if (_tokenType == JsonTokenType.None) { bytesNeeded -= JsonWriterHelper.NewLineUtf8.Length; } Ensure(bytesNeeded); Span <byte> byteBuffer = _buffer; int idx = 0; if (_tokenType != JsonTokenType.None) { WriteNewLine(ref byteBuffer, ref idx); } idx += JsonWriterHelper.WriteIndentation(byteBuffer.Slice(idx, indent)); byteBuffer[idx++] = JsonConstants.Solidus; byteBuffer[idx++] = (byte)'*'; // TODO: Replace with JsonConstants.Asterisk OperationStatus status = Encodings.Utf16.ToUtf8(escapedValue, byteBuffer.Slice(idx), out int consumed, out int written); Debug.Assert(status != OperationStatus.DestinationTooSmall); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowArgumentExceptionInvalidUtf8String(); } Debug.Assert(consumed == escapedValue.Length); idx += written; byteBuffer[idx++] = (byte)'*'; // TODO: Replace with JsonConstants.Asterisk byteBuffer[idx++] = JsonConstants.Solidus; Advance(idx); }
/// <summary> /// Read the next token from the data buffer. /// </summary> /// <returns>True if the token was read successfully, else false.</returns> public bool Read() { if (UseFastUtf8) { return(ReadUtf8()); } else if (UseFastUtf16) { return(ReadUtf16()); } else { JsonThrowHelper.ThrowNotImplementedException(); return(false); } }
private void ValidateStart(byte token) { if (_inObject) { Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray); JsonThrowHelper.ThrowJsonWriterException(token, _tokenType); } else { Debug.Assert(_tokenType != JsonTokenType.StartObject); if (_tokenType != JsonTokenType.None && !_isNotPrimitive) { JsonThrowHelper.ThrowJsonWriterException(token, _tokenType); } } }
private void WriteStartUtf8Pretty(ReadOnlySpan <byte> nameSpanByte, int bytesNeeded, byte token) { int indent = _indent & RemoveFlagsBitMask; Span <byte> byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (_indent < 0) { byteBuffer[idx++] = JsonConstants.ListSeperator; } // \r\n versus \n, depending on OS if (JsonWriterHelper.NewLineUtf8.Length == 2) { byteBuffer[idx++] = JsonConstants.CarriageReturn; } byteBuffer[idx++] = JsonConstants.LineFeed; while (indent-- > 0) { byteBuffer[idx++] = JsonConstants.Space; byteBuffer[idx++] = JsonConstants.Space; } byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpanByte, byteBuffer.Slice(idx), out int consumed, out int written); Debug.Assert(consumed == nameSpanByte.Length); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; byteBuffer[idx++] = JsonConstants.Space; byteBuffer[idx++] = token; _bufferWriter.Advance(idx); }
public bool TryGetValue(Utf8Span propertyName, out JsonObject value) { DbRow record = GetRecord(0); if (record.Length == 0) { JsonThrowHelper.ThrowKeyNotFoundException(); } if (record.Type != JsonValueType.Object) { JsonThrowHelper.ThrowInvalidOperationException(); } for (int i = DbRow.Size; i <= _database.Length; i += DbRow.Size) { record = GetRecord(i); if (!record.IsSimpleValue) { i += record.Length * DbRow.Size; continue; } if (_jsonData.Slice(record.Location, record.Length).SequenceEqual(propertyName.Bytes)) { int newStart = i + DbRow.Size; record = GetRecord(newStart); int newEnd = record.IsSimpleValue ? i + 2 * DbRow.Size : i + (record.Length + 2) * DbRow.Size; value = new JsonObject(_jsonData, _database.Slice(newStart, newEnd - newStart)); return(true); } JsonValueType valueType = GetType(i + DbRow.Size); if (valueType > JsonValueType.Array) { i += DbRow.Size; } } value = default; return(false); }
private bool ReadNext() { bool result = false; do { _consumed += _jsonReader.BytesConsumed; int leftOver = _buffer.Length - (int)_jsonReader.BytesConsumed; int amountToRead = StreamSegmentSize; if (leftOver > 0) { _stream.Position -= leftOver; if (_jsonReader.BytesConsumed == 0) { if (leftOver > 1_000_000_000) { JsonThrowHelper.ThrowArgumentException("Cannot fit left over data from the previous chunk and the next chunk of data into a 2 GB buffer."); } // This is guaranteed to not overflow due to the check above. amountToRead += leftOver * 2; ResizeBuffer(amountToRead); } } if (_pooledArray.Length < StreamSegmentSize) { ResizeBuffer(StreamSegmentSize); } int numberOfBytes = _stream.Read(_pooledArray, 0, amountToRead); _isFinalBlock = numberOfBytes == 0; // TODO: Can this be inferred differently based on leftOver and numberOfBytes _buffer = _pooledArray.AsSpan(0, numberOfBytes); _jsonReader = new JsonUtf8Reader(_buffer, _isFinalBlock, _jsonReader.CurrentState); result = _jsonReader.Read(); } while (!result && !_isFinalBlock); return(result); }
private void WriteStart(ref ReadOnlySpan <byte> propertyName, byte token) { // TODO: Use throw helper with proper error messages if (propertyName.Length > JsonConstants.MaxTokenSize || CurrentDepth >= JsonConstants.MaxPossibleDepth) { JsonThrowHelper.ThrowJsonWriterOrArgumentException(propertyName, _currentDepth); } if (_writerOptions.SlowPath) { WriteStartSlow(ref propertyName, token); } else { WriteStartFast(ref propertyName, token); } _currentDepth &= JsonConstants.RemoveFlagsBitMask; _currentDepth++; }
public void WriteArray(ReadOnlySpan <byte> propertyName, ReadOnlySpan <DateTime> values) { // TODO: Use throw helper with proper error messages if (propertyName.Length > JsonConstants.MaxTokenSize || CurrentDepth >= JsonConstants.MaxPossibleDepth) { JsonThrowHelper.ThrowJsonWriterOrArgumentException(propertyName, _currentDepth); } if (_writerOptions.SlowPath) { WriteArraySlow(ref propertyName, ref values); } else { WriteArrayFast(ref propertyName, ref values); } _currentDepth |= 1 << 31; _tokenType = JsonTokenType.EndArray; }
private void WriteStart(byte token) { // TODO: Use throw helper with proper error messages if (CurrentDepth >= JsonConstants.MaxWriterDepth) { JsonThrowHelper.ThrowJsonWriterException("Depth too large."); } if (_writerOptions.SlowPath) { WriteStartSlow(token); } else { WriteStartMinimized(token); } _currentDepth &= JsonConstants.RemoveFlagsBitMask; _currentDepth++; _isNotPrimitive = true; }
private void ValidateStart(byte token) { if (_inObject) { Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray); if (_tokenType != JsonTokenType.PropertyName) { JsonThrowHelper.ThrowJsonWriterException(token, _tokenType); //TODO: Add resource message } } else { Debug.Assert(_tokenType != JsonTokenType.StartObject); if (_tokenType == JsonTokenType.PropertyName || (_tokenType != JsonTokenType.None && !_isNotPrimitive)) { JsonThrowHelper.ThrowJsonWriterException(token, _tokenType); //TODO: Add resource message } } UpdateBitStackOnStart(token); }
private void WriteAttributeUtf8Pretty(ReadOnlySpan <byte> nameSpan, ReadOnlySpan <byte> valueSpan) { //quote {name} quote colon quote {value} quote, hence 5 int bytesNeeded = 5; if (_indent < 0) { bytesNeeded++; } if (Encodings.Utf16.ToUtf8Length(nameSpan, out int bytesNeededName) != OperationStatus.Done) { JsonThrowHelper.ThrowArgumentExceptionInvalidUtf8String(); } if (Encodings.Utf16.ToUtf8Length(valueSpan, out int bytesNeededValue) != OperationStatus.Done) { JsonThrowHelper.ThrowArgumentExceptionInvalidUtf8String(); } bytesNeeded += bytesNeededName; bytesNeeded += bytesNeededValue; bytesNeeded += JsonWriterHelper.NewLineUtf8.Length + 1 + (_indent & RemoveFlagsBitMask) * 2; WriteAttributeUtf8Pretty(nameSpan, valueSpan, bytesNeeded); }
private static void EscapeNextChars(ref ReadOnlySpan <char> value, int firstChar, ref Span <char> destination, ref int consumed, ref int written) { int nextChar = -1; if (InRange(firstChar, 0xD800, 0xDFFF)) { consumed++; if (value.Length <= consumed || firstChar >= 0xDC00) { JsonThrowHelper.ThrowJsonWriterException("Invalid UTF-16 string ending in an invalid surrogate pair."); } nextChar = value[consumed]; if (!InRange(nextChar, 0xDC00, 0xDFFF)) { JsonThrowHelper.ThrowJsonWriterException("Invalid UTF-16 string ending in an invalid surrogate pair."); } } destination[written++] = '\\'; switch (firstChar) { case '\n': destination[written++] = 'n'; break; case '\r': destination[written++] = 'r'; break; case '\t': destination[written++] = 't'; break; case '\\': destination[written++] = '\\'; break; case '/': destination[written++] = '/'; break; case '\b': destination[written++] = 'b'; break; case '\f': destination[written++] = 'f'; break; default: destination[written++] = 'u'; WriteHex(firstChar, ref destination, ref written); if (nextChar != -1) { destination[written++] = '\\'; destination[written++] = 'u'; WriteHex(nextChar, ref destination, ref written); } break; } }
private void WriteStartUtf8Pretty(ReadOnlySpan <byte> nameSpanByte, byte token) { // quote {name} quote colon open-brace, hence 4 int bytesNeeded = 4; if (_indent < 0) { bytesNeeded++; } if (Encodings.Utf16.ToUtf8Length(nameSpanByte, out int bytesNeededValue) != OperationStatus.Done) { JsonThrowHelper.ThrowArgumentExceptionInvalidUtf8String(); } bytesNeeded += bytesNeededValue; int indent = _indent & RemoveFlagsBitMask; // For the new line, \r\n or \n, and the space after the colon bytesNeeded += JsonWriterHelper.NewLineUtf8.Length + 1 + indent * 2; Span <byte> byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (_indent < 0) { byteBuffer[idx++] = JsonConstants.ListSeperator; } // \r\n versus \n, depending on OS if (JsonWriterHelper.NewLineUtf8.Length == 2) { byteBuffer[idx++] = JsonConstants.CarriageReturn; } byteBuffer[idx++] = JsonConstants.LineFeed; while (indent-- > 0) { byteBuffer[idx++] = JsonConstants.Space; byteBuffer[idx++] = JsonConstants.Space; } byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpanByte, byteBuffer.Slice(idx), out int consumed, out int written); Debug.Assert(consumed == nameSpanByte.Length); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; byteBuffer[idx++] = JsonConstants.Space; byteBuffer[idx++] = token; _bufferWriter.Advance(idx); }
private void WriteAttributeUtf8Pretty(ReadOnlySpan <byte> nameSpan, long value) { // quote {name} quote colon, hence 3 int bytesNeeded = 3; if (_indent < 0) { bytesNeeded++; } if (Encodings.Utf16.ToUtf8Length(nameSpan, out int bytesNeededName) != OperationStatus.Done) { JsonThrowHelper.ThrowArgumentExceptionInvalidUtf8String(); } bytesNeeded += bytesNeededName; // For the new line, \r\n or \n, and the space after the colon bytesNeeded += JsonWriterHelper.NewLineUtf8.Length + 1 + (_indent & RemoveFlagsBitMask) * 2; bool insertNegationSign = false; if (value < 0) { insertNegationSign = true; value = -value; bytesNeeded += 1; } int digitCount = JsonWriterHelper.CountDigits((ulong)value); bytesNeeded += digitCount; Span <byte> byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (_indent < 0) { byteBuffer[idx++] = JsonConstants.ListSeperator; } idx += AddNewLineAndIndentation(byteBuffer.Slice(idx)); byteBuffer[idx++] = JsonConstants.Quote; OperationStatus status = Encodings.Utf16.ToUtf8(nameSpan, byteBuffer.Slice(idx), out int consumed, out int written); if (status != OperationStatus.Done) { JsonThrowHelper.ThrowFormatException(); } Debug.Assert(consumed == nameSpan.Length); idx += written; byteBuffer[idx++] = JsonConstants.Quote; byteBuffer[idx++] = JsonConstants.KeyValueSeperator; byteBuffer[idx++] = JsonConstants.Space; _indent |= 1 << 31; if (insertNegationSign) { byteBuffer[idx++] = (byte)'-'; } JsonWriterHelper.WriteDigitsUInt64D((ulong)value, byteBuffer.Slice(idx, digitCount)); _bufferWriter.Advance(bytesNeeded); }