File indexing completed on 2024-05-26 05:56:31

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2023 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 "bytearraysearchutils.hpp"
0010 
0011 // Okteta core
0012 #include <Okteta/AbstractByteArrayModel>
0013 
0014 namespace Kasten {
0015 
0016 namespace ByteArraySearchUtils {
0017 
0018 // TODO: add a compare API to AbstractByteArrayModel
0019 static
0020 bool isSearchDataEqual(const Okteta::AbstractByteArrayModel* byteArrayModel, Okteta::AddressRange selection,
0021                        const QByteArray& searchData)
0022 {
0023     if (searchData.size() != selection.width()) {
0024         return false;
0025     }
0026     Okteta::Address address = selection.start();
0027     for (int i = 0; i < searchData.size(); ++i, ++address) {
0028         if (byteArrayModel->byte(address) != static_cast<Okteta::Byte>(searchData.at(i))) {
0029             return false;
0030         }
0031     }
0032     return true;
0033 }
0034 
0035 bool getSearchIndexes(Okteta::Address* searchFirstIndex, Okteta::Address* searchLastIndex,
0036                       const Okteta::AbstractByteArrayModel* byteArrayModel,
0037                       Okteta::AddressRange selection,
0038                       Okteta::Address cursorPosition,
0039                       const QByteArray& searchData,
0040                       FindDirection direction,
0041                       bool fromCursor, bool inSelection)
0042 {
0043     if (inSelection) {
0044         if (!selection.isValid()) {
0045             // nothing selected, so skip any search
0046             return false;
0047         }
0048         if (searchData.size() > selection.width()) {
0049             // searched data does not even fit, so skip any search
0050             // TODO: catch in dialog already
0051             return false ;
0052         }
0053 
0054         *searchFirstIndex = selection.start();
0055         *searchLastIndex =  selection.end();
0056     } else {
0057         if (searchData.size() > byteArrayModel->size()) {
0058             // searched data does not even fit, so skip any search
0059             // also handles case of empty bytearray
0060             // TODO: catch in dialog already
0061             return false;
0062         }
0063 
0064         if (fromCursor) {
0065             // assuming that selection is coupled with cursor
0066             if (selection.isValid()) {
0067                 // skip current selection if matching
0068                 if (isSearchDataEqual(byteArrayModel, selection, searchData)) {
0069                     if (direction == FindForward) {
0070                         *searchFirstIndex = selection.nextBehindEnd();
0071                         *searchLastIndex = selection.end();
0072                     } else {
0073                         *searchLastIndex = selection.start() - 1;
0074                         *searchFirstIndex = selection.start();
0075                     }
0076                 } else {
0077                     // treating selection as extended cursor
0078                     if (direction == FindForward) {
0079                         *searchFirstIndex = selection.start();
0080                         // no wrap needed when starting at 0
0081                         *searchLastIndex = (selection.start() == 0) ? byteArrayModel->size() - 1 : selection.start() - 1;
0082                     } else {
0083                         *searchLastIndex = selection.end();
0084                         // no wrap needed when starting at end
0085                         *searchFirstIndex = (selection.end() == byteArrayModel->size() - 1) ? 0 : selection.nextBehindEnd();
0086                     }
0087                 }
0088             } else {
0089                 if (direction == FindForward) {
0090                     *searchFirstIndex = cursorPosition;
0091                     // no wrap needed when starting at 0
0092                     *searchLastIndex = (*searchFirstIndex == 0) ? byteArrayModel->size() - 1 : *searchFirstIndex - 1;
0093                 } else {
0094                     *searchLastIndex = cursorPosition - 1;
0095                     // no wrap needed when starting at end
0096                     *searchFirstIndex = (*searchLastIndex == byteArrayModel->size() - 1) ? 0 : *searchLastIndex + 1;
0097                 }
0098             }
0099         } else {
0100             *searchFirstIndex = 0;
0101             *searchLastIndex = byteArrayModel->size() - 1;
0102         }
0103     }
0104 
0105     return true;
0106 }
0107 
0108 }
0109 
0110 }