2 * Firebird ADO.NET Data provider for .NET and Mono
4 * The contents of this file are subject to the Initial
5 * Developer's Public License Version 1.0 (the "License");
6 * you may not use this file except in compliance with the
7 * License. You may obtain a copy of the License at
8 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
10 * Software distributed under the License is distributed on
11 * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
12 * express or implied. See the License for the specific
13 * language governing rights and limitations under the License.
15 * Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16 * All Rights Reserved.
20 using System.Collections;
24 using System.Globalization;
26 using FirebirdSql.Data.Common;
28 namespace FirebirdSql.Data.Gds
30 internal class XdrStream : Stream
34 private static byte[] fill;
35 private static byte[] pad;
39 #region Static Properties
41 internal static byte[] Fill
47 fill = new byte[32767];
48 for (int i = 0; i < fill.Length; i++)
58 private static byte[] Pad
64 pad = new byte[] { 0, 0, 0, 0 };
75 private byte[] buffer;
76 private Charset charset;
77 private Stream innerStream;
81 #region Stream Properties
83 public override bool CanWrite
85 get { return this.innerStream.CanWrite; }
88 public override bool CanRead
90 get { return this.innerStream.CanRead; }
93 public override bool CanSeek
95 get { return this.innerStream.CanSeek; }
98 public override long Position
100 get { return this.innerStream.Position; }
101 set { this.innerStream.Position = value; }
104 public override long Length
106 get { return this.innerStream.Length; }
113 public XdrStream() : this(Charset.DefaultCharset)
117 public XdrStream(Charset charset) : this(new MemoryStream(), charset)
121 public XdrStream(byte[] buffer, Charset charset) : this(new MemoryStream(buffer), charset)
125 public XdrStream(Stream innerStream, Charset charset) : base()
127 this.buffer = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
128 this.innerStream = innerStream;
129 this.charset = charset;
134 #region Stream methods
136 public override void Close()
138 if (this.innerStream != null)
140 this.innerStream.Close();
145 this.innerStream = null;
148 public override void Flush()
150 this.CheckDisposed();
152 this.innerStream.Flush();
155 public override void SetLength(long length)
157 this.CheckDisposed();
159 this.innerStream.SetLength(length);
162 public override long Seek(long offset, System.IO.SeekOrigin loc)
164 this.CheckDisposed();
166 return this.innerStream.Seek(offset, loc);
169 public override int Read(byte[] buffer, int offset, int count)
171 this.CheckDisposed();
175 return this.innerStream.Read(buffer, offset, count);
178 throw new InvalidOperationException("Read operations are not allowed by this stream");
181 public override void WriteByte(byte value)
183 this.CheckDisposed();
185 this.innerStream.WriteByte(value);
188 public override void Write(byte[] buffer, int offset, int count)
190 this.CheckDisposed();
194 this.innerStream.Write(buffer, offset, count);
198 throw new InvalidOperationException("Write operations are not allowed by this stream");
202 public byte[] ToArray()
204 this.CheckDisposed();
206 if (this.innerStream is MemoryStream)
208 return ((MemoryStream)this.innerStream).ToArray();
211 throw new InvalidOperationException();
216 #region Xdr Read Methods
218 public byte[] ReadBytes(int count)
220 byte[] buffer = new byte[count];
221 this.Read(buffer, 0, buffer.Length);
226 public byte[] ReadOpaque(int length)
228 byte[] buffer = new byte[length];
233 while (readed < length)
235 readed += this.Read(buffer, readed, length - readed);
238 int padLength = ((4 - length) & 3);
241 this.Read(Pad, 0, padLength);
248 public byte[] ReadBuffer()
250 return this.ReadOpaque(this.ReadInt32());
253 public string ReadString()
255 return this.ReadString(this.charset);
258 public string ReadString(int length)
260 return this.ReadString(this.charset, length);
263 public string ReadString(Charset charset)
265 return this.ReadString(charset, this.ReadInt32());
268 public string ReadString(Charset charset, int length)
270 byte[] buffer = this.ReadOpaque(length);
272 return charset.GetString(buffer, 0, buffer.Length);
275 public short ReadInt16()
277 return Convert.ToInt16(this.ReadInt32());
280 public int ReadInt32()
282 this.Read(buffer, 0, 4);
284 return IPAddress.HostToNetworkOrder(BitConverter.ToInt32(buffer, 0));
287 public long ReadInt64()
289 this.Read(buffer, 0, 8);
291 return IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer, 0));
294 public Guid ReadGuid(int length)
296 return new Guid(this.ReadOpaque(length));
299 public float ReadSingle()
301 return BitConverter.ToSingle(BitConverter.GetBytes(this.ReadInt32()), 0);
304 public double ReadDouble()
306 return BitConverter.ToDouble(BitConverter.GetBytes(this.ReadInt64()), 0);
309 public DateTime ReadDateTime()
311 DateTime date = this.ReadDate();
312 DateTime time = this.ReadTime();
314 return new System.DateTime(
315 date.Year, date.Month, date.Day,
316 time.Hour, time.Minute, time.Second, time.Millisecond);
319 public DateTime ReadDate()
321 return TypeDecoder.DecodeDate(this.ReadInt32());
324 public DateTime ReadTime()
326 return TypeDecoder.DecodeTime(this.ReadInt32());
329 public decimal ReadDecimal(int type, int scale)
335 case IscCodes.SQL_SHORT:
336 value = TypeDecoder.DecodeDecimal(this.ReadInt16(), scale, type);
339 case IscCodes.SQL_LONG:
340 value = TypeDecoder.DecodeDecimal(this.ReadInt32(), scale, type);
343 case IscCodes.SQL_QUAD:
344 case IscCodes.SQL_INT64:
345 value = TypeDecoder.DecodeDecimal(this.ReadInt64(), scale, type);
348 case IscCodes.SQL_DOUBLE:
349 case IscCodes.SQL_D_FLOAT:
350 value = Convert.ToDecimal(this.ReadDouble());
357 public object ReadValue(DbField field)
359 object fieldValue = null;
360 Charset innerCharset = (this.charset.Name != "NONE") ? this.charset : field.Charset;
362 switch (field.DbDataType)
364 case DbDataType.Char:
366 string s = this.ReadString(innerCharset, field.Length);
368 if ((field.Length % field.Charset.BytesPerCharacter) == 0 &&
369 s.Length > field.CharCount)
371 fieldValue = s.Substring(0, field.CharCount);
380 case DbDataType.VarChar:
381 fieldValue = this.ReadString(innerCharset).TrimEnd();
384 case DbDataType.SmallInt:
385 fieldValue = this.ReadInt16();
388 case DbDataType.Integer:
389 fieldValue = this.ReadInt32();
392 case DbDataType.Array:
393 case DbDataType.Binary:
394 case DbDataType.Text:
395 case DbDataType.BigInt:
396 fieldValue = this.ReadInt64();
399 case DbDataType.Decimal:
400 case DbDataType.Numeric:
401 fieldValue = this.ReadDecimal(
406 case DbDataType.Float:
407 fieldValue = this.ReadSingle();
410 case DbDataType.Guid:
411 fieldValue = this.ReadGuid(field.Length);
414 case DbDataType.Double:
415 fieldValue = this.ReadDouble();
418 case DbDataType.Date:
419 fieldValue = this.ReadDate();
422 case DbDataType.Time:
423 fieldValue = this.ReadTime();
426 case DbDataType.TimeStamp:
427 fieldValue = this.ReadDateTime();
431 int sqlInd = this.ReadInt32();
437 else if (sqlInd == -1)
443 throw new IscException("invalid sqlind value: " + sqlInd);
449 #region Xdr Write Methods
451 public void WriteOpaque(byte[] buffer)
453 this.WriteOpaque(buffer, buffer.Length);
456 public void WriteOpaque(byte[] buffer, int length)
458 if (buffer != null && length > 0)
460 this.Write(buffer, 0, buffer.Length);
461 this.Write(Fill, 0, length - buffer.Length);
462 this.Write(Pad, 0, ((4 - length) & 3));
466 public void WriteBuffer(byte[] buffer)
468 this.WriteBuffer(buffer, buffer == null ? 0 : buffer.Length);
471 public void WriteBuffer(byte[] buffer, int length)
474 if (buffer != null && length > 0)
476 this.Write(buffer, 0, length);
477 this.Write(Pad, 0, ((4 - length) & 3));
481 public void WriteBlobBuffer(byte[] buffer)
483 int length = buffer.Length; // 2 for short for buffer length
485 if (length > short.MaxValue)
487 throw (new IOException()); //Need a value???
490 this.Write(length + 2);
491 this.Write(length + 2); //bizarre but true! three copies of the length
492 this.WriteByte((byte)((length >> 0) & 0xff));
493 this.WriteByte((byte)((length >> 8) & 0xff));
494 this.Write(buffer, 0, length);
496 this.Write(Pad, 0, ((4 - length + 2) & 3));
499 public void WriteTyped(int type, byte[] buffer)
506 this.WriteByte((byte)type);
511 length = buffer.Length + 1;
513 this.WriteByte((byte)type);
514 this.Write(buffer, 0, buffer.Length);
516 this.Write(Pad, 0, ((4 - length) & 3));
519 public void Write(string value)
521 byte[] buffer = this.charset.GetBytes(value);
523 this.WriteBuffer(buffer, buffer.Length);
526 public void Write(short value)
528 this.Write((int)value);
531 public void Write(int value)
533 this.Write(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(value)), 0, 4);
536 public void Write(long value)
538 this.Write(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(value)), 0, 8);
541 public void Write(float value)
543 byte[] buffer = BitConverter.GetBytes(value);
545 this.Write(BitConverter.ToInt32(buffer, 0));
548 public void Write(double value)
550 byte[] buffer = BitConverter.GetBytes(value);
552 this.Write(BitConverter.ToInt64(buffer, 0));
555 public void Write(decimal value, int type, int scale)
557 object numeric = TypeEncoder.EncodeDecimal(value, scale, type);
561 case IscCodes.SQL_SHORT:
562 this.Write((short)numeric);
565 case IscCodes.SQL_LONG:
566 this.Write((int)numeric);
569 case IscCodes.SQL_QUAD:
570 case IscCodes.SQL_INT64:
571 this.Write((long)numeric);
574 case IscCodes.SQL_DOUBLE:
575 case IscCodes.SQL_D_FLOAT:
576 this.Write((double)value);
581 public void Write(DateTime value)
583 this.WriteDate(value);
584 this.WriteTime(value);
587 public void WriteDate(DateTime value)
589 this.Write(TypeEncoder.EncodeDate(Convert.ToDateTime(value)));
592 public void WriteTime(DateTime value)
594 this.Write(TypeEncoder.EncodeTime(Convert.ToDateTime(value)));
597 public void Write(Descriptor descriptor)
599 for (int i = 0; i < descriptor.Count; i++)
601 this.Write(descriptor[i]);
605 public void Write(DbField param)
607 Charset innerCharset = (this.charset.Name != "NONE") ? this.charset : param.Charset;
613 switch (param.DbDataType)
615 case DbDataType.Char:
617 string svalue = param.DbValue.GetString();
619 if ((param.Length % param.Charset.BytesPerCharacter) == 0 &&
620 svalue.Length > param.CharCount)
622 throw new IscException(335544321);
625 this.WriteOpaque(innerCharset.GetBytes(svalue), param.Length);
629 case DbDataType.VarChar:
631 string svalue = param.DbValue.GetString().TrimEnd();
633 if ((param.Length % param.Charset.BytesPerCharacter) == 0 &&
634 svalue.Length > param.CharCount)
636 throw new IscException(335544321);
639 byte[] data = innerCharset.GetBytes(svalue);
641 this.WriteBuffer(data, data.Length);
645 case DbDataType.SmallInt:
646 this.Write(param.DbValue.GetInt16());
649 case DbDataType.Integer:
650 this.Write(param.DbValue.GetInt32());
653 case DbDataType.BigInt:
654 case DbDataType.Array:
655 case DbDataType.Binary:
656 case DbDataType.Text:
657 this.Write(param.DbValue.GetInt64());
660 case DbDataType.Decimal:
661 case DbDataType.Numeric:
663 param.DbValue.GetDecimal(),
668 case DbDataType.Float:
669 this.Write(param.DbValue.GetFloat());
672 case DbDataType.Guid:
673 this.WriteOpaque(param.DbValue.GetGuid().ToByteArray());
676 case DbDataType.Double:
677 this.Write(param.DbValue.GetDouble());
680 case DbDataType.Date:
681 this.Write(param.DbValue.EncodeDate());
684 case DbDataType.Time:
685 this.Write(param.DbValue.EncodeTime());
688 case DbDataType.TimeStamp:
689 this.Write(param.DbValue.EncodeDate());
690 this.Write(param.DbValue.EncodeTime());
694 throw new IscException("Unknown sql data type: " + param.DataType);
697 this.Write(param.NullFlag);
701 throw new IscException(IscCodes.isc_net_write_err);
707 #region Private Methods
709 private void CheckDisposed()
711 if (this.innerStream == null)
713 throw new ObjectDisposedException("The XdrStream is closed.");