@taichunmin/crc
Version:
A cross platform alternative for calculating Cyclic Redundancy Checks (CRC) values.
325 lines (290 loc) • 7.34 kB
text/typescript
import { setObject } from './common2'
import { reflect, u8ToHex } from './common1'
export class GenericCrc8 {
name: string
readonly initial: number
readonly poly: number
readonly refin: boolean
readonly refout: boolean
readonly tbl = new Uint8Array(256)
readonly u8 = new Uint8Array(1)
readonly xorout: number
constructor (opts: {
name: string
poly: number
initial: number
xorout: number
refin: boolean
refout: boolean
}) {
this.name = opts.name
this.poly = opts.poly
this.initial = opts.initial
this.xorout = opts.xorout
this.refin = opts.refin
this.refout = opts.refout
this.buildPoly(opts.poly)
}
buildPoly (poly: number): void {
const [u8, refin, tbl] = [this.u8, this.refin, this.tbl]
for (let i = 0; i < 256; i++) {
u8[0] = refin ? reflect.u8(i) : i
tbl[i] = 0
for (let j = 0; j < 8; j++) {
tbl[i] = (((tbl[i] ^ u8[0]) & 0x80) !== 0 ? poly : 0) ^ (tbl[i] << 1)
u8[0] <<= 1
}
if (refin) tbl[i] = reflect.u8(tbl[i])
}
}
getCrc (buf: Uint8Array): number {
const [u8, refout, tbl, xorout] = [this.u8, this.refout, this.tbl, this.xorout]
u8[0] = refout ? reflect.u8(this.initial) : this.initial
for (const b of buf) u8[0] = tbl[u8[0] ^ b]
return u8[0] ^ xorout
}
dumpPoly (space = 0): string {
const [u8, tbl] = [this.u8, this.tbl]
const lines = []
for (let i = 0; i < 32; i++) {
const line = []
for (let j = 0; j < 8; j++) {
u8[0] = tbl[i * 8 + j]
line.push(u8ToHex(u8[0]))
}
lines.push(''.padStart(space) + line.join(', ') + ',\n')
}
return lines.join('')
}
exportCrcFn (): string {
const prev = u8ToHex((this.refout ? reflect.u8(this.initial) : this.initial) ^ this.xorout)
const xorout = this.xorout === 0 ? '' : ` ^ ${u8ToHex(this.xorout)}`
return `import { setObject, u8 } from './common2'
const POLY_TABLE = new Uint8Array([
${this.dumpPoly(2).trim()}
])
/**
* - poly: ${u8ToHex(this.poly)}
* - initial: ${u8ToHex(this.initial)}
* - xorout: ${u8ToHex(this.xorout)}
* - refin: ${this.refin}
* - refout: ${this.refout}
*/
export default function ${this.name} (buf: Uint8Array = new Uint8Array(), prev: number = ${prev}): number {
u8[0] = prev${xorout}
for (const b of buf) u8[0] = POLY_TABLE[u8[0] ^ b]
return u8[0]${xorout}
}
setObject(globalThis, ['taichunmin', 'crc', '${this.name}'], ${this.name})
`
}
exportTest1 (): string {
const hexToCrc = (hex: string): string => u8ToHex(this.getCrc(Buffer.from(hex, 'hex'))).slice(2)
return `
describe('${this.name}', () => {
test.each([
{ crc: '${hexToCrc('')}', hex: '' },
{ crc: '${hexToCrc('31')}', hex: '31' },
{ crc: '${hexToCrc('48656C6C6F20576F726C6421')}', hex: '48656C6C6F20576F726C6421' },
{ crc: '${hexToCrc('313233343536373839')}', hex: '313233343536373839' },
])('#getCrc(Buffer.from("$hex", "hex")) = 0x$crc', ({ hex, crc }) => {
const u8arr = hexToU8Arr(hex)
expect(sut.${this.name}.getCrc(u8arr)).toBe(parseInt(crc, 16))
})
})
`
}
exportTest2 (): string {
const hexToCrc = (hex: string): string => u8ToHex(this.getCrc(Buffer.from(hex, 'hex'))).slice(2)
return `
describe('${this.name}', () => {
test.each([
{ crc: '${hexToCrc('')}', hex: '' },
{ crc: '${hexToCrc('31')}', hex: '31' },
{ crc: '${hexToCrc('48656C6C6F20576F726C6421')}', hex: '48656C6C6F20576F726C6421' },
{ crc: '${hexToCrc('313233343536373839')}', hex: '313233343536373839' },
])('#getCrc(Buffer.from("$hex", "hex")) = 0x$crc', ({ hex, crc }) => {
const u8arr = hex === '' ? undefined : hexToU8Arr(hex)
expect(${this.name}(u8arr)).toBe(parseInt(crc, 16))
})
test.each([
{ crc: '${hexToCrc('48656C6C6F20576F726C6421')}', hex: '48656C6C6F20576F726C6421' },
{ crc: '${hexToCrc('313233343536373839')}', hex: '313233343536373839' },
])('#getCrc(Buffer.from("$hex", "hex")) = 0x$crc', ({ hex, crc }) => {
const u8arr = hexToU8Arr(hex)
const prev = ${this.name}(u8arr.subarray(0, 1))
expect(${this.name}(u8arr.subarray(1), prev)).toBe(parseInt(crc, 16))
})
})
`
}
}
setObject(globalThis, ['taichunmin', 'crc', 'GenericCrc8'], GenericCrc8)
export const crc8 = new GenericCrc8({
name: 'crc8',
poly: 0x07,
initial: 0x00,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8autosar = new GenericCrc8({
name: 'crc8autosar',
poly: 0x2F,
initial: 0xFF,
xorout: 0xFF,
refin: false,
refout: false,
})
export const crc8bluetooth = new GenericCrc8({
name: 'crc8bluetooth',
poly: 0xA7,
initial: 0x00,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8cardx = new GenericCrc8({
name: 'crc8cardx',
poly: 0x07,
initial: 0x2C,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8cdma2000 = new GenericCrc8({
name: 'crc8cdma2000',
poly: 0x9B,
initial: 0xFF,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8darc = new GenericCrc8({
name: 'crc8darc',
poly: 0x39,
initial: 0x00,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8dvbs2 = new GenericCrc8({
name: 'crc8dvbs2',
poly: 0xD5,
initial: 0x00,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8ebu = new GenericCrc8({
name: 'crc8ebu',
poly: 0x1D,
initial: 0xFF,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8gsma = new GenericCrc8({
name: 'crc8gsma',
poly: 0x1D,
initial: 0x00,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8gsmb = new GenericCrc8({
name: 'crc8gsmb',
poly: 0x49,
initial: 0x00,
xorout: 0xFF,
refin: false,
refout: false,
})
export const crc8hitag = new GenericCrc8({
name: 'crc8hitag',
poly: 0x1D,
initial: 0xFF,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8icode = new GenericCrc8({
name: 'crc8icode',
poly: 0x1D,
initial: 0xFD,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8itu = new GenericCrc8({
name: 'crc8itu',
poly: 0x07,
initial: 0x00,
xorout: 0x55,
refin: false,
refout: false,
})
export const crc8legic = new GenericCrc8({
name: 'crc8legic',
poly: 0x63,
initial: 0x55,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8mad = new GenericCrc8({
name: 'crc8mad',
poly: 0x1D,
initial: 0xC7,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8maxim = new GenericCrc8({
name: 'crc8maxim',
poly: 0x31,
initial: 0x00,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8nrsc5 = new GenericCrc8({
name: 'crc8nrsc5',
poly: 0x31,
initial: 0xFF,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8opensafety = new GenericCrc8({
name: 'crc8opensafety',
poly: 0x2F,
initial: 0x00,
xorout: 0x00,
refin: false,
refout: false,
})
export const crc8rohc = new GenericCrc8({
name: 'crc8rohc',
poly: 0x07,
initial: 0xFF,
xorout: 0x00,
refin: true,
refout: true,
})
export const crc8saej1850 = new GenericCrc8({
name: 'crc8saej1850',
poly: 0x1D,
initial: 0xFF,
xorout: 0xFF,
refin: false,
refout: false,
})
export const crc8wcdma = new GenericCrc8({
name: 'crc8wcdma',
poly: 0x9B,
initial: 0x00,
xorout: 0x00,
refin: true,
refout: true,
})