[System.Security.SecurityCritical] // auto-generated
internal override unsafe int GetChars(byte* bytes, int byteCount,
char* chars, int charCount, DecoderNLS baseDecoder)
{
Contract.Assert(byteCount >=0, "[UTF7Encoding.GetChars]byteCount >=0");
Contract.Assert(bytes!=null, "[UTF7Encoding.GetChars]bytes!=null");
Contract.Assert(charCount >=0, "[UTF7Encoding.GetChars]charCount >=0");
// Might use a decoder
UTF7Encoding.Decoder decoder = (UTF7Encoding.Decoder) baseDecoder;
// Get our output buffer info.
Encoding.EncodingCharBuffer buffer = new Encoding.EncodingCharBuffer(
this, decoder, chars, charCount, bytes, byteCount);
// Get decoder info
int bits = 0;
int bitCount = -1;
bool firstByte = false;
if (decoder != null)
{
bits = decoder.bits;
bitCount = decoder.bitCount;
firstByte = decoder.firstByte;
Contract.Assert(firstByte == false || decoder.bitCount <= 0,
"[UTF7Encoding.GetChars]If remembered bits, then first byte flag shouldn't be set");
}
// We may have had bits in the decoder that we couldn't output last time, so do so now
if (bitCount >= 16)
{
// Check our decoder buffer
if (!buffer.AddChar((char)((bits >> (bitCount - 16)) & 0xFFFF)))
ThrowCharsOverflow(decoder, true); // Always throw, they need at least 1 char even in Convert
// Used this one, clean up extra bits
bitCount -= 16;
}
// Loop through the input
while (buffer.MoreData)
{
byte currentByte = buffer.GetNextByte();
int c;
if (bitCount >= 0)
{
//
// Modified base 64 encoding.
//
sbyte v;
if (currentByte < 0x80 && ((v = base64Values[currentByte]) >=0))
{
firstByte = false;
bits = (bits << 6) | ((byte)v);
bitCount += 6;
if (bitCount >= 16)
{
c = (bits >> (bitCount - 16)) & 0xFFFF;
bitCount -= 16;
}
// If not enough bits just continue
else continue;
}
else
{
// If it wasn't a base 64 byte, everything's going to turn off base 64 mode
bitCount = -1;
if (currentByte != '-')
{
// >= 0x80 (because of 1st if statemtn)
// We need this check since the base64Values[b] check below need b <= 0x7f.
// This is not a valid base 64 byte. Terminate the shifted-sequence and
// emit this byte.
// not in base 64 table
// According to the RFC 1642 and the example code of UTF-7
// in Unicode 2.0, we should just zero-extend the invalid UTF7 byte
// Chars won't be updated unless this works, try to fallback
if (!buffer.Fallback(currentByte))
break; // Stop here, didn't throw
// Used that byte, we're done with it
continue;
}
//
// The encoding for '+' is "+-".
//
if (firstByte) c = '+';
// We just turn it off if not emitting a +, so we're done.
else continue;
}
//
// End of modified base 64 encoding block.
//
}
else if (currentByte == '+')
{
//
// Found the start of a modified base 64 encoding block or a plus sign.
//
bitCount = 0;
firstByte = true;
continue;
}
else
{
// Normal character
if (currentByte >= 0x80)
{
// Try to fallback
if (!buffer.Fallback(currentByte))
break; // Stop here, didn't throw
// Done falling back
continue;
}
// Use the normal character
c = currentByte;
}
if (c >= 0)
{
// Check our buffer
if (!buffer.AddChar((char)c))
{
// No room. If it was a plain char we'll try again later.
// Note, we'll consume this byte and stick it in decoder, even if we can't output it
if (bitCount >= 0) // Can we rememmber this byte (char)
{
buffer.AdjustBytes(+1); // Need to readd the byte that AddChar subtracted when it failed
bitCount += 16; // We'll still need that char we have in our bits
}
break; // didn't throw, stop
}
}
}
// Stick stuff in the decoder if we can (chars == null if counting, so don't store decoder)
if (chars != null && decoder != null)
{
// MustFlush? (Could've been cleared by ThrowCharsOverflow if Convert & didn't reach end of buffer)
if (decoder.MustFlush)
{
// RFC doesn't specify what would happen if we have non-0 leftover bits, we just drop them
decoder.bits = 0;
decoder.bitCount = -1;
decoder.firstByte = false;
}
else
{
decoder.bits = bits;
decoder.bitCount = bitCount;
decoder.firstByte = firstByte;
}
decoder.m_bytesUsed = buffer.BytesUsed;
}
// else ignore any hanging bits.
// Return our count
return buffer.Count;
}