/* Copyright 2010-2016 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.IO; namespace MongoDB.Bson.IO { /// /// Represents extension methods on BsonStream. /// public static class BsonStreamExtensions { // static fields private static readonly bool[] __validBsonTypes = new bool[256]; // static constructor static BsonStreamExtensions() { foreach (BsonType bsonType in Enum.GetValues(typeof(BsonType))) { __validBsonTypes[(byte)bsonType] = true; } } // static methods /// /// Backpatches the size. /// /// The stream. /// The start position. public static void BackpatchSize(this BsonStream stream, long startPosition) { if (stream == null) { throw new ArgumentNullException("stream"); } if (startPosition < 0 || startPosition > stream.Length) { throw new ArgumentOutOfRangeException("startPosition"); } var size = stream.Position - startPosition; if (size > int.MaxValue) { var message = string.Format("Size {0} is larger than {1} (Int32.MaxValue).", size, int.MaxValue); throw new FormatException(message); } var endPosition = stream.Position; stream.Position = startPosition; stream.WriteInt32((int)size); stream.Position = endPosition; } /// /// Reads the binary sub type. /// /// The stream. /// The binary sub type. public static BsonBinarySubType ReadBinarySubType(this BsonStream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } var b = stream.ReadByte(); if (b == -1) { throw new EndOfStreamException(); } return (BsonBinarySubType)b; } /// /// Reads a boolean from the stream. /// /// The stream. /// A boolean. public static bool ReadBoolean(this BsonStream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } var b = stream.ReadByte(); if (b == -1) { throw new EndOfStreamException(); } return b != 0; } /// /// Reads the BSON type. /// /// The stream. /// The BSON type. public static BsonType ReadBsonType(this BsonStream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } var b = stream.ReadByte(); if (b == -1) { throw new EndOfStreamException(); } if (!__validBsonTypes[b]) { var message = string.Format("Detected unknown BSON type \"\\x{0:x2}\". Are you using the latest driver version?", b); throw new FormatException(message); } return (BsonType)b; } /// /// Reads bytes from the stream. /// /// The stream. /// The buffer. /// The offset. /// The count. public static void ReadBytes(this BsonStream stream, byte[] buffer, int offset, int count) { if (stream == null) { throw new ArgumentNullException("stream"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (count == 1) { var b = stream.ReadByte(); if (b == -1) { throw new EndOfStreamException(); } buffer[offset] = (byte)b; } else { while (count > 0) { var bytesRead = stream.Read(buffer, offset, count); if (bytesRead == 0) { throw new EndOfStreamException(); } offset += bytesRead; count -= bytesRead; } } } /// /// Reads bytes from the stream. /// /// The stream. /// The count. /// The bytes. public static byte[] ReadBytes(this BsonStream stream, int count) { if (stream == null) { throw new ArgumentNullException("stream"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } var bytes = new byte[count]; stream.ReadBytes(bytes, 0, count); return bytes; } /// /// Writes a binary sub type to the stream. /// /// The stream. /// The value. public static void WriteBinarySubType(this BsonStream stream, BsonBinarySubType value) { if (stream == null) { throw new ArgumentNullException("stream"); } stream.WriteByte((byte)value); } /// /// Writes a boolean to the stream. /// /// The stream. /// The value. public static void WriteBoolean(this BsonStream stream, bool value) { if (stream == null) { throw new ArgumentNullException("stream"); } stream.WriteByte(value ? (byte)1 : (byte)0); } /// /// Writes a BsonType to the stream. /// /// The stream. /// The value. public static void WriteBsonType(this BsonStream stream, BsonType value) { if (stream == null) { throw new ArgumentNullException("stream"); } stream.WriteByte((byte)value); } /// /// Writes bytes to the stream. /// /// The stream. /// The buffer. /// The offset. /// The count. public static void WriteBytes(this BsonStream stream, byte[] buffer, int offset, int count) { if (stream == null) { throw new ArgumentNullException("stream"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (count == 1) { stream.WriteByte(buffer[offset]); } else { stream.Write(buffer, offset, count); } } /// /// Writes a slice to the stream. /// /// The stream. /// The slice. public static void WriteSlice(this BsonStream stream, IByteBuffer slice) { if (stream == null) { throw new ArgumentNullException("stream"); } if (slice == null) { throw new ArgumentNullException("slice"); } var position = 0; var count = slice.Length; while (count > 0) { var segment = slice.AccessBackingBytes(position); var partialCount = Math.Min(count, segment.Count); stream.WriteBytes(segment.Array, segment.Offset, partialCount); position += partialCount; count -= partialCount; } } } }