public int nextSymbol() throws IOException {

		final BZip2BitInputStream bitInputStream = this.bitInputStream;

		// Move to next group selector if required
		if (((++this.groupPosition % BZip2Constants.HUFFMAN_GROUP_RUN_LENGTH) == 0)) {
			this.groupIndex++;
			if (this.groupIndex == this.selectors.length) {
				throw new BZip2Exception ("Error decoding BZip2 block");
			}
			this.currentTable = this.selectors[this.groupIndex] & 0xff;
		}

		final int currentTable = this.currentTable;
		final int[] tableLimits = this.codeLimits[currentTable];
		int codeLength = this.minimumLengths[currentTable];

		// Starting with the minimum bit length for the table, read additional bits one at a time
		// until a complete code is recognised
		int codeBits = bitInputStream.readBits (codeLength);
		for (; codeLength <= BZip2Constants.HUFFMAN_DECODE_MAXIMUM_CODE_LENGTH; codeLength++) {
			if (codeBits <= tableLimits[codeLength]) {
				// Convert the code to a symbol index and return
				return this.codeSymbols[currentTable][codeBits - this.codeBases[currentTable][codeLength]];
			}
			codeBits = (codeBits << 1) | bitInputStream.readBits (1);
		}

		// A valid code was not recognised
		throw new BZip2Exception ("Error decoding BZip2 block");

	}