blob: 57c1aaac916d0857504b14c4088256ffad720118 [file] [log] [blame] [edit]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#include "crc_generate.h"
#include "crc_internal.h"
#include "log.h"
crc_t
crcMostSignificantBit (unsigned int width) {
return CRC_C(1) << (width - 1);
}
crc_t
crcReflectBits (crc_t fromValue, unsigned int width) {
crc_t fromBit = crcMostSignificantBit(width);
crc_t toBit = 1;
crc_t toValue = 0;
while (fromBit) {
if (fromValue & fromBit) toValue |= toBit;
fromBit >>= 1;
toBit <<= 1;
}
return toValue;
}
void
crcReflectValue (crc_t *value, const CRCAlgorithm *algorithm) {
*value = crcReflectBits(*value, algorithm->checksumWidth);
}
void
crcReflectByte (uint8_t *byte) {
*byte = crcReflectBits(*byte, CRC_BYTE_WIDTH);
}
static uint8_t crcDirectDataTranslationTable[CRC_BYTE_INDEXED_TABLE_SIZE] = {1};
static uint8_t crcReflectedDataTranslationTable[CRC_BYTE_INDEXED_TABLE_SIZE] = {1};
static void
crcMakeDataTranslationTable (CRCProperties *properties, const CRCAlgorithm *algorithm) {
if (algorithm->reflectData) {
uint8_t *table = crcReflectedDataTranslationTable;
properties->dataTranslationTable = table;
if (*table) {
for (unsigned int index=0; index<=UINT8_MAX; index+=1) {
uint8_t *byte = &table[index];
*byte = index;
crcReflectByte(byte);
}
}
} else {
uint8_t *table = crcDirectDataTranslationTable;
properties->dataTranslationTable = table;
if (*table) {
for (unsigned int index=0; index<=UINT8_MAX; index+=1) {
table[index] = index;
}
}
}
}
static void
crcMakeRemainderCache (CRCProperties *properties, const CRCAlgorithm *algorithm) {
// Compute the remainder for each possible dividend.
for (unsigned int dividend=0; dividend<=UINT8_MAX; dividend+=1) {
// Start with the dividend followed by zeros.
crc_t remainder = dividend << properties->byteShift;
// Perform modulo-2 division, a bit at a time.
for (unsigned int bit=CRC_BYTE_WIDTH; bit>0; bit-=1) {
// Try to divide the current data bit.
if (remainder & properties->mostSignificantBit) {
remainder <<= 1;
remainder ^= algorithm->generatorPolynomial;
} else {
remainder <<= 1;
}
}
// Store the result into the table.
properties->remainderCache[dividend] = remainder & properties->valueMask;
}
}
void
crcMakeProperties (CRCProperties *properties, const CRCAlgorithm *algorithm) {
properties->byteShift = algorithm->checksumWidth - CRC_BYTE_WIDTH;
properties->mostSignificantBit = crcMostSignificantBit(algorithm->checksumWidth);
properties->valueMask = (properties->mostSignificantBit - 1) | properties->mostSignificantBit;
crcMakeDataTranslationTable(properties, algorithm);
crcMakeRemainderCache(properties, algorithm);
}
void
crcResetGenerator (CRCGenerator *crc) {
crc->currentValue = crc->algorithm.initialValue;
}
CRCGenerator *
crcNewGenerator (const CRCAlgorithm *algorithm) {
CRCGenerator *crc;
const char *name = algorithm->primaryName;
size_t size = sizeof(*crc) + strlen(name) + 1;
if ((crc = malloc(size))) {
memset(crc, 0, size);
crc->algorithm = *algorithm;
strcpy(crc->algorithmName, name);
crc->algorithm.primaryName = crc->algorithmName;
crcMakeProperties(&crc->properties, &crc->algorithm);
crcResetGenerator(crc);
return crc;
} else {
logMallocError();
}
return NULL;
}
void
crcDestroyGenerator (CRCGenerator *crc) {
free(crc);
}
void
crcAddByte (CRCGenerator *crc, uint8_t byte) {
byte = crc->properties.dataTranslationTable[byte];
byte ^= crc->currentValue >> crc->properties.byteShift;
crc->currentValue = crc->properties.remainderCache[byte] ^ (crc->currentValue << CRC_BYTE_WIDTH);
crc->currentValue &= crc->properties.valueMask;
}
void
crcAddData (CRCGenerator *crc, const void *data, size_t size) {
const uint8_t *byte = data;
const uint8_t *end = byte + size;
while (byte < end) crcAddByte(crc, *byte++);
}
crc_t
crcGetValue (const CRCGenerator *crc) {
return crc->currentValue;
}
crc_t
crcGetChecksum (const CRCGenerator *crc) {
const CRCAlgorithm *algorithm = &crc->algorithm;
crc_t checksum = crc->currentValue;
if (crc->algorithm.reflectResult) crcReflectValue(&checksum, algorithm);
checksum ^= algorithm->xorMask;
return checksum;
}
crc_t
crcGetResidue (CRCGenerator *crc) {
const CRCAlgorithm *algorithm = &crc->algorithm;
crc_t originalValue = crc->currentValue;
crc_t checksum = crcGetChecksum(crc);
unsigned int size = algorithm->checksumWidth / CRC_BYTE_WIDTH;
uint8_t data[size];
if (algorithm->reflectResult) {
uint8_t *byte = data;
const uint8_t *end = byte + size;
while (byte < end) {
*byte++ = checksum;
checksum >>= CRC_BYTE_WIDTH;
}
} else {
uint8_t *byte = data + size;
while (byte-- > data) {
*byte = checksum;
checksum >>= CRC_BYTE_WIDTH;
}
}
crcAddData(crc, data, size);
crc_t residue = crc->currentValue;
if (algorithm->reflectResult) crcReflectValue(&residue, algorithm);
crc->currentValue = originalValue;
return residue;
}
const CRCAlgorithm *
crcGetAlgorithm (const CRCGenerator *crc) {
return &crc->algorithm;
}
const CRCProperties *
crcGetProperties (const CRCGenerator *crc) {
return &crc->properties;
}