/* 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));
}
}
}