1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
using System;
using System.Data.Common;
using System.Diagnostics;
using Microsoft.SqlServer.Server;
namespace System.Data.SqlClient
{
sealed internal class SqlSequentialTextReaderSmi : System.IO.TextReader
{
private SmiEventSink_Default _sink;
private ITypedGettersV3 _getters;
private int _columnIndex; // The index of out column in the table
private long _position; // Current position in the stream
private long _length; // Total length of the stream
private int _peekedChar; // Current peeked character (if any)
internal SqlSequentialTextReaderSmi(SmiEventSink_Default sink, ITypedGettersV3 getters, int columnIndex, long length)
{
_sink = sink;
_getters = getters;
_columnIndex = columnIndex;
_length = length;
_position = 0;
_peekedChar = -1;
}
internal int ColumnIndex
{
get { return _columnIndex; }
}
public override int Peek()
{
if (!HasPeekedChar)
{
_peekedChar = Read();
}
Debug.Assert(_peekedChar == -1 || ((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue)), string.Format("Bad peeked character: {0}", _peekedChar));
return _peekedChar;
}
public override int Read()
{
if (IsClosed)
{
throw ADP.ObjectDisposed(this);
}
int readChar = -1;
// If there is already a peeked char, then return it
if (HasPeekedChar)
{
readChar = _peekedChar;
_peekedChar = -1;
}
// If there is data available try to read a char
else if (_position < _length)
{
char[] tempBuffer = new char[1];
int charsRead = ValueUtilsSmi.GetChars_Unchecked(_sink, _getters, _columnIndex, _position, tempBuffer, 0, 1);
if (charsRead == 1)
{
readChar = tempBuffer[0];
_position++;
}
}
Debug.Assert(readChar == -1 || ((readChar >= char.MinValue) && (readChar <= char.MaxValue)), string.Format("Bad read character: {0}", readChar));
return readChar;
}
public override int Read(char[] buffer, int index, int count)
{
SqlSequentialTextReader.ValidateReadParameters(buffer, index, count);
if (IsClosed)
{
throw ADP.ObjectDisposed(this);
}
int charsRead = 0;
// Load in peeked char
if ((count > 0) && (HasPeekedChar))
{
Debug.Assert((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue), string.Format("Bad peeked character: {0}", _peekedChar));
buffer[index + charsRead] = (char)_peekedChar;
charsRead++;
_peekedChar = -1;
}
// Read whichever is less: however much the user asked for, or however much we have
// NOTE: It is safe to do this since count <= Int32.MaxValue, therefore the Math.Min should always result in an int
int charsNeeded = (int)Math.Min((long)(count - charsRead), _length - _position);
// If we need more data and there is data avaiable, read
if (charsNeeded > 0)
{
int newCharsRead = ValueUtilsSmi.GetChars_Unchecked(_sink, _getters, _columnIndex, _position, buffer, index + charsRead, charsNeeded);
_position += newCharsRead;
charsRead += newCharsRead;
}
return charsRead;
}
/// <summary>
/// Forces the TextReader to act as if it was closed
/// This does not actually close the stream, read off the rest of the data or dispose this
/// </summary>
internal void SetClosed()
{
_sink = null;
_getters = null;
_peekedChar = -1;
}
/// <summary>
/// True if this TextReader is supposed to be closed
/// </summary>
private bool IsClosed
{
get { return ((_sink == null) || (_getters == null)); }
}
/// <summary>
/// True if there is a peeked character available
/// </summary>
private bool HasPeekedChar
{
get { return (_peekedChar >= char.MinValue); }
}
}
}
|