File indexing completed on 2024-06-23 05:48:59
0001 /* 0002 This file is part of the Okteta Kasten Framework, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2009, 2010, 2011, 2012, 2013 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_DATAINFORMATION_HPP 0010 #define KASTEN_DATAINFORMATION_HPP 0011 0012 // Qt core 0013 #include <QString> 0014 #include <QPair> 0015 #include <QMetaType> 0016 0017 // Okteta 0018 #include <Okteta/Size> 0019 #include <Okteta/Address> 0020 0021 #include "datainformationbase.hpp" 0022 #include "additionaldata.hpp" 0023 #include "../script/scriptlogger.hpp" 0024 #include "primitivedatatype.hpp" 0025 0026 /** Implement the clone() method and add the copy constructor declaration 0027 * After this macro visibility will be set to protected */ 0028 #define DATAINFORMATION_CLONE_DECL(type, supertype) \ 0029 public: \ 0030 inline type* clone() const override { return new type(*this); } \ 0031 protected: \ 0032 type(const type& d) 0033 0034 /** Implements the clone() method and add the start of the copy constructor (up to delegating). 0035 * After this macro visibility will be set to protected */ 0036 #define DATAINFORMATION_CLONE(type, supertype) DATAINFORMATION_CLONE_DECL(type, supertype) : supertype(d) 0037 0038 namespace Okteta { 0039 class AbstractByteArrayModel; 0040 } 0041 0042 class QScriptEngine; 0043 class QScriptValue; 0044 class QScriptClass; 0045 class QVariant; 0046 class QWidget; 0047 class ScriptLogger; 0048 class TopLevelDataInformation; 0049 class ScriptHandlerInfo; 0050 0051 /** Interface that must be implemented by all datatypes */ 0052 class DataInformation : public DataInformationBase 0053 { 0054 friend class ScriptHandler; // so mHasBeenUpdated/hasBeenValidated can be set 0055 friend class PrimitiveDataInformationWrapper; // to set mHasBeenUpdated 0056 friend class PointerDataInformation; // to set mWasAbleToRead on pointer target 0057 friend class DefaultScriptClass; // to set mValidationSucessful and validationError 0058 template <PrimitiveDataType type> friend class PrimitiveArrayData; // to set mWasAbleToRead (when returning a script value) 0059 0060 protected: 0061 explicit DataInformation(const DataInformation&); 0062 0063 public: 0064 virtual DataInformation* clone() const = 0; 0065 explicit DataInformation(const QString& name, DataInformationBase* parent = nullptr); 0066 ~DataInformation() override; 0067 0068 enum Columns 0069 { 0070 ColumnName = 0, 0071 ColumnType, 0072 ColumnValue, 0073 ColumnSize, 0074 COLUMN_COUNT 0075 }; 0076 enum class DataInformationEndianess 0077 { 0078 EndianessFromSettings = 0, 0079 EndianessInherit, 0080 EndianessLittle, 0081 EndianessBig 0082 }; 0083 0084 // methods for children: 0085 virtual unsigned int childCount() const = 0; 0086 virtual DataInformation* childAt(unsigned int) const = 0; 0087 /** @brief Looks for a child of this object with given name 0088 * @param name The name of the child to find 0089 * @return the child with given @p name or @c NULL if none found with that name 0090 */ 0091 virtual DataInformation* child(const QString& name) const; 0092 /** 0093 * @param start the starting address of the whole structure 0094 * @return the position in the file where this element is located 0095 */ 0096 virtual BitCount64 positionInFile(Okteta::Address start) const; 0097 /** 0098 * @param child the direct child we want to find the address for 0099 * @param start the start of the root element 0100 * @return the address of @p child in the file 0101 */ 0102 virtual BitCount64 childPosition(const DataInformation* child, Okteta::Address start) const = 0; 0103 0104 // for the model: 0105 virtual Qt::ItemFlags flags(int column, bool fileLoaded = true) const; 0106 int row() const; 0107 /** get the necessary data (for the model) */ 0108 virtual QVariant data(int column, int role) const; 0109 0110 QString typeName() const; 0111 /** by default just returns an empty QString */ 0112 QString valueString() const; 0113 QString name() const; 0114 void setName(const QString& newName); 0115 virtual QString tooltipString() const; 0116 /** needs to be virtual for bitfields */ 0117 virtual QString sizeString() const; 0118 0119 // delegate functions: 0120 /** create a QWidget for the QItemDelegate */ 0121 virtual QWidget* createEditWidget(QWidget* parent) const = 0; 0122 /** get the needed data from the widget */ 0123 virtual QVariant dataFromWidget(const QWidget* w) const = 0; 0124 /** initialize the delegate widget with the correct data */ 0125 virtual void setWidgetData(QWidget* w) const = 0; 0126 0127 // reading and writing 0128 /** the size in bits of this element */ 0129 virtual BitCount32 size() const = 0; 0130 0131 /** Reads the necessary data from @p input and returns the number of bytes read 0132 * 0133 * @param input the byte array to read from 0134 * @param address the starting offset to read from 0135 * @param bitsRemaining the number of bits remaining in @p out 0136 * @param bitOffset the bits that have already been read from the current byte 0137 * (should be modified in this method) 0138 * 0139 * @return the number of bits read or @c -1 if none were read 0140 */ 0141 virtual qint64 readData(const Okteta::AbstractByteArrayModel* input, Okteta::Address address, 0142 BitCount64 bitsRemaining, quint8* bitOffset) = 0; 0143 /** sets mWasAbleToRead to false for all children and this object. 0144 * Gets called once before the reading of the whole structure starts. */ 0145 void beginRead(); 0146 /** Writes the current data contained in this object to out. 0147 * 0148 * @param value a QVariant object holding the new data to write 0149 * @param out the byte array the value is written to 0150 * @param address the address in @p out 0151 * @param bitsRemaining number of bits remaining in @p out 0152 * @param bitOffset the bit to start at in the first byte 0153 * 0154 * @return @c true on success, @c false otherwise 0155 */ 0156 virtual bool setData(const QVariant& value, Okteta::AbstractByteArrayModel* out, 0157 Okteta::Address address, BitCount64 bitsRemaining, quint8 bitOffset) = 0; 0158 0159 bool isTopLevel() const override; 0160 TopLevelDataInformation* topLevelDataInformation() const; 0161 DataInformation* mainStructure(); 0162 0163 QScriptValue updateFunc() const; 0164 void setUpdateFunc(const QScriptValue& func); 0165 QScriptValue validationFunc() const; 0166 void setValidationFunc(const QScriptValue& func); 0167 QString validationError() const; 0168 bool validationSuccessful() const; 0169 0170 bool hasBeenUpdated() const; 0171 bool hasBeenValidated() const; 0172 DataInformationEndianess byteOrder() const; 0173 QSysInfo::Endian effectiveByteOrder() const; 0174 void setByteOrder(DataInformationEndianess newByteOrder); 0175 QString fullObjectPath() const; 0176 0177 virtual void resetValidationState(); // virtual for DataInformationWithChildren 0178 bool wasAbleToRead() const; 0179 /** 0180 * This method is virtual since DummyDataInformation has to override it. 0181 * 0182 * @param engine the script engine 0183 * @param handlerInfo the object holding the script classes 0184 * @return a QScriptValue wrapping this object 0185 */ 0186 virtual QScriptValue toScriptValue(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo); 0187 /** the same as above, just using the properties from TopLevelDataInformation */ 0188 QScriptValue toScriptValue(TopLevelDataInformation* top); 0189 void setParent(DataInformationBase* newParent); 0190 DataInformationBase* parent() const; 0191 ScriptLogger* logger() const; 0192 /** just a shorthand for logger->info(this) */ 0193 QDebug logInfo() const; 0194 /** just a shorthand for logger->warn(this) */ 0195 QDebug logWarn() const; 0196 /** just a shorthand for logger->error(this) */ 0197 QDebug logError() const; 0198 /** whether data was logged from here (and which level it was) 0199 * @return ScriptLogger::LogInvalid if no data was logged or the level of the most severe log 0200 */ 0201 ScriptLogger::LogLevel loggedData() const; 0202 void setLoggedData(ScriptLogger::LogLevel lvl) const; 0203 0204 /** 0205 * Find the index of a DataInformation in this object, needed to calculate the row 0206 * @return the index of @p data or -1 if not found 0207 */ 0208 virtual int indexOf(const DataInformation* const data) const = 0; 0209 /** Set a custom string to be used for typeName() instead of the default. 0210 * @param customTypeName the new name. Pass an empty or null string to revert to default behaviour 0211 */ 0212 void setCustomTypeName(const QString& customTypeName); 0213 QScriptValue toStringFunction() const; 0214 void setToStringFunction(const QScriptValue& func); 0215 0216 protected: 0217 static QString sizeString(BitCount32 size); 0218 static QString tooltipString(const QString& nameString, const QString& valueString, 0219 const QString& typeString, const QString& sizeString, 0220 unsigned int childCount = 0, 0221 const QString& validationMessage = QString()); 0222 static QVariant eofReachedData(int role); 0223 void setAdditionalFunction(AdditionalData::AdditionalDataType entry, const QScriptValue& value, const char* name); 0224 0225 private: 0226 virtual QString valueStringImpl() const; 0227 virtual QString typeNameImpl() const = 0; 0228 /** So that this object can be wrapped by the correct javascript object*/ 0229 virtual QScriptClass* scriptClass(ScriptHandlerInfo* handlerInfo) const = 0; 0230 0231 private: 0232 void setValidationError(const QString& errorMessage); // only called by ScriptHandler 0233 QSysInfo::Endian byteOrderFromSettings() const; // so there is no need to include structureviewpreferences.hpp here 0234 QString customToString(const QScriptValue& func) const; 0235 0236 protected: 0237 AdditionalData mAdditionalData; 0238 DataInformationBase* mParent; 0239 QString mName; 0240 bool mValidationSuccessful : 1; 0241 bool mHasBeenValidated : 1; 0242 bool mHasBeenUpdated : 1; 0243 bool mWasAbleToRead : 1; 0244 bool mWasAbleToReadBefore : 1; 0245 DataInformationEndianess mByteOrder = DataInformationEndianess::EndianessInherit; 0246 mutable ScriptLogger::LogLevel mLoggedData : 2; // mutable is ugly but i guess it is the best solution 0247 }; 0248 0249 Q_DECLARE_METATYPE(DataInformation*) 0250 Q_DECLARE_METATYPE(const DataInformation*) 0251 0252 inline Qt::ItemFlags DataInformation::flags(int column, bool fileLoaded) const 0253 { 0254 Q_UNUSED(column) 0255 Q_UNUSED(fileLoaded); 0256 return Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0257 } 0258 0259 inline QString DataInformation::name() const 0260 { 0261 return mName; 0262 } 0263 0264 inline void DataInformation::setName(const QString& newName) 0265 { 0266 mName = newName; 0267 } 0268 0269 inline DataInformation* DataInformation::childAt(unsigned int) const 0270 { 0271 return nullptr; 0272 } 0273 0274 inline unsigned int DataInformation::childCount() const 0275 { 0276 return 0; 0277 } 0278 0279 inline bool DataInformation::wasAbleToRead() const 0280 { 0281 return mWasAbleToRead; 0282 } 0283 0284 inline DataInformation::DataInformationEndianess DataInformation::byteOrder() const 0285 { 0286 return mByteOrder; 0287 } 0288 0289 inline void DataInformation::setByteOrder(DataInformation::DataInformationEndianess newByteOrder) 0290 { 0291 mByteOrder = newByteOrder; 0292 } 0293 0294 inline bool DataInformation::isTopLevel() const 0295 { 0296 return false; 0297 } 0298 0299 inline void DataInformation::setParent(DataInformationBase* newParent) 0300 { 0301 Q_CHECK_PTR(newParent); 0302 mParent = newParent; 0303 } 0304 0305 inline DataInformationBase* DataInformation::parent() const 0306 { 0307 return mParent; 0308 } 0309 0310 inline QDebug DataInformation::logInfo() const 0311 { 0312 return logger()->info(this); 0313 } 0314 0315 inline QDebug DataInformation::logWarn() const 0316 { 0317 return logger()->warn(this); 0318 } 0319 0320 inline QDebug DataInformation::logError() const 0321 { 0322 return logger()->error(this); 0323 } 0324 0325 inline ScriptLogger::LogLevel DataInformation::loggedData() const 0326 { 0327 return mLoggedData; 0328 } 0329 0330 inline void DataInformation::setLoggedData(ScriptLogger::LogLevel lvl) const 0331 { 0332 mLoggedData = lvl; 0333 } 0334 0335 inline bool DataInformation::hasBeenUpdated() const 0336 { 0337 return mHasBeenUpdated; 0338 } 0339 0340 inline bool DataInformation::validationSuccessful() const 0341 { 0342 return mValidationSuccessful; 0343 } 0344 0345 inline bool DataInformation::hasBeenValidated() const 0346 { 0347 return mHasBeenValidated; 0348 } 0349 0350 inline QScriptValue DataInformation::updateFunc() const 0351 { 0352 return mAdditionalData.get(AdditionalData::AdditionalDataType::UpdateFunction).value<QScriptValue>(); 0353 } 0354 0355 inline QScriptValue DataInformation::validationFunc() const 0356 { 0357 return mAdditionalData.get(AdditionalData::AdditionalDataType::ValidationFunction).value<QScriptValue>(); 0358 } 0359 0360 inline QScriptValue DataInformation::toStringFunction() const 0361 { 0362 return mAdditionalData.get(AdditionalData::AdditionalDataType::ToStringFunction).value<QScriptValue>(); 0363 } 0364 0365 inline void DataInformation::setUpdateFunc(const QScriptValue& func) 0366 { 0367 setAdditionalFunction(AdditionalData::AdditionalDataType::UpdateFunction, func, "update function"); 0368 } 0369 0370 inline void DataInformation::setValidationFunc(const QScriptValue& func) 0371 { 0372 setAdditionalFunction(AdditionalData::AdditionalDataType::ValidationFunction, func, "validation function"); 0373 } 0374 0375 inline void DataInformation::setToStringFunction(const QScriptValue& func) 0376 { 0377 setAdditionalFunction(AdditionalData::AdditionalDataType::ToStringFunction, func, "to string function"); 0378 } 0379 0380 inline QString DataInformation::validationError() const 0381 { 0382 return mAdditionalData.get(AdditionalData::AdditionalDataType::ValidationError).toString(); 0383 } 0384 0385 inline QSysInfo::Endian DataInformation::effectiveByteOrder() const 0386 { 0387 switch (mByteOrder) 0388 { 0389 case DataInformationEndianess::EndianessBig: 0390 return QSysInfo::BigEndian; 0391 case DataInformationEndianess::EndianessLittle: 0392 return QSysInfo::LittleEndian; 0393 case DataInformationEndianess::EndianessFromSettings: 0394 return byteOrderFromSettings(); 0395 default: // inherit 0396 if (mParent && !mParent->isTopLevel()) { 0397 return mParent->asDataInformation()->effectiveByteOrder(); 0398 } 0399 return byteOrderFromSettings(); 0400 } 0401 } 0402 0403 inline QString DataInformation::typeName() const 0404 { 0405 QVariant v = mAdditionalData.get(AdditionalData::AdditionalDataType::CustomTypeName); 0406 if (Q_UNLIKELY(v.isValid())) { // custom type names will be used rarely 0407 return v.toString(); 0408 } 0409 return typeNameImpl(); 0410 } 0411 0412 inline QString DataInformation::valueString() const 0413 { 0414 QVariant v = mAdditionalData.get(AdditionalData::AdditionalDataType::ToStringFunction); 0415 if (Q_UNLIKELY(v.isValid())) { // custom to string functions will be used rarely 0416 return customToString(v.value<QScriptValue>()); 0417 } 0418 return valueStringImpl(); 0419 } 0420 0421 #endif /* KASTEN_DATAINFORMATION_HPP */