View Javadoc
1   package au.gov.amsa.util;
2   
3   public final class SixBit {
4   
5   	/** Precompiled list of int to six bit mappings. */
6   	private static final int[] INT_TO_SIX_BIT = createIntToSixBit();
7   
8   	private static int[] createIntToSixBit() {
9   		int[] toSixbit = new int[256 * 256]; // we actually only use 256, but we
10  		                                     // parse chars around instead of
11  		                                     // bytes
12  		for (int chr = 0; chr < toSixbit.length; chr++) {
13  			if (chr < 48 || chr > 119 || chr > 87 && chr < 96) {
14  				toSixbit[chr] = -1;
15  			} else if (chr < 0x60) {
16  				toSixbit[chr] = chr - 48 & 0x3F;
17  			} else {
18  				toSixbit[chr] = chr - 56 & 0x3F;
19  			}
20  		}
21  		return toSixbit;
22  	}
23  
24  	/**
25  	 * Converts sixBit string characters to bits (boolean values in the array
26  	 * bitSet) but just between the bit range {@code from} to {@code to}
27  	 * exclusive.
28  	 * 
29  	 * @param str
30  	 * @param padBits
31  	 * @param bitSet
32  	 * @param calculated
33  	 * @param from
34  	 * @param to
35  	 */
36  	public static void convertSixBitToBits(String str, int padBits, boolean bitSet[],
37  	        boolean[] calculated, int from, int to) {
38  		if (str.length() == 0)
39  			return;
40  		int index = from - from % 6;
41  		int strFrom = from / 6;
42  		int slen = str.length() - 1;
43  		int strTo = to / 6 + 1;
44  		for (int i = strFrom; i < Math.min(strTo, slen); i++) {
45  			if (!calculated[i]) {
46  				char chr = str.charAt(i);
47  				int binVal = INT_TO_SIX_BIT[chr];
48  				if (binVal == -1) {
49  					throw new SixBitException("Illegal sixbit ascii char: " + chr);
50  				}
51  				bitSet[index] = (binVal & 32) > 0;
52  				bitSet[index + 1] = (binVal & 16) > 0;
53  				bitSet[index + 2] = (binVal & 8) > 0;
54  				bitSet[index + 3] = (binVal & 4) > 0;
55  				bitSet[index + 4] = (binVal & 2) > 0;
56  				bitSet[index + 5] = (binVal & 1) > 0;
57  
58  				calculated[i] = true;
59  			}
60  
61  			index += 6;
62  		}
63  		if (strTo > slen) {
64  			// Process the last char which might be padded
65  			char chr = str.charAt(slen);
66  			int binVal = INT_TO_SIX_BIT[chr];
67  			if (binVal == -1) {
68  				throw new SixBitException("Illegal sixbit ascii char: " + chr);
69  			}
70  			int bits = 6 - padBits;
71  
72  			switch (bits) {
73  			case 6:
74  				bitSet[index + 5] = (binVal & 1) > 0;
75  			case 5:
76  				bitSet[index + 4] = (binVal & 2) > 0;
77  			case 4:
78  				bitSet[index + 3] = (binVal & 4) > 0;
79  			case 3:
80  				bitSet[index + 2] = (binVal & 8) > 0;
81  			case 2:
82  				bitSet[index + 1] = (binVal & 16) > 0;
83  			case 1:
84  				bitSet[index] = (binVal & 32) > 0;
85  			}
86  
87  			calculated[slen] = true;
88  		}
89  	}
90  
91  	public static long getValue(int from, int to, boolean[] bitSet) {
92  		if (to > bitSet.length) {
93  			throw new SixBitException(bitSet.length + " is not enough bits. At least " + to
94  			        + " expected.");
95  		}
96  		long val = 0;
97  		long powMask = 1;
98  		for (int i = to - 1; i >= from; i--) {
99  			if (bitSet[i]) {
100 				val += powMask;
101 			}
102 			powMask <<= 1;
103 		}
104 		return val;
105 	}
106 
107 	public static long getSignedValue(int from, int to, boolean[] bitSet) {
108 		if (to > bitSet.length) {
109 			throw new SixBitException(bitSet.length + " is not enough bits. At least " + to
110 			        + " expected.");
111 		}
112 		long val = 0;
113 		long powMask = 1;
114 
115 		for (int i = to - 1; i >= from; i--) {
116 			if (bitSet[i]) {
117 				val += powMask;
118 			}
119 			powMask <<= 1;
120 		}
121 		if (bitSet[from]) {
122 			val = val - powMask;
123 		}
124 		return val;
125 	}
126 
127 	public static String getString(int from, int to, boolean[] bitSet) {
128 		int len = (to - from) / 6;
129 		char[] resStr = new char[len];
130 		int pos = from;
131 		int i;
132 		for (i = 0; i < len; i++) {
133 			// Note that SixBit.getValue() should never return a value > 63
134 			// because it is only using 6 bits so intToAscii should never throw
135 			// a SixBitException.
136 			char ch = (char) intToAscii((char) SixBit.getValue(pos, pos + 6, bitSet));
137 			// stops at the first instance of @ character
138 			if (ch == '@') {
139 				len = i;
140 				break;
141 			}
142 			resStr[i] = ch;
143 			pos += 6;
144 		}
145 		// remove trailing @ characters and spaces
146 		while (len > 0 && (resStr[len - 1] == ' '))
147 			len -= 1;
148 		return new String(resStr, 0, len);
149 	}
150 
151 	/**
152 	 * Convert six bit int value to character
153 	 *
154 	 * @param val
155 	 * @return
156 	 */
157 	private static int intToAscii(int val) {
158 		if (val > 63) {
159 			throw new SixBitException("Char value " + val + " not allowed");
160 		} else if (val < 32) {
161 			return val + 64;
162 		} else {
163 			return val;
164 		}
165 	}
166 
167 }