internal bool TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead)
{
int charsRead = 0;
int charsLeft = 0;
char[] newbuf;
if (stateObj._longlen == 0)
{
Debug.Assert(stateObj._longlenleft == 0);
totalCharsRead = 0;
return true; // No data
}
Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL),
"Out of sync plp read request");
Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!");
charsLeft = len;
// If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time
if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN)
{
buff = new char[(int)Math.Min((int)stateObj._longlen, len)];
}
if (stateObj._longlenleft == 0)
{
ulong ignored;
if (!stateObj.TryReadPlpLength(false, out ignored))
{
totalCharsRead = 0;
return false;
}
if (stateObj._longlenleft == 0)
{ // Data read complete
totalCharsRead = 0;
return true;
}
}
totalCharsRead = 0;
while (charsLeft > 0)
{
charsRead = (int)Math.Min((stateObj._longlenleft + 1) >> 1, (ulong)charsLeft);
if ((buff == null) || (buff.Length < (offst + charsRead)))
{
// Grow the array
newbuf = new char[offst + charsRead];
if (buff != null)
{
Buffer.BlockCopy(buff, 0, newbuf, 0, offst * 2);
}
buff = newbuf;
}
if (charsRead > 0)
{
if (!TryReadPlpUnicodeCharsChunk(buff, offst, charsRead, stateObj, out charsRead))
{
return false;
}
charsLeft -= charsRead;
offst += charsRead;
totalCharsRead += charsRead;
}
// Special case single byte left
if (stateObj._longlenleft == 1 && (charsLeft > 0))
{
byte b1;
if (!stateObj.TryReadByte(out b1))
{
return false;
}
stateObj._longlenleft--;
ulong ignored;
if (!stateObj.TryReadPlpLength(false, out ignored))
{
return false;
}
Debug.Assert((stateObj._longlenleft != 0), "ReadPlpUnicodeChars: Odd byte left at the end!");
byte b2;
if (!stateObj.TryReadByte(out b2))
{
return false;
}
stateObj._longlenleft--;
// Put it at the end of the array. At this point we know we have an extra byte.
buff[offst] = (char)(((b2 & 0xff) << 8) + (b1 & 0xff));
offst = checked((int)offst + 1);
charsRead++;
charsLeft--;
totalCharsRead++;
}
if (stateObj._longlenleft == 0)
{ // Read the next chunk or cleanup state if hit the end
ulong ignored;
if (!stateObj.TryReadPlpLength(false, out ignored))
{
return false;
}
}
if (stateObj._longlenleft == 0) // Data read complete
break;
}
return true;
}