Home | History | Annotate | Download | only in dec
      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    */
     46   static void readMoreInput(State s) {
     47     if (s.halfOffset > HALF_WATERLINE) {
     48       doReadMoreInput(s);
     49     }
     50   }
     51 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    160   private static void prepare(State s) {
    161     readMoreInput(s);
    162     checkHealth(s, 0);
    163     doFillBitWindow(s);
    164     doFillBitWindow(s);
    165   }
    166 
    167   static void reload(State s) {
    168     if (s.bitOffset == BITNESS) {
    169       prepare(s);
    170     }
    171   }
    172 
    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 
    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 
    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    */
    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