Subversion Repositories mkgmap

Rev

Rev 3408 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package uk.me.parabola.imgfmt.app.labelenc;

import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;

/**
 * Convert the 6-bit label format back to a java string.
 */

public class Format6Decoder implements CharacterDecoder {
        private final ByteArrayOutputStream out = new ByteArrayOutputStream();
        private boolean needReset;

        private boolean symbol;
        private boolean lowerCaseOrSeparator;

        private int store;
        private int nbits;

        private final Charset charset = Charset.forName("ascii");

        public boolean addByte(int in) {
                int b = 0xff & in; //wipe out high bits (in case of negative byte)

                if (needReset) {
                        needReset = false;
                        out.reset();
                }

                store <<= 8;
                store |= b;
                nbits += 8;

                while (nbits >= 6) {
                        convertChar((store >> (nbits-6)) & 0x3f);

                        if (needReset) {
                                // Skip until the next byte boundary.  Note that may mean that
                                // we skip more or *less* than 6 bits.
                                if (nbits > 8)
                                        nbits = 8;
                                else
                                        nbits = 0;

                                break;
                        } else
                                nbits -= 6;
                }

                return needReset;
        }

        public DecodedText getText() {
                byte[] ba = out.toByteArray();
                DecodedText text = new DecodedText(ba, charset);

                assert nbits == 0 || nbits == 8;
                // If there is a byte left inside the decoder then we have to let our
                // caller know, so that they can adjust the offset of the next label
                // appropriately.
                if (nbits == 8)
                        text.setOffsetAdjustment(-1);
                return text;
        }

        public void reset() {
                needReset = false;
                out.reset();
                store = 0;
                nbits = 0;
        }


        /**
         * Convert a single 6 bit quantity into a character.
         * @param b The six bit int.
         */

        private void convertChar(int b) {
                if (b > 0x2f) {
                        needReset = true;
                        return;
                }

                char c;

                if (symbol) {
                        symbol = false;
                        c = Format6Encoder.SYMBOLS.charAt(b);
                }
                else if(lowerCaseOrSeparator) {
                        lowerCaseOrSeparator = false;
                        if(b == 0x2b || b == 0x2c) {
                                c = (char)(b - 0x10); // "thin" separator
                        }
                        else if(Character.isLetter(b)) {
                                // lower case letter
                                c = Character.toLowerCase(Format6Encoder.LETTERS.charAt(b));
                        }
                        else {
                                // not a letter so just use as is (could be a digit)
                                c = Format6Encoder.LETTERS.charAt(b);
                        }
                }
                else {
                        switch(b) {
                        case 0x1B:
                                // next char is lower case or a separator
                                lowerCaseOrSeparator = true;
                                return;

                        case 0x1C:
                                // next char is symbol
                                symbol = true;
                                return;

                        case 0x1D:
                        case 0x1E:
                        case 0x1F:
                                // these are separators - use as is
                                c = (char)b;
                                break;

                        default:
                                c = Format6Encoder.LETTERS.charAt(b);
                                break;
                        }
                }
                out.write(c);
        }
}