New test.
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlBinary.cs
1 //
2 // System.Data.SqlTypes.SqlBinary
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Tim Coleman (tim@timcoleman.com)
7 //   Ville Palo (vi64pa@koti.soon.fi)
8 //
9 // (C) Ximian, Inc.
10 // (C) Copyright 2002 Tim Coleman
11 //
12
13 //
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System;
37 using System.Globalization;
38
39 namespace System.Data.SqlTypes
40 {
41         /// <summary>
42         /// Represents a variable-length stream of binary data to be stored in or retrieved from a database.
43         /// </summary>
44         public struct SqlBinary : INullable, IComparable
45         {
46
47                 #region Fields
48
49                 byte[] value;
50                 private bool notNull;
51
52                 public static readonly SqlBinary Null;
53
54                 #endregion
55
56                 #region Constructors
57                 
58                 public SqlBinary (byte[] value) 
59                 {
60                         this.value = value;
61                         notNull = true;
62                 }
63
64                 #endregion
65
66                 #region Properties
67
68                 public bool IsNull {
69                         get { return !notNull; }
70                 }
71
72                 public byte this[int index] {
73                         get { 
74                                 if (this.IsNull)
75                                         throw new SqlNullValueException ("The property contains Null.");
76                                 else if (index >= this.Length)
77                                         throw new IndexOutOfRangeException ("The index parameter indicates a position beyond the length of the byte array.");
78                                 else
79                                         return value [index]; 
80                         }
81                 }
82
83                 public int Length {
84                         get { 
85                                 if (this.IsNull)
86                                         throw new SqlNullValueException ("The property contains Null.");
87                                 else
88                                         return value.Length;
89                         }
90                 }
91
92                 public byte[] Value 
93                 {
94                         get { 
95                                 if (this.IsNull) 
96                                         throw new SqlNullValueException ("The property contains Null.");
97                                 else 
98                                         return value; 
99                         }
100                 }
101
102                 #endregion
103
104                 #region Methods
105
106                 public int CompareTo (object value) 
107                 {
108                         if (value == null)
109                                 return 1;
110                         else if (!(value is SqlBinary))
111                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlBinary"));
112                         else if (((SqlBinary)value).IsNull)
113                                 return 1;
114                         else
115                                 return Compare (this, (SqlBinary)value);
116                 }
117
118                 public static SqlBinary Concat (SqlBinary x, SqlBinary y) 
119                 {
120                         return (x + y);
121                 }
122
123                 public override bool Equals (object value) 
124                 {
125                         if (!(value is SqlBinary))
126                                 return false;
127                         else if (this.IsNull && ((SqlBinary)value).IsNull)
128                                 return true;
129                         else if (((SqlBinary)value).IsNull)
130                                 return false;
131                         else
132                                 return (bool) (this == (SqlBinary)value);
133                 }
134
135                 public static SqlBoolean Equals(SqlBinary x, SqlBinary y) 
136                 {
137                         return (x == y);
138                 }
139
140                 public override int GetHashCode () 
141                 {
142                         // FIXME: I'm not sure is this a right way
143                         int result = 10;
144                         for (int i = 0; i < value.Length; i++) {
145                                 
146                                 result = 91 * result + (int)value [i];
147                         }
148                         
149                         return result;
150                 }
151
152                 #endregion
153
154                 #region Operators
155
156                 public static SqlBoolean GreaterThan (SqlBinary x, SqlBinary y) 
157                 {
158                         return (x > y);
159                 }
160
161                 public static SqlBoolean GreaterThanOrEqual (SqlBinary x, SqlBinary y) 
162                 {
163                         return (x >= y);
164                 }
165
166                 public static SqlBoolean LessThan (SqlBinary x, SqlBinary y) 
167                 {
168                         return (x < y);
169                 }
170
171                 public static SqlBoolean LessThanOrEqual (SqlBinary x, SqlBinary y) 
172                 {
173                         return (x <= y);
174                 }
175
176                 public static SqlBoolean NotEquals (SqlBinary x, SqlBinary y) 
177                 {
178                         return (x != y);
179                 }
180
181                 public SqlGuid ToSqlGuid () 
182                 {
183                         return (SqlGuid)this;
184                 }
185
186                 public override string ToString () 
187                 {
188                         if (!notNull)
189                                 return "Null";
190                         return "SqlBinary(" + value.Length + ")";
191                 }
192
193                 #endregion
194
195                 #region Operators
196
197                 [MonoTODO]
198                 public static SqlBinary operator + (SqlBinary x, SqlBinary y) 
199                 {
200                         byte [] b = new byte [x.Value.Length + y.Value.Length];
201                         int j = 0;
202                         int i;
203
204                         for (i = 0; i < x.Value.Length; i++) 
205                                 b [i] = x.Value [i];
206                         
207
208                         for (; i < (x.Value.Length + y.Value.Length); i++) {
209                                 b [i] = y.Value [j];
210                                 j++;
211                         }       
212                         
213                         return new SqlBinary (b);
214                 }
215                         
216                 public static SqlBoolean operator == (SqlBinary x, SqlBinary y) 
217                 {
218                         if (x.IsNull || y.IsNull) 
219                                 return SqlBoolean.Null;
220                         else
221                                 return new SqlBoolean (Compare (x, y) == 0);
222                 }
223
224                 public static SqlBoolean operator > (SqlBinary x, SqlBinary y) 
225                 {
226                         if (x.IsNull || y.IsNull) 
227                                 return SqlBoolean.Null;
228
229                         return new SqlBoolean (Compare (x, y) > 0);
230                 }
231
232                 public static SqlBoolean operator >= (SqlBinary x, SqlBinary y) 
233                 {
234                         if (x.IsNull || y.IsNull) 
235                                 return SqlBoolean.Null;
236
237                         return new SqlBoolean (Compare (x, y) >= 0);
238                 }
239
240                 public static SqlBoolean operator != (SqlBinary x, SqlBinary y) 
241                 {
242                         if (x.IsNull || y.IsNull) 
243                                 return SqlBoolean.Null;
244                         else
245                                 return new SqlBoolean (Compare (x, y) != 0);
246                 }
247
248                 public static SqlBoolean operator < (SqlBinary x, SqlBinary y) 
249                 {
250                         if (x.IsNull || y.IsNull) 
251                                 return SqlBoolean.Null;
252
253                         return new SqlBoolean (Compare (x, y) < 0);
254                 }
255
256                 public static SqlBoolean operator <= (SqlBinary x, SqlBinary y) 
257                 {
258                         if (x.IsNull || y.IsNull) 
259                                 return SqlBoolean.Null;
260
261                         return new SqlBoolean (Compare (x, y) <= 0);
262                 }
263
264                 public static explicit operator byte[] (SqlBinary x) 
265                 {
266                         return x.Value;
267                 }
268
269                 public static explicit operator SqlBinary (SqlGuid x) 
270                 {
271                         return new SqlBinary (x.ToByteArray ());
272                 }
273
274                 public static implicit operator SqlBinary (byte[] x) 
275                 {
276                         return new SqlBinary (x);
277                 }
278
279                 #endregion
280
281                 // Helper method to Compare methods and operators.
282                 // Returns 0 if x == y
283                 //         1 if x > y
284                 //        -1 if x < y
285                 private static int Compare(SqlBinary x, SqlBinary y)
286                 {
287                         
288                         int LengthDiff = 0;
289
290                         // If they are different size test are bytes something else than 0
291                         if (x.Value.Length != y.Value.Length) {
292                                 
293                                 LengthDiff = x.Value.Length - y.Value.Length;
294
295                                 // If more than zero, x is longer
296                                 if (LengthDiff > 0) {
297                                         
298                                         for (int i = x.Value.Length - 1; i > x.Value.Length - LengthDiff; i--) {
299                                                 // If byte is more than zero the x is bigger
300                                                 if (x.Value [i] != (byte)0)
301                                                         return 1;
302                                         }
303                                 } else {
304
305                                         for (int i = y.Value.Length - 1; i > y.Value.Length - LengthDiff; i--) {
306                                                 // If byte is more than zero then y is bigger
307                                                 if (y.Value [i] != (byte)0)
308                                                         return -1;
309                                         }
310                                 }                               
311                         }
312
313                         // choose shorter
314                         int lenght = (LengthDiff > 0) ? y.Value.Length : x.Value.Length;
315
316                         for (int i = lenght - 1 ; i > 0; i--) {
317                                 
318                                 byte X = x.Value [i];
319                                 byte Y = y.Value [i];
320                                 
321                                 if (X > Y) 
322                                         return 1;
323                                 else if (X < Y)
324                                         return -1;
325                         }
326
327                         // If we are here, x and y were same size
328                         return 0;
329                 }
330
331         }
332 }