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); } }