public long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length)
{
if (_xmlReader == null)
{
SqlStream sqlStream = new SqlStream(_columnOrdinal, _reader, true /* addByteOrderMark */, false /* processAllRows*/, false /*advanceReader*/);
_xmlReader = sqlStream.ToXmlReader();
_strWriter = new StringWriter((System.IFormatProvider)null);
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.CloseOutput = true; // close the memory stream when done
writerSettings.ConformanceLevel = ConformanceLevel.Fragment;
_xmlWriter = XmlWriter.Create(_strWriter, writerSettings);
}
int charsToSkip = 0;
int cnt = 0;
if (dataIndex < _charsRemoved)
{
throw ADP.NonSeqByteAccess(dataIndex, _charsRemoved, nameof(GetChars));
}
else if (dataIndex > _charsRemoved)
{
charsToSkip = (int)(dataIndex - _charsRemoved);
}
// If buffer parameter is null, we have to return -1 since there is no way for us to know the
// total size up front without reading and converting the XML.
if (buffer == null)
{
return (long)(-1);
}
StringBuilder strBldr = _strWriter.GetStringBuilder();
while (!_xmlReader.EOF)
{
if (strBldr.Length >= (length + charsToSkip))
{
break;
}
// Can't call _xmlWriter.WriteNode here, since it reads all of the data in before returning the first char.
// Do own implementation of WriteNode instead that reads just enough data to return the required number of chars
//_xmlWriter.WriteNode(_xmlReader, true);
// _xmlWriter.Flush();
WriteXmlElement();
if (charsToSkip > 0)
{
// Aggressively remove the characters we want to skip to avoid growing StringBuilder size too much
cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip;
strBldr.Remove(0, cnt);
charsToSkip -= cnt;
_charsRemoved += (long)cnt;
}
}
if (charsToSkip > 0)
{
cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip;
strBldr.Remove(0, cnt);
charsToSkip -= cnt;
_charsRemoved += (long)cnt;
}
if (strBldr.Length == 0)
{
return 0;
}
// At this point charsToSkip must be 0
Debug.Assert(charsToSkip == 0);
cnt = strBldr.Length < length ? strBldr.Length : length;
for (int i = 0; i < cnt; i++)
{
buffer[bufferIndex + i] = strBldr[i];
}
// Remove the characters we have already returned
strBldr.Remove(0, cnt);
_charsRemoved += (long)cnt;
return (long)cnt;
}