1717
1818package org .apache .commons .codec .digest ;
1919
20+ import java .util .Objects ;
2021import java .util .function .Supplier ;
2122import java .util .zip .Checksum ;
2223
2324/**
2425 * CRC-16 checksum implementation based on polynomial {@code x<sup>16</spu> + x^15 + x^2 + 1 (0x8005)} and the initial value {@code 0x0000}. This CRC variant is
2526 * also known as CRC-16-MODBUS.
27+ * <p>
28+ * Since there are so many CRC-16 variants, we do not pick a default.
29+ * </p>
2630 *
2731 * @see <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">Cyclic redundancy check</a>
2832 * @see <a href="https://reveng.sourceforge.io/crc-catalogue/16.htm">Catalogue of parametrised CRC algorithms with 16 bits</a>
@@ -37,8 +41,8 @@ public class CRC16 implements Checksum {
3741 */
3842 public static class Builder implements Supplier <CRC16 > {
3943
40- private int init = DEFAULT_INIT ;
41- private int [] t = T_DEFAULT ;
44+ private int init = INIT_DEFAULT ;
45+ private int [] table ;
4246
4347 /**
4448 * Constructs a new instance.
@@ -69,16 +73,26 @@ public Builder setInit(final int init) {
6973 /**
7074 * Sets the lookup table.
7175 *
72- * @param t the lookup table, making a clone of the input array.
76+ * @param table the lookup table, making a clone of the input array, must not be null .
7377 * @return {@code this} instance.
7478 */
75- public Builder setTable (final int [] t ) {
76- this .t = t != null ? t .clone () : T_DEFAULT ;
79+ public Builder setTable (final int [] table ) {
80+ return table (Objects .requireNonNull (table , "table" ).clone ());
81+ }
82+
83+ /**
84+ * Sets the lookup table without making a clone.
85+ *
86+ * @param table the lookup table, must not be null.
87+ * @return {@code this} instance.
88+ */
89+ private Builder table (final int [] table ) {
90+ this .table = Objects .requireNonNull (table , "table" );
7791 return this ;
7892 }
7993 }
8094
81- private static final int DEFAULT_INIT = 0x0000 ;
95+ private static final int INIT_DEFAULT = 0x0000 ;
8296 // @formatter:off
8397 private static final int [] T_MODBUS = {
8498 0x0000 , 0xC0C1 , 0xC181 , 0x0140 , 0xC301 , 0x03C0 , 0x0280 , 0xC241 ,
@@ -114,11 +128,49 @@ public Builder setTable(final int[] t) {
114128 0x4400 , 0x84C1 , 0x8581 , 0x4540 , 0x8701 , 0x47C0 , 0x4680 , 0x8641 ,
115129 0x8201 , 0x42C0 , 0x4380 , 0x8341 , 0x4100 , 0x81C1 , 0x8081 , 0x4040
116130 };
117-
118- private static final int [] T_DEFAULT = T_MODBUS ;
131+ // @formatter:on
132+ // @formatter:off
133+ private static final int [] T_CCITT = {
134+ 0x0000 , 0x1189 , 0x2312 , 0x329B , 0x4624 , 0x57AD , 0x6536 , 0x74BF ,
135+ 0x8C48 , 0x9DC1 , 0xAF5A , 0xBED3 , 0xCA6C , 0xDBE5 , 0xE97E , 0xF8F7 ,
136+ 0x1081 , 0x0108 , 0x3393 , 0x221A , 0x56A5 , 0x472C , 0x75B7 , 0x643E ,
137+ 0x9CC9 , 0x8D40 , 0xBFDB , 0xAE52 , 0xDAED , 0xCB64 , 0xF9FF , 0xE876 ,
138+ 0x2102 , 0x308B , 0x0210 , 0x1399 , 0x6726 , 0x76AF , 0x4434 , 0x55BD ,
139+ 0xAD4A , 0xBCC3 , 0x8E58 , 0x9FD1 , 0xEB6E , 0xFAE7 , 0xC87C , 0xD9F5 ,
140+ 0x3183 , 0x200A , 0x1291 , 0x0318 , 0x77A7 , 0x662E , 0x54B5 , 0x453C ,
141+ 0xBDCB , 0xAC42 , 0x9ED9 , 0x8F50 , 0xFBEF , 0xEA66 , 0xD8FD , 0xC974 ,
142+ 0x4204 , 0x538D , 0x6116 , 0x709F , 0x0420 , 0x15A9 , 0x2732 , 0x36BB ,
143+ 0xCE4C , 0xDFC5 , 0xED5E , 0xFCD7 , 0x8868 , 0x99E1 , 0xAB7A , 0xBAF3 ,
144+ 0x5285 , 0x430C , 0x7197 , 0x601E , 0x14A1 , 0x0528 , 0x37B3 , 0x263A ,
145+ 0xDECD , 0xCF44 , 0xFDDF , 0xEC56 , 0x98E9 , 0x8960 , 0xBBFB , 0xAA72 ,
146+ 0x6306 , 0x728F , 0x4014 , 0x519D , 0x2522 , 0x34AB , 0x0630 , 0x17B9 ,
147+ 0xEF4E , 0xFEC7 , 0xCC5C , 0xDDD5 , 0xA96A , 0xB8E3 , 0x8A78 , 0x9BF1 ,
148+ 0x7387 , 0x620E , 0x5095 , 0x411C , 0x35A3 , 0x242A , 0x16B1 , 0x0738 ,
149+ 0xFFCF , 0xEE46 , 0xDCDD , 0xCD54 , 0xB9EB , 0xA862 , 0x9AF9 , 0x8B70 ,
150+ 0x8408 , 0x9581 , 0xA71A , 0xB693 , 0xC22C , 0xD3A5 , 0xE13E , 0xF0B7 ,
151+ 0x0840 , 0x19C9 , 0x2B52 , 0x3ADB , 0x4E64 , 0x5FED , 0x6D76 , 0x7CFF ,
152+ 0x9489 , 0x8500 , 0xB79B , 0xA612 , 0xD2AD , 0xC324 , 0xF1BF , 0xE036 ,
153+ 0x18C1 , 0x0948 , 0x3BD3 , 0x2A5A , 0x5EE5 , 0x4F6C , 0x7DF7 , 0x6C7E ,
154+ 0xA50A , 0xB483 , 0x8618 , 0x9791 , 0xE32E , 0xF2A7 , 0xC03C , 0xD1B5 ,
155+ 0x2942 , 0x38CB , 0x0A50 , 0x1BD9 , 0x6F66 , 0x7EEF , 0x4C74 , 0x5DFD ,
156+ 0xB58B , 0xA402 , 0x9699 , 0x8710 , 0xF3AF , 0xE226 , 0xD0BD , 0xC134 ,
157+ 0x39C3 , 0x284A , 0x1AD1 , 0x0B58 , 0x7FE7 , 0x6E6E , 0x5CF5 , 0x4D7C ,
158+ 0xC60C , 0xD785 , 0xE51E , 0xF497 , 0x8028 , 0x91A1 , 0xA33A , 0xB2B3 ,
159+ 0x4A44 , 0x5BCD , 0x6956 , 0x78DF , 0x0C60 , 0x1DE9 , 0x2F72 , 0x3EFB ,
160+ 0xD68D , 0xC704 , 0xF59F , 0xE416 , 0x90A9 , 0x8120 , 0xB3BB , 0xA232 ,
161+ 0x5AC5 , 0x4B4C , 0x79D7 , 0x685E , 0x1CE1 , 0x0D68 , 0x3FF3 , 0x2E7A ,
162+ 0xE70E , 0xF687 , 0xC41C , 0xD595 , 0xA12A , 0xB0A3 , 0x8238 , 0x93B1 ,
163+ 0x6B46 , 0x7ACF , 0x4854 , 0x59DD , 0x2D62 , 0x3CEB , 0x0E70 , 0x1FF9 ,
164+ 0xF78F , 0xE606 , 0xD49D , 0xC514 , 0xB1AB , 0xA022 , 0x92B9 , 0x8330 ,
165+ 0x7BC7 , 0x6A4E , 0x58D5 , 0x495C , 0x3DE3 , 0x2C6A , 0x1EF1 , 0x0F78
166+ };
167+ // @formatter:on
119168
120169 /**
121170 * Creates a new builder.
171+ * <p>
172+ * Since there are so many CRC-16 variants, we do not pick a default.
173+ * </p>
122174 *
123175 * @return a new builder.
124176 */
@@ -127,45 +179,61 @@ public static Builder builder() {
127179 }
128180
129181 /**
130- * Creates a new default CRC16.
182+ * Creates a new CRC16-CCITT.
183+ * <p>
184+ * The init value is {@code 0x0000}.
185+ * </p>
131186 *
132- * @return a new default CRC16.
187+ * @return a new CRC16-CCITT .
133188 */
134- public static CRC16 crc16 () {
135- return builder ().setInit (DEFAULT_INIT ). setTable ( T_DEFAULT ).get ();
189+ public static CRC16 ccitt () {
190+ return builder ().setInit (0x0000 ). table ( T_CCITT ).get ();
136191 }
137192
138193 /**
139- * Creates a new MODBUS CRC16 .
194+ * Gets a copy of the CCITT table .
140195 *
141- * @return a new MODBUS CRC16 .
196+ * @return a copy of the CCITT table .
142197 */
143- public static CRC16 modbus () {
144- return builder (). setInit ( 0xFFFF ). setTable ( T_MODBUS ). get ();
198+ public static int [] getCcittTable () {
199+ return T_CCITT . clone ();
145200 }
146201
147- // @formatter:on
148202 /**
149- * CRC.
203+ * Gets a copy of the MODBUS table.
204+ *
205+ * @return a copy of the MODBUS table.
150206 */
151- private int crc ;
152- private final int init ;
153- private final int [] t ;
207+ public static int [] getModbusTable () {
208+ return T_MODBUS . clone () ;
209+ }
154210
155211 /**
156- * Constructs a new instance.
212+ * Creates a new CRC16-MODBUS.
213+ * <p>
214+ * The init value is {@code 0xFFFF}.
215+ * </p>
216+ *
217+ * @return a new CRC16-MODBUS.
157218 */
158- public CRC16 () {
159- this ( builder ());
219+ public static CRC16 modbus () {
220+ return builder (). setInit ( 0xFFFF ). table ( T_MODBUS ). get ( );
160221 }
161222
223+ /**
224+ * CRC.
225+ */
226+ private int crc ;
227+ private final int init ;
228+ private final int [] table ;
229+
162230 /**
163231 * Constructs a new instance.
164232 */
165233 private CRC16 (final Builder builder ) {
166234 this .init = builder .init ;
167235 this .crc = builder .init ;
168- this .t = builder .t ;
236+ this .table = Objects . requireNonNull ( builder .table , "table" ) ;
169237 }
170238
171239 /**
@@ -196,6 +264,6 @@ public void update(final byte[] b, final int off, final int len) {
196264
197265 @ Override
198266 public void update (final int b ) {
199- crc = crc >>> 8 ^ t [(crc ^ b ) & 0xff ];
267+ crc = crc >>> 8 ^ table [(crc ^ b ) & 0xff ];
200268 }
201269}
0 commit comments