File indexing completed on 2024-04-14 05:45:44
0001 /* 0002 This file is part of the Okteta Core library, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2003, 2008-2009 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 "abstractbytearraymodel.hpp" 0010 #include "abstractbytearraymodel_p.hpp" 0011 0012 // lib 0013 #include "charcodec.hpp" 0014 #include "character.hpp" 0015 0016 namespace Okteta { 0017 0018 static constexpr int SearchedByteCountSignalLimit = 10000; 0019 0020 AbstractByteArrayModel::AbstractByteArrayModel(AbstractByteArrayModelPrivate* dd, QObject* parent) 0021 : QObject(parent) 0022 , d_ptr(dd) 0023 {} 0024 0025 AbstractByteArrayModel::AbstractByteArrayModel(QObject* parent) 0026 : QObject(parent) 0027 , d_ptr(new AbstractByteArrayModelPrivate(this)) 0028 {} 0029 0030 AbstractByteArrayModel::~AbstractByteArrayModel() = default; 0031 0032 bool AbstractByteArrayModel::isReadOnly() const { return false; } 0033 0034 void AbstractByteArrayModel::setReadOnly(bool isReadOnly) 0035 { 0036 Q_UNUSED(isReadOnly) 0037 } 0038 0039 Size AbstractByteArrayModel::insert(Address offset, const Byte* insertData, int insertLength) 0040 { 0041 return replace(offset, 0, insertData, insertLength); 0042 } 0043 0044 Size AbstractByteArrayModel::remove(const AddressRange& removeRange) 0045 { 0046 replace(removeRange, nullptr, 0); 0047 return removeRange.width(); // TODO: check if this is true 0048 } 0049 0050 Size AbstractByteArrayModel::copyTo(Byte* dest, const AddressRange& _copyRange) const 0051 { 0052 AddressRange copyRange(_copyRange); 0053 copyRange.restrictEndTo(size() - 1); 0054 0055 const Address copyRangeEnd = copyRange.end(); 0056 for (Address i = copyRange.start(); i <= copyRangeEnd; ++i) { 0057 *dest++ = byte(i); 0058 } 0059 0060 return copyRange.width(); 0061 } 0062 0063 Address AbstractByteArrayModel::indexOf(const Byte* pattern, int patternLength, Address fromOffset, Address toOffset) const 0064 { 0065 Address result = -1; 0066 0067 const Address lastOffset = size() - 1; 0068 if ((toOffset < 0) || lastOffset < toOffset) { 0069 toOffset = lastOffset; 0070 } 0071 0072 const Address lastFrom = toOffset - patternLength + 1; 0073 Size nextSignalByteCount = fromOffset + SearchedByteCountSignalLimit; 0074 0075 for (Address i = fromOffset; i <= lastFrom; ++i) { 0076 int c = 0; 0077 for (; c < patternLength; ++c) { 0078 if (pattern[c] != byte(i + c)) { 0079 break; 0080 } 0081 } 0082 0083 if (nextSignalByteCount <= i) { 0084 nextSignalByteCount += SearchedByteCountSignalLimit; 0085 Q_EMIT searchedBytes(i - fromOffset + 1); 0086 } 0087 0088 if (c == patternLength) { 0089 result = i; 0090 break; 0091 } 0092 } 0093 0094 return result; 0095 } 0096 0097 Address AbstractByteArrayModel::lastIndexOf(const Byte* pattern, int patternLength, Address fromOffset, Address toOffset) const 0098 { 0099 Address result = -1; 0100 0101 const Address lastFrom = size() - patternLength; 0102 0103 if (fromOffset < 0) { 0104 fromOffset = lastFrom + 1 + fromOffset; 0105 } else if (fromOffset > lastFrom) { 0106 fromOffset = lastFrom; 0107 } 0108 0109 if (toOffset < 0) { 0110 toOffset = 0; 0111 } 0112 0113 Size nextSignalByteCount = fromOffset - SearchedByteCountSignalLimit; 0114 0115 for (Address i = fromOffset; i >= toOffset; --i) { 0116 int c = 0; 0117 for (; c < patternLength; ++c) { 0118 if (pattern[c] != byte(i + c)) { 0119 break; 0120 } 0121 } 0122 0123 if (nextSignalByteCount >= i) { 0124 nextSignalByteCount -= SearchedByteCountSignalLimit; 0125 Q_EMIT searchedBytes(i - fromOffset + 1); 0126 } 0127 0128 if (c == patternLength) { 0129 result = i; 0130 break; 0131 } 0132 } 0133 0134 return result; 0135 } 0136 0137 static QByteArray toLower(const QByteArray& _pattern, const CharCodec* charCodec) 0138 { 0139 QByteArray result(_pattern); 0140 0141 const int patternLength = result.size(); 0142 char* pattern = result.data(); 0143 for (int i = 0; i < patternLength; ++i) { 0144 const Character decodedChar = charCodec->decode(pattern[i]); 0145 0146 if (decodedChar.isUndefined()) { 0147 continue; 0148 } 0149 0150 charCodec->encode(reinterpret_cast<Byte*>(&pattern[i]), decodedChar.toLower()); 0151 } 0152 0153 return result; 0154 } 0155 0156 Address AbstractByteArrayModel::indexOfCaseInsensitive(const CharCodec* charCodec, const QByteArray& _pattern, Address fromOffset, Address toOffset) const 0157 { 0158 Address result = -1; 0159 0160 const QByteArray lowerPattern = toLower(_pattern, charCodec); 0161 const Byte* const pattern = reinterpret_cast<const Byte*>(lowerPattern.constData()); 0162 const int patternLength = lowerPattern.size(); 0163 const Address lastOffset = size() - 1; 0164 if ((toOffset < 0) || lastOffset < toOffset) { 0165 toOffset = lastOffset; 0166 } 0167 const Address lastFrom = toOffset - patternLength + 1; 0168 0169 Address nextSignalByteCount = fromOffset + SearchedByteCountSignalLimit; 0170 0171 for (Address i = fromOffset; i <= lastFrom; ++i) { 0172 int c = 0; 0173 for (; c < patternLength; ++c) { 0174 Byte _byte = byte(i + c); 0175 0176 // turn to lowercase if possible 0177 // TODO: optimize, like caching and not reencoding chars without a lower letter 0178 const Okteta::Character decodedChar = charCodec->decode(_byte); 0179 if (!decodedChar.isUndefined()) { 0180 charCodec->encode(&_byte, decodedChar.toLower()); 0181 } 0182 0183 if (_byte != pattern[c]) { 0184 break; 0185 } 0186 } 0187 0188 if (nextSignalByteCount <= i) { 0189 nextSignalByteCount += SearchedByteCountSignalLimit; 0190 Q_EMIT searchedBytes(i - fromOffset + 1); 0191 } 0192 0193 if (c == patternLength) { 0194 result = i; 0195 break; 0196 } 0197 } 0198 0199 return result; 0200 } 0201 0202 Address AbstractByteArrayModel::lastIndexOfCaseInsensitive(const CharCodec* charCodec, const QByteArray& _pattern, Address fromOffset, Address toOffset) const 0203 { 0204 Address result = -1; 0205 0206 const QByteArray lowerPattern = toLower(_pattern, charCodec); 0207 const Byte* const pattern = reinterpret_cast<const Byte*>(lowerPattern.constData()); 0208 const int patternLength = lowerPattern.size(); 0209 const Address lastFrom = size() - patternLength; 0210 0211 if (fromOffset < 0) { 0212 fromOffset = lastFrom + 1 + fromOffset; 0213 } else if (fromOffset > lastFrom) { 0214 fromOffset = lastFrom; 0215 } 0216 0217 if (toOffset < 0) { 0218 toOffset = 0; 0219 } 0220 0221 Address nextSignalByteCount = fromOffset - SearchedByteCountSignalLimit; 0222 0223 for (Address i = fromOffset; i >= toOffset; --i) { 0224 int c = 0; 0225 for (; c < patternLength; ++c) { 0226 Byte _byte = byte(i + c); 0227 0228 // turn to lowercase if possible 0229 // TODO: optimize, like caching and not reencoding chars without a lower letter 0230 const Okteta::Character decodedChar = charCodec->decode(_byte); 0231 if (!decodedChar.isUndefined()) { 0232 charCodec->encode(&_byte, decodedChar.toLower()); 0233 } 0234 0235 if (_byte != pattern[c]) { 0236 break; 0237 } 0238 } 0239 0240 if (nextSignalByteCount >= i) { 0241 nextSignalByteCount -= SearchedByteCountSignalLimit; 0242 Q_EMIT searchedBytes(i - fromOffset + 1); 0243 } 0244 0245 if (c == patternLength) { 0246 result = i; 0247 break; 0248 } 0249 } 0250 0251 return result; 0252 } 0253 0254 } 0255 0256 #include "moc_abstractbytearraymodel.cpp"