Created
November 1, 2019 13:01
-
-
Save emelent/948c78259ae3693a2f8aa43522439109 to your computer and use it in GitHub Desktop.
Ripped some code off of http://www.sunshine2k.de/coding/javascript/crc/crc_js.html strictly for computing crc's
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var UInt64 = (function () { | |
function UInt64(numOrUint64, lowVal) { | |
if (typeof numOrUint64 === 'number') { | |
this.highVal = numOrUint64 & 0xFFFFFFFF; | |
this.lowVal = lowVal & 0xFFFFFFFF; | |
} | |
else { | |
this.highVal = numOrUint64.highVal; | |
this.lowVal = numOrUint64.lowVal; | |
} | |
} | |
UInt64.prototype.clone = function () { | |
return new UInt64(this); | |
}; | |
UInt64.FromString = function (strHigh, strLow) { | |
var numHigh = 0, numLow = 0; | |
if (strLow == undefined) { | |
/* the first parameter string contains the whole number */ | |
/* remove preceeding '0x' prefix */ | |
if (strHigh.substr(0, 2) === "0x") { | |
strHigh = strHigh.substr(2, strHigh.length - 2); | |
} | |
/* pad to full 16 digits */ | |
while (strHigh.length < 16) { | |
strHigh = '0' + strHigh; | |
} | |
numHigh = parseInt(strHigh.substr(0, 8), 16); | |
numLow = parseInt(strHigh.substr(8, 15), 16); | |
} | |
else { | |
/* two 32bit numbers are provided */ | |
/* handle high part */ | |
/* remove preceeding '0x' prefix */ | |
if (strHigh.substr(0, 2) === "0x") { | |
strHigh = strHigh.substr(2, strHigh.length - 2); | |
} | |
/* pad to full 8 digits */ | |
while (strHigh.length < 8) { | |
strHigh = '0' + strHigh; | |
} | |
numHigh = parseInt(strHigh, 16); | |
/* handle low part */ | |
/* remove preceeding '0x' prefix */ | |
if (strLow.substr(0, 2) === "0x") { | |
strLow = strLow.substr(2, strLow.length - 2); | |
} | |
/* pad to full 8 digits */ | |
while (strLow.length < 8) { | |
strLow = '0' + strLow; | |
} | |
numLow = parseInt(strLow, 16); | |
} | |
return new UInt64(numHigh, numLow); | |
}; | |
UInt64.prototype.and = function (otherUInt64OrNumber) { | |
if (typeof otherUInt64OrNumber === 'number') { | |
this.highVal = 0; | |
this.lowVal = this.lowVal & otherUInt64OrNumber; | |
} | |
else { | |
this.highVal = this.highVal & otherUInt64OrNumber.highVal; | |
this.lowVal = this.lowVal & otherUInt64OrNumber.lowVal; | |
} | |
return this; | |
}; | |
UInt64.prototype.shl = function (dist) { | |
for (var i = 0; i < dist; i++) { | |
this.highVal = this.highVal << 1; | |
if ((this.lowVal & 0x80000000) != 0) { | |
this.highVal |= 0x01; | |
} | |
this.lowVal = this.lowVal << 1; | |
} | |
return this; | |
}; | |
UInt64.prototype.shr = function (dist) { | |
for (var i = 0; i < dist; i++) { | |
this.lowVal = this.lowVal >>> 1; | |
if ((this.highVal & 0x00000001) != 0) { | |
this.lowVal |= 0x80000000; | |
} | |
this.highVal = this.highVal >>> 1; | |
} | |
return this; | |
}; | |
UInt64.prototype.isZero = function () { | |
return ((this.highVal == 0) && (this.lowVal == 0)); | |
}; | |
UInt64.prototype.xor = function (otherUInt64) { | |
this.highVal = this.highVal ^ otherUInt64.highVal; | |
this.lowVal = this.lowVal ^ otherUInt64.lowVal; | |
return this; | |
}; | |
UInt64.prototype.reflect = function () { | |
var newHighVal = 0, newLowVal = 0; | |
for (var i = 0; i < 32; i++) { | |
if ((this.highVal & (1 << (31 - i))) != 0) { | |
newLowVal |= (1 << i); | |
} | |
if ((this.lowVal & (1 << i)) != 0) { | |
newHighVal |= (1 << (31 - i)); | |
} | |
} | |
this.lowVal = newLowVal; | |
this.highVal = newHighVal; | |
return this; | |
}; | |
UInt64.prototype.toHexString = function () { | |
var str = ""; | |
var stringUtil = new StringUtil(); | |
str += stringUtil.getNumberAsHexStr32FixedWidth(this.highVal); | |
str += (stringUtil.getNumberAsHexStr32FixedWidth(this.lowVal).substring(2, 10)); | |
return str; | |
}; | |
UInt64.prototype.asNumber = function () { | |
return ((this.highVal << 32) | this.lowVal); | |
}; | |
return UInt64; | |
})(); | |
/* | |
* Struct to contain one instance of a CRC algorithm model */ | |
function CrcModel(width, name, polynomial, initial, finalXor, inputReflected, resultReflected) { | |
this.width = width | |
this.name = name; | |
if (width == 64) { | |
this.polynomial = UInt64.FromString(polynomial); | |
this.initial = UInt64.FromString(initial); | |
this.finalXor = UInt64.FromString(finalXor); | |
} | |
else { | |
this.polynomial = polynomial; | |
this.initial = initial; | |
this.finalXor = finalXor; | |
} | |
this.inputReflected = inputReflected; | |
this.resultReflected = resultReflected; | |
} | |
/* Known CRC algorihtms */ | |
const CrcDatabase = { | |
CRC8: new CrcModel(8, "CRC8", 0x07, 0x00, 0x00, false, false), | |
CRC8_SAE_j1850: new CrcModel(8, "CRC8_SAE_J1850", 0x1D, 0xFF, 0xFF, false, false), | |
CRC8_SAE_J1850_ZERO: new CrcModel(8, "CRC8_SAE_J1850_ZERO", 0x1D, 0x00, 0x00, false, false), | |
CRC8_8H2F: new CrcModel(8, "CRC8_8H2F", 0x2F, 0xFF, 0xFF, false, false), | |
CRC8_CDMA2000: new CrcModel(8, "CRC8_CDMA2000", 0x9B, 0xFF, 0x00, false, false), | |
CRC8_DARC: new CrcModel(8, "CRC8_DARC", 0x39, 0x00, 0x00, true, true), | |
CRC8_DVB_S2: new CrcModel(8, "CRC8_DVB_S2", 0xD5, 0x00, 0x00, false, false), | |
CRC8_EBU: new CrcModel(8, "CRC8_EBU", 0x1D, 0xFF, 0x00, true, true), | |
CRC8_ICODE: new CrcModel(8, "CRC8_ICODE", 0x1D, 0xFD, 0x00, false, false), | |
CRC8_ITU: new CrcModel(8, "CRC8_ITU", 0x07, 0x00, 0x55, false, false), | |
CRC8_MAXIM: new CrcModel(8, "CRC8_MAXIM", 0x31, 0x00, 0x00, true, true), | |
CRC8_ROHC: new CrcModel(8, "CRC8_ROHC", 0x07, 0xFF, 0x00, true, true), | |
CRC8_WCDMA: new CrcModel(8, "CRC8_WCDMA", 0x9B, 0x00, 0x00, true, true), | |
CRC16_CCIT_ZERO: new CrcModel(16, "CRC16_CCIT_ZERO", 0x1021, 0x0000, 0x0000, false, false), | |
CRC16_ARC: new CrcModel(16, "CRC16_ARC", 0x8005, 0x0000, 0x0000, true, true), | |
CRC16_AUG_CCITT: new CrcModel(16, "CRC16_AUG_CCITT", 0x1021, 0x1D0F, 0x0000, false, false), | |
CRC16_BUYPASS: new CrcModel(16, "CRC16_BUYPASS", 0x8005, 0x0000, 0x0000, false, false), | |
CRC16_CCITT_FALSE: new CrcModel(16, "CRC16_CCITT_FALSE", 0x1021, 0xFFFF, 0x0000, false, false), | |
CRC16_CDMA2000: new CrcModel(16, "CRC16_CDMA2000", 0xC867, 0xFFFF, 0x0000, false, false), | |
CRC16_DDS_110: new CrcModel(16, "CRC16_DDS_110", 0x8005, 0x800D, 0x0000, false, false), | |
CRC16_DECT_R: new CrcModel(16, "CRC16_DECT_R", 0x0589, 0x0000, 0x0001, false, false), | |
CRC16_DECT_X: new CrcModel(16, "CRC16_DECT_X", 0x0589, 0x0000, 0x0000, false, false), | |
CRC16_DNP: new CrcModel(16, "CRC16_DNP", 0x3D65, 0x0000, 0xFFFF, true, true), | |
CRC16_EN_13757: new CrcModel(16, "CRC16_EN_13757", 0x3D65, 0x0000, 0xFFFF, false, false), | |
CRC16_GENIBUS: new CrcModel(16, "CRC16_GENIBUS", 0x1021, 0xFFFF, 0xFFFF, false, false), | |
CRC16_MAXIM: new CrcModel(16, "CRC16_MAXIM", 0x8005, 0x0000, 0xFFFF, true, true), | |
CRC16_MCRF4XX: new CrcModel(16, "CRC16_MCRF4XX", 0x1021, 0xFFFF, 0x0000, true, true), | |
CRC16_RIELLO: new CrcModel(16, "CRC16_RIELLO", 0x1021, 0xB2AA, 0x0000, true, true), | |
CRC16_T10_DIF: new CrcModel(16, "CRC16_T10_DIF", 0x8BB7, 0x0000, 0x0000, false, false), | |
CRC16_TELEDISK: new CrcModel(16, "CRC16_TELEDISK", 0xA097, 0x0000, 0x0000, false, false), | |
CRC16_TMS37157: new CrcModel(16, "CRC16_TMS37157", 0x1021, 0x89EC, 0x0000, true, true), | |
CRC16_USB: new CrcModel(16, "CRC16_USB", 0x8005, 0xFFFF, 0xFFFF, true, true), | |
CRC16_A: new CrcModel(16, "CRC16_A", 0x1021, 0xC6C6, 0x0000, true, true), | |
CRC16_KERMIT: new CrcModel(16, "CRC16_KERMIT", 0x1021, 0x0000, 0x0000, true, true), | |
CRC16_MODBUS: new CrcModel(16, "CRC16_MODBUS", 0x8005, 0xFFFF, 0x0000, true, true), | |
CRC16_X_25: new CrcModel(16, "CRC16_X_25", 0x1021, 0xFFFF, 0xFFFF, true, true), | |
CRC16_XMODEM: new CrcModel(16, "CRC16_XMODEM", 0x1021, 0x0000, 0x0000, false, false), | |
CRC32: new CrcModel(32, "CRC32", 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true), | |
CRC32_BZIP2: new CrcModel(32, "CRC32_BZIP2", 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, false, false), | |
CRC32_C: new CrcModel(32, "CRC32_C", 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true), | |
CRC32_D: new CrcModel(32, "CRC32_D", 0xA833982B, 0xFFFFFFFF, 0xFFFFFFFF, true, true), | |
CRC32_MPEG2: new CrcModel(32, "CRC32_MPEG2", 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false), | |
CRC32_POSIX: new CrcModel(32, "CRC32_POSIX", 0x04C11DB7, 0x00000000, 0xFFFFFFFF, false, false), | |
CRC32_Q: new CrcModel(32, "CRC32_Q", 0x814141AB, 0x00000000, 0x00000000, false, false), | |
CRC32_JAMCRC: new CrcModel(32, "CRC32_JAMCRC", 0x04C11DB7, 0xFFFFFFFF, 0x00000000, true, true), | |
CRC32_XFER: new CrcModel(32, "CRC32_XFER", 0x000000AF, 0x00000000, 0x00000000, false, false), | |
CRC64_ECMA_182: new CrcModel(64, "CRC64_ECMA_182", "0x42f0e1eba9ea3693", "0x0000000000000000", "0x0000000000000000", false, false), | |
CRC64_GO_ISO: new CrcModel(64, "CRC64_GO_ISO", "0x000000000000001B", "0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", true, true), | |
CRC64_WE: new CrcModel(64, "CRC64_WE", "0x42f0e1eba9ea3693", "0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", false, false), | |
CRC64_XZ: new CrcModel(64, "CRC64_XZ", "0x42f0e1eba9ea3693", "0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", true, true) | |
} | |
var Crc = function (model) { | |
/* private variables */ | |
// crc model variables | |
var width; | |
var polynomial; | |
var initialVal; | |
var finalXorVal; | |
var inputReflected; | |
var resultReflected; | |
var crcTable; // lookup table | |
var castMask; | |
var msbMask; | |
/* 'constructor' */ | |
if (arguments.length == 1 && typeof arguments[0] === "object") { | |
width = model.width; | |
polynomial = model.polynomial; | |
initialVal = model.initial; | |
finalXorVal = model.finalXor; | |
inputReflected = model.inputReflected; | |
resultReflected = model.resultReflected; | |
} | |
else { | |
new Error("Invalid arguments"); | |
} | |
switch (width) | |
{ | |
case 8: castMask = 0xFF; break; | |
case 16: castMask = 0xFFFF; break; | |
case 32: castMask = 0xFFFFFFFF; break; | |
case 64: castMask = new UInt64(0xFFFFFFFF, 0xFFFFFFFF); break; | |
default: throw "Invalid CRC width"; break; | |
} | |
if (width == 64) { | |
msbMask = new UInt64(0x80000000, 0x00000000); | |
} | |
else { | |
msbMask = 0x01 << (width - 1); | |
} | |
/* 'constructor' END */ | |
this.calcCrcTable = function () | |
{ | |
crcTable = new Array(256); | |
if (width == 64) { | |
for (var divident = 0; divident < 256; divident++) { | |
var currByte = new UInt64(0, divident); | |
currByte.shl(56).and(castMask); | |
for (var bit = 0; bit < 8; bit++) { | |
if (!(new UInt64(currByte).and(msbMask).isZero())) { | |
currByte.shl(1); | |
currByte.xor(polynomial); | |
} | |
else { | |
currByte.shl(1); | |
} | |
} | |
crcTable[divident] = currByte.and(castMask); | |
} | |
} | |
else { | |
for (var divident = 0; divident < 256; divident++) { | |
var currByte = (divident << (width - 8)) & castMask; | |
for (var bit = 0; bit < 8; bit++) { | |
if ((currByte & msbMask) != 0) { | |
currByte <<= 1; | |
currByte ^= polynomial; | |
} | |
else { | |
currByte <<= 1; | |
} | |
} | |
crcTable[divident] = (currByte & castMask); | |
} | |
} | |
} | |
this.calcCrcTableReversed = function () | |
{ | |
crcTable = new Array(256); | |
if (width == 64) { | |
for (var divident = 0; divident < 256; divident++) { | |
var reflectedDivident = new CrcUtil().Reflect8(divident); | |
var currByte = new UInt64(0, reflectedDivident); | |
currByte.shl(56).and(castMask); | |
for (var bit = 0; bit < 8; bit++) { | |
if (!(new UInt64(currByte).and(msbMask).isZero())) { | |
currByte.shl(1); | |
currByte.xor(polynomial); | |
} | |
else { | |
currByte.shl(1); | |
} | |
} | |
currByte = currByte.reflect(); | |
crcTable[divident] = currByte.and(castMask); | |
} | |
} | |
else { | |
for (var divident = 0; divident < 256; divident++) { | |
var reflectedDivident = new CrcUtil().Reflect8(divident); | |
var currByte = (reflectedDivident << (width - 8)) & castMask; | |
for (var bit = 0; bit < 8; bit++) { | |
if ((currByte & msbMask) != 0) { | |
currByte <<= 1; | |
currByte ^= polynomial; | |
} | |
else { | |
currByte <<= 1; | |
} | |
} | |
currByte = new CrcUtil().ReflectGeneric(currByte, width); | |
crcTable[divident] = (currByte & castMask); | |
} | |
} | |
} | |
if (!this.crcTable) | |
{ | |
this.calcCrcTable(); | |
} | |
this.compute = function (bytes) | |
{ | |
if (width == 64) { | |
var crc = initialVal.clone(); | |
for (var i = 0; i < bytes.length; i++) { | |
var curByte = bytes[i] & 0xFF; | |
if (inputReflected) { | |
curByte = new CrcUtil().Reflect8(curByte); | |
} | |
/* update the MSB of crc value with next input byte */ | |
var curByteShifted56 = new UInt64(0, curByte).shl(56); | |
crc.xor(curByteShifted56).and(castMask); | |
/* this MSB byte value is the index into the lookup table */ | |
var pos = (crc.clone().shr(56)).and(0xFF).asNumber(); | |
/* shift out this index */ | |
crc.shl(8).and(castMask); | |
/* XOR-in remainder from lookup table using the calculated index */ | |
crc.xor(crcTable[pos]).and(castMask); | |
} | |
if (resultReflected) { | |
crc.reflect(); | |
} | |
return crc.xor(finalXorVal).and(castMask); | |
} | |
else { | |
var crc = initialVal; | |
for (var i = 0; i < bytes.length; i++) { | |
var curByte = bytes[i] & 0xFF; | |
if (inputReflected) { | |
curByte = new CrcUtil().Reflect8(curByte); | |
} | |
/* update the MSB of crc value with next input byte */ | |
crc = (crc ^ (curByte << (width - 8))) & castMask; | |
/* this MSB byte value is the index into the lookup table */ | |
var pos = (crc >> (width - 8)) & 0xFF; | |
/* shift out this index */ | |
crc = (crc << 8) & castMask; | |
/* XOR-in remainder from lookup table using the calculated index */ | |
crc = (crc ^ crcTable[pos]) & castMask; | |
} | |
if (resultReflected) { | |
crc = new CrcUtil().ReflectGeneric(crc, width); | |
} | |
return ((crc ^ finalXorVal) & castMask); | |
} | |
} | |
this.getLookupTable = function () | |
{ | |
return crcTable; | |
} | |
}; | |
/* | |
* CRC utility functions to reflect numbers. | |
*/ | |
var CrcUtil = function () | |
{ | |
/* singleton */ | |
if (CrcUtil.prototype._singletonInstance) | |
{ | |
return CrcUtil.prototype._singletonInstance; | |
} | |
CrcUtil.prototype._singletonInstance = this; | |
this.Reflect8 = function(val) | |
{ | |
var resByte = 0; | |
for (var i = 0; i < 8; i++) | |
{ | |
if ((val & (1 << i)) != 0) | |
{ | |
resByte |= ( (1 << (7 - i)) & 0xFF); | |
} | |
} | |
return resByte; | |
} | |
this.Reflect16 = function (val) | |
{ | |
var resByte = 0; | |
for (var i = 0; i < 16; i++) | |
{ | |
if ((val & (1 << i)) != 0) | |
{ | |
resByte |= ((1 << (15 - i)) & 0xFFFF); | |
} | |
} | |
return resByte; | |
} | |
this.Reflect32 = function (val) | |
{ | |
var resByte = 0; | |
for (var i = 0; i < 32; i++) | |
{ | |
if ((val & (1 << i)) != 0) | |
{ | |
resByte |= ((1 << (31 - i)) & 0xFFFFFFFF); | |
} | |
} | |
return resByte; | |
} | |
this.ReflectGeneric = function (val, width) | |
{ | |
var resByte = 0; | |
for (var i = 0; i < width; i++) | |
{ | |
if ((val & (1 << i)) != 0) | |
{ | |
resByte |= (1 << ((width-1) - i)); | |
} | |
} | |
return resByte; | |
} | |
}; | |
function hexToBytes(str) { | |
var a = []; | |
for (var i = 0, len = str.length; i < len; i+=2) { | |
a.push(parseInt(str.substr(i,2),16)); | |
} | |
return a; | |
} | |
export default { | |
CrcModel, | |
Crc, | |
hexToBytes, | |
CrcModels: CrcDatabase | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment