1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "rotatebytearrayfilter.hpp"
10 
11 // Okteta core
12 #include <Okteta/AbstractByteArrayModel>
13 // KF
14 #include <KLocalizedString>
15 // Qt
16 #include <QtGlobal>
17 // Std
18 #include <cstdlib>
19 
20 static constexpr int RotateBitsPerByte = 8;
21 
RotateByteArrayFilter()22 RotateByteArrayFilter::RotateByteArrayFilter()
23     : AbstractByteArrayFilter(
24         i18nc("name of the filter; it moves the bits and pushes the ones over the end to the begin again",
25               "ROTATE data"))
26 {}
27 
28 RotateByteArrayFilter::~RotateByteArrayFilter() = default;
29 
parameterSet()30 AbstractByteArrayFilterParameterSet* RotateByteArrayFilter::parameterSet() { return &mParameterSet; }
31 
filter(Okteta::Byte * result,Okteta::AbstractByteArrayModel * model,const Okteta::AddressRange & range) const32 bool RotateByteArrayFilter::filter(Okteta::Byte* result,
33                                    Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range) const
34 {
35     const int groupSize = mParameterSet.groupSize();
36     const int groupBitCount = (groupSize * RotateBitsPerByte);
37     const int groupShiftBitWidth = std::abs(mParameterSet.moveBitWidth()) % groupBitCount;
38 
39     const int shiftByteWidth = groupShiftBitWidth / RotateBitsPerByte;
40     const int shiftBitWidth = groupShiftBitWidth - shiftByteWidth * RotateBitsPerByte;
41     const int otherShiftBitWidth = RotateBitsPerByte - shiftBitWidth;
42     int filteredBytesCount = 0;
43 
44     const bool toRight = (mParameterSet.moveBitWidth() > 0);
45     if (toRight) {
46         int r = 0;
47         Okteta::Address m = range.start();
48         while (m <= range.end()) {
49             int g = 0;
50             // round the edge byte layer shift
51             while (g < shiftByteWidth && m + groupSize <= range.end()) {
52                 result[r++] = model->byte((m++) + groupSize - shiftByteWidth);
53                 ++g;
54             }
55             // normal byte layer shift
56             while (g < groupSize && m <= range.end()) {
57                 result[r++] = model->byte((m++) - shiftByteWidth);
58                 ++g;
59             }
60 
61             // bit layer shift
62             const unsigned char last = (unsigned char) result[r - 1];
63             for (int b = 1; b <= g; ++b) {
64                 result[r - b] = (unsigned char)result[r - b] >> shiftBitWidth;
65                 if (b < g) {
66                     result[r - b] |= (unsigned char)result[r - b - 1] << otherShiftBitWidth;
67                 } else if (g == groupSize) {
68                     result[r - b] |= last << otherShiftBitWidth;
69                 }
70             }
71 
72             filteredBytesCount += g;
73             if (filteredBytesCount >= FilteredByteCountSignalLimit) {
74                 filteredBytesCount = 0;
75                 emit filteredBytes(m - range.start());
76             }
77         }
78     } else {
79         int r = 0;
80         Okteta::Address m = range.start();
81         while (m <= range.end()) {
82             int g = 0;
83             // normal byte layer shift
84             while (g + shiftByteWidth < groupSize && m + shiftByteWidth <= range.end()) {
85                 result[r++] = model->byte((m++) - shiftByteWidth);
86                 ++g;
87             }
88             // round the edge byte layer shift
89             while (g < groupSize && m <= range.end()) {
90                 result[r++] = model->byte((m++) + shiftByteWidth - groupSize);
91                 ++g;
92             }
93 
94             // bit layer shift
95             const unsigned char first = result[r - g];
96             for (int b = g; b > 0; --b) {
97                 result[r - b] = (unsigned char)result[r - b] << shiftBitWidth;
98                 if (b > 1) {
99                     result[r - b] |= (unsigned char)result[r - b + 1] >> otherShiftBitWidth;
100                 } else if (g == groupSize) {
101                     result[r - b] |= first >> otherShiftBitWidth;
102                 }
103             }
104 
105             filteredBytesCount += g;
106             if (filteredBytesCount >= FilteredByteCountSignalLimit) {
107                 filteredBytesCount = 0;
108                 emit filteredBytes(m - range.start());
109             }
110         }
111     }
112 
113     return true;
114 }
115