SqlSequentialTextReaderSmi.cs 4.5 KB

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