private int ReadBytes(Encoding encoding, int byteBlock, int charBlock, byte[] buffer, int offset, int byteCount, bool readContent)
{
// If there are any trailing buffer return them.
if (_trailByteCount > 0)
{
int actual = Math.Min(_trailByteCount, byteCount);
Buffer.BlockCopy(_trailBytes, 0, buffer, offset, actual);
_trailByteCount -= actual;
Buffer.BlockCopy(_trailBytes, actual, _trailBytes, 0, _trailByteCount);
return actual;
}
XmlNodeType nodeType = _node.NodeType;
if (nodeType == XmlNodeType.Element || nodeType == XmlNodeType.EndElement)
return 0;
int maxCharCount;
if (byteCount < byteBlock)
{
// Convert at least charBlock chars
maxCharCount = charBlock;
}
else
{
// Round down to the nearest multiple of charBlock
maxCharCount = byteCount / byteBlock * charBlock;
}
char[] chars = GetCharBuffer(maxCharCount);
int charCount = 0;
while (true)
{
// If we didn't align on the boundary, then we might have some remaining characters
if (_trailCharCount > 0)
{
Array.Copy(_trailChars, 0, chars, charCount, _trailCharCount);
charCount += _trailCharCount;
_trailCharCount = 0;
}
// Read until we at least get a charBlock
while (charCount < charBlock)
{
int actualCharCount;
if (readContent)
{
actualCharCount = ReadContentAsChars(chars, charCount, maxCharCount - charCount);
// When deserializing base64 content which contains new line chars (CR, LF) chars from ReadObject, the reader reads in chunks of base64 content, LF char, base64 content, LF char and so on
// Relying on encoding.GetBytes' exception to handle LF char would result in performance degradation so skipping LF char here
if (actualCharCount == 1 && chars[charCount] == '\n')
continue;
}
else
{
actualCharCount = ReadValueChunk(chars, charCount, maxCharCount - charCount);
}
if (actualCharCount == 0)
break;
charCount += actualCharCount;
}
// Trim so its a multiple of charBlock
if (charCount >= charBlock)
{
_trailCharCount = (charCount % charBlock);
if (_trailCharCount > 0)
{
if (_trailChars == null)
_trailChars = new char[4];
charCount = charCount - _trailCharCount;
Array.Copy(chars, charCount, _trailChars, 0, _trailCharCount);
}
}
try
{
if (byteCount < byteBlock)
{
if (_trailBytes == null)
_trailBytes = new byte[3];
_trailByteCount = encoding.GetBytes(chars, 0, charCount, _trailBytes, 0);
int actual = Math.Min(_trailByteCount, byteCount);
Buffer.BlockCopy(_trailBytes, 0, buffer, offset, actual);
_trailByteCount -= actual;
Buffer.BlockCopy(_trailBytes, actual, _trailBytes, 0, _trailByteCount);
return actual;
}
else
{
// charCount is a multiple of charBlock and we have enough room to convert everything
return encoding.GetBytes(chars, 0, charCount, buffer, offset);
}
}
catch (FormatException exception)
{
// Something was wrong with the format, see if we can strip the spaces
int i = 0;
int j = 0;
while (true)
{
while (j < charCount && XmlConverter.IsWhitespace(chars[j]))
j++;
if (j == charCount)
break;
chars[i++] = chars[j++];
}
// No spaces, so don't try again
if (i == charCount)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(exception.Message, exception.InnerException));
charCount = i;
}
}
}