1 /* Copyright 2015 Google Inc. All Rights Reserved. 2 3 Distributed under MIT license. 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 */ 6 7 package org.brotli.dec; 8 9 /** 10 * Bit reading helpers. 11 */ 12 final class BitReader { 13 14 // Possible values: {5, 6}. 5 corresponds to 32-bit build, 6 to 64-bit. This value is used for 15 // conditional compilation -> produced artifacts might be binary INCOMPATIBLE (JLS 13.2). 16 private static final int LOG_BITNESS = 6; 17 private static final int BITNESS = 1 << LOG_BITNESS; 18 19 private static final int BYTENESS = BITNESS / 8; 20 private static final int CAPACITY = 4096; 21 // After encountering the end of the input stream, this amount of zero bytes will be appended. 22 private static final int SLACK = 64; 23 private static final int BUFFER_SIZE = CAPACITY + SLACK; 24 // Don't bother to replenish the buffer while this number of bytes is available. 25 private static final int SAFEGUARD = 36; 26 private static final int WATERLINE = CAPACITY - SAFEGUARD; 27 28 // "Half" refers to "half of native integer type", i.e. on 64-bit machines it is 32-bit type, 29 // on 32-bit machines it is 16-bit. 30 private static final int HALF_BITNESS = BITNESS / 2; 31 private static final int HALF_SIZE = BYTENESS / 2; 32 private static final int HALVES_CAPACITY = CAPACITY / HALF_SIZE; 33 private static final int HALF_BUFFER_SIZE = BUFFER_SIZE / HALF_SIZE; 34 private static final int HALF_WATERLINE = WATERLINE / HALF_SIZE; 35 36 private static final int LOG_HALF_SIZE = LOG_BITNESS - 4; 37 38 /** 39 * Fills up the input buffer. 40 * 41 * <p> No-op if there are at least 36 bytes present after current position. 42 * 43 * <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the 44 * buffer. 45 */ readMoreInput(State s)46 static void readMoreInput(State s) { 47 if (s.halfOffset > HALF_WATERLINE) { 48 doReadMoreInput(s); 49 } 50 } 51 doReadMoreInput(State s)52 static void doReadMoreInput(State s) { 53 if (s.endOfStreamReached != 0) { 54 if (halfAvailable(s) >= -2) { 55 return; 56 } 57 throw new BrotliRuntimeException("No more input"); 58 } 59 int readOffset = s.halfOffset << LOG_HALF_SIZE; 60 int bytesInBuffer = CAPACITY - readOffset; 61 // Move unused bytes to the head of the buffer. 62 Utils.copyBytesWithin(s.byteBuffer, 0, readOffset, CAPACITY); 63 s.halfOffset = 0; 64 while (bytesInBuffer < CAPACITY) { 65 int spaceLeft = CAPACITY - bytesInBuffer; 66 int len = Utils.readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft); 67 // EOF is -1 in Java, but 0 in C#. 68 if (len <= 0) { 69 s.endOfStreamReached = 1; 70 s.tailBytes = bytesInBuffer; 71 bytesInBuffer += HALF_SIZE - 1; 72 break; 73 } 74 bytesInBuffer += len; 75 } 76 bytesToNibbles(s, bytesInBuffer); 77 } 78 checkHealth(State s, int endOfStream)79 static void checkHealth(State s, int endOfStream) { 80 if (s.endOfStreamReached == 0) { 81 return; 82 } 83 int byteOffset = (s.halfOffset << LOG_HALF_SIZE) + ((s.bitOffset + 7) >> 3) - BYTENESS; 84 if (byteOffset > s.tailBytes) { 85 throw new BrotliRuntimeException("Read after end"); 86 } 87 if ((endOfStream != 0) && (byteOffset != s.tailBytes)) { 88 throw new BrotliRuntimeException("Unused bytes after end"); 89 } 90 } 91 fillBitWindow(State s)92 static void fillBitWindow(State s) { 93 if (s.bitOffset >= HALF_BITNESS) { 94 // Same as doFillBitWindow. JVM fails to inline it. 95 if (BITNESS == 64) { 96 s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS) 97 | (s.accumulator64 >>> HALF_BITNESS); 98 } else { 99 s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS) 100 | (s.accumulator32 >>> HALF_BITNESS); 101 } 102 s.bitOffset -= HALF_BITNESS; 103 } 104 } 105 doFillBitWindow(State s)106 private static void doFillBitWindow(State s) { 107 if (BITNESS == 64) { 108 s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS) 109 | (s.accumulator64 >>> HALF_BITNESS); 110 } else { 111 s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS) 112 | (s.accumulator32 >>> HALF_BITNESS); 113 } 114 s.bitOffset -= HALF_BITNESS; 115 } 116 peekBits(State s)117 static int peekBits(State s) { 118 if (BITNESS == 64) { 119 return (int) (s.accumulator64 >>> s.bitOffset); 120 } else { 121 return s.accumulator32 >>> s.bitOffset; 122 } 123 } 124 readFewBits(State s, int n)125 static int readFewBits(State s, int n) { 126 int val = peekBits(s) & ((1 << n) - 1); 127 s.bitOffset += n; 128 return val; 129 } 130 readBits(State s, int n)131 static int readBits(State s, int n) { 132 if (HALF_BITNESS >= 24) { 133 return readFewBits(s, n); 134 } else { 135 return (n <= 16) ? readFewBits(s, n) : readManyBits(s, n); 136 } 137 } 138 readManyBits(State s, int n)139 private static int readManyBits(State s, int n) { 140 int low = readFewBits(s, 16); 141 doFillBitWindow(s); 142 return low | (readFewBits(s, n - 16) << 16); 143 } 144 initBitReader(State s)145 static void initBitReader(State s) { 146 s.byteBuffer = new byte[BUFFER_SIZE]; 147 if (BITNESS == 64) { 148 s.accumulator64 = 0; 149 s.intBuffer = new int[HALF_BUFFER_SIZE]; 150 } else { 151 s.accumulator32 = 0; 152 s.shortBuffer = new short[HALF_BUFFER_SIZE]; 153 } 154 s.bitOffset = BITNESS; 155 s.halfOffset = HALVES_CAPACITY; 156 s.endOfStreamReached = 0; 157 prepare(s); 158 } 159 prepare(State s)160 private static void prepare(State s) { 161 readMoreInput(s); 162 checkHealth(s, 0); 163 doFillBitWindow(s); 164 doFillBitWindow(s); 165 } 166 reload(State s)167 static void reload(State s) { 168 if (s.bitOffset == BITNESS) { 169 prepare(s); 170 } 171 } 172 jumpToByteBoundary(State s)173 static void jumpToByteBoundary(State s) { 174 int padding = (BITNESS - s.bitOffset) & 7; 175 if (padding != 0) { 176 int paddingBits = readFewBits(s, padding); 177 if (paddingBits != 0) { 178 throw new BrotliRuntimeException("Corrupted padding bits"); 179 } 180 } 181 } 182 halfAvailable(State s)183 static int halfAvailable(State s) { 184 int limit = HALVES_CAPACITY; 185 if (s.endOfStreamReached != 0) { 186 limit = (s.tailBytes + (HALF_SIZE - 1)) >> LOG_HALF_SIZE; 187 } 188 return limit - s.halfOffset; 189 } 190 copyBytes(State s, byte[] data, int offset, int length)191 static void copyBytes(State s, byte[] data, int offset, int length) { 192 if ((s.bitOffset & 7) != 0) { 193 throw new BrotliRuntimeException("Unaligned copyBytes"); 194 } 195 196 // Drain accumulator. 197 while ((s.bitOffset != BITNESS) && (length != 0)) { 198 data[offset++] = (byte) peekBits(s); 199 s.bitOffset += 8; 200 length--; 201 } 202 if (length == 0) { 203 return; 204 } 205 206 // Get data from shadow buffer with "sizeof(int)" granularity. 207 int copyNibbles = Math.min(halfAvailable(s), length >> LOG_HALF_SIZE); 208 if (copyNibbles > 0) { 209 int readOffset = s.halfOffset << LOG_HALF_SIZE; 210 int delta = copyNibbles << LOG_HALF_SIZE; 211 System.arraycopy(s.byteBuffer, readOffset, data, offset, delta); 212 offset += delta; 213 length -= delta; 214 s.halfOffset += copyNibbles; 215 } 216 if (length == 0) { 217 return; 218 } 219 220 // Read tail bytes. 221 if (halfAvailable(s) > 0) { 222 // length = 1..3 223 fillBitWindow(s); 224 while (length != 0) { 225 data[offset++] = (byte) peekBits(s); 226 s.bitOffset += 8; 227 length--; 228 } 229 checkHealth(s, 0); 230 return; 231 } 232 233 // Now it is possible to copy bytes directly. 234 while (length > 0) { 235 int len = Utils.readInput(s.input, data, offset, length); 236 if (len == -1) { 237 throw new BrotliRuntimeException("Unexpected end of input"); 238 } 239 offset += len; 240 length -= len; 241 } 242 } 243 244 /** 245 * Translates bytes to halves (int/short). 246 */ bytesToNibbles(State s, int byteLen)247 static void bytesToNibbles(State s, int byteLen) { 248 byte[] byteBuffer = s.byteBuffer; 249 int halfLen = byteLen >> LOG_HALF_SIZE; 250 if (BITNESS == 64) { 251 int[] intBuffer = s.intBuffer; 252 for (int i = 0; i < halfLen; ++i) { 253 intBuffer[i] = ((byteBuffer[i * 4] & 0xFF)) 254 | ((byteBuffer[(i * 4) + 1] & 0xFF) << 8) 255 | ((byteBuffer[(i * 4) + 2] & 0xFF) << 16) 256 | ((byteBuffer[(i * 4) + 3] & 0xFF) << 24); 257 } 258 } else { 259 short[] shortBuffer = s.shortBuffer; 260 for (int i = 0; i < halfLen; ++i) { 261 shortBuffer[i] = (short) ((byteBuffer[i * 2] & 0xFF) 262 | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8)); 263 } 264 } 265 } 266 } 267