error messages review
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Gds / XdrStream.cs
1 /*\r
2  *      Firebird ADO.NET Data provider for .NET and     Mono \r
3  * \r
4  *         The contents of this file are subject to the Initial \r
5  *         Developer's Public License Version 1.0 (the "License"); \r
6  *         you may not use this file except in compliance with the \r
7  *         License. You may obtain a copy of the License at \r
8  *         http://www.firebirdsql.org/index.php?op=doc&id=idpl\r
9  *\r
10  *         Software distributed under the License is distributed on \r
11  *         an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either \r
12  *         express or implied. See the License for the specific \r
13  *         language governing rights and limitations under the License.\r
14  * \r
15  *      Copyright (c) 2002, 2005 Carlos Guzman Alvarez\r
16  *      All Rights Reserved.\r
17  */\r
18 \r
19 using System;\r
20 using System.Collections;\r
21 using System.IO;\r
22 using System.Net;\r
23 using System.Text;\r
24 using System.Globalization;\r
25 \r
26 using FirebirdSql.Data.Common;\r
27 \r
28 namespace FirebirdSql.Data.Gds\r
29 {\r
30         internal class XdrStream : Stream\r
31         {\r
32                 #region Static Fields\r
33 \r
34                 private static byte[] fill;\r
35                 private static byte[] pad;\r
36 \r
37                 #endregion\r
38 \r
39                 #region Static Properties\r
40 \r
41                 internal static byte[] Fill\r
42                 {\r
43                         get\r
44                         {\r
45                                 if (fill == null)\r
46                                 {\r
47                                         fill = new byte[32767];\r
48                                         for (int i = 0; i < fill.Length; i++)\r
49                                         {\r
50                                                 fill[i] = 32;\r
51                                         }\r
52                                 }\r
53 \r
54                                 return fill;\r
55                         }\r
56                 }\r
57 \r
58                 private static byte[] Pad\r
59                 {\r
60                         get\r
61                         {\r
62                                 if (pad == null)\r
63                                 {\r
64                                         pad = new byte[] { 0, 0, 0, 0 };\r
65                                 }\r
66 \r
67                                 return pad;\r
68                         }\r
69                 }\r
70 \r
71                 #endregion\r
72 \r
73                 #region Fields\r
74 \r
75                 private byte[]  buffer;\r
76                 private Charset charset;\r
77                 private Stream  innerStream;\r
78 \r
79                 #endregion\r
80 \r
81                 #region Stream Properties\r
82 \r
83                 public override bool CanWrite\r
84                 {\r
85                         get { return this.innerStream.CanWrite; }\r
86                 }\r
87 \r
88                 public override bool CanRead\r
89                 {\r
90                         get { return this.innerStream.CanRead; }\r
91                 }\r
92 \r
93                 public override bool CanSeek\r
94                 {\r
95                         get { return this.innerStream.CanSeek; }\r
96                 }\r
97 \r
98                 public override long Position\r
99                 {\r
100                         get { return this.innerStream.Position; }\r
101                         set { this.innerStream.Position = value; }\r
102                 }\r
103 \r
104                 public override long Length\r
105                 {\r
106                         get { return this.innerStream.Length; }\r
107                 }\r
108 \r
109                 #endregion\r
110 \r
111                 #region Constructors\r
112 \r
113                 public XdrStream() : this(Charset.DefaultCharset)\r
114                 {\r
115                 }\r
116 \r
117                 public XdrStream(Charset charset) : this(new MemoryStream(), charset)\r
118                 {\r
119                 }\r
120 \r
121                 public XdrStream(byte[] buffer, Charset charset) : this(new MemoryStream(buffer), charset)\r
122                 {\r
123                 }\r
124 \r
125                 public XdrStream(Stream innerStream, Charset charset) : base()\r
126                 {\r
127                         this.buffer                     = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };\r
128                         this.innerStream        = innerStream;\r
129                         this.charset            = charset;\r
130                 }\r
131 \r
132                 #endregion\r
133 \r
134                 #region Stream methods\r
135 \r
136                 public override void Close()\r
137                 {\r
138                         if (this.innerStream != null)\r
139                         {\r
140                                 this.innerStream.Close();\r
141                         }\r
142 \r
143                         this.buffer                     = null;\r
144                         this.charset            = null;\r
145                         this.innerStream        = null;\r
146                 }\r
147 \r
148                 public override void Flush()\r
149                 {\r
150                         this.CheckDisposed();\r
151 \r
152                         this.innerStream.Flush();\r
153                 }\r
154 \r
155                 public override void SetLength(long length)\r
156                 {\r
157                         this.CheckDisposed();\r
158 \r
159                         this.innerStream.SetLength(length);\r
160                 }\r
161 \r
162                 public override long Seek(long offset, System.IO.SeekOrigin loc)\r
163                 {\r
164                         this.CheckDisposed();\r
165 \r
166                         return this.innerStream.Seek(offset, loc);\r
167                 }\r
168 \r
169                 public override int Read(byte[] buffer, int offset, int count)\r
170                 {\r
171                         this.CheckDisposed();\r
172 \r
173                         if (this.CanRead)\r
174                         {\r
175                                 return this.innerStream.Read(buffer, offset, count);\r
176                         }\r
177 \r
178                         throw new InvalidOperationException("Read operations are not allowed by this stream");\r
179                 }\r
180 \r
181                 public override void WriteByte(byte value)\r
182                 {\r
183                         this.CheckDisposed();\r
184 \r
185                         this.innerStream.WriteByte(value);\r
186                 }\r
187 \r
188                 public override void Write(byte[] buffer, int offset, int count)\r
189                 {\r
190                         this.CheckDisposed();\r
191 \r
192                         if (this.CanWrite)\r
193                         {\r
194                                 this.innerStream.Write(buffer, offset, count);\r
195                         }\r
196                         else\r
197                         {\r
198                                 throw new InvalidOperationException("Write operations are not allowed by this stream");\r
199                         }\r
200                 }\r
201 \r
202                 public byte[] ToArray()\r
203                 {\r
204                         this.CheckDisposed();\r
205 \r
206                         if (this.innerStream is MemoryStream)\r
207                         {\r
208                                 return ((MemoryStream)this.innerStream).ToArray();\r
209                         }\r
210 \r
211                         throw new InvalidOperationException();\r
212                 }\r
213 \r
214                 #endregion\r
215 \r
216                 #region Xdr     Read Methods\r
217 \r
218                 public byte[] ReadBytes(int count)\r
219                 {\r
220                         byte[] buffer = new byte[count];\r
221                         this.Read(buffer, 0, buffer.Length);\r
222 \r
223                         return buffer;\r
224                 }\r
225 \r
226                 public byte[] ReadOpaque(int length)\r
227                 {\r
228                         byte[] buffer = new byte[length];\r
229                         int readed = 0;\r
230 \r
231                         if (length > 0)\r
232                         {\r
233                                 while (readed < length)\r
234                                 {\r
235                                         readed += this.Read(buffer, readed, length - readed);\r
236                                 }\r
237 \r
238                                 int padLength = ((4 - length) & 3);\r
239                                 if (padLength > 0)\r
240                                 {\r
241                                         this.Read(Pad, 0, padLength);\r
242                                 }\r
243                         }\r
244 \r
245                         return buffer;\r
246                 }\r
247 \r
248                 public byte[] ReadBuffer()\r
249                 {\r
250                         return this.ReadOpaque(this.ReadInt32());\r
251                 }\r
252 \r
253                 public string ReadString()\r
254                 {\r
255                         return this.ReadString(this.charset);\r
256                 }\r
257 \r
258                 public string ReadString(int length)\r
259                 {\r
260                         return this.ReadString(this.charset, length);\r
261                 }\r
262 \r
263                 public string ReadString(Charset charset)\r
264                 {\r
265                         return this.ReadString(charset, this.ReadInt32());\r
266                 }\r
267 \r
268                 public string ReadString(Charset charset, int length)\r
269                 {\r
270                         byte[] buffer = this.ReadOpaque(length);\r
271 \r
272                         return charset.GetString(buffer, 0, buffer.Length);\r
273                 }\r
274 \r
275                 public short ReadInt16()\r
276                 {\r
277                         return Convert.ToInt16(this.ReadInt32());\r
278                 }\r
279 \r
280                 public int ReadInt32()\r
281                 {\r
282                         this.Read(buffer, 0, 4);\r
283 \r
284                         return IPAddress.HostToNetworkOrder(BitConverter.ToInt32(buffer, 0));\r
285                 }\r
286 \r
287                 public long ReadInt64()\r
288                 {\r
289                         this.Read(buffer, 0, 8);\r
290 \r
291                         return IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer, 0));\r
292                 }\r
293 \r
294                 public Guid ReadGuid(int length)\r
295                 {\r
296                         return new Guid(this.ReadOpaque(length));\r
297                 }\r
298 \r
299                 public float ReadSingle()\r
300                 {\r
301                         return BitConverter.ToSingle(BitConverter.GetBytes(this.ReadInt32()), 0);\r
302                 }\r
303 \r
304                 public double ReadDouble()\r
305                 {\r
306                         return BitConverter.ToDouble(BitConverter.GetBytes(this.ReadInt64()), 0);\r
307                 }\r
308 \r
309                 public DateTime ReadDateTime()\r
310                 {\r
311                         DateTime date = this.ReadDate();\r
312                         DateTime time = this.ReadTime();\r
313 \r
314                         return new System.DateTime(\r
315                                 date.Year, date.Month, date.Day,\r
316                                 time.Hour, time.Minute, time.Second, time.Millisecond);\r
317                 }\r
318 \r
319                 public DateTime ReadDate()\r
320                 {\r
321                         return TypeDecoder.DecodeDate(this.ReadInt32());\r
322                 }\r
323 \r
324                 public DateTime ReadTime()\r
325                 {\r
326                         return TypeDecoder.DecodeTime(this.ReadInt32());\r
327                 }\r
328 \r
329                 public decimal ReadDecimal(int type, int scale)\r
330                 {\r
331                         decimal value = 0;\r
332 \r
333                         switch (type & ~1)\r
334                         {\r
335                                 case IscCodes.SQL_SHORT:\r
336                                         value = TypeDecoder.DecodeDecimal(this.ReadInt16(), scale, type);\r
337                                         break;\r
338 \r
339                                 case IscCodes.SQL_LONG:\r
340                                         value = TypeDecoder.DecodeDecimal(this.ReadInt32(), scale, type);\r
341                                         break;\r
342 \r
343                                 case IscCodes.SQL_QUAD:\r
344                                 case IscCodes.SQL_INT64:\r
345                                         value = TypeDecoder.DecodeDecimal(this.ReadInt64(), scale, type);\r
346                                         break;\r
347 \r
348                                 case IscCodes.SQL_DOUBLE:\r
349                                 case IscCodes.SQL_D_FLOAT:\r
350                                         value = Convert.ToDecimal(this.ReadDouble());\r
351                                         break;\r
352                         }\r
353 \r
354                         return value;\r
355                 }\r
356 \r
357                 public object ReadValue(DbField field)\r
358                 {\r
359                         object fieldValue = null;\r
360                         Charset innerCharset = (this.charset.Name != "NONE") ? this.charset : field.Charset;\r
361 \r
362                         switch (field.DbDataType)\r
363                         {\r
364                                 case DbDataType.Char:\r
365                                         {\r
366                                                 string s = this.ReadString(innerCharset, field.Length);\r
367 \r
368                                                 if ((field.Length % field.Charset.BytesPerCharacter) == 0 &&\r
369                                                         s.Length > field.CharCount)\r
370                                                 {\r
371                                                         fieldValue = s.Substring(0, field.CharCount);\r
372                                                 }\r
373                                                 else\r
374                                                 {\r
375                                                         fieldValue = s;\r
376                                                 }\r
377                                         }\r
378                                         break;\r
379 \r
380                                 case DbDataType.VarChar:\r
381                                         fieldValue = this.ReadString(innerCharset).TrimEnd();\r
382                                         break;\r
383 \r
384                                 case DbDataType.SmallInt:\r
385                                         fieldValue = this.ReadInt16();\r
386                                         break;\r
387 \r
388                                 case DbDataType.Integer:\r
389                                         fieldValue = this.ReadInt32();\r
390                                         break;\r
391 \r
392                                 case DbDataType.Array:\r
393                                 case DbDataType.Binary:\r
394                                 case DbDataType.Text:\r
395                                 case DbDataType.BigInt:\r
396                                         fieldValue = this.ReadInt64();\r
397                                         break;\r
398 \r
399                                 case DbDataType.Decimal:\r
400                                 case DbDataType.Numeric:\r
401                                         fieldValue = this.ReadDecimal(\r
402                                                 field.DataType,\r
403                                                 field.NumericScale);\r
404                                         break;\r
405 \r
406                                 case DbDataType.Float:\r
407                                         fieldValue = this.ReadSingle();\r
408                                         break;\r
409 \r
410                                 case DbDataType.Guid:\r
411                                         fieldValue = this.ReadGuid(field.Length);\r
412                                         break;\r
413 \r
414                                 case DbDataType.Double:\r
415                                         fieldValue = this.ReadDouble();\r
416                                         break;\r
417 \r
418                                 case DbDataType.Date:\r
419                                         fieldValue = this.ReadDate();\r
420                                         break;\r
421 \r
422                                 case DbDataType.Time:\r
423                                         fieldValue = this.ReadTime();\r
424                                         break;\r
425 \r
426                                 case DbDataType.TimeStamp:\r
427                                         fieldValue = this.ReadDateTime();\r
428                                         break;\r
429                         }\r
430 \r
431                         int sqlInd = this.ReadInt32();\r
432 \r
433                         if (sqlInd == 0)\r
434                         {\r
435                                 return fieldValue;\r
436                         }\r
437                         else if (sqlInd == -1)\r
438                         {\r
439                                 return null;\r
440                         }\r
441                         else\r
442                         {\r
443                                 throw new IscException("invalid sqlind value: " + sqlInd);\r
444                         }\r
445                 }\r
446 \r
447                 #endregion\r
448 \r
449                 #region Xdr     Write Methods\r
450 \r
451                 public void WriteOpaque(byte[] buffer)\r
452                 {\r
453                         this.WriteOpaque(buffer, buffer.Length);\r
454                 }\r
455 \r
456                 public void WriteOpaque(byte[] buffer, int length)\r
457                 {\r
458                         if (buffer != null && length > 0)\r
459                         {\r
460                                 this.Write(buffer, 0, buffer.Length);\r
461                                 this.Write(Fill, 0, length - buffer.Length);\r
462                                 this.Write(Pad, 0, ((4 - length) & 3));\r
463                         }\r
464                 }\r
465 \r
466                 public void WriteBuffer(byte[] buffer)\r
467                 {\r
468                         this.WriteBuffer(buffer, buffer == null ? 0 : buffer.Length);\r
469                 }\r
470 \r
471                 public void WriteBuffer(byte[] buffer, int length)\r
472                 {\r
473                         this.Write(length);\r
474                         if (buffer != null && length > 0)\r
475                         {\r
476                                 this.Write(buffer, 0, length);\r
477                                 this.Write(Pad, 0, ((4 - length) & 3));\r
478                         }\r
479                 }\r
480 \r
481                 public void WriteBlobBuffer(byte[] buffer)\r
482                 {\r
483                         int length = buffer.Length;     // 2 for short for buffer length\r
484 \r
485                         if (length > short.MaxValue)\r
486                         {\r
487                                 throw (new IOException()); //Need a     value???\r
488                         }\r
489 \r
490                         this.Write(length + 2);\r
491                         this.Write(length + 2); //bizarre but true!     three copies of the     length\r
492                         this.WriteByte((byte)((length >> 0) & 0xff));\r
493                         this.WriteByte((byte)((length >> 8) & 0xff));\r
494                         this.Write(buffer, 0, length);\r
495 \r
496                         this.Write(Pad, 0, ((4 - length + 2) & 3));\r
497                 }\r
498 \r
499                 public void WriteTyped(int type, byte[] buffer)\r
500                 {\r
501                         int length;\r
502 \r
503                         if (buffer == null)\r
504                         {\r
505                                 this.Write(1);\r
506                                 this.WriteByte((byte)type);\r
507                                 length = 1;\r
508                         }\r
509                         else\r
510                         {\r
511                                 length = buffer.Length + 1;\r
512                                 this.Write(length);\r
513                                 this.WriteByte((byte)type);\r
514                                 this.Write(buffer, 0, buffer.Length);\r
515                         }\r
516                         this.Write(Pad, 0, ((4 - length) & 3));\r
517                 }\r
518 \r
519                 public void Write(string value)\r
520                 {\r
521                         byte[] buffer = this.charset.GetBytes(value);\r
522 \r
523                         this.WriteBuffer(buffer, buffer.Length);\r
524                 }\r
525 \r
526                 public void Write(short value)\r
527                 {\r
528                         this.Write((int)value);\r
529                 }\r
530 \r
531                 public void Write(int value)\r
532                 {\r
533                         this.Write(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(value)), 0, 4);\r
534                 }\r
535 \r
536                 public void Write(long value)\r
537                 {\r
538                         this.Write(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(value)), 0, 8);\r
539                 }\r
540 \r
541                 public void Write(float value)\r
542                 {\r
543                         byte[] buffer = BitConverter.GetBytes(value);\r
544 \r
545                         this.Write(BitConverter.ToInt32(buffer, 0));\r
546                 }\r
547 \r
548                 public void Write(double value)\r
549                 {\r
550                         byte[] buffer = BitConverter.GetBytes(value);\r
551 \r
552                         this.Write(BitConverter.ToInt64(buffer, 0));\r
553                 }\r
554 \r
555                 public void Write(decimal value, int type, int scale)\r
556                 {\r
557                         object numeric = TypeEncoder.EncodeDecimal(value, scale, type);\r
558 \r
559                         switch (type & ~1)\r
560                         {\r
561                                 case IscCodes.SQL_SHORT:\r
562                                         this.Write((short)numeric);\r
563                                         break;\r
564 \r
565                                 case IscCodes.SQL_LONG:\r
566                                         this.Write((int)numeric);\r
567                                         break;\r
568 \r
569                                 case IscCodes.SQL_QUAD:\r
570                                 case IscCodes.SQL_INT64:\r
571                                         this.Write((long)numeric);\r
572                                         break;\r
573 \r
574                                 case IscCodes.SQL_DOUBLE:\r
575                                 case IscCodes.SQL_D_FLOAT:\r
576                                         this.Write((double)value);\r
577                                         break;\r
578                         }\r
579                 }\r
580 \r
581                 public void Write(DateTime value)\r
582                 {\r
583                         this.WriteDate(value);\r
584                         this.WriteTime(value);\r
585                 }\r
586 \r
587                 public void WriteDate(DateTime value)\r
588                 {\r
589                         this.Write(TypeEncoder.EncodeDate(Convert.ToDateTime(value)));\r
590                 }\r
591 \r
592                 public void WriteTime(DateTime value)\r
593                 {\r
594                         this.Write(TypeEncoder.EncodeTime(Convert.ToDateTime(value)));\r
595                 }\r
596 \r
597                 public void Write(Descriptor descriptor)\r
598                 {\r
599                         for (int i = 0; i < descriptor.Count; i++)\r
600                         {\r
601                                 this.Write(descriptor[i]);\r
602                         }\r
603                 }\r
604 \r
605                 public void Write(DbField param)\r
606                 {\r
607                         Charset innerCharset = (this.charset.Name != "NONE") ? this.charset : param.Charset;\r
608 \r
609                         param.FixNull();\r
610 \r
611                         try\r
612                         {\r
613                                 switch (param.DbDataType)\r
614                                 {\r
615                                         case DbDataType.Char:\r
616                                                 {\r
617                                                         string svalue = param.DbValue.GetString();\r
618 \r
619                                                         if ((param.Length % param.Charset.BytesPerCharacter) == 0 &&\r
620                                                                 svalue.Length > param.CharCount)\r
621                                                         {\r
622                                                                 throw new IscException(335544321);\r
623                                                         }\r
624 \r
625                                                         this.WriteOpaque(innerCharset.GetBytes(svalue), param.Length);\r
626                                                 }\r
627                                                 break;\r
628 \r
629                                         case DbDataType.VarChar:\r
630                                                 {\r
631                                                         string svalue = param.DbValue.GetString().TrimEnd();\r
632 \r
633                                                         if ((param.Length % param.Charset.BytesPerCharacter) == 0 &&\r
634                                                                 svalue.Length > param.CharCount)\r
635                                                         {\r
636                                                                 throw new IscException(335544321);\r
637                                                         }\r
638 \r
639                                                         byte[] data = innerCharset.GetBytes(svalue);\r
640 \r
641                                                         this.WriteBuffer(data, data.Length);\r
642                                                 }\r
643                                                 break;\r
644 \r
645                                         case DbDataType.SmallInt:\r
646                                                 this.Write(param.DbValue.GetInt16());\r
647                                                 break;\r
648 \r
649                                         case DbDataType.Integer:\r
650                                                 this.Write(param.DbValue.GetInt32());\r
651                                                 break;\r
652 \r
653                                         case DbDataType.BigInt:\r
654                                         case DbDataType.Array:\r
655                                         case DbDataType.Binary:\r
656                                         case DbDataType.Text:\r
657                                                 this.Write(param.DbValue.GetInt64());\r
658                                                 break;\r
659 \r
660                                         case DbDataType.Decimal:\r
661                                         case DbDataType.Numeric:\r
662                                                 this.Write(\r
663                                                         param.DbValue.GetDecimal(),\r
664                                                         param.DataType,\r
665                                                         param.NumericScale);\r
666                                                 break;\r
667 \r
668                                         case DbDataType.Float:\r
669                                                 this.Write(param.DbValue.GetFloat());\r
670                                                 break;\r
671 \r
672                                         case DbDataType.Guid:\r
673                                                 this.WriteOpaque(param.DbValue.GetGuid().ToByteArray());\r
674                                                 break;\r
675 \r
676                                         case DbDataType.Double:\r
677                                                 this.Write(param.DbValue.GetDouble());\r
678                                                 break;\r
679 \r
680                                         case DbDataType.Date:\r
681                                                 this.Write(param.DbValue.EncodeDate());\r
682                                                 break;\r
683 \r
684                                         case DbDataType.Time:\r
685                                                 this.Write(param.DbValue.EncodeTime());\r
686                                                 break;\r
687 \r
688                                         case DbDataType.TimeStamp:\r
689                                                 this.Write(param.DbValue.EncodeDate());\r
690                                                 this.Write(param.DbValue.EncodeTime());\r
691                                                 break;\r
692 \r
693                                         default:\r
694                                                 throw new IscException("Unknown sql data type: " + param.DataType);\r
695                                 }\r
696 \r
697                                 this.Write(param.NullFlag);\r
698                         }\r
699                         catch (IOException)\r
700                         {\r
701                                 throw new IscException(IscCodes.isc_net_write_err);\r
702                         }\r
703                 }\r
704 \r
705                 #endregion\r
706 \r
707                 #region Private Methods\r
708 \r
709                 private void CheckDisposed()\r
710                 {\r
711                         if (this.innerStream == null)\r
712                         {\r
713                                 throw new ObjectDisposedException("The XdrStream is closed.");\r
714                         }\r
715                 }\r
716 \r
717                 #endregion\r
718         }\r
719 }\r