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: 2009, 2022 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "modsum32bytearraychecksumalgorithm.hpp"
0010 
0011 // Okteta core
0012 #include <Okteta/AbstractByteArrayModel>
0013 // KF
0014 #include <KConfigGroup>
0015 #include <KLocalizedString>
0016 // Qt
0017 #include <QtEndian>
0018 
0019 static constexpr char ModSum32ConfigGroupId[] = "ModularSum32";
0020 
0021 ModSum32ByteArrayChecksumAlgorithm::ModSum32ByteArrayChecksumAlgorithm()
0022     : AbstractByteArrayChecksumAlgorithm(
0023         i18nc("name of the checksum algorithm", "Modular sum 32-bit"),
0024         QStringLiteral("ModularSum32")
0025       )
0026 {}
0027 
0028 ModSum32ByteArrayChecksumAlgorithm::~ModSum32ByteArrayChecksumAlgorithm() = default;
0029 
0030 AbstractByteArrayChecksumParameterSet* ModSum32ByteArrayChecksumAlgorithm::parameterSet() { return &mParameterSet; }
0031 
0032 void ModSum32ByteArrayChecksumAlgorithm::loadConfig(const KConfigGroup& configGroup)
0033 {
0034     const KConfigGroup algorithmConfigGroup = configGroup.group(ModSum32ConfigGroupId);
0035 
0036     mParameterSet.loadConfig(algorithmConfigGroup);
0037 }
0038 
0039 void ModSum32ByteArrayChecksumAlgorithm::saveConfig(KConfigGroup& configGroup) const
0040 {
0041     KConfigGroup algorithmConfigGroup = configGroup.group(ModSum32ConfigGroupId);
0042 
0043     mParameterSet.saveConfig(algorithmConfigGroup);
0044 }
0045 
0046 bool ModSum32ByteArrayChecksumAlgorithm::calculateChecksum(QString* result,
0047                                                            const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
0048 {
0049     const bool useLittleEndian = (mParameterSet.endianness() == QSysInfo::LittleEndian);
0050     quint32 modSum = useLittleEndian ?
0051                      calculateModSumWithLittleEndian(model, range) :
0052                      calculateModSumWithBigEndian(model, range);
0053 
0054     modSum = ~modSum + 1;
0055 
0056     if (useLittleEndian) {
0057         modSum = qbswap(modSum);
0058     }
0059 
0060     *result = QStringLiteral("%1").arg(modSum, 8, 16, QChar::fromLatin1('0'));
0061     return true;
0062 }
0063 
0064 quint32 ModSum32ByteArrayChecksumAlgorithm::calculateModSumWithBigEndian(const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
0065 {
0066     quint32 modSum = 0x000000;
0067     Okteta::Address nextBlockEnd = range.start() + CalculatedByteCountSignalLimit;
0068 
0069     // TODO: move padding checks into extra code before and after loop
0070     for (Okteta::Address i = range.start(); i <= range.end(); ++i) {
0071         quint32 value = (quint32)(quint8)(model->byte(i)) << 24;
0072         ++i;
0073         if (i <= range.end()) {
0074             value |= (quint32)(quint8)(model->byte(i)) << 16;
0075             ++i;
0076             if (i <= range.end()) {
0077                 value |= (quint32)(quint8)(model->byte(i)) << 8;
0078                 ++i;
0079                 if (i <= range.end()) {
0080                     value |= (quint32)(quint8)(model->byte(i));
0081                 }
0082             }
0083         }
0084 
0085         modSum += value;
0086 #if 0
0087         const uchar value = (crcBits & 0xFF) + model->byte(i);
0088         crcBits >>= 8;
0089         crcBits ^= lookupTable[value];
0090 #endif
0091         if (i >= nextBlockEnd) {
0092             nextBlockEnd += CalculatedByteCountSignalLimit;
0093             Q_EMIT calculatedBytes(range.localIndex(i) + 1);
0094         }
0095     }
0096 
0097     return modSum;
0098 }
0099 
0100 quint32 ModSum32ByteArrayChecksumAlgorithm::calculateModSumWithLittleEndian(const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
0101 {
0102     quint32 modSum = 0x000000;
0103     Okteta::Address nextBlockEnd = range.start() + CalculatedByteCountSignalLimit;
0104 
0105     // TODO: move padding checks into extra code before and after loop
0106     for (Okteta::Address i = range.start(); i <= range.end(); ++i) {
0107         quint32 value = (quint32)(quint8)(model->byte(i));
0108         ++i;
0109         if (i <= range.end()) {
0110             value |= (quint32)(quint8)(model->byte(i)) << 8;
0111             ++i;
0112             if (i <= range.end()) {
0113                 value |= (quint32)(quint8)(model->byte(i)) << 16;
0114                 ++i;
0115                 if (i <= range.end()) {
0116                     value |= (quint32)(quint8)(model->byte(i)) << 24;
0117                 }
0118             }
0119         }
0120 
0121         modSum += value;
0122 
0123         if (i >= nextBlockEnd) {
0124             nextBlockEnd += CalculatedByteCountSignalLimit;
0125             Q_EMIT calculatedBytes(range.localIndex(i) + 1);
0126         }
0127     }
0128 
0129     return modSum;
0130 }
0131 
0132 #include "moc_modsum32bytearraychecksumalgorithm.cpp"