Add more CRC32 algorithms

This commit is contained in:
Anton Tananaev
2026-04-12 10:54:55 -07:00
parent 8fec46eb32
commit b3443ec8d4
3 changed files with 60 additions and 21 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
* Copyright 2012 - 2026 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,13 +17,26 @@ package org.traccar.helper;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.zip.CRC32;
public final class Checksum {
private Checksum() {
}
public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00);
public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00);
public static final Algorithm CRC8_DALLAS = new Algorithm(8, 0x31, 0x00, true, true, 0x00);
public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000);
public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF);
public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000);
public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000);
public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000);
public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000);
public static final Algorithm CRC32_STANDARD = new Algorithm(32, 0x04C11DB7, 0xFFFFFFFF, true, true, 0xFFFFFFFF);
public static final Algorithm CRC32_MPEG2 = new Algorithm(32, 0x04C11DB7, 0xFFFFFFFF, false, false, 0x00000000);
public static class Algorithm {
private final int poly;
@@ -39,7 +52,13 @@ public final class Checksum {
this.refIn = refIn;
this.refOut = refOut;
this.xorOut = xorOut;
this.table = bits == 8 ? initTable8() : initTable16();
if (bits == 8) {
this.table = initTable8();
} else if (bits == 16) {
this.table = initTable16();
} else {
this.table = initTable32();
}
}
private int[] initTable8() {
@@ -76,6 +95,22 @@ public final class Checksum {
return table;
}
private int[] initTable32() {
int[] table = new int[256];
for (int i = 0; i < 256; i++) {
int crc = i << 24;
for (int j = 0; j < 8; j++) {
if ((crc & 0x80000000) != 0) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
table[i] = crc;
}
return table;
}
}
private static int reverse(int value, int bits) {
@@ -117,23 +152,19 @@ public final class Checksum {
return (crc ^ algorithm.xorOut) & 0xFFFF;
}
public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00);
public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00);
public static final Algorithm CRC8_DALLAS = new Algorithm(8, 0x31, 0x00, true, true, 0x00);
public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000);
public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF);
public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000);
public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000);
public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000);
public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000);
public static int crc32(ByteBuffer buf) {
CRC32 checksum = new CRC32();
public static int crc32(Algorithm algorithm, ByteBuffer buf) {
int crc = algorithm.init;
while (buf.hasRemaining()) {
checksum.update(buf.get());
int b = buf.get() & 0xFF;
if (algorithm.refIn) {
b = reverse(b, 8);
}
crc = (crc << 8) ^ algorithm.table[((crc >> 24) & 0xFF) ^ b];
}
return (int) checksum.getValue();
if (algorithm.refOut) {
crc = reverse(crc, 32);
}
return crc ^ algorithm.xorOut;
}
public static int xor(ByteBuffer buf) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
* Copyright 2013 - 2026 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,7 +70,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
ByteBuf request = Unpooled.buffer(8);
request.writeShortLE(type);
request.writeShortLE(0);
request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 4)));
request.writeIntLE(Checksum.crc32(Checksum.CRC32_STANDARD, request.nioBuffer(0, 4)));
channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress()));
}
@@ -83,7 +83,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
request.writeShortLE(6);
request.writeIntLE((int) lastIndex);
request.writeShortLE(512);
request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 10)));
request.writeIntLE(Checksum.crc32(Checksum.CRC32_STANDARD, request.nioBuffer(0, 10)));
channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress()));
}
}

View File

@@ -31,6 +31,14 @@ public class ChecksumTest {
assertEquals(0x31c3, Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer()));
}
@Test
public void testCrc32() {
ByteBuf buf = Unpooled.copiedBuffer("123456789", StandardCharsets.US_ASCII);
assertEquals(0xcbf43926, Checksum.crc32(Checksum.CRC32_STANDARD, buf.nioBuffer()));
assertEquals(0x0376e6e7, Checksum.crc32(Checksum.CRC32_MPEG2, buf.nioBuffer()));
}
@Test
public void testLuhn() {
assertEquals(7, Checksum.luhn(12345678901234L));