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"