Пример #1
0
        internal override unsafe int GetBytes(char *chars, int charCount,
                                              byte *bytes, int byteCount, EncoderNLS baseEncoder)
        {
            Debug.Assert(byteCount >= 0, "[UTF7Encoding.GetBytes]byteCount >=0");
            Debug.Assert(chars != null, "[UTF7Encoding.GetBytes]chars!=null");
            Debug.Assert(charCount >= 0, "[UTF7Encoding.GetBytes]charCount >=0");

            // Get encoder info
            UTF7Encoding.Encoder encoder = (UTF7Encoding.Encoder)baseEncoder;

            // Default bits & count
            int bits     = 0;
            int bitCount = -1;

            // prepare our helpers
            Encoding.EncodingByteBuffer buffer = new Encoding.EncodingByteBuffer(
                this, encoder, bytes, byteCount, chars, charCount);

            if (encoder != null)
            {
                bits     = encoder.bits;
                bitCount = encoder.bitCount;

                // May have had too many left over
                while (bitCount >= 6)
                {
                    bitCount -= 6;
                    // If we fail we'll never really have enough room
                    if (!buffer.AddByte(_base64Bytes[(bits >> bitCount) & 0x3F]))
                    {
                        ThrowBytesOverflow(encoder, buffer.Count == 0);
                    }
                }
            }

            while (buffer.MoreData)
            {
                char currentChar = buffer.GetNextChar();

                if (currentChar < 0x80 && _directEncode[currentChar])
                {
                    if (bitCount >= 0)
                    {
                        if (bitCount > 0)
                        {
                            // Try to add the next byte
                            if (!buffer.AddByte(_base64Bytes[bits << 6 - bitCount & 0x3F]))
                            {
                                break;                                          // Stop here, didn't throw
                            }
                            bitCount = 0;
                        }

                        // Need to get emit '-' and our char, 2 bytes total
                        if (!buffer.AddByte((byte)'-'))
                        {
                            break;                                          // Stop here, didn't throw
                        }
                        bitCount = -1;
                    }

                    // Need to emit our char
                    if (!buffer.AddByte((byte)currentChar))
                    {
                        break;                                          // Stop here, didn't throw
                    }
                }
                else if (bitCount < 0 && currentChar == '+')
                {
                    if (!buffer.AddByte((byte)'+', (byte)'-'))
                    {
                        break;                                          // Stop here, didn't throw
                    }
                }
                else
                {
                    if (bitCount < 0)
                    {
                        // Need to emit a + and 12 bits (3 bytes)
                        // Only 12 of the 16 bits will be emitted this time, the other 4 wait 'til next time
                        if (!buffer.AddByte((byte)'+'))
                        {
                            break;                                          // Stop here, didn't throw
                        }
                        // We're now in bit mode, but haven't stored data yet
                        bitCount = 0;
                    }

                    // Add our bits
                    bits      = bits << 16 | currentChar;
                    bitCount += 16;

                    while (bitCount >= 6)
                    {
                        bitCount -= 6;
                        if (!buffer.AddByte(_base64Bytes[(bits >> bitCount) & 0x3F]))
                        {
                            bitCount   += 6;                            // We didn't use these bits
                            currentChar = buffer.GetNextChar();         // We're processing this char still, but AddByte
                                                                        // --'d it when we ran out of space
                            break;                                      // Stop here, not enough room for bytes
                        }
                    }

                    if (bitCount >= 6)
                    {
                        break;                  // Didn't have room to encode enough bits
                    }
                }
            }

            // Now if we have bits left over we have to encode them.
            // MustFlush may have been cleared by encoding.ThrowBytesOverflow earlier if converting
            if (bitCount >= 0 && (encoder == null || encoder.MustFlush))
            {
                // Do we have bits we have to stick in?
                if (bitCount > 0)
                {
                    if (buffer.AddByte(_base64Bytes[(bits << (6 - bitCount)) & 0x3F]))
                    {
                        // Emitted spare bits, 0 bits left
                        bitCount = 0;
                    }
                }

                // If converting and failed bitCount above, then we'll fail this too
                if (buffer.AddByte((byte)'-'))
                {
                    // turned off bit mode';
                    bits     = 0;
                    bitCount = -1;
                }
                else
                {
                    // If not successful, convert will maintain state for next time, also
                    // AddByte will have decremented our char count, however we need it to remain the same
                    buffer.GetNextChar();
                }
            }

            // Do we have an encoder we're allowed to use?
            // bytes == null if counting, so don't use encoder then
            if (bytes != null && encoder != null)
            {
                // We already cleared bits & bitcount for mustflush case
                encoder.bits       = bits;
                encoder.bitCount   = bitCount;
                encoder._charsUsed = buffer.CharsUsed;
            }

            return(buffer.Count);
        }