File indexing completed on 2024-06-23 05:49:00
0001 /* 0002 This file is part of the Okteta Kasten Framework, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2010, 2011 Alex Richardson <alex.richardson@gmx.de> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #ifndef KASTEN_TOPLEVELDATAINFORMATION_HPP 0010 #define KASTEN_TOPLEVELDATAINFORMATION_HPP 0011 0012 #include "datainformationbase.hpp" 0013 #include "../script/scripthandler.hpp" 0014 #include <Okteta/ArrayChangeMetricsList> 0015 // Qt 0016 #include <QHash> 0017 #include <QFileInfo> 0018 #include <QSharedPointer> 0019 #include <QQueue> 0020 // Std 0021 #include <memory> 0022 0023 namespace Okteta { 0024 class AbstractByteArrayModel; 0025 } // namespace Okteta 0026 0027 class ScriptLogger; 0028 class ScriptHandlerInfo; 0029 class QScriptEngine; 0030 class ScriptHandler; 0031 class DataInformation; 0032 class PointerDataInformation; 0033 0034 class TopLevelDataInformation : public QObject 0035 , public DataInformationBase 0036 { 0037 Q_OBJECT 0038 0039 public: 0040 /** create a new TopLevelDataInformation wrapping @p data 0041 * @param data the object to wrap (takes ownership). If data is dummy then this object is invalid 0042 * @param logger the logger to use (takes ownership). If null a new one is created 0043 * @param engine the script engine to use. If null this object contains no dynamic elements 0044 * @param structureFile the file which this was loaded from 0045 */ 0046 explicit TopLevelDataInformation(DataInformation* data, ScriptLogger* logger = nullptr, 0047 QScriptEngine* engine = nullptr, const QFileInfo& structureFile = QFileInfo()); 0048 ~TopLevelDataInformation() override; 0049 0050 using Ptr = QSharedPointer<TopLevelDataInformation>; 0051 using List = QVector<Ptr>; 0052 static const Okteta::Address INVALID_OFFSET; 0053 0054 public: 0055 void validate(); 0056 /** Reads the necessary data from @p input 0057 * 0058 * @param input the byte array to read from 0059 * @param address the starting offset to read from (will be ignored if the offset is locked) 0060 * @param changesList the list with changes to @p input, so that it is possible to check whether reading is necessary 0061 * This parameter is only useful if the structure was locked to a specific position. 0062 * @param forceRead whether to always read data, ignoring the change list 0063 */ 0064 void read(const Okteta::AbstractByteArrayModel* input, Okteta::Address address, 0065 const Okteta::ArrayChangeMetricsList& changesList, bool forceRead); 0066 QScriptEngine* scriptEngine() const; 0067 0068 DataInformation* actualDataInformation() const; 0069 void setActualDataInformation(DataInformation* newData); 0070 bool isValid() const; 0071 void lockPositionToOffset(Okteta::Address offset, const Okteta::AbstractByteArrayModel* model); 0072 void unlockPosition(const Okteta::AbstractByteArrayModel* model); 0073 bool isLockedFor(const Okteta::AbstractByteArrayModel* model) const; 0074 Okteta::Address lockPositionFor(const Okteta::AbstractByteArrayModel* model) const; 0075 bool isLockedByDefault() const; 0076 void setDefaultLockOffset(Okteta::Address offset); 0077 int indexOf(const DataInformation* const data) const; 0078 int index() const; 0079 void setIndex(int newIndex); 0080 ScriptHandler* scriptHandler() const; 0081 ScriptLogger* logger() const; 0082 void setChildDataChanged(); 0083 void enqueueReadData(PointerDataInformation* toRead); 0084 0085 bool isTopLevel() const override; 0086 0087 // only public so that DataInformation and subclasses can call them (TODO move) 0088 void _childCountAboutToChange(DataInformation* sender, uint oldCount, uint newCount); 0089 void _childCountChanged(DataInformation* sender, uint oldCount, uint newCount); 0090 0091 private: 0092 bool isReadingNecessary(const Okteta::AbstractByteArrayModel* model, Okteta::Address address, 0093 const Okteta::ArrayChangeMetricsList& changesList); 0094 0095 public Q_SLOTS: 0096 void resetValidationState(); 0097 void newModelActivated(Okteta::AbstractByteArrayModel* model); 0098 0099 private Q_SLOTS: 0100 void removeByteArrayModelFromList(QObject* obj); 0101 Q_SIGNALS: 0102 void dataChanged(); 0103 /** items are inserted before @p startIndex */ 0104 void childrenAboutToBeInserted(DataInformation* sender, uint startIndex, uint endIndex); 0105 /** items are inserted before @p startIndex */ 0106 void childrenInserted(const DataInformation* sender, uint startIndex, uint endIndex); 0107 /** items are removed before @p startIndex */ 0108 void childrenAboutToBeRemoved(DataInformation* sender, uint startIndex, uint endIndex); 0109 /** items are inserted before @p startIndex */ 0110 void childrenRemoved(const DataInformation* sender, uint startIndex, uint endIndex); 0111 0112 private: 0113 std::unique_ptr<DataInformation> mData; 0114 std::unique_ptr<ScriptHandler> mScriptHandler; 0115 std::unique_ptr<ScriptLogger> mLogger; 0116 QFileInfo mStructureFile; 0117 /** Save the position this structure is locked to for each ByteArrayModel 0118 * QObject::destroyed() has to be connected to slot removeByteArrayModel() 0119 * so that no dangling pointers remain 0120 */ 0121 QHash<const Okteta::AbstractByteArrayModel*, Okteta::Address> mLockedPositions; 0122 int mIndex = -1; 0123 bool mValid : 1; 0124 bool mChildDataChanged : 1; 0125 Okteta::Address mDefaultLockOffset = INVALID_OFFSET; 0126 Okteta::Address mLastReadOffset = INVALID_OFFSET; 0127 const Okteta::AbstractByteArrayModel* mLastModel = nullptr; 0128 QQueue<PointerDataInformation*> mDelayedRead; 0129 0130 friend class LockToOffsetTest; // needs to call isReadingNecessary() 0131 }; 0132 0133 inline DataInformation* TopLevelDataInformation::actualDataInformation() const 0134 { 0135 return mData.get(); 0136 } 0137 0138 inline bool TopLevelDataInformation::isValid() const 0139 { 0140 return mValid; 0141 } 0142 0143 inline int TopLevelDataInformation::index() const 0144 { 0145 return mIndex; 0146 } 0147 0148 inline void TopLevelDataInformation::setIndex(int newIndex) 0149 { 0150 mIndex = newIndex; 0151 } 0152 0153 inline void TopLevelDataInformation::setChildDataChanged() 0154 { 0155 mChildDataChanged = true; 0156 } 0157 0158 inline ScriptLogger* TopLevelDataInformation::logger() const 0159 { 0160 return mLogger.get(); 0161 } 0162 0163 inline ScriptHandler* TopLevelDataInformation::scriptHandler() const 0164 { 0165 return mScriptHandler.get(); 0166 } 0167 0168 inline void TopLevelDataInformation::_childCountAboutToChange(DataInformation* sender, uint oldCount, uint newCount) 0169 { 0170 if (newCount < oldCount) { // newCount is smaller so oldCount is at least 1 -> no underflow 0171 Q_EMIT childrenAboutToBeRemoved(sender, newCount, oldCount - 1); 0172 } else if (newCount > oldCount) { // newCount is larger so it is at least 1 -> no underflow 0173 Q_EMIT childrenAboutToBeInserted(sender, oldCount, newCount - 1); 0174 } 0175 } 0176 0177 inline void TopLevelDataInformation::_childCountChanged(DataInformation* sender, uint oldCount, uint newCount) 0178 { 0179 if (newCount < oldCount) { // newCount is smaller so oldCount is at least 1 -> no underflow 0180 Q_EMIT childrenRemoved(sender, newCount, oldCount - 1); 0181 } else if (newCount > oldCount) { // newCount is larger so it is at least 1 -> no underflow 0182 Q_EMIT childrenInserted(sender, oldCount, newCount - 1); 0183 } 0184 } 0185 0186 #endif /* KASTEN_TOPLEVELDATAINFORMATION_HPP */