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 */