/* Copyright 2010-2014 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.Linq; namespace MongoDB.Bson { /// /// Represents BSON binary data. /// [Serializable] public class BsonBinaryData : BsonValue, IComparable, IEquatable { // private fields private byte[] _bytes; private BsonBinarySubType _subType; private GuidRepresentation _guidRepresentation; // only relevant if subType is UuidStandard or UuidLegacy // constructors /// /// Initializes a new instance of the BsonBinaryData class. /// /// The binary data. public BsonBinaryData(byte[] bytes) : this(bytes, BsonBinarySubType.Binary) { } /// /// Initializes a new instance of the BsonBinaryData class. /// /// The binary data. /// The binary data subtype. public BsonBinaryData(byte[] bytes, BsonBinarySubType subType) : this(bytes, subType, GuidRepresentation.Unspecified) { } /// /// Initializes a new instance of the BsonBinaryData class. /// /// The binary data. /// The binary data subtype. /// The representation for Guids. public BsonBinaryData(byte[] bytes, BsonBinarySubType subType, GuidRepresentation guidRepresentation) : base(BsonType.Binary) { if (bytes == null) { throw new ArgumentNullException("bytes"); } if (subType == BsonBinarySubType.UuidStandard || subType == BsonBinarySubType.UuidLegacy) { if (bytes.Length != 16) { var message = string.Format( "Length must be 16, not {0}, when subType is {1}.", bytes.Length, subType); throw new ArgumentException(message); } var expectedSubType = (guidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy; if (subType != expectedSubType) { var message = string.Format( "SubType must be {0}, not {1}, when GuidRepresentation is {2}.", expectedSubType, subType, GuidRepresentation); throw new ArgumentException(message); } } else { if (guidRepresentation != GuidRepresentation.Unspecified) { var message = string.Format( "GuidRepresentation must be Unspecified, not {0}, when SubType is not UuidStandard or UuidLegacy.", guidRepresentation); throw new ArgumentException(message); } } _bytes = bytes; _subType = subType; _guidRepresentation = guidRepresentation; } /// /// Initializes a new instance of the BsonBinaryData class. /// /// A Guid. public BsonBinaryData(Guid guid) : this(guid, BsonDefaults.GuidRepresentation) { } /// /// Initializes a new instance of the BsonBinaryData class. /// /// A Guid. /// The representation for Guids. public BsonBinaryData(Guid guid, GuidRepresentation guidRepresentation) : this(GuidConverter.ToBytes(guid, guidRepresentation), (guidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy, guidRepresentation) { } // public properties /// /// Gets the binary data. /// public byte[] Bytes { get { return _bytes; } } /// /// Gets the representation to use when representing the Guid as BSON binary data. /// public GuidRepresentation GuidRepresentation { get { return _guidRepresentation; } } /// /// Gets the BsonBinaryData as a Guid if the subtype is UuidStandard or UuidLegacy, otherwise null. /// #pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary [Obsolete("Use Value instead.")] public override object RawValue { get { if (_subType == BsonBinarySubType.Binary || _subType == BsonBinarySubType.OldBinary) { return _bytes; } else if (_subType == BsonBinarySubType.UuidStandard || _subType == BsonBinarySubType.UuidLegacy) { return ToGuid(); } else { return null; } } } #pragma warning restore 618 /// /// Gets the binary data subtype. /// public BsonBinarySubType SubType { get { return _subType; } } // public operators /// /// Converts a byte array to a BsonBinaryData. /// /// A byte array. /// A BsonBinaryData. public static implicit operator BsonBinaryData(byte[] bytes) { return new BsonBinaryData(bytes); } /// /// Converts a Guid to a BsonBinaryData. /// /// A Guid. /// A BsonBinaryData. public static implicit operator BsonBinaryData(Guid value) { return new BsonBinaryData(value); } /// /// Compares two BsonBinaryData values. /// /// The first BsonBinaryData. /// The other BsonBinaryData. /// True if the two BsonBinaryData values are not equal according to ==. public static bool operator !=(BsonBinaryData lhs, BsonBinaryData rhs) { return !(lhs == rhs); } /// /// Compares two BsonBinaryData values. /// /// The first BsonBinaryData. /// The other BsonBinaryData. /// True if the two BsonBinaryData values are equal according to ==. public static bool operator ==(BsonBinaryData lhs, BsonBinaryData rhs) { if (object.ReferenceEquals(lhs, null)) { return object.ReferenceEquals(rhs, null); } return lhs.Equals(rhs); } // public static methods /// /// Creates a new BsonBinaryData. /// /// The binary data. /// A BsonBinaryData or null. [Obsolete("Use new BsonBinaryData(byte[] bytes) instead.")] public static BsonBinaryData Create(byte[] bytes) { return Create(bytes, BsonBinarySubType.Binary); } /// /// Creates a new BsonBinaryData. /// /// The binary data. /// The binary data subtype. /// A BsonBinaryData or null. [Obsolete("Use new BsonBinaryData(byte[] bytes, BsonBinarySubtype subType) instead.")] public static BsonBinaryData Create(byte[] bytes, BsonBinarySubType subType) { if (bytes != null) { return new BsonBinaryData(bytes, subType); } else { return null; } } /// /// Creates a new BsonBinaryData. /// /// The binary data. /// The binary data subtype. /// The representation for Guids. /// A BsonBinaryData or null. [Obsolete("Use new BsonBinaryData(byte[] bytes, BsonBinarySubtype subType, GuidRepresentation guidRepresentation) instead.")] public static BsonBinaryData Create( byte[] bytes, BsonBinarySubType subType, GuidRepresentation guidRepresentation) { if (bytes != null) { return new BsonBinaryData(bytes, subType, guidRepresentation); } else { return null; } } /// /// Creates a new BsonBinaryData. /// /// A Guid. /// A BsonBinaryData. [Obsolete("Use new BsonBinaryData(Guid guid) instead.")] public static BsonBinaryData Create(Guid guid) { return new BsonBinaryData(guid); } /// /// Creates a new BsonBinaryData. /// /// A Guid. /// The representation for Guids. /// A BsonBinaryData. [Obsolete("Use new BsonBinaryData(Guid guid, GuidRepresentation guidRepresentation) instead.")] public static BsonBinaryData Create(Guid guid, GuidRepresentation guidRepresentation) { return new BsonBinaryData(guid, guidRepresentation); } /// /// Creates a new BsonBinaryData. /// /// An object to be mapped to a BsonBinaryData. /// A BsonBinaryData or null. public new static BsonBinaryData Create(object value) { if (value != null) { return (BsonBinaryData)BsonTypeMapper.MapToBsonValue(value, BsonType.Binary); } else { return null; } } // public methods /// /// Compares this BsonBinaryData to another BsonBinaryData. /// /// The other BsonBinaryData. /// A 32-bit signed integer that indicates whether this BsonBinaryData is less than, equal to, or greather than the other. public int CompareTo(BsonBinaryData other) { if (other == null) { return 1; } int r = _subType.CompareTo(other._subType); if (r != 0) { return r; } for (int i = 0; i < _bytes.Length && i < other._bytes.Length; i++) { r = _bytes[i].CompareTo(other._bytes[i]); if (r != 0) { return r; } } return _bytes.Length.CompareTo(other._bytes.Length); } /// /// Compares the BsonBinaryData to another BsonValue. /// /// The other BsonValue. /// A 32-bit signed integer that indicates whether this BsonBinaryData is less than, equal to, or greather than the other BsonValue. public override int CompareTo(BsonValue other) { if (other == null) { return 1; } var otherBinaryData = other as BsonBinaryData; if (otherBinaryData != null) { return CompareTo(otherBinaryData); } return CompareTypeTo(other); } /// /// Compares this BsonBinaryData to another BsonBinaryData. /// /// The other BsonBinaryData. /// True if the two BsonBinaryData values are equal. public bool Equals(BsonBinaryData rhs) { if (object.ReferenceEquals(rhs, null) || GetType() != rhs.GetType()) { return false; } // note: guidRepresentation is not considered when testing for Equality return object.ReferenceEquals(this, rhs) || _subType == rhs._subType && _bytes.SequenceEqual(rhs._bytes); } /// /// Compares this BsonBinaryData to another object. /// /// The other object. /// True if the other object is a BsonBinaryData and equal to this one. public override bool Equals(object obj) { return Equals(obj as BsonBinaryData); // works even if obj is null or of a different type } /// /// Gets the hash code. /// /// The hash code. public override int GetHashCode() { // see Effective Java by Joshua Bloch // note: guidRepresentation is not considered when computing the hash code int hash = 17; hash = 37 * hash + BsonType.GetHashCode(); foreach (byte b in _bytes) { hash = 37 * hash + b; } hash = 37 * hash + _subType.GetHashCode(); return hash; } /// /// Converts this BsonBinaryData to a Guid. /// /// A Guid. public Guid ToGuid() { return ToGuid(_guidRepresentation); } /// /// Converts this BsonBinaryData to a Guid. /// /// The representation for Guids. /// A Guid. public Guid ToGuid(GuidRepresentation guidRepresentation) { if (_subType != BsonBinarySubType.UuidStandard && _subType != BsonBinarySubType.UuidLegacy) { var message = string.Format("SubType must be UuidStandard or UuidLegacy, not {0}.", _subType); throw new InvalidOperationException(message); } if (guidRepresentation == GuidRepresentation.Unspecified) { throw new ArgumentException("GuidRepresentation cannot be Unspecified."); } return GuidConverter.FromBytes(_bytes, guidRepresentation); } /// /// Returns a string representation of the binary data. /// /// A string representation of the binary data. public override string ToString() { return string.Format("{0}:0x{1}", _subType, BsonUtils.ToHexString(_bytes)); } } }