internal override unsafe int GetChars(byte *bytes, int byteCount, char *chars, int charCount, DecoderNLS baseDecoder) { Debug.Assert(byteCount >= 0, "[UTF7Encoding.GetChars]byteCount >=0"); Debug.Assert(bytes != null, "[UTF7Encoding.GetChars]bytes!=null"); Debug.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; Debug.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._bytesUsed = buffer.BytesUsed; } // else ignore any hanging bits. // Return our count return(buffer.Count); }