/// <summary> /// Reads the name of an element from the reader (using a trie). /// </summary> /// <typeparam name="TValue">The type of the value.</typeparam> /// <param name="trie">The trie.</param> /// <param name="found">Whether the element name was found in the trie.</param> /// <param name="value">If found is true, the value found in the trie for the element name.</param> /// <returns> /// The name of the element. /// </returns> public override string ReadName <TValue>(BsonTrie <TValue> trie, out bool found, out TValue value) { if (trie == null) { throw new ArgumentNullException("trie"); } if (Disposed) { ThrowObjectDisposedException(); } if (State == BsonReaderState.Type) { ReadBsonType(); } if (State != BsonReaderState.Name) { ThrowInvalidState("ReadName", BsonReaderState.Name); } CurrentName = ReadNameWithTrie(trie, out found, out value); State = BsonReaderState.Value; return(CurrentName); }
/// <summary> /// Reads the name of an element from the reader (using a trie). /// </summary> /// <typeparam name="TValue">The type of the value.</typeparam> /// <param name="trie">The trie.</param> /// <param name="found">Whether the element name was found in the trie.</param> /// <param name="value">If found is true, the value found in the trie for the element name.</param> /// <returns> /// The name of the element. /// </returns> public virtual string ReadName <TValue>(BsonTrie <TValue> trie, out bool found, out TValue value) { // overridden in BsonBinaryReader to use the trie for UTF8 decoding var name = ReadName(); found = trie.TryGetValue(name, out value); return(name); }
/// <summary> /// Reads a BsonType from the reader. /// </summary> /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam> /// <param name="bsonTrie">An optional trie to search for a value that matches the next element name.</param> /// <param name="found">Set to true if a matching value was found in the trie.</param> /// <param name="value">Set to the matching value found in the trie or null if no matching value was found.</param> /// <returns>A BsonType.</returns> public override BsonType ReadBsonType <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value) { if (Disposed) { ThrowObjectDisposedException(); } found = false; value = default(TValue); if (State == BsonReaderState.Initial || State == BsonReaderState.ScopeDocument) { // there is an implied type of Document for the top level and for scope documents CurrentBsonType = BsonType.Document; State = BsonReaderState.Value; return(CurrentBsonType); } if (State != BsonReaderState.Type) { ThrowInvalidState("ReadBsonType", BsonReaderState.Type); } switch (_context.ContextType) { case ContextType.Array: _currentValue = _context.GetNextValue(); if (_currentValue == null) { State = BsonReaderState.EndOfArray; return(BsonType.EndOfDocument); } State = BsonReaderState.Value; break; case ContextType.Document: var currentElement = _context.GetNextElement(); if (currentElement == null) { State = BsonReaderState.EndOfDocument; return(BsonType.EndOfDocument); } if (bsonTrie != null) { found = bsonTrie.TryGetValue(currentElement.Name, out value); } CurrentName = currentElement.Name; _currentValue = currentElement.Value; State = BsonReaderState.Name; break; default: throw new BsonInternalException("Invalid ContextType."); } CurrentBsonType = _currentValue.BsonType; return(CurrentBsonType); }
/// <summary> /// Reads an element name. /// </summary> /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam> /// <param name="bsonTrie">An optional BsonTrie to use during decoding.</param> /// <param name="found">Set to true if the string was found in the trie.</param> /// <param name="value">Set to the value found in the trie; otherwise, null.</param> /// <returns>A string.</returns> public string ReadName <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value) { ThrowIfDisposed(); found = false; value = default(TValue); if (bsonTrie == null) { return(ReadCString(new UTF8Encoding(false, true))); // always use strict encoding for names } var savedPosition = _byteBuffer.Position; var bsonTrieNode = bsonTrie.Root; while (true) { var keyByte = _byteBuffer.ReadByte(); if (keyByte == 0) { if (bsonTrieNode.HasValue) { found = true; value = bsonTrieNode.Value; return(bsonTrieNode.ElementName); } else { var nullPosition = _byteBuffer.Position - 1; _byteBuffer.Position = savedPosition; return(ReadCString(new UTF8Encoding(false, true), nullPosition)); // always use strict encoding for names } } bsonTrieNode = bsonTrieNode.GetChild(keyByte); if (bsonTrieNode == null) { var nullPosition = _byteBuffer.FindNullByte(); // starting from where we got so far _byteBuffer.Position = savedPosition; return(ReadCString(new UTF8Encoding(false, true), nullPosition)); // always use strict encoding for names } } }
private string ReadNameWithTrie <TValue>(BsonTrie <TValue> trie, out bool found, out TValue value) { found = false; value = default(TValue); var savedPosition = _streamReader.Position; var node = trie.Root; while (true) { var keyByte = _streamReader.ReadByte(); if (keyByte == -1) { throw new EndOfStreamException(); } else if (keyByte == 0) { if (node.HasValue) { found = true; value = node.Value; return(node.ElementName); } else { _streamReader.Position = savedPosition; return(_streamReader.ReadCString()); } } node = node.GetChild((byte)keyByte); if (node == null) { _streamReader.Position = savedPosition; return(_streamReader.ReadCString()); } } }
/// <summary> /// Reads a BsonType from the reader. /// </summary> /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam> /// <param name="bsonTrie">An optional trie to search for a value that matches the next element name.</param> /// <param name="found">Set to true if a matching value was found in the trie.</param> /// <param name="value">Set to the matching value found in the trie or null if no matching value was found.</param> /// <returns>A BsonType.</returns> public abstract BsonType ReadBsonType <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value);
// constructors /// <summary> /// Initializes a new instance of the <see cref="TrieNameDecoder{TValue}"/> class. /// </summary> /// <param name="trie">The trie.</param> public TrieNameDecoder(BsonTrie <TValue> trie) { _trie = trie; }
/// <summary> /// Reads a BsonType from the reader. /// </summary> /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam> /// <param name="bsonTrie">An optional trie to search for a value that matches the next element name.</param> /// <param name="found">Set to true if a matching value was found in the trie.</param> /// <param name="value">Set to the matching value found in the trie or null if no matching value was found.</param> /// <returns>A BsonType.</returns> public override BsonType ReadBsonType <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value) { if (Disposed) { ThrowObjectDisposedException(); } found = false; value = default(TValue); if (State == BsonReaderState.Initial || State == BsonReaderState.Done || State == BsonReaderState.ScopeDocument) { // there is an implied type of Document for the top level and for scope documents CurrentBsonType = BsonType.Document; State = BsonReaderState.Value; return(CurrentBsonType); } if (State != BsonReaderState.Type) { ThrowInvalidState("ReadBsonType", BsonReaderState.Type); } CurrentBsonType = _buffer.ReadBsonType(); if (CurrentBsonType == BsonType.EndOfDocument) { switch (_context.ContextType) { case ContextType.Array: State = BsonReaderState.EndOfArray; return(BsonType.EndOfDocument); case ContextType.Document: case ContextType.ScopeDocument: State = BsonReaderState.EndOfDocument; return(BsonType.EndOfDocument); default: var message = string.Format("BsonType EndOfDocument is not valid when ContextType is {0}.", _context.ContextType); throw new FileFormatException(message); } } else { switch (_context.ContextType) { case ContextType.Array: _buffer.SkipCString(); // ignore array element names State = BsonReaderState.Value; break; case ContextType.Document: case ContextType.ScopeDocument: CurrentName = _buffer.ReadCString(bsonTrie, out found, out value); State = BsonReaderState.Name; break; default: throw new BsonInternalException("Unexpected ContextType."); } return(CurrentBsonType); } }
/// <summary> /// Reads a BSON CString from the reader (a null terminated string). /// </summary> /// <param name="bsonTrie">An optional BsonTrie to use during decoding.</param> /// <param name="found">Set to true if the string was found in the trie.</param> /// <param name="value">Set to the value found in the trie; otherwise, null.</param> /// <returns>A string.</returns> public string ReadCString <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value) { if (_disposed) { throw new ObjectDisposedException("BsonBuffer"); } found = false; value = default(TValue); // optimize for the case where the null terminator is on the same chunk int partialCount; if (_chunkIndex < _chunks.Count - 1) { partialCount = __chunkSize - _chunkOffset; // remaining part of any chunk but the last } else { partialCount = _length - _position; // populated part of last chunk } var bsonTrieNode = bsonTrie != null ? bsonTrie.Root : null; var index = IndexOfNull(_chunk, _chunkOffset, partialCount, ref bsonTrieNode); if (index != -1) { var stringLength = index - _chunkOffset; string cstring; if (bsonTrieNode != null && bsonTrieNode.HasValue) { cstring = bsonTrieNode.ElementName; value = bsonTrieNode.Value; found = true; } else { cstring = DecodeUtf8String(_chunk, _chunkOffset, stringLength); } Position += stringLength + 1; return(cstring); } // the null terminator is not on the same chunk so keep looking starting with the next chunk var localChunkIndex = _chunkIndex + 1; var localPosition = localChunkIndex * __chunkSize; while (localPosition < _length) { var localChunk = _chunks[localChunkIndex]; if (localChunkIndex < _chunks.Count - 1) { partialCount = __chunkSize; // all of any chunk but the last } else { partialCount = _length - localPosition; // populated part of last chunk } index = IndexOfNull(localChunk, 0, partialCount, ref bsonTrieNode); if (index != -1) { localPosition += index; var stringLength = localPosition - _position; string cstring; if (bsonTrieNode != null && bsonTrieNode.HasValue) { cstring = bsonTrieNode.ElementName; value = bsonTrieNode.Value; found = true; Position += stringLength + 1; } else { cstring = __utf8Encoding.GetString(ReadBytes(stringLength)); // ReadBytes advances over string Position += 1; // skip over null byte at end } return(cstring); } localChunkIndex++; localPosition += __chunkSize; } throw new FileFormatException("String is missing null terminator."); }