View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.digest;
19  
20  import java.util.Objects;
21  import java.util.function.Supplier;
22  import java.util.zip.Checksum;
23  
24  /**
25   * CRC-16 checksum implementations you can customize with a table and init value.
26   * <p>
27   * Since there are so many CRC-16 variants, we do not pick a default.
28   * </p>
29   * <p>
30   * For example, to create a create a custom variant of CRC16-MODBUS with an init value of {@code 0x0000}, use:
31   * </p>
32   *
33   * <pre>
34   * Checksum crc16 = CRC16.builder().setTable(CRC16.getModbusTable()).setInit(0x0000).get();
35   * </pre>
36   *
37   * @see <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">Cyclic redundancy check</a>
38   * @see <a href="https://reveng.sourceforge.io/crc-catalogue/16.htm">Catalogue of parametrised CRC algorithms with 16 bits</a>
39   * @see <a href="https://www.lammertbies.nl/comm/info/crc-calculation">On-line CRC calculation and free library</a>
40   * @see <a href="https://crccalc.com/?crc=123456789&method=&datatype=ascii&outtype=hex">crccalc</a>
41   * @since 1.20.0
42   */
43  public final class Crc16 implements Checksum {
44  
45      /**
46       * Builds {@link Crc16} instances.
47       */
48      public static final class Builder implements Supplier<Crc16> {
49  
50          private int init;
51          private int[] table;
52          private int xorOut;
53  
54          /**
55           * Constructs a new instance.
56           */
57          public Builder() {
58              // empty
59          }
60  
61          /**
62           * Creates a new {@link Crc16} instance.
63           */
64          @Override
65          public Crc16 get() {
66              return new Crc16(this);
67          }
68  
69          /**
70           * Sets the initial value.
71           *
72           * @param init the initial value.
73           * @return {@code this} instance.
74           */
75          public Builder setInit(final int init) {
76              this.init = init;
77              return this;
78          }
79  
80          /**
81           * Sets the lookup table.
82           *
83           * @param table the lookup table, making a clone of the input array, must not be null.
84           * @return {@code this} instance.
85           */
86          public Builder setTable(final int[] table) {
87              return table(Objects.requireNonNull(table, "table").clone());
88          }
89  
90          /**
91           * Sets the XorOut value to XOR to the current checksum returned by {@link Crc16#getValue()}.
92           *
93           * @param xorOut the XorOut value.
94           * @return {@code this} instance.
95           */
96          public Builder setXorOut(final int xorOut) {
97              this.xorOut = xorOut;
98              return this;
99          }
100 
101         /**
102          * Sets the lookup table without making a clone.
103          *
104          * @param table the lookup table, must not be null.
105          * @return {@code this} instance.
106          */
107         private Builder table(final int[] table) {
108             this.table = Objects.requireNonNull(table, "table");
109             return this;
110         }
111     }
112 
113     // @formatter:off
114     private static final int[] ARC = {
115         0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
116         0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
117         0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
118         0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
119         0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
120         0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
121         0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
122         0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
123         0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
124         0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
125         0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
126         0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
127         0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
128         0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
129         0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
130         0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
131         0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
132         0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
133         0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
134         0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
135         0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
136         0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
137         0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
138         0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
139         0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
140         0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
141         0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
142         0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
143         0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
144         0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
145         0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
146         0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
147     };
148     private static final int ARC_INIT = 0x0000;
149     private static final int[] CCITT = {
150         0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
151         0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
152         0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
153         0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
154         0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
155         0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
156         0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
157         0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
158         0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
159         0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
160         0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
161         0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
162         0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
163         0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
164         0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
165         0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
166         0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
167         0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
168         0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
169         0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
170         0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
171         0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
172         0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
173         0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
174         0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
175         0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
176         0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
177         0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
178         0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
179         0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
180         0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
181         0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
182     };
183     private static final int CCITT_INIT = 0x0000;
184     private static final int[] DNP = {
185         0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A,
186         0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13,
187         0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1,
188         0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78,
189         0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35,
190         0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC,
191         0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E,
192         0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7,
193         0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4,
194         0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D,
195         0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF,
196         0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26,
197         0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B,
198         0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2,
199         0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00,
200         0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489,
201         0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526,
202         0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF,
203         0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D,
204         0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4,
205         0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89,
206         0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300,
207         0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2,
208         0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B,
209         0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678,
210         0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1,
211         0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413,
212         0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A,
213         0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7,
214         0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E,
215         0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC,
216         0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235
217     };
218     private static final int DNP_INIT = 0x0000;
219     private static final int DNP_XOROUT = 0xFFFF;
220     private static final int[] IBM_SDLC = CCITT;
221     private static final int IBM_SDLC_INIT = 0xFFFF;
222     private static final int IBM_SDLC_XOROUT = 0xFFFF;
223     private static final int[] MAXIM = ARC;
224     private static final int MAXIM_INIT = 0x0000;
225     private static final int MAXIM_XOROUT = 0xFFFF;
226     private static final int[] MCRF4XX = CCITT;
227     private static final int MCRF4XX_INIT = 0xFFFF;
228     private static final int[] MODBUS = ARC;
229     private static final int MODBUS_INIT = 0xFFFF;
230     private static final int[] NRSC5 = {
231         0x0000, 0x35A4, 0x6B48, 0x5EEC, 0xD690, 0xE334, 0xBDD8, 0x887C,
232         0x0D01, 0x38A5, 0x6649, 0x53ED, 0xDB91, 0xEE35, 0xB0D9, 0x857D,
233         0x1A02, 0x2FA6, 0x714A, 0x44EE, 0xCC92, 0xF936, 0xA7DA, 0x927E,
234         0x1703, 0x22A7, 0x7C4B, 0x49EF, 0xC193, 0xF437, 0xAADB, 0x9F7F,
235         0x3404, 0x01A0, 0x5F4C, 0x6AE8, 0xE294, 0xD730, 0x89DC, 0xBC78,
236         0x3905, 0x0CA1, 0x524D, 0x67E9, 0xEF95, 0xDA31, 0x84DD, 0xB179,
237         0x2E06, 0x1BA2, 0x454E, 0x70EA, 0xF896, 0xCD32, 0x93DE, 0xA67A,
238         0x2307, 0x16A3, 0x484F, 0x7DEB, 0xF597, 0xC033, 0x9EDF, 0xAB7B,
239         0x6808, 0x5DAC, 0x0340, 0x36E4, 0xBE98, 0x8B3C, 0xD5D0, 0xE074,
240         0x6509, 0x50AD, 0x0E41, 0x3BE5, 0xB399, 0x863D, 0xD8D1, 0xED75,
241         0x720A, 0x47AE, 0x1942, 0x2CE6, 0xA49A, 0x913E, 0xCFD2, 0xFA76,
242         0x7F0B, 0x4AAF, 0x1443, 0x21E7, 0xA99B, 0x9C3F, 0xC2D3, 0xF777,
243         0x5C0C, 0x69A8, 0x3744, 0x02E0, 0x8A9C, 0xBF38, 0xE1D4, 0xD470,
244         0x510D, 0x64A9, 0x3A45, 0x0FE1, 0x879D, 0xB239, 0xECD5, 0xD971,
245         0x460E, 0x73AA, 0x2D46, 0x18E2, 0x909E, 0xA53A, 0xFBD6, 0xCE72,
246         0x4B0F, 0x7EAB, 0x2047, 0x15E3, 0x9D9F, 0xA83B, 0xF6D7, 0xC373,
247         0xD010, 0xE5B4, 0xBB58, 0x8EFC, 0x0680, 0x3324, 0x6DC8, 0x586C,
248         0xDD11, 0xE8B5, 0xB659, 0x83FD, 0x0B81, 0x3E25, 0x60C9, 0x556D,
249         0xCA12, 0xFFB6, 0xA15A, 0x94FE, 0x1C82, 0x2926, 0x77CA, 0x426E,
250         0xC713, 0xF2B7, 0xAC5B, 0x99FF, 0x1183, 0x2427, 0x7ACB, 0x4F6F,
251         0xE414, 0xD1B0, 0x8F5C, 0xBAF8, 0x3284, 0x0720, 0x59CC, 0x6C68,
252         0xE915, 0xDCB1, 0x825D, 0xB7F9, 0x3F85, 0x0A21, 0x54CD, 0x6169,
253         0xFE16, 0xCBB2, 0x955E, 0xA0FA, 0x2886, 0x1D22, 0x43CE, 0x766A,
254         0xF317, 0xC6B3, 0x985F, 0xADFB, 0x2587, 0x1023, 0x4ECF, 0x7B6B,
255         0xB818, 0x8DBC, 0xD350, 0xE6F4, 0x6E88, 0x5B2C, 0x05C0, 0x3064,
256         0xB519, 0x80BD, 0xDE51, 0xEBF5, 0x6389, 0x562D, 0x08C1, 0x3D65,
257         0xA21A, 0x97BE, 0xC952, 0xFCF6, 0x748A, 0x412E, 0x1FC2, 0x2A66,
258         0xAF1B, 0x9ABF, 0xC453, 0xF1F7, 0x798B, 0x4C2F, 0x12C3, 0x2767,
259         0x8C1C, 0xB9B8, 0xE754, 0xD2F0, 0x5A8C, 0x6F28, 0x31C4, 0x0460,
260         0x811D, 0xB4B9, 0xEA55, 0xDFF1, 0x578D, 0x6229, 0x3CC5, 0x0961,
261         0x961E, 0xA3BA, 0xFD56, 0xC8F2, 0x408E, 0x752A, 0x2BC6, 0x1E62,
262         0x9B1F, 0xAEBB, 0xF057, 0xC5F3, 0x4D8F, 0x782B, 0x26C7, 0x1363
263     };
264     // @formatter:off
265     private static final int NRSC5_INIT = 0xFFFF;
266     private static final int[] USB = ARC;
267     private static final int USB_INIT = 0xFFFF;
268     private static final int USB_XOROUT = 0xFFFF;
269 
270     /**
271      * Creates a new CRC16-CCITT Checksum.
272      *
273      * <ul>
274      * <li>The init value is {@code 0x0000}.</li>
275      * <li>The XorOut value is {@code 0x0000}.</li>
276      * </ul>
277      * <p>
278      * Also known as:
279      * </p>
280      * <ul>
281      * <li>CRC-16/ARC</li>
282      * <li>ARC</li>
283      * <li>CRC-16</li>
284      * <li>CRC-16/LHA</li>
285      * <li>CRC-IBM</li>
286      * </ul>
287      *
288      * @return a new CRC16-CCITT Checksum.
289      */
290     public static Crc16 arc() {
291         return builder().setInit(ARC_INIT).table(ARC).get();
292     }
293 
294     /**
295      * Creates a new builder.
296      *
297      * <p>
298      * Since there are so many CRC-16 variants, we do not pick a default.
299      * </p>
300      *
301      * @return a new builder.
302      */
303     public static Builder builder() {
304         return new Builder();
305     }
306 
307     /**
308      * Creates a new CRC16-CCITT Checksum.
309      * <ul>
310      * <li>The init value is {@code 0x0000}.</li>
311      * <li>The XorOut value is {@code 0x0000}.</li>
312      * </ul>
313      * <p>
314      * Also known as:
315      * </p>
316      * <ul>
317      * <li>CRC-16/KERMIT</li>
318      * <li>CRC-16/BLUETOOTH</li>
319      * <li>CRC-16/CCITT</li>
320      * <li>CRC-16/CCITT-TRUE</li>
321      * <li>CRC-16/V-41-LSB</li>
322      * <li>CRC-CCITT</li>
323      * <li>KERMIT</li>
324      * </ul>
325      *
326      * @return a new CRC16-CCITT Checksum.
327      */
328     public static Crc16 ccitt() {
329         return builder().setInit(CCITT_INIT).table(CCITT).get();
330     }
331 
332     /**
333      * Creates a new CRC16-DNP Checksum.
334      *
335      * <ul>
336      * <li>The init value is {@code 0x0000}.</li>
337      * <li>The XorOut value is {@code 0xFFFF}.</li>
338      * </ul>
339      *
340      * @return a new CRC16-DNP Checksum.
341      */
342     public static Crc16 dnp() {
343         return builder().setInit(DNP_INIT).setXorOut(DNP_XOROUT).table(DNP).get();
344     }
345 
346     /**
347      * Gets a copy of the CRC16-CCITT table.
348      *
349      * @return a copy of the CCRC16-CITT table.
350      */
351     public static int[] getArcTable() {
352         return ARC.clone();
353     }
354 
355     /**
356      * Gets a copy of the CRC16-CCITT table.
357      *
358      * @return a copy of the CCRC16-CITT table.
359      */
360     public static int[] getCcittTable() {
361         return CCITT.clone();
362     }
363 
364     /**
365      * Gets a copy of the CRC16-DNP table.
366      *
367      * @return a copy of the CCRC16-DNP table.
368      */
369     public static int[] getDnpTable() {
370         return DNP.clone();
371     }
372 
373     /**
374      * Gets a copy of the CRC16-IBM-SDLC table.
375      *
376      * @return a copy of the CRC16-IBM-SDLC table.
377      */
378     public static int[] getIbmSdlcTable() {
379         return IBM_SDLC.clone();
380     }
381 
382     /**
383      * Gets a copy of the CRC16-MAXIM table.
384      *
385      * @return a copy of the CRC16-MAXIM table.
386      */
387     public static int[] getMaximTable() {
388         return MAXIM.clone();
389     }
390 
391     /**
392      * Gets a copy of the CRC16-MCRF4XX table.
393      *
394      * @return a copy of the CRC16-MCRF4XX table.
395      */
396     public static int[] getMcrf4xxTable() {
397         return MCRF4XX.clone();
398     }
399 
400     /**
401      * Gets a copy of the CRC16-MODBUS table.
402      *
403      * @return a copy of the CRC16-MODBUS table.
404      */
405     public static int[] getModbusTable() {
406         return MODBUS.clone();
407     }
408 
409     /**
410      * Gets a copy of the CRC16-NRSC-5 table.
411      *
412      * @return a copy of the CRC16-NRSC-5 table.
413      */
414     public static int[] getNrsc5Table() {
415         return NRSC5.clone();
416     }
417 
418     /**
419      * Creates a new CRC16-IBM-SDLC Checksum.
420      *
421      * <ul>
422      * <li>The init value is {@code 0xFFFF}.</li>
423      * <li>The XorOut value is {@code 0xFFFF}.</li>
424      * </ul>
425      * <p>
426      * Also known as:
427      * </p>
428      * <ul>
429      * <li>CRC-16/IBM-SDLC</li>
430      * <li>CRC-16/ISO-HDLC</li>
431      * <li>CRC-16/ISO-IEC-14443-3-B</li>
432      * <li>CRC-16/X-25</li>
433      * <li>CRC-B</li>
434      * <li>X-25</li>
435      * </ul>
436      *
437      * @return a new CRC16-IBM-SDLC Checksum.
438      */
439     public static Crc16 ibmSdlc() {
440         return builder().setInit(IBM_SDLC_INIT).setXorOut(IBM_SDLC_XOROUT).table(IBM_SDLC).get();
441     }
442 
443     /**
444      * Creates a new instance for CRC16-MAXIM Checksum.
445      *
446      * <p>
447      * CRC-16 checksum implementation based on polynomial {@code x<sup>16</spu> + x^15 + x^2 + 1 (0x8005)}.
448      * </p>
449      * <ul>
450      * <li>The init value is {@code 0xFFFF}.</li>
451      * <li>The XorOut value is {@code 0xFFFF}.</li>
452      * </ul>
453      * <p>
454      * Also known as:
455      * </p>
456      * <ul>
457      * <li>CRC-16/MAXIM-DOW</li>
458      * </ul>
459      *
460      * @return a new CRC16-MAXIM Checksum.
461      */
462     public static Crc16 maxim() {
463         return builder().setInit(MAXIM_INIT).setXorOut(MAXIM_XOROUT).table(MAXIM).get();
464     }
465 
466     /**
467      * Creates a new instance for CRC16-MCRF4XX Checksum.
468      *
469      * <ul>
470      * <li>The init value is {@code 0xFFFF}.</li>
471      * <li>The XorOut value is {@code 0x0000}.</li>
472      * </ul>
473      *
474      * @return a new CRC16-MCRF4XX Checksum.
475      */
476     public static Crc16 mcrf4xx() {
477         return builder().setInit(MCRF4XX_INIT).table(MCRF4XX).get();
478     }
479 
480     /**
481      * Creates a new instance for CRC16-MODBUS Checksum.
482      *
483      * <p>
484      * CRC-16 checksum implementation based on polynomial {@code x<sup>16</spu> + x^15 + x^2 + 1 (0x8005)}.
485      * </p>
486      * <ul>
487      * <li>The init value is {@code 0xFFFF}.</li>
488      * <li>The XorOut value is {@code 0x0000}.</li>
489      * </ul>
490      * <p>
491      * Also known as:
492      * </p>
493      * <ul>
494      * <li>CRC-16/MODBUST</li>
495      * <li>MODBUST</li>
496      * </ul>
497      *
498      * @return a new CRC16-MODBUS Checksum.
499      */
500     public static Crc16 modbus() {
501         return builder().setInit(MODBUS_INIT).table(MODBUS).get();
502     }
503 
504     /**
505      * Creates a new instance for CRC16-NRSC-5 Checksum.
506      *
507      * <ul>
508      * <li>The init value is {@code 0xFFFF}.</li>
509      * <li>The XorOut value is {@code 0x0000}.</li>
510      * </ul>
511      *
512      * @return a new CRC16-NRSC-5 Checksum.
513      */
514     public static Crc16 nrsc5() {
515         return builder().setInit(NRSC5_INIT).table(NRSC5).get();
516     }
517 
518     /**
519      * Creates a new instance for CRC16-USB Checksum.
520      *
521      * <ul>
522      * <li>The init value is {@code 0xFFFF}.</li>
523      * <li>The XorOut value is {@code 0xFFFF}.</li>
524      * </ul>
525      *
526      * @return a new CRC16-USB Checksum.
527      */
528     public static Crc16 usb() {
529         return builder().setInit(USB_INIT).setXorOut(USB_XOROUT).table(USB).get();
530     }
531 
532     /**
533      * CRC.
534      */
535     private int crc;
536     private final int init;
537     private final int[] table;
538     private final int xorOut;
539 
540     /**
541      * Constructs a new instance.
542      */
543     private Crc16(final Builder builder) {
544         this.init = builder.init;
545         this.xorOut = builder.xorOut;
546         this.crc = builder.init;
547         this.table = Objects.requireNonNull(builder.table, "table");
548     }
549 
550     @Override
551     public long getValue() {
552         return crc ^ xorOut;
553     }
554 
555     @Override
556     public void reset() {
557         crc = init;
558     }
559 
560     @Override
561     public String toString() {
562         return String.format("%s [init=0x%04X, crc=0x%04X, xorOut=0x%04X, crc^xorOut=0x%04X]", getClass().getSimpleName(), init, crc, xorOut, getValue());
563     }
564 
565     @Override
566     public void update(final byte[] b, final int off, final int len) {
567         final int end = len + off;
568         for (int i = off; i < end; i++) {
569             update(b[i]);
570         }
571     }
572 
573     @Override
574     public void update(final int b) {
575         crc = crc >>> 8 ^ table[(crc ^ b) & 0xff];
576     }
577 }