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 #ifndef OKTETA_ABSTRACTBYTEARRAYMODEL_HPP
0010 #define OKTETA_ABSTRACTBYTEARRAYMODEL_HPP
0011 
0012 // lib
0013 #include "oktetacore_export.hpp"
0014 #include "addressrange.hpp"
0015 #include "size.hpp"
0016 #include "byte.hpp"
0017 // Qt
0018 #include <QObject>
0019 #include <QByteArray>
0020 // Std
0021 #include <memory>
0022 
0023 namespace Okteta {
0024 
0025 class ArrayChangeMetricsList;
0026 class CharCodec;
0027 class AbstractByteArrayModelPrivate;
0028 
0029 /** could it be useful to hide the data access behind an iterator? *
0030 class KDataBufferIterator
0031 {
0032 public:
0033     bool hasNext();
0034     char next();
0035 protected:
0036 
0037 protected:
0038     char *
0039     int Length;
0040 }
0041 
0042 bool KDataBufferIterator::hasNext()
0043 {
0044 }
0045 // this function should be simple as possible
0046 char KDataBufferIterator::next()
0047 {
0048    // if next span is empty
0049    if(  )
0050         return *NextChar++;
0051 }
0052  */
0053 
0054 /** base class for all Data buffers that are used to display
0055  * TODO: think about a way to inform KHexEdit that there has been
0056  * a change in the buffer outside. what kind of changes are possible?
0057  *
0058  * Operations on the data:
0059  *
0060  * Finding: is implemented stateless. FindNext has to be done by perhaps a FindManager
0061  * Replacing: not available. Implement within a ReplaceManager
0062  *
0063  * @author Friedrich W. H. Kossebau
0064  */
0065 
0066 class OKTETACORE_EXPORT AbstractByteArrayModel : public QObject
0067 {
0068     friend class KAbstractByteArrayModelIterator;
0069 
0070     Q_OBJECT
0071 
0072 protected:
0073     OKTETACORE_NO_EXPORT explicit AbstractByteArrayModel(AbstractByteArrayModelPrivate* d, QObject* parent = nullptr);
0074     explicit AbstractByteArrayModel(QObject* parent = nullptr);
0075 
0076 public:
0077     ~AbstractByteArrayModel() override;
0078 
0079 public: // data access API
0080     /** locates working range
0081      * The idea behind is to tell buffer which range will be requested in the following time,
0082      * so that e.g. the corresponding pages will be loaded in advance
0083      * TODO: do we really need this? Where will this lead to real enhancements?
0084      * @param Range
0085      * @return @c true if successfully, @c false otherwise
0086      */
0087     // virtual bool prepareRange( const Section &Range ) const = 0;
0088     /** convenience function, same as above */
0089     // bool prepareRange( int Offset, int Length ) const;
0090 
0091     /** creates an iterator to */
0092     // virtual KDataBufferIterator *iterator() const = 0;
0093     /** expects pointer to memory, should be in prepared range
0094      * it is only expected to be a valid pointer until any further call
0095      * to this or any modifying function
0096      * @param Section
0097      * @return pointer to
0098      */
0099     // virtual const char *dataSet( const Section &Section ) const = 0;
0100     /** convenience function, same as above */
0101     // const char *dataSet( int Offset, int Length ) const;
0102 
0103     /** requests a single byte
0104      * if the offset is not valid the behaviour is undefined
0105      * @param offset offset of the datum requested
0106      */
0107     virtual Byte byte(Address offset) const = 0;
0108 
0109     /**
0110      * @return the size of the data
0111      */
0112     virtual Size size() const = 0;
0113 
0114 public: // state read API
0115     /**
0116      * Default returns @c true.
0117      * @return @c true if the buffer can only be read, @c false if writing is allowed
0118      */
0119     virtual bool isReadOnly() const;
0120     /**
0121      * @return @c true if the buffer has been modified, @c false otherwise
0122      */
0123     virtual bool isModified() const = 0;
0124 
0125 // TODO: for data outside the model using char* and int as well as QByteArray should always work, no?
0126 
0127 public: // modification API
0128     /** inserts bytes copied from the given source at Position.
0129      * The original data beginnung at the position is moved
0130      * with the buffer enlarged as needed
0131      * If the buffer is readOnly this is a noop and returns 0.
0132      * @param offset
0133      * @param insertData data source
0134      * @param insertLength number of bytes to copy
0135      * @return length of inserted data
0136      */
0137     virtual Size insert(Address offset, const Byte* insertData, int insertLength);
0138     Size insert(Address offset, const QByteArray& insertData);
0139 
0140     /** removes beginning with position as much as possible
0141      * @param removeRange
0142      * @return length of removed data
0143      */
0144     virtual Size remove(const AddressRange& removeRange);
0145     /** convenience function, behaves as above */
0146     Size remove(Address offset, Size removeLength);
0147 
0148     /** replaces as much as possible
0149      * @param removeRange
0150      * @param insertData
0151      * @param insertLength
0152      * @return length of inserted data
0153      */
0154     virtual Size replace(const AddressRange& removeRange, const Byte* insertData, int insertLength) = 0;
0155     /** convenience function, behaves as above */
0156     Size replace(const AddressRange& removeRange, const QByteArray& insertData);
0157     /** convenience function, behaves as above */
0158     Size replace(Address offset, Size removeLength,
0159                  const Byte* insertData, Size insertLength);
0160 
0161     // todo use parameters grouped differrently?
0162     /** moves the second section before the start of the first
0163      * which is the same as moving the first behind the second.
0164      * @param firstStart position of the data where the section should be moved behind
0165      * @param secondRange data range to be moved
0166      * @return @p true if operation was successful, @p false otherwise
0167      */
0168     virtual bool swap(Address firstStart, const AddressRange& secondRange) = 0;
0169 
0170     /**
0171      * fills the buffer with the FillChar. If the buffer is to small it will be extended as much as possible.
0172      * @param fillByte byte to use
0173      * @param offset position where the filling starts
0174      * @param fillLength number of bytes to fill. If Length is -1, the buffer is filled till the end.
0175      * @return number of filled bytes
0176      */
0177     virtual Size fill(Byte fillByte, Address offset = 0, Size fillLength = -1) = 0;
0178     Size fill(Byte fillChar, const AddressRange& fillRange);
0179 
0180     /** sets a single byte
0181      * if the offset is not valid the behaviour is undefined
0182      * @param offset offset of the datum requested
0183      * @param byte new byte value
0184      */
0185     virtual void setByte(Address offset, Byte byte) = 0;
0186 
0187     /** sets the modified flag for the buffer
0188      * @param modified
0189      */
0190     virtual void setModified(bool modified) = 0;
0191 
0192     /** sets the readonly flag for the byte array if this is possible.
0193      * Default implementation does not do anything.
0194      * @param isReadOnly new state
0195      */
0196     virtual void setReadOnly(bool isReadOnly);
0197 
0198 public: // service functions
0199     /** copies the data of the section into a given array Dest. If the section extends the buffers range
0200      * the section is limited to the buffer's end. If the section is invalid the behaviour is undefined.
0201      * @param dest pointer to a char array large enough to hold the copied section
0202      * @param copyRange
0203      * @return number of copied bytes
0204      */
0205     virtual Size copyTo(Byte* dest, const AddressRange& copyRange) const;
0206     /** convenience function, behaves as above */
0207     Size copyTo(Byte* dest, Address offset, Size copyLength) const;
0208 
0209 public: // finding API
0210     /** searches beginning with byte at Pos.
0211      * @param pattern
0212      * @param patternLength length of search string
0213      * @param fromOffset the position to start the search
0214      * @param toOffset the position to end the search (-1 is to the end of the data stream)
0215      * @return index of the first or -1
0216      */
0217     virtual Address indexOf(const Byte* pattern, int patternLength, Address fromOffset = 0, Address toOffset = -1) const;
0218     Address indexOf(const QByteArray& pattern, Address fromOffset = 0, Address toOffset = -1) const;
0219     Address indexOfCaseInsensitive(const CharCodec* charCodec, const QByteArray& pattern, Address fromOffset = 0, Address toOffset = -1) const;
0220 
0221     /** searches for a given data string
0222      * The section limits the data within which the key has to be found
0223      * If the end of the section is lower than the start the search continues at the start???
0224      * @param
0225      * @param Length length of search string
0226      * @param Section section within the keydata is to be found
0227      * @return index of the first occurrence or -1
0228      */
0229 //     virtual int indexOf( const char*KeyData, int Length, const Section &Section ) const { return -1; }//= 0;
0230     /** searches backward beginning with byte at Pos.
0231      * @param pattern
0232      * @param patternLength length of search string
0233      * @param fromOffset the position to start the search. If -1 the search starts at the end.
0234      * @return index of the first  or -1
0235      */
0236     virtual Address lastIndexOf(const Byte* pattern, int patternLength, Address fromOffset = -1, Address toOffset = 0) const;
0237     Address lastIndexOf(const QByteArray& pattern, Address fromOffset = -1, Address toOffset = 0) const;
0238     Address lastIndexOfCaseInsensitive(const CharCodec* charCodec, const QByteArray& pattern, Address fromOffset = -1, Address toOffset = 0) const;
0239 
0240 /*     virtual int find( const QString &expr, bool cs, bool wo, bool forward = true, int *index = 0 ); */
0241 
0242 Q_SIGNALS:
0243     // TODO: how to deal replacing with fixed size of buffer?
0244     void contentsChanged(const Okteta::ArrayChangeMetricsList& changeList);
0245 
0246     void readOnlyChanged(bool isReadOnly);
0247     void modifiedChanged(bool isModified);
0248 
0249     // TODO: how to handle a typedef with signals
0250     void searchedBytes(Okteta::Size bytes) const;
0251 
0252 protected:
0253     const std::unique_ptr<AbstractByteArrayModelPrivate> d_ptr;
0254 
0255 private:
0256     Q_DECLARE_PRIVATE(AbstractByteArrayModel)
0257 };
0258 
0259 // TODO: find why static_cast fails
0260 inline Size AbstractByteArrayModel::insert(Address offset, const QByteArray& insertData)
0261 { return insert(offset, reinterpret_cast<const Byte*>(insertData.constData()), insertData.size()); }
0262 
0263 inline Size AbstractByteArrayModel::remove(Address offset, Size removeLength)
0264 { return remove(AddressRange::fromWidth(offset, removeLength)); }
0265 
0266 inline Size AbstractByteArrayModel::replace(const AddressRange& removeRange, const QByteArray& insertData)
0267 { return replace(removeRange, reinterpret_cast<const Byte*>(insertData.constData()), insertData.size());}
0268 
0269 inline Size AbstractByteArrayModel::replace(Address offset, Size removeLength,
0270                                             const Byte* insertData, Size insertLength)
0271 { return replace(AddressRange::fromWidth(offset, removeLength), insertData, insertLength); }
0272 
0273 inline Size AbstractByteArrayModel::fill(const Byte fillChar, const AddressRange& fillRange)
0274 { return fill(fillChar, fillRange.start(), fillRange.width()); }
0275 
0276 inline Size AbstractByteArrayModel::copyTo(Byte* dest, Address offset, Size copyLength) const
0277 { return copyTo(dest, AddressRange::fromWidth(offset, copyLength)); }
0278 
0279 inline Address AbstractByteArrayModel::indexOf(const QByteArray& pattern, Address fromOffset, Address toOffset) const
0280 { return indexOf(reinterpret_cast<const Byte*>(pattern.constData()), pattern.size(), fromOffset, toOffset); }
0281 
0282 inline Address AbstractByteArrayModel::lastIndexOf(const QByteArray& pattern, Address fromOffset, Address toOffset) const
0283 { return lastIndexOf(reinterpret_cast<const Byte*>(pattern.constData()), pattern.size(), fromOffset, toOffset); }
0284 
0285 }
0286 
0287 #endif