1 //------------------------------------------------------------------------------
2 // <copyright file="SQLBinary.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">junfang</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="true" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
10 //**************************************************************************
11 // @File: SqlBinary.cs
15 // Purpose: Implementation of SqlBinary which is corresponding to
16 // data type "binary/varbinary" in SQL Server
22 // 1/30/2000 JunFang Created and implemented as first drop.
25 //**************************************************************************
28 using System
.Data
.Common
;
29 using System
.Globalization
;
31 using System
.Xml
.Schema
;
32 using System
.Xml
.Serialization
;
34 namespace System
.Data
.SqlTypes
{
37 [XmlSchemaProvider("GetXsdType")]
38 public struct SqlBinary
: INullable
, IComparable
, IXmlSerializable
{
39 private byte[] m_value
; // null if m_value is null
43 private SqlBinary(bool fNull
) {
49 /// Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlBinary'/> class with a binary object to be stored.
52 public SqlBinary(byte[] value) {
53 // if value is null, this generates a SqlBinary.Null
57 m_value
= new byte[value.Length
];
58 value.CopyTo(m_value
, 0);
64 /// Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlBinary'/> class with a binary object to be stored. This constructor will not copy the value.
67 internal SqlBinary(byte[] value, bool ignored
) {
68 // if value is null, this generates a SqlBinary.Null
79 /// Gets whether or not <see cref='System.Data.SqlTypes.SqlBinary.Value'/> is null.
83 get { return(m_value == null);}
91 /// value of the SQL binary object retrieved.
97 throw new SqlNullValueException();
99 byte[] value = new byte[m_value
.Length
];
100 m_value
.CopyTo(value, 0);
107 public byte this[int index
] {
110 throw new SqlNullValueException();
112 return m_value
[index
];
119 /// Gets the length in bytes of <see cref='System.Data.SqlTypes.SqlBinary.Value'/>.
125 return m_value
.Length
;
127 throw new SqlNullValueException();
131 // Implicit conversion from byte[] to SqlBinary
132 // Alternative: constructor SqlBinary(bytep[])
135 /// Converts a binary object to a <see cref='System.Data.SqlTypes.SqlBinary'/>.
138 public static implicit operator SqlBinary(byte[] x
) {
139 return new SqlBinary(x
);
142 // Explicit conversion from SqlBinary to byte[]. Throw exception if x is Null.
143 // Alternative: Value property
146 /// Converts a <see cref='System.Data.SqlTypes.SqlBinary'/> to a binary object.
149 public static explicit operator byte[](SqlBinary x
) {
155 /// Returns a string describing a <see cref='System.Data.SqlTypes.SqlBinary'/> object.
158 public override String
ToString() {
159 return IsNull
? SQLResource
.NullString
: "SqlBinary(" + m_value
.Length
.ToString(CultureInfo
.InvariantCulture
) + ")";
167 // Arithmetic operators
170 /// Adds two instances of <see cref='System.Data.SqlTypes.SqlBinary'/> together.
173 // Alternative method: SqlBinary.Concat
174 public static SqlBinary
operator +(SqlBinary x
, SqlBinary y
) {
175 if (x
.IsNull
|| y
.IsNull
)
178 byte[] rgbResult
= new byte[x
.Value
.Length
+ y
.Value
.Length
];
179 x
.Value
.CopyTo(rgbResult
, 0);
180 y
.Value
.CopyTo(rgbResult
, x
.Value
.Length
);
182 return new SqlBinary(rgbResult
);
188 private static EComparison
PerformCompareByte(byte[] x
, byte[] y
) {
189 // the smaller length of two arrays
190 int len
= (x
.Length
< y
.Length
) ? x
.Length
: y
.Length
;
193 for (i
= 0; i
< len
; ++i
) {
196 return EComparison
.LT
;
198 return EComparison
.GT
;
202 if (x
.Length
== y
.Length
)
203 return EComparison
.EQ
;
205 // if the remaining bytes are all zeroes, they are still equal.
207 byte bZero
= (byte)0;
209 if (x
.Length
< y
.Length
) {
210 // array X is shorter
211 for (i
= len
; i
< y
.Length
; ++i
) {
213 return EComparison
.LT
;
217 // array Y is shorter
218 for (i
= len
; i
< x
.Length
; ++i
) {
220 return EComparison
.GT
;
224 return EComparison
.EQ
;
229 // Implicit conversions
231 // Explicit conversions
233 // Explicit conversion from SqlGuid to SqlBinary
236 /// Converts a <see cref='System.Data.SqlTypes.SqlGuid'/> to a <see cref='System.Data.SqlTypes.SqlBinary'/>
240 // Alternative method: SqlGuid.ToSqlBinary
241 public static explicit operator SqlBinary(SqlGuid x
) {
242 return x
.IsNull
? SqlBinary
.Null
: new SqlBinary(x
.ToByteArray());
247 // Overloading comparison operators
250 /// Compares two instances of <see cref='System.Data.SqlTypes.SqlBinary'/> for
254 public static SqlBoolean
operator==(SqlBinary x
, SqlBinary y
) {
255 if (x
.IsNull
|| y
.IsNull
)
256 return SqlBoolean
.Null
;
258 return new SqlBoolean(PerformCompareByte(x
.Value
, y
.Value
) == EComparison
.EQ
);
263 /// Compares two instances of <see cref='System.Data.SqlTypes.SqlBinary'/>
267 public static SqlBoolean
operator!=(SqlBinary x
, SqlBinary y
) {
273 /// Compares the first <see cref='System.Data.SqlTypes.SqlBinary'/> for being less than the
274 /// second <see cref='System.Data.SqlTypes.SqlBinary'/>.
277 public static SqlBoolean
operator<(SqlBinary x
, SqlBinary y
) {
278 if (x
.IsNull
|| y
.IsNull
)
279 return SqlBoolean
.Null
;
281 return new SqlBoolean(PerformCompareByte(x
.Value
, y
.Value
) == EComparison
.LT
);
286 /// Compares the first <see cref='System.Data.SqlTypes.SqlBinary'/> for being greater than the second <see cref='System.Data.SqlTypes.SqlBinary'/>.
289 public static SqlBoolean
operator>(SqlBinary x
, SqlBinary y
) {
290 if (x
.IsNull
|| y
.IsNull
)
291 return SqlBoolean
.Null
;
293 return new SqlBoolean(PerformCompareByte(x
.Value
, y
.Value
) == EComparison
.GT
);
298 /// Compares the first <see cref='System.Data.SqlTypes.SqlBinary'/> for being less than or equal to the second <see cref='System.Data.SqlTypes.SqlBinary'/>.
301 public static SqlBoolean
operator<=(SqlBinary x
, SqlBinary y
) {
302 if (x
.IsNull
|| y
.IsNull
)
303 return SqlBoolean
.Null
;
305 EComparison cmpResult
= PerformCompareByte(x
.Value
, y
.Value
);
306 return new SqlBoolean(cmpResult
== EComparison
.LT
|| cmpResult
== EComparison
.EQ
);
311 /// Compares the first <see cref='System.Data.SqlTypes.SqlBinary'/> for being greater than or equal the second <see cref='System.Data.SqlTypes.SqlBinary'/>.
314 public static SqlBoolean
operator>=(SqlBinary x
, SqlBinary y
) {
315 if (x
.IsNull
|| y
.IsNull
)
316 return SqlBoolean
.Null
;
318 EComparison cmpResult
= PerformCompareByte(x
.Value
, y
.Value
);
319 return new SqlBoolean(cmpResult
== EComparison
.GT
|| cmpResult
== EComparison
.EQ
);
322 //--------------------------------------------------
323 // Alternative methods for overloaded operators
324 //--------------------------------------------------
326 // Alternative method for operator +
327 public static SqlBinary
Add(SqlBinary x
, SqlBinary y
) {
331 public static SqlBinary
Concat(SqlBinary x
, SqlBinary y
) {
335 // Alternative method for operator ==
336 public static SqlBoolean
Equals(SqlBinary x
, SqlBinary y
) {
340 // Alternative method for operator !=
341 public static SqlBoolean
NotEquals(SqlBinary x
, SqlBinary y
) {
345 // Alternative method for operator <
346 public static SqlBoolean
LessThan(SqlBinary x
, SqlBinary y
) {
350 // Alternative method for operator >
351 public static SqlBoolean
GreaterThan(SqlBinary x
, SqlBinary y
) {
355 // Alternative method for operator <=
356 public static SqlBoolean
LessThanOrEqual(SqlBinary x
, SqlBinary y
) {
360 // Alternative method for operator >=
361 public static SqlBoolean
GreaterThanOrEqual(SqlBinary x
, SqlBinary y
) {
365 // Alternative method for conversions.
366 public SqlGuid
ToSqlGuid() {
367 return (SqlGuid
)this;
371 // Compares this object to another object, returning an integer that
372 // indicates the relationship.
373 // Returns a value less than zero if this < object, zero if this = object,
374 // or a value greater than zero if this > object.
375 // null is considered to be less than any instance.
376 // If object is not of same type, this method throws an ArgumentException.
378 /// <para>[To be supplied.]</para>
380 public int CompareTo(Object
value) {
381 if (value is SqlBinary
) {
382 SqlBinary i
= (SqlBinary
)value;
386 throw ADP
.WrongType(value.GetType(), typeof(SqlBinary
));
389 public int CompareTo(SqlBinary
value) {
390 // If both Null, consider them equal.
391 // Otherwise, Null is less than anything.
393 return value.IsNull
? 0 : -1;
394 else if (value.IsNull
)
397 if (this < value) return -1;
398 if (this > value) return 1;
402 // Compares this instance with a specified object
404 /// <para>[To be supplied.]</para>
406 public override bool Equals(Object
value) {
407 if (!(value is SqlBinary
)) {
411 SqlBinary i
= (SqlBinary
)value;
413 if (i
.IsNull
|| IsNull
)
414 return (i
.IsNull
&& IsNull
);
416 return (this == i
).Value
;
419 // Hash a byte array.
420 // Trailing zeroes/spaces would affect the hash value, so caller needs to
421 // perform trimming as necessary.
422 internal static int HashByteArray(byte[] rgbValue
, int length
)
424 SQLDebug
.Check(length
>= 0);
429 SQLDebug
.Check(rgbValue
.Length
>= length
);
434 // Size of CRC window (hashing bytes, ssstr, sswstr, numeric)
435 const int x_cbCrcWindow
= 4;
436 // const int iShiftVal = (sizeof ulValue) * (8*sizeof(char)) - x_cbCrcWindow;
437 const int iShiftVal
= 4 * 8 - x_cbCrcWindow
;
439 for(int i
= 0; i
< length
; i
++)
441 ulHi
= (ulValue
>> iShiftVal
) & 0xff;
442 ulValue
<<= x_cbCrcWindow
;
443 ulValue
= ulValue ^ rgbValue
[i
] ^ ulHi
;
448 // For hashing purpose
450 /// <para>[To be supplied.]</para>
452 public override int GetHashCode()
457 //First trim off extra '\0's
458 int cbLen
= m_value
.Length
;
459 while (cbLen
> 0 && m_value
[cbLen
- 1] == 0)
462 return HashByteArray(m_value
, cbLen
);
466 /// <para>[To be supplied.]</para>
468 XmlSchema IXmlSerializable
.GetSchema() { return null; }
471 /// <para>[To be supplied.]</para>
473 void IXmlSerializable
.ReadXml(XmlReader reader
) {
474 string isNull
= reader
.GetAttribute("nil", XmlSchema
.InstanceNamespace
);
475 if (isNull
!= null && XmlConvert
.ToBoolean(isNull
)) {
476 // VSTFDevDiv# 479603 - SqlTypes read null value infinitely and never read the next value. Fix - Read the next value.
477 reader
.ReadElementString();
481 string base64
= reader
.ReadElementString();
482 if (base64
== null) {
483 m_value
= new byte[0];
486 base64
= base64
.Trim();
488 if (base64
.Length
== 0) {
489 m_value
= new byte[0];
492 m_value
= Convert
.FromBase64String(base64
);
499 /// <para>[To be supplied.]</para>
501 void IXmlSerializable
.WriteXml(XmlWriter writer
) {
503 writer
.WriteAttributeString("xsi", "nil", XmlSchema
.InstanceNamespace
, "true");
506 writer
.WriteString(Convert
.ToBase64String(m_value
));
511 /// <para>[To be supplied.]</para>
513 public static XmlQualifiedName
GetXsdType(XmlSchemaSet schemaSet
) {
514 return new XmlQualifiedName("base64Binary", XmlSchema
.Namespace
);
519 /// Represents a null value that can be assigned to
520 /// the <see cref='System.Data.SqlTypes.SqlBinary.Value'/> property of an
521 /// instance of the <see cref='System.Data.SqlTypes.SqlBinary'/> class.
524 public static readonly SqlBinary Null
= new SqlBinary(true);
528 } // namespace System.Data.SqlTypes