File indexing completed on 2024-06-23 05:48:48

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2019 Lars Maier <lars.maier@tefax.net>
0005     SPDX-FileCopyrightText: 2022 Friedrich W. H. Kossebau <kossebau@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008 */
0009 
0010 #include "crc64bytearraychecksumalgorithm.hpp"
0011 
0012 // Okteta core
0013 #include <Okteta/AbstractByteArrayModel>
0014 // KF
0015 #include <KConfigGroup>
0016 #include <KLocalizedString>
0017 
0018 static constexpr char Crc64ChecksumConfigGroupId[] = "CRC64";
0019 
0020 struct Crc64AlgorithmSpec
0021 {
0022     quint64 polynomial;
0023     quint64 initialValue;
0024     quint64 finalXorValue;
0025     bool inputReflected;
0026     bool outputReflected;
0027 };
0028 
0029 static const Crc64AlgorithmSpec algorithms[] = {
0030     // ECMA-182
0031     { 0x42F0E1EBA9EA3693, 0x0, 0x0, false, false },
0032 
0033     // ISO 3309
0034     { 0x000000000000001B, 0xFFFFFFFFFFFFFFFFLLU,0xFFFFFFFFFFFFFFFFLLU, true, true}
0035 
0036     // Add more algorithms here
0037 };
0038 
0039 static void fillTable(quint64 poly, quint64 *table)
0040 {
0041     for (size_t i = 0; i < 256; i++) {
0042         quint64 crc = 0;
0043         for (size_t j = 0; j < 8; j++) {
0044             bool b = (i >> (7U - j)) & 0x01U;
0045             if (((crc >> 63U) != 0) != b) {
0046                 crc = (crc << 1U) ^ poly;
0047             } else {
0048                 crc = (crc << 1U);
0049             }
0050         }
0051         table[i] = crc;
0052     }
0053 }
0054 
0055 static quint64 reflect64(quint64 x)
0056 {
0057     quint64 y = 0;
0058     for (size_t i = 0; i < 64; i++) {
0059         if ((x >> i) & 0x01U) {
0060             y |= 0x01LLU << (63 - i);
0061         }
0062     }
0063 
0064     return y;
0065 }
0066 
0067 static uchar reflect8(uchar x)
0068 {
0069     uchar y = 0;
0070 
0071     for (size_t i = 0; i < 8; i++) {
0072         if ((x >> i) & 0x01U) {
0073             y |= 0x01U << (7 - i);
0074         }
0075     }
0076 
0077     return y;
0078 }
0079 
0080 Crc64ByteArrayChecksumAlgorithm::Crc64ByteArrayChecksumAlgorithm()
0081     : AbstractByteArrayChecksumAlgorithm(
0082           i18nc("name of the checksum algorithm, Cyclic Redundancy Check 64", "CRC-64"),
0083           QStringLiteral("CRC64")
0084       )
0085 {}
0086 
0087 Crc64ByteArrayChecksumAlgorithm::~Crc64ByteArrayChecksumAlgorithm() = default;
0088 
0089 AbstractByteArrayChecksumParameterSet*
0090 Crc64ByteArrayChecksumAlgorithm::parameterSet() { return &mParameterSet; }
0091 
0092 void Crc64ByteArrayChecksumAlgorithm::loadConfig(const KConfigGroup& configGroup)
0093 {
0094     const KConfigGroup algorithmConfigGroup = configGroup.group(Crc64ChecksumConfigGroupId);
0095 
0096     mParameterSet.loadConfig(algorithmConfigGroup);
0097 }
0098 
0099 void Crc64ByteArrayChecksumAlgorithm::saveConfig(KConfigGroup& configGroup) const
0100 {
0101     KConfigGroup algorithmConfigGroup = configGroup.group(Crc64ChecksumConfigGroupId);
0102 
0103     mParameterSet.saveConfig(algorithmConfigGroup);
0104 }
0105 
0106 bool Crc64ByteArrayChecksumAlgorithm::calculateChecksum(QString* result,
0107                                                         const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
0108 {
0109     const Crc64AlgorithmSpec *spec = &algorithms[static_cast<size_t>(mParameterSet.crc64Variant())];
0110 
0111     quint64 lookupTable[256];
0112     fillTable(spec->polynomial, lookupTable);
0113 
0114     quint64 crcBits = spec->initialValue;
0115     Okteta::Address nextBlockEnd = range.start() + CalculatedByteCountSignalLimit;
0116     for (Okteta::Address i = range.start(); i <= range.end(); ++i) {
0117 
0118         uchar value = model->byte(i);
0119         if (spec->inputReflected) {
0120             value = reflect8(value);
0121         }
0122 
0123         const uchar idx = (crcBits >> 56U) ^ value;
0124         crcBits = (crcBits << 8U) ^ lookupTable[idx & 0xffU];
0125 
0126         if (i >= nextBlockEnd) {
0127             nextBlockEnd += CalculatedByteCountSignalLimit;
0128             Q_EMIT calculatedBytes(range.localIndex(i) + 1);
0129         }
0130     }
0131 
0132     if (spec->outputReflected) {
0133         crcBits = reflect64(crcBits);
0134     }
0135     crcBits = crcBits ^ spec->finalXorValue;
0136 
0137     *result = QStringLiteral("%1").arg(crcBits, 16, 16, QChar::fromLatin1('0'));
0138     return true;
0139 }
0140 
0141 #include "moc_crc64bytearraychecksumalgorithm.cpp"