public static int decode()

in geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/connection/IMAPResponseTokenizer.java [699:813]


    public static int decode(String original, int index, StringBuffer result) throws MessagingException {
        // look for the section terminator
        int terminator = original.indexOf('-', index);

        // unmatched?
        if (terminator == -1) {
            throw new MessagingException("Invalid UTF-7 encoded string");
        }

        // is this just an escaped "&"?
        if (terminator == index + 1) {
            // append and skip over this.
            result.append('&');
            return index + 2;
        }

        // step over the starting char
        index++;

        int chars = terminator - index;
        int quads = chars / 4;
        int residual = chars % 4;

        // buffer for decoded characters
        byte[] buffer = new byte[4];
        int bufferCount = 0;

        // process each of the full triplet pairs
        for (int i = 0; i < quads; i++) {
            byte b1 = decodingTable[original.charAt(index++) & 0xff];
            byte b2 = decodingTable[original.charAt(index++) & 0xff];
            byte b3 = decodingTable[original.charAt(index++) & 0xff];
            byte b4 = decodingTable[original.charAt(index++) & 0xff];

            buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));
            buffer[bufferCount++] = (byte)((b2 << 4) | (b3 >> 2));
            buffer[bufferCount++] = (byte)((b3 << 6) | b4);

            // we've written 3 bytes to the buffer, but we might have a residual from a previous
            // iteration to deal with.
            if (bufferCount == 4) {
                // two complete chars here
                b1 = buffer[0];
                b2 = buffer[1];
                result.append((char)((b1 << 8) + (b2 & 0xff)));
                b1 = buffer[2];
                b2 = buffer[3];
                result.append((char)((b1 << 8) + (b2 & 0xff)));
                bufferCount = 0;
            }
            else {
                // we need to save the 3rd byte for the next go around
                b1 = buffer[0];
                b2 = buffer[1];
                result.append((char)((b1 << 8) + (b2 & 0xff)));
                buffer[0] = buffer[2];
                bufferCount = 1;
            }
        }

        // properly encoded, we should have an even number of bytes left.

        switch (residual) {
            // no residual...so we better not have an extra in the buffer
            case 0:
                // this is invalid...we have an odd number of bytes so far,
                if (bufferCount == 1) {
                    throw new MessagingException("Invalid UTF-7 encoded string");
                }
            // one byte left.  This shouldn't be valid.  We need at least 2 bytes to
            // encode one unprintable char.
            case 1:
                throw new MessagingException("Invalid UTF-7 encoded string");

            // ok, we have two bytes left, which can only encode a single byte.  We must have
            // a dangling unhandled char.
            case 2:
            {
                if (bufferCount != 1) {
                    throw new MessagingException("Invalid UTF-7 encoded string");
                }
                byte b1 = decodingTable[original.charAt(index++) & 0xff];
                byte b2 = decodingTable[original.charAt(index++) & 0xff];
                buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));

                b1 = buffer[0];
                b2 = buffer[1];
                result.append((char)((b1 << 8) + (b2 & 0xff)));
                break;
            }

            // we have 2 encoded chars.  In this situation, we can't have a leftover.
            case 3:
            {
                // this is invalid...we have an odd number of bytes so far,
                if (bufferCount == 1) {
                    throw new MessagingException("Invalid UTF-7 encoded string");
                }
                byte b1 = decodingTable[original.charAt(index++) & 0xff];
                byte b2 = decodingTable[original.charAt(index++) & 0xff];
                byte b3 = decodingTable[original.charAt(index++) & 0xff];

                buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));
                buffer[bufferCount++] = (byte)((b2 << 4) | (b3 >> 2));

                b1 = buffer[0];
                b2 = buffer[1];
                result.append((char)((b1 << 8) + (b2 & 0xff)));
                break;
            }
        }

        // return the new scan location
        return terminator + 1;
    }