001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.codec.digest;
019
020import java.util.Objects;
021import java.util.function.Supplier;
022import java.util.zip.Checksum;
023
024/**
025 * CRC-16 checksum implementations you can customize with a table and init value.
026 * <p>
027 * Since there are so many CRC-16 variants, we do not pick a default.
028 * </p>
029 * <p>
030 * For example, to create a create a custom variant of CRC16-MODBUS with an init value of {@code 0x0000}, use:
031 * </p>
032 *
033 * <pre>
034 * Checksum crc16 = CRC16.builder().setTable(CRC16.getModbusTable()).setInit(0x0000).get();
035 * </pre>
036 *
037 * @see <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">Cyclic redundancy check</a>
038 * @see <a href="https://reveng.sourceforge.io/crc-catalogue/16.htm">Catalogue of parametrised CRC algorithms with 16 bits</a>
039 * @see <a href="https://www.lammertbies.nl/comm/info/crc-calculation">On-line CRC calculation and free library</a>
040 * @see <a href="https://crccalc.com/?crc=123456789&method=&datatype=ascii&outtype=hex">crccalc</a>
041 * @since 1.20.0
042 */
043public final class Crc16 implements Checksum {
044
045    /**
046     * Builds {@link Crc16} instances.
047     */
048    public static final class Builder implements Supplier<Crc16> {
049
050        private int init;
051        private int[] table;
052        private int xorOut;
053
054        /**
055         * Constructs a new instance.
056         */
057        public Builder() {
058            // empty
059        }
060
061        /**
062         * Creates a new {@link Crc16} instance.
063         */
064        @Override
065        public Crc16 get() {
066            return new Crc16(this);
067        }
068
069        /**
070         * Sets the initial value.
071         *
072         * @param init the initial value.
073         * @return {@code this} instance.
074         */
075        public Builder setInit(final int init) {
076            this.init = init;
077            return this;
078        }
079
080        /**
081         * Sets the lookup table.
082         *
083         * @param table the lookup table, making a clone of the input array, must not be null.
084         * @return {@code this} instance.
085         */
086        public Builder setTable(final int[] table) {
087            return table(Objects.requireNonNull(table, "table").clone());
088        }
089
090        /**
091         * Sets the XorOut value to XOR to the current checksum returned by {@link Crc16#getValue()}.
092         *
093         * @param xorOut the XorOut value.
094         * @return {@code this} instance.
095         */
096        public Builder setXorOut(final int xorOut) {
097            this.xorOut = xorOut;
098            return this;
099        }
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}