View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.handler.codec.compression;
17  
18  import io.netty5.buffer.api.Buffer;
19  
20  /**
21   * An bit reader that allows the reading of single bit booleans, bit strings of
22   * arbitrary length (up to 32 bits), and bit aligned 32-bit integers. A single byte
23   * at a time is read from the {@link Buffer} when more bits are required.
24   */
25  class Bzip2BitReader {
26      /**
27       * Maximum count of possible readable bytes to check.
28       */
29      private static final int MAX_COUNT_OF_READABLE_BYTES = Integer.MAX_VALUE >>> 3;
30  
31      /**
32       * The {@link Buffer} from which to read data.
33       */
34      private Buffer in;
35  
36      /**
37       * A buffer of bits read from the input stream that have not yet been returned.
38       */
39      private long bitBuffer;
40  
41      /**
42       * The number of bits currently buffered in {@link #bitBuffer}.
43       */
44      private int bitCount;
45  
46      /**
47       * Set the {@link Buffer} from which to read data.
48       */
49      void setBuffer(Buffer in) {
50          this.in = in;
51      }
52  
53      /**
54       * Reads up to 32 bits from the {@link Buffer}.
55       * @param count The number of bits to read (maximum {@code 32} as a size of {@code int})
56       * @return The bits requested, right-aligned within the integer
57       */
58      int readBits(final int count) {
59          if (count < 0 || count > 32) {
60              throw new IllegalArgumentException("count: " + count + " (expected: 0-32 )");
61          }
62          int bitCount = this.bitCount;
63          long bitBuffer = this.bitBuffer;
64  
65          if (bitCount < count) {
66              long readData;
67              int offset;
68              switch (in.readableBytes()) {
69                  case 1: {
70                      readData = in.readUnsignedByte();
71                      offset = 8;
72                      break;
73                  }
74                  case 2: {
75                      readData = in.readUnsignedShort();
76                      offset = 16;
77                      break;
78                  }
79                  case 3: {
80                      readData = in.readUnsignedMedium();
81                      offset = 24;
82                      break;
83                  }
84                  default: {
85                      readData = in.readUnsignedInt();
86                      offset = 32;
87                      break;
88                  }
89              }
90  
91              bitBuffer = bitBuffer << offset | readData;
92              bitCount += offset;
93              this.bitBuffer = bitBuffer;
94          }
95  
96          this.bitCount = bitCount -= count;
97          return (int) (bitBuffer >>> bitCount & (count != 32 ? (1 << count) - 1 : 0xFFFFFFFFL));
98      }
99  
100     /**
101      * Reads a single bit from the {@link Buffer}.
102      * @return {@code true} if the bit read was {@code 1}, otherwise {@code false}
103      */
104     boolean readBoolean() {
105         return readBits(1) != 0;
106     }
107 
108     /**
109      * Reads 32 bits of input as an integer.
110      * @return The integer read
111      */
112     int readInt() {
113         return readBits(32);
114     }
115 
116     /**
117      * Refill the {@link Buffer} by one byte.
118      */
119     void refill() {
120         int readData = in.readUnsignedByte();
121         bitBuffer = bitBuffer << 8 | readData;
122         bitCount += 8;
123     }
124 
125     /**
126      * Checks that at least one bit is available for reading.
127      * @return {@code true} if one bit is available for reading, otherwise {@code false}
128      */
129     boolean isReadable() {
130         return bitCount > 0 || in.readableBytes() > 0;
131     }
132 
133     /**
134      * Checks that the specified number of bits available for reading.
135      * @param count The number of bits to check
136      * @return {@code true} if {@code count} bits are available for reading, otherwise {@code false}
137      */
138     boolean hasReadableBits(int count) {
139         if (count < 0) {
140             throw new IllegalArgumentException("count: " + count + " (expected value greater than 0)");
141         }
142         return bitCount >= count || (in.readableBytes() << 3 & Integer.MAX_VALUE) >= count - bitCount;
143     }
144 
145     /**
146      * Checks that the specified number of bytes available for reading.
147      * @param count The number of bytes to check
148      * @return {@code true} if {@code count} bytes are available for reading, otherwise {@code false}
149      */
150     boolean hasReadableBytes(int count) {
151         if (count < 0 || count > MAX_COUNT_OF_READABLE_BYTES) {
152             throw new IllegalArgumentException("count: " + count
153                     + " (expected: 0-" + MAX_COUNT_OF_READABLE_BYTES + ')');
154         }
155         return hasReadableBits(count << 3);
156     }
157 }