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

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2008, 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 "rotatebytearrayfilter.hpp"
0010 
0011 // Okteta core
0012 #include <Okteta/AbstractByteArrayModel>
0013 // KF
0014 #include <KConfigGroup>
0015 #include <KLocalizedString>
0016 // Std
0017 #include <cstdlib>
0018 
0019 static constexpr char RotateFilterConfigGroupId[] = "Rotate";
0020 
0021 static constexpr int RotateBitsPerByte = 8;
0022 
0023 RotateByteArrayFilter::RotateByteArrayFilter()
0024     : AbstractByteArrayFilter(
0025         i18nc("name of the filter; it moves the bits and pushes the ones over the end to the begin again",
0026               "ROTATE data"),
0027         QStringLiteral("Rotate")
0028       )
0029 {}
0030 
0031 RotateByteArrayFilter::~RotateByteArrayFilter() = default;
0032 
0033 AbstractByteArrayFilterParameterSet* RotateByteArrayFilter::parameterSet() { return &mParameterSet; }
0034 
0035 void RotateByteArrayFilter::loadConfig(const KConfigGroup& configGroup)
0036 {
0037     const KConfigGroup filterConfigGroup = configGroup.group(RotateFilterConfigGroupId);
0038 
0039     mParameterSet.loadConfig(filterConfigGroup);
0040 }
0041 
0042 void RotateByteArrayFilter::saveConfig(KConfigGroup& configGroup) const
0043 {
0044     KConfigGroup filterConfigGroup = configGroup.group(RotateFilterConfigGroupId);
0045 
0046     mParameterSet.saveConfig(filterConfigGroup);
0047 }
0048 
0049 bool RotateByteArrayFilter::filter(Okteta::Byte* result,
0050                                    Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
0051 {
0052     const int groupSize = mParameterSet.groupSize();
0053     const int groupBitCount = (groupSize * RotateBitsPerByte);
0054     const int groupShiftBitWidth = std::abs(mParameterSet.moveBitWidth()) % groupBitCount;
0055 
0056     const int shiftByteWidth = groupShiftBitWidth / RotateBitsPerByte;
0057     const int shiftBitWidth = groupShiftBitWidth - shiftByteWidth * RotateBitsPerByte;
0058     const int otherShiftBitWidth = RotateBitsPerByte - shiftBitWidth;
0059     int filteredBytesCount = 0;
0060 
0061     const bool toRight = (mParameterSet.moveBitWidth() > 0);
0062     if (toRight) {
0063         int r = 0;
0064         Okteta::Address m = range.start();
0065         while (m <= range.end()) {
0066             int g = 0;
0067             // round the edge byte layer shift
0068             while (g < shiftByteWidth && m + groupSize <= range.end()) {
0069                 result[r++] = model->byte((m++) + groupSize - shiftByteWidth);
0070                 ++g;
0071             }
0072             // normal byte layer shift
0073             while (g < groupSize && m <= range.end()) {
0074                 result[r++] = model->byte((m++) - shiftByteWidth);
0075                 ++g;
0076             }
0077 
0078             // bit layer shift
0079             const auto last = static_cast<unsigned char>(result[r - 1]);
0080             for (int b = 1; b <= g; ++b) {
0081                 result[r - b] = (unsigned char)result[r - b] >> shiftBitWidth;
0082                 if (b < g) {
0083                     result[r - b] |= (unsigned char)result[r - b - 1] << otherShiftBitWidth;
0084                 } else if (g == groupSize) {
0085                     result[r - b] |= last << otherShiftBitWidth;
0086                 }
0087             }
0088 
0089             filteredBytesCount += g;
0090             if (filteredBytesCount >= FilteredByteCountSignalLimit) {
0091                 filteredBytesCount = 0;
0092                 Q_EMIT filteredBytes(m - range.start());
0093             }
0094         }
0095     } else {
0096         int r = 0;
0097         Okteta::Address m = range.start();
0098         while (m <= range.end()) {
0099             int g = 0;
0100             // normal byte layer shift
0101             while (g + shiftByteWidth < groupSize && m + shiftByteWidth <= range.end()) {
0102                 result[r++] = model->byte((m++) - shiftByteWidth);
0103                 ++g;
0104             }
0105             // round the edge byte layer shift
0106             while (g < groupSize && m <= range.end()) {
0107                 result[r++] = model->byte((m++) + shiftByteWidth - groupSize);
0108                 ++g;
0109             }
0110 
0111             // bit layer shift
0112             const unsigned char first = result[r - g];
0113             for (int b = g; b > 0; --b) {
0114                 result[r - b] = (unsigned char)result[r - b] << shiftBitWidth;
0115                 if (b > 1) {
0116                     result[r - b] |= (unsigned char)result[r - b + 1] >> otherShiftBitWidth;
0117                 } else if (g == groupSize) {
0118                     result[r - b] |= first >> otherShiftBitWidth;
0119                 }
0120             }
0121 
0122             filteredBytesCount += g;
0123             if (filteredBytesCount >= FilteredByteCountSignalLimit) {
0124                 filteredBytesCount = 0;
0125                 Q_EMIT filteredBytes(m - range.start());
0126             }
0127         }
0128     }
0129 
0130     return true;
0131 }
0132 
0133 #include "moc_rotatebytearrayfilter.cpp"