File indexing completed on 2024-04-14 15:52:43

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