diff --git a/kasten/controllers/view/charsetconversion/charsetconversionview.cpp b/kasten/controllers/view/charsetconversion/charsetconversionview.cpp index c0856037..4c4bc862 100644 --- a/kasten/controllers/view/charsetconversion/charsetconversionview.cpp +++ b/kasten/controllers/view/charsetconversion/charsetconversionview.cpp @@ -1,242 +1,242 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2011 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "charsetconversionview.h" // tool #include "charsetconversiontool.h" // Okteta Kasten gui #include // Okteta core #include // KF5 #include #include #include #include // Qt #include #include #include #include #include #include namespace Kasten { CharsetConversionView::CharsetConversionView( CharsetConversionTool* tool, QWidget* parent ) : QWidget( parent ), mTool( tool ) { QVBoxLayout* baseLayout = new QVBoxLayout( this ); baseLayout->setMargin( 0 ); // source/target charset QHBoxLayout* directionCharsetLayout = new QHBoxLayout(); mDirectionComboBox = new KComboBox( this ); const QStringList directionList = QStringList() << i18nc("@item:inmenu Is converted _from_ charset (selected in combobox next to this)", "From") << i18nc("@item:inmenu Is converted _to_ charset (selected in combobox next to this)", "To"); mDirectionComboBox->addItems( directionList ); mDirectionComboBox->setCurrentIndex( mTool->conversionDirection() ); const QString directionToolTip = i18nc( "@info:tooltip", "The direction the bytes are converted, to or from the selected charset." ); mDirectionComboBox->setToolTip( directionToolTip ); const QString directionWhatsThis = i18nc( "@info:whatsthis", "Select the direction the bytes are converted, to or from the selected charset." ); mDirectionComboBox->setWhatsThis( directionWhatsThis ); connect( mDirectionComboBox, static_cast(&KComboBox::activated), mTool, &CharsetConversionTool::setConversionDirection ); directionCharsetLayout->addWidget( mDirectionComboBox ); mOtherCharSetComboBox = new KComboBox( this ); const QStringList charCodecNames = Okteta::CharCodec::codecNames(); const int indexOfCurrentCharCodec = charCodecNames.indexOf( mTool->otherCharCodecName() ); mOtherCharSetComboBox->addItems( charCodecNames ); mOtherCharSetComboBox->setCurrentIndex( indexOfCurrentCharCodec ); const QString targetCharsetToolTip = i18nc( "@info:tooltip", "The charset the bytes are converted to." ); mOtherCharSetComboBox->setToolTip( targetCharsetToolTip ); const QString targetCharsetWhatsThis = i18nc( "@info:whatsthis", "Select the charset the bytes are converted to." ); mOtherCharSetComboBox->setWhatsThis( targetCharsetWhatsThis ); connect( mOtherCharSetComboBox, static_cast(&KComboBox::activated), mTool, &CharsetConversionTool::setOtherCharCodecName ); directionCharsetLayout->addWidget( mOtherCharSetComboBox, 10 ); baseLayout->addLayout( directionCharsetLayout ); // settings QGroupBox* settingsBox = new QGroupBox( i18nc("@title:group","Parameters"), this ); QFormLayout* settingsLayout = new QFormLayout(); const QString substituteMissingCharLabelText = i18nc( "@option:check substitute bytes whose char is not part of the target charset", "Substitute missing:" ); mSubstituteMissingCharCheckBox = new QCheckBox( this ); mSubstituteMissingCharCheckBox->setChecked( mTool->isSubstitutingMissingChars() ); const QString substituteMissingCharToolTip = i18nc( "@info:tooltip", "Selects if bytes should be substituted with a default byte " "if its char in the source charset is not part of the target charset." ); const QString substituteMissingCharWhatsThis = i18nc( "@info:whatsthis", "Set to true if bytes should be substituted with a default byte " "if its char in the source charset is not part of the target charset." ); mSubstituteMissingCharCheckBox->setToolTip( substituteMissingCharToolTip ); mSubstituteMissingCharCheckBox->setWhatsThis( substituteMissingCharWhatsThis ); connect( mSubstituteMissingCharCheckBox, &QCheckBox::toggled, mTool, &CharsetConversionTool::setSubstitutingMissingChars ); settingsLayout->addRow( substituteMissingCharLabelText, mSubstituteMissingCharCheckBox ); // TODO: control what happens on conflicts or unmatched chars in the target set // option to try only if no conflicts or unmatched chars are hit // choosing substitute for unmatched and resolve conflicts (general/case-by-case) // TODO: extra button to request check if all chars are matched, shows state // TODO: option to switch view to target charset, once done, if "to" other charset // default byte const QString substituteByteLabelText = i18nc( "@label:textbox byte to use for chars which are not part of the target charset", "Substitute byte:" ); mSubstituteByteEdit = new Okteta::ByteArrayComboBox( this ); mSubstituteByteEdit->setMinLength( 1 ); mSubstituteByteEdit->setMaxLength( 1 ); const QString substituteByteToolTip = i18nc( "@info:tooltip", "The byte to use for chars which are not part of the target charset." ); const QString substituteByteWhatsThis = i18nc( "@info:whatsthis", "Define the byte to use for chars which are not part of the target charset." ); mSubstituteByteEdit->setToolTip( substituteByteToolTip ); mSubstituteByteEdit->setWhatsThis( substituteByteWhatsThis ); // mSubstituteByteEdit->setEnabled( mTool->isSubstitutingMissingChars() ); mSubstituteByteEdit->setEnabled( false ); // TODO: fix char entering and enable again connect( mSubstituteByteEdit, &Okteta::ByteArrayComboBox::byteArrayChanged, this, &CharsetConversionView::onDefaultByteEditChanged ); // connect( mSubstituteMissingCharCheckBox, SIGNAL(toggled(bool)), // mSubstituteByteEdit, SLOT(setEnabled(bool)) ); mSubstituteByteEdit->setByteArray( QByteArray(1, mTool->substituteByte()) ); settingsLayout->addRow( substituteByteLabelText, mSubstituteByteEdit ); settingsBox->setLayout( settingsLayout ); baseLayout->addWidget( settingsBox ); // action QHBoxLayout* actionsLayout = new QHBoxLayout(); actionsLayout->addStretch(); const KGuiItem convertGuiItem = KGuiItem( i18n("Con&vert"), QStringLiteral("run-build"), i18nc("@info:tooltip", "Converts the bytes in the selected range."), xi18nc("@info:whatsthis", "If you press the Convert button, " "all bytes in the selected range " "will be replaced by bytes which represent the same character " "in the selected target charset.") ); mConvertButton = new QPushButton( this ); KGuiItem::assign( mConvertButton, convertGuiItem ); connect( mConvertButton, &QPushButton::clicked, this, &CharsetConversionView::onConvertButtonClicked ); actionsLayout->addWidget( mConvertButton ); baseLayout->addLayout( actionsLayout ); baseLayout->addStretch(); connect( mTool, &CharsetConversionTool::isApplyableChanged, this, &CharsetConversionView::onApplyableChanged ); connect( mTool, &CharsetConversionTool::conversionDone, this, &CharsetConversionView::onConversionDone ); } void CharsetConversionView::onApplyableChanged( bool isApplyable ) { mConvertButton->setEnabled( isApplyable ); } void CharsetConversionView::onDefaultByteEditChanged( const QByteArray& byteArray ) { Q_UNUSED( byteArray ); } void CharsetConversionView::onConvertButtonClicked() { mTool->convertChars(); } void CharsetConversionView::onConversionDone( bool success, int convertedBytesCount, const QMap& failedPerByteCount ) { const QString messageBoxTitle = mTool->title(); if( success ) { QString conversionReport = (convertedBytesCount==0) ? i18nc( "@info", "No bytes converted.") : i18ncp( "@info", "1 byte converted.", "%1 bytes converted.", convertedBytesCount ); if( mTool->isSubstitutingMissingChars() ) { int totalFailedByteCount = 0; foreach( int failedByteCount, failedPerByteCount ) totalFailedByteCount += failedByteCount; //TODO: show table with failed bytes and their number. - conversionReport += QStringLiteral( "
" ); + conversionReport += QLatin1String( "
" ); conversionReport += (totalFailedByteCount==0) ? i18nc( "@info", "No bytes substituted.") : i18ncp( "@info", "1 byte substituted.", "%1 bytes substituted.", totalFailedByteCount ); } KMessageBox::information( /*mParentWidget*/0, conversionReport, messageBoxTitle ); } else { // TODO: show/goto byte which on which conversion fails KMessageBox::sorry( /*mParentWidget*/0, i18nc("@info", "Conversion cancelled because of chars which are not " "in the target charset."), messageBoxTitle ); } } CharsetConversionView::~CharsetConversionView() {} } diff --git a/kasten/controllers/view/poddecoder/typeeditors/sintspinbox.cpp b/kasten/controllers/view/poddecoder/typeeditors/sintspinbox.cpp index 6c34d6ca..a4555c36 100644 --- a/kasten/controllers/view/poddecoder/typeeditors/sintspinbox.cpp +++ b/kasten/controllers/view/poddecoder/typeeditors/sintspinbox.cpp @@ -1,103 +1,103 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2009 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "sintspinbox.h" // Qt #include QValidator::State SIntSpinBox::validate( QString& input, int& pos ) const { Q_UNUSED( pos ); QValidator::State result; if( input.isEmpty() - || (mMinimum < 0 && input == QStringLiteral("-")) ) + || (mMinimum < 0 && input == QLatin1String("-")) ) { mValue = 0; result = QValidator::Intermediate; } else { bool ok; qint64 newValue = input.toLongLong( &ok ); if( !ok || (newValue > mMaximum) || (newValue < mMinimum) ) result = QValidator::Invalid; else { mValue = newValue; result = QValidator::Acceptable; } } return result; } void SIntSpinBox::fixup( QString& input ) const { Q_UNUSED( input ); // TODO: what can be done here? remove localized stuff? } void SIntSpinBox::stepBy( int steps ) { if( steps == 0 ) return; if( steps > 0 ) { const qint64 left = mMaximum - mValue; mValue = ( static_cast(steps) > left ) ? mMaximum : mValue + steps; } else { const qint64 left = mValue - mMinimum; mValue = ( static_cast(-steps) > left ) ? mMinimum : mValue + steps; } updateEditLine(); } QAbstractSpinBox::StepEnabled SIntSpinBox::stepEnabled() const { StepEnabled result; if( mValue > mMinimum ) result |= StepDownEnabled; if( mValue < mMaximum ) result |= StepUpEnabled; return result; } void SIntSpinBox::updateEditLine() const { const QString text = QString::number( mValue, mBase ); lineEdit()->setText( text ); } diff --git a/kasten/controllers/view/replace/replacecontroller.cpp b/kasten/controllers/view/replace/replacecontroller.cpp index a525387a..4bcfebed 100644 --- a/kasten/controllers/view/replace/replacecontroller.cpp +++ b/kasten/controllers/view/replace/replacecontroller.cpp @@ -1,134 +1,134 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2006-2009 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "replacecontroller.h" // controller #include "kreplacedialog.h" #include "kreplaceprompt.h" #include "replacetool.h" // KF5 #include #include #include #include #include // Qt #include namespace Kasten { // TODO: for docked widgets signal widgets if embedded or floating, if horizontal/vertical ReplaceController::ReplaceController( KXMLGUIClient* guiClient, QWidget* parentWidget ) : mParentWidget( parentWidget ), mReplaceDialog( 0 ), mReplacePrompt( 0 ) { KActionCollection* ActionCollection = guiClient->actionCollection(); mReplaceAction = KStandardAction::replace( this, SLOT(replace()), ActionCollection ); mTool = new ReplaceTool(); mTool->setUserQueryAgent( this ); connect( mTool, &ReplaceTool::isApplyableChanged, mReplaceAction, &QAction::setEnabled ); connect( mTool, &ReplaceTool::finished, this, &ReplaceController::onFinished ); mReplaceAction->setEnabled( false ); } void ReplaceController::setTargetModel( AbstractModel* model ) { mTool->setTargetModel( model ); } void ReplaceController::replace() { // ensure dialog if( !mReplaceDialog ) mReplaceDialog = new KReplaceDialog( mTool, mParentWidget ); mReplaceDialog->show(); } void ReplaceController::onFinished( bool previousFound, int noOfReplacements ) { if( mReplacePrompt ) mReplacePrompt->hide(); const QString messageBoxTitle = i18nc( "@title:window", "Replace" ); const QString replacementReport = (noOfReplacements==0) ? i18nc( "@info", "No replacements made.") : i18ncp( "@info", "1 replacement made.", "%1 replacements made.", noOfReplacements ); if( ! previousFound ) KMessageBox::sorry( mParentWidget, i18nc("@info","Replace pattern not found in byte array."), messageBoxTitle ); else KMessageBox::information( mParentWidget, replacementReport, messageBoxTitle ); } bool ReplaceController::queryContinue( KFindDirection direction, int noOfReplacements ) const { const QString messageBoxTitle = i18nc( "@title:window", "Replace" ); const QString replacementReport = (noOfReplacements==0) ? i18nc( "@info", "No replacements made.") : i18ncp( "@info", "1 replacement made.", "%1 replacements made.", noOfReplacements ); const QString question = ( direction == FindForward ) ? xi18nc( "@info", "End of byte array reached.Continue from the beginning?" ) : xi18nc( "@info", "Beginning of byte array reached.Continue from the end?" ); - const QString message = replacementReport + QStringLiteral("

") + question; + const QString message = replacementReport + QLatin1String("

") + question; const int answer = KMessageBox::questionYesNo( mParentWidget, message, messageBoxTitle, KStandardGuiItem::cont(), KStandardGuiItem::cancel() ); const bool result = ( answer != KMessageBox::No ); return result; } ReplaceBehaviour ReplaceController::queryReplaceCurrent() const { if( !mReplacePrompt ) mReplacePrompt = new KReplacePrompt( mParentWidget ); mReplacePrompt->show(); const ReplaceBehaviour answer = mReplacePrompt->query(); if( answer == ReplaceAll || answer == CancelReplacing ) mReplacePrompt->hide(); return answer; } ReplaceController::~ReplaceController() { delete mReplaceDialog; delete mReplacePrompt; delete mTool; } } diff --git a/kasten/controllers/view/structures/datatypes/primitive/chardatainformation.cpp b/kasten/controllers/view/structures/datatypes/primitive/chardatainformation.cpp index 08229ae3..0ba32277 100644 --- a/kasten/controllers/view/structures/datatypes/primitive/chardatainformation.cpp +++ b/kasten/controllers/view/structures/datatypes/primitive/chardatainformation.cpp @@ -1,151 +1,151 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "chardatainformation.h" // KF5 #include #include // Qt #include #include #include "structviewpreferences.h" namespace { QString charString(quint8 value) { switch (value) { case '\0': return QStringLiteral("'\\0'"); case '\a': return QStringLiteral("'\\a'"); case '\b': return QStringLiteral("'\\b'"); case '\f': return QStringLiteral("'\\f'"); case '\n': return QStringLiteral("'\\n'"); case '\r': return QStringLiteral("'\\r'"); case '\t': return QStringLiteral("'\\t'"); case '\v': return QStringLiteral("'\\v'"); default: break; } QChar qchar = QChar(quint32(value)); if (!qchar.isPrint()) qchar = QChar::ReplacementCharacter; return QString(QLatin1Char('\'') + qchar + QLatin1Char('\'')); } } QString CharDataInformationMethods::staticValueString(quint8 value) { QString charStr = charString(value); if (Kasten::StructViewPreferences::showCharNumericalValue()) { int base = Kasten::StructViewPreferences::charDisplayBase(); const QString num = (base == 10 && Kasten::StructViewPreferences::localeAwareDecimalFormatting()) ? QLocale().toString(value) : QString::number(value, base); - charStr += QStringLiteral(" (") + PrimitiveDataInformation::basePrefix(base) + charStr += QLatin1String(" (") + PrimitiveDataInformation::basePrefix(base) + num + QLatin1Char(')'); } return charStr; } QWidget* CharDataInformationMethods::staticCreateEditWidget(QWidget* parent) { return new KLineEdit(parent); } QVariant CharDataInformationMethods::staticDataFromWidget(const QWidget* w) { //TODO fix this code!! const KLineEdit* edit = qobject_cast (w); if (edit) { QString text = edit->text(); if (text.length() == 0) { return QVariant(); } if (text.length() == 1) { //TODO char codec return (unsigned char) text.at(0).toLatin1(); } if (text.at(0) == QLatin1Char('\\')) { //escape sequence if (text.at(1) == QLatin1Char('x')) { //hex escape: bool okay; QString valStr = text.mid(2, 2); //only 2 chars quint8 val = valStr.toInt(&okay, 16); if (okay) return val; else return QVariant(); } else if (text.at(1) == QLatin1Char('n')) { return (quint8) '\n'; //newline } else if (text.at(1) == QLatin1Char('t')) { return (quint8) '\t'; //tab } else if (text.at(1) == QLatin1Char('r')) { return (quint8) '\r'; //cr } else { //octal escape: bool okay; QString valStr = text.mid(1, 3); //only 2 chars quint8 val = valStr.toInt(&okay, 8); if (okay) return val; else return QVariant(); } } } return QVariant(); } void CharDataInformationMethods::staticSetWidgetData(quint8 value, QWidget* w) { KLineEdit* edit = qobject_cast (w); if (edit) { QChar qchar(value, 0); if (! qchar.isPrint()) qchar = QChar(QChar::ReplacementCharacter); edit->setText( qchar ); } } QScriptValue CharDataInformationMethods::asScriptValue(quint8 value, QScriptEngine* engine, ScriptHandlerInfo* handler) { Q_UNUSED(engine); Q_UNUSED(handler); return QScriptValue(QString(value > 127 ? QChar::ReplacementCharacter : QChar(value, 0))); } diff --git a/kasten/controllers/view/structures/datatypes/primitive/enumdefinition.cpp b/kasten/controllers/view/structures/datatypes/primitive/enumdefinition.cpp index f586572d..d4d315dc 100644 --- a/kasten/controllers/view/structures/datatypes/primitive/enumdefinition.cpp +++ b/kasten/controllers/view/structures/datatypes/primitive/enumdefinition.cpp @@ -1,185 +1,185 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "enumdefinition.h" #include #include #include #include "../../script/scriptlogger.h" QMap EnumDefinition::parseEnumValues(const QScriptValue& val, const LoggerWithContext& logger, PrimitiveDataType type) { QMap enumValues; QScriptValueIterator it(val); while (it.hasNext()) { it.next(); QScriptValue val = it.value(); QPair conv; if (val.isNumber()) { double num = val.toNumber(); conv = convertToEnumEntry(it.name(), num, logger, type); } else { QString numStr = val.toString(); conv = convertToEnumEntry(it.name(), numStr, logger, type); } if (conv == QPair()) continue; enumValues.insert(conv.first, conv.second); } return enumValues; } QPair EnumDefinition::convertToEnumEntry(const QString& name, const QVariant& value, const LoggerWithContext& logger, PrimitiveDataType type) { Q_ASSERT(!name.isEmpty()); //name must not be empty, else default constructed return would be valid! quint64 maxValue = 0.0; qint64 minValue; switch (type.value) { case Type_Bitfield: //assume all 64 bits are used, we do not have the necessary information here maxValue = std::numeric_limits::max(); minValue = std::numeric_limits::min(); break; case Type_Bool8: //fall through case Type_UInt8: maxValue = std::numeric_limits::max(); minValue = 0; break; case Type_Bool16: //fall through case Type_UInt16: maxValue = std::numeric_limits::max(); minValue = 0; break; case Type_Bool32: //fall through case Type_UInt32: maxValue = std::numeric_limits::max(); minValue = 0; break; case Type_Bool64: //fall through case Type_UInt64: maxValue = std::numeric_limits::max(); minValue = 0; break; case Type_Int8: maxValue = std::numeric_limits::max(); minValue = std::numeric_limits::min(); break; case Type_Int16: maxValue = std::numeric_limits::max(); minValue = std::numeric_limits::min(); break; case Type_Int32: maxValue = std::numeric_limits::max(); minValue = std::numeric_limits::min(); break; case Type_Int64: maxValue = std::numeric_limits::max(); minValue = std::numeric_limits::min(); break; default: logger.warn() << type << "is an invalid type for an enumeration, no values were parsed"; return QPair(); } AllPrimitiveTypes intValue; if (value.type() == QVariant::Double) { const double num = value.toDouble(); //this is the largest double which maps to an integer exactly, ...993 is not representable anymore //...992 would still be representable, however it may be that ...993 was rounded down to that, be safe //and force the user to write such large numbers as strings if (num <= 9007199254740991.0) { intValue = qint64(num); } else { logger.warn() << "The value" << num << "in enum" << name << " is larger than the biggest double value that can represent" " any smaller integer exactly, skipping it.\n" "Write the value as a string so it can be converted" "to an integer exactly."; return QPair(); } } else { const QString valueString = value.toString(); bool ok = false; - if (valueString.startsWith(QStringLiteral("0x"))) + if (valueString.startsWith(QLatin1String("0x"))) { intValue = valueString.mid(2).toULongLong(&ok, 16); } else { if (type == Type_UInt64 || type == Type_Bool64) intValue = valueString.toULongLong(&ok, 10); else intValue = valueString.toLongLong(&ok, 10); } if (!ok) { const auto msgTemplate = QStringLiteral("Could not convert '%1' to an enum constant, name was: %2"); QString errMessage = QString(msgTemplate).arg(valueString, name); logger.warn() << errMessage; return QPair(); } } quint64 asUnsigned = intValue.value(); if (asUnsigned > maxValue) { QString errMessage = QStringLiteral( "Enumerator %1: %2 is larger than the maximum possible for type %3 (%4)"); errMessage = errMessage.arg(name, QString::number(asUnsigned), PrimitiveType::standardTypeName(type), QString::number(maxValue)); logger.warn() << errMessage; return QPair(); } qint64 asSigned = intValue.value(); if (minValue != 0 && asSigned < minValue) { QString errMessage = QStringLiteral( "Enumerator %1: %2 is smaller than the minimum possible for type %3 (%4)"); errMessage = errMessage.arg(name, QString::number(asSigned), PrimitiveType::standardTypeName(type), QString::number(minValue)); logger.warn() << errMessage; return QPair(); } return QPair(intValue, name); } diff --git a/kasten/controllers/view/structures/datatypes/primitive/flagdatainformation.cpp b/kasten/controllers/view/structures/datatypes/primitive/flagdatainformation.cpp index 1396f24d..8a32a238 100644 --- a/kasten/controllers/view/structures/datatypes/primitive/flagdatainformation.cpp +++ b/kasten/controllers/view/structures/datatypes/primitive/flagdatainformation.cpp @@ -1,127 +1,127 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "flagdatainformation.h" #include #include FlagDataInformation::FlagDataInformation(const QString& name, PrimitiveDataInformation* type, EnumDefinition::Ptr enumDef, DataInformation* parent) : EnumDataInformation(name, type, enumDef, parent) { Q_ASSERT_X(type->type() != Type_Double && type->type() != Type_Float && type->type() != Type_Invalid, "FlagDataInformation::FlagDataInformation", "Bitflags only work with integers!"); } typedef QPair FlagPair; template static void removeFromArray(QVarLengthArray& array, int index) { Q_ASSERT(index >= 0 && index < array.size()); int max = array.size() - 1; for (int i = index; i < max; ++i) { array[i] = array[i + 1]; } array.removeLast(); } QString FlagDataInformation::valueStringImpl() const { Q_ASSERT(mWasAbleToRead); QMapIterator iter(mEnum->values()); //I doubt more than 10 flags will be set very often -> only then do we need a malloc QVarLengthArray arr; const quint64 value = mValue->value().value(); while(iter.hasNext()) { iter.next(); const quint64 flag = iter.key().value(); if ((value & flag) == flag) { //flag is set arr.append(qMakePair(iter.value(), flag)); } } //now we have all flags, check if some overlap for (int i = 0; i < arr.size(); ++i) { const quint64 firstFlag = arr.at(i).second; for (int j = 0; j < arr.size();) { if (j == i) { j++; continue; } //check if they overlap quint64 secondFlag = arr.at(j).second; if ((firstFlag & secondFlag) == secondFlag) { //they overlap, remove the second flag removeFromArray(arr, j); if (j < i) i--; // i was pushed back by one as well } else j++; } } //if array has zero elements just return the value in hexadecimal if (arr.size() == 0) { return i18n("0x%1 (no matching flags)", QString::number(value, 16)); } //make sure all we also show remaining bits at the end quint64 usedBits = 0; QString result; for (int i = 0, size = arr.size(); i < size; ++i) { if (i != 0) - result += QStringLiteral(" | "); + result += QLatin1String(" | "); result += arr.at(i).first; usedBits |= arr.at(i).second; } //TODO remove a NONE flag if others present (value = 0) //TODO set invalid if value not completely covered by flags if (usedBits != value) { quint64 missing = value & ~usedBits; - result += QStringLiteral(" | 0x") + QString::number(missing, 16); + result += QLatin1String(" | 0x") + QString::number(missing, 16); } return result; } QString FlagDataInformation::typeNameImpl() const { return i18nc("Displayed in the type column. first comes the name " "of the enum, then the underlying type (e.g. uint32)", "flag %1 (%2)", mEnum->name(), mValue->typeName()); } diff --git a/kasten/controllers/view/structures/datatypes/primitivefactory.cpp b/kasten/controllers/view/structures/datatypes/primitivefactory.cpp index 2706e9f4..24897afb 100644 --- a/kasten/controllers/view/structures/datatypes/primitivefactory.cpp +++ b/kasten/controllers/view/structures/datatypes/primitivefactory.cpp @@ -1,107 +1,107 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "primitivefactory.h" #include "primitive/primitivetemplateinfo.h" #include "../script/scriptlogger.h" namespace PrimitiveFactory { PrimitiveDataType typeStringToType(const QString& string, const LoggerWithContext& logger) { const QString typeStr = string.trimmed().toLower(); - if (typeStr == QStringLiteral("bool8")) + if (typeStr == QLatin1String("bool8")) return Type_Bool8; - if (typeStr == QStringLiteral("bool16")) + if (typeStr == QLatin1String("bool16")) return Type_Bool16; - if (typeStr == QStringLiteral("bool32")) + if (typeStr == QLatin1String("bool32")) return Type_Bool32; - if (typeStr == QStringLiteral("bool64")) + if (typeStr == QLatin1String("bool64")) return Type_Bool64; - if (typeStr == QStringLiteral("int8")) + if (typeStr == QLatin1String("int8")) return Type_Int8; - if (typeStr == QStringLiteral("uint8")) + if (typeStr == QLatin1String("uint8")) return Type_UInt8; - if (typeStr == QStringLiteral("int16")) + if (typeStr == QLatin1String("int16")) return Type_Int16; - if (typeStr == QStringLiteral("uint16")) + if (typeStr == QLatin1String("uint16")) return Type_UInt16; - if (typeStr == QStringLiteral("int32")) + if (typeStr == QLatin1String("int32")) return Type_Int32; - if (typeStr == QStringLiteral("uint32")) + if (typeStr == QLatin1String("uint32")) return Type_UInt32; - if (typeStr == QStringLiteral("int64")) + if (typeStr == QLatin1String("int64")) return Type_Int64; - if (typeStr == QStringLiteral("uint64")) + if (typeStr == QLatin1String("uint64")) return Type_UInt64; - if (typeStr == QStringLiteral("char")) + if (typeStr == QLatin1String("char")) return Type_Char; - if (typeStr == QStringLiteral("float")) + if (typeStr == QLatin1String("float")) return Type_Float; - if (typeStr == QStringLiteral("double")) + if (typeStr == QLatin1String("double")) return Type_Double; logger.warn() << typeStr << "does not name a valid primitive type"; return Type_Invalid; //just return a default value } PrimitiveDataInformation* newInstance(const QString& name, PrimitiveDataType type, const LoggerWithContext& logger, DataInformation* parent) { switch (type.value) { case Type_Char: return new PrimitiveInfo::Class(name, parent); case Type_Int8: return new PrimitiveInfo::Class(name, parent); case Type_Int16: return new PrimitiveInfo::Class(name, parent); case Type_Int32: return new PrimitiveInfo::Class(name, parent); case Type_Int64: return new PrimitiveInfo::Class(name, parent); case Type_UInt8: return new PrimitiveInfo::Class(name, parent); case Type_UInt16: return new PrimitiveInfo::Class(name, parent); case Type_UInt32: return new PrimitiveInfo::Class(name, parent); case Type_UInt64: return new PrimitiveInfo::Class(name, parent); case Type_Bool8: return new PrimitiveInfo::Class(name, parent); case Type_Bool16: return new PrimitiveInfo::Class(name, parent); case Type_Bool32: return new PrimitiveInfo::Class(name, parent); case Type_Bool64: return new PrimitiveInfo::Class(name, parent); case Type_Float: return new PrimitiveInfo::Class(name, parent); case Type_Double: return new PrimitiveInfo::Class(name, parent); default: logger.error().nospace() << "could not convert '" << type << "' to a primitive type"; return 0; //invalid type } } } diff --git a/kasten/controllers/view/structures/datatypes/strings/utf16stringdata.cpp b/kasten/controllers/view/structures/datatypes/strings/utf16stringdata.cpp index 9f76cc6c..52fb6deb 100644 --- a/kasten/controllers/view/structures/datatypes/strings/utf16stringdata.cpp +++ b/kasten/controllers/view/structures/datatypes/strings/utf16stringdata.cpp @@ -1,242 +1,242 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "utf16stringdata.h" #include "../../structlogging.h" #include #include #include #include "../topleveldatainformation.h" #include "../dummydatainformation.h" #include "stringdatainformation.h" Utf16StringData::Utf16StringData(StringDataInformation* parent) : StringData(parent), mNonBMPCount(0) { } Utf16StringData::~Utf16StringData() { } QString Utf16StringData::charType() const { return mLittleEndian ? i18n("UTF16-LE char") : i18n("UTF16-BE char"); } QString Utf16StringData::typeName() const { return mLittleEndian ? i18n("UTF16-LE string") : i18n("UTF16-BE string"); } uint Utf16StringData::count() const { return mCodePoints.size(); } QString Utf16StringData::stringValue(int row) const { //TODO details Q_ASSERT((uint)row < count()); //TODO show invalid values uint val = mCodePoints.at(row); QString number = QString::number(val, 16).toUpper(); if (number.length() == 1) - number = QStringLiteral("0") + number; + number = QLatin1Char('0') + number; if (val > UNICODE_MAX) return i18n("Value too big: 0x%1", number); else if (val > BMP_MAX) { QString ret(2, Qt::Uninitialized); ret[0] = QChar::highSurrogate(val); ret[1] = QChar::lowSurrogate(val); return i18n("%1 (U+%2)", ret, number); } else return i18n("%1 (U+%2)", QString(QChar(mCodePoints.at(row))), number); } QString Utf16StringData::completeString(bool skipInvalid) const { QVarLengthArray data(mCodePoints.size() + mNonBMPCount); int codePointCount = mCodePoints.size(); int i = 0; for (int idx = 0; idx < codePointCount; ++idx) { uint val = mCodePoints.at(idx); if (val > UNICODE_MAX) { if (skipInvalid) continue; else data[i] = QChar::ReplacementCharacter; } else if (val > BMP_MAX) { data[i] = QChar::highSurrogate(val); i++; data[i] = QChar::lowSurrogate(val); } else { data[i] = QChar((ushort)val); } i++; } return QString(data.constData(), i); } qint64 Utf16StringData::read(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining) { const int oldSize = count(); mNonBMPCount = 0; if (mMode == CharCount) { mCodePoints.reserve(mLength.maxChars); } else if (mMode == ByteCount) { mCodePoints.reserve(mLength.maxBytes / 2); } mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, oldSize, 0); mParent->topLevelDataInformation()->_childCountChanged(mParent, oldSize, 0); const uint oldMax = mCodePoints.size(); quint64 remaining = bitsRemaining; Okteta::Address addr = address; uint count = 0; mEofReached = false; if (((mMode & CharCount) && mLength.maxChars == 0) || ((mMode & ByteCount) && mLength.maxBytes < 2)) return 0; bool eofAtStart = false; if (bitsRemaining < 16) eofAtStart = true; while (true) { if (remaining < 16) { mEofReached = true; break; } uint codePoint; ushort val; bool terminate = false; if (mLittleEndian) val = input->byte(addr) | (input->byte(addr + 1) << 8); else val = (input->byte(addr) << 8) | input->byte(addr + 1); //high surrogate -> if is followed by low surrogate we have a 4 bit char if (QChar::isHighSurrogate(val)) { if (remaining < 32 || ((mMode & ByteCount) && (addr + 2 - address) / 2 >= Okteta::Address(mLength.maxBytes / 2))) { codePoint = val; mEofReached = true; terminate = true; } else { ushort val2; if (mLittleEndian) val2 = input->byte(addr + 2) | (input->byte(addr + 3) << 8); else val2 = (input->byte(addr + 2) << 8) | input->byte(addr + 3); if (QChar::isLowSurrogate(val2)) { codePoint = QChar::surrogateToUcs4(val, val2); remaining -= 16; addr += 2; mNonBMPCount++; // codepoint > 0xffff -> non BMP } else codePoint = val; } } else { codePoint = val; } if (count < oldMax) mCodePoints[count] = codePoint; else mCodePoints.append(codePoint); remaining -= 16; addr += 2; count++; //now check if we have to terminate if (mMode & Sequence) { if (codePoint == mTerminationCodePoint) terminate = true; } if (mMode & ByteCount) { // divide by two in case someone set length to an odd number of bytes if ((addr - address) / 2 >= Okteta::Address(mLength.maxBytes / 2)) terminate = true; } if (mMode & CharCount) { if (count >= mLength.maxChars) terminate = true; } if (mMode == None) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no termination mode set!!"; Q_ASSERT(false); } if (terminate) break; } mCodePoints.resize(count); mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, 0, count); mParent->topLevelDataInformation()->_childCountChanged(mParent, 0, count); if (eofAtStart) return -1; return (addr - address) * 8; } BitCount32 Utf16StringData::size() const { //add 16 for every non BMP char, since they use 32 bits return (mCodePoints.size() + mNonBMPCount) * 16; } BitCount32 Utf16StringData::sizeAt(uint i) const { Q_ASSERT(i <= count()); uint val = mCodePoints.at(i); return val > 0xffff ? 32 : 16; } diff --git a/kasten/controllers/view/structures/datatypes/strings/utf32stringdata.cpp b/kasten/controllers/view/structures/datatypes/strings/utf32stringdata.cpp index c53ed89f..bbbfbc94 100644 --- a/kasten/controllers/view/structures/datatypes/strings/utf32stringdata.cpp +++ b/kasten/controllers/view/structures/datatypes/strings/utf32stringdata.cpp @@ -1,210 +1,210 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "utf32stringdata.h" #include "../../structlogging.h" #include #include #include #include "../topleveldatainformation.h" #include "../dummydatainformation.h" #include "stringdatainformation.h" Utf32StringData::Utf32StringData(StringDataInformation* parent) : StringData(parent), mNonBMPCount(0) { } Utf32StringData::~Utf32StringData() { } QString Utf32StringData::charType() const { return mLittleEndian ? i18n("UTF32-LE char") : i18n("UTF32-BE char"); } QString Utf32StringData::typeName() const { return mLittleEndian ? i18n("UTF32-LE string") : i18n("UTF32-BE string"); } uint Utf32StringData::count() const { return mCodePoints.size(); } QString Utf32StringData::stringValue(int row) const { //TODO details Q_ASSERT((uint)row < count()); //TODO show invalid values uint val = mCodePoints.at(row); QString number = QString::number(val, 16).toUpper(); if (number.length() == 1) - number = QStringLiteral("0") + number; + number = QLatin1Char('0') + number; if (val > UNICODE_MAX) return i18n("Value too big: 0x%1", number); else if (val > BMP_MAX) { QString ret(2, Qt::Uninitialized); ret[0] = QChar::highSurrogate(val); ret[1] = QChar::lowSurrogate(val); return i18n("%1 (U+%2)", ret, number); } else return i18n("%1 (U+%2)", QString(QChar(mCodePoints.at(row))), number); } QString Utf32StringData::completeString(bool skipInvalid) const { QVarLengthArray data(mCodePoints.size() + mNonBMPCount); int codePointCount = mCodePoints.size(); int i = 0; for (int idx = 0; idx < codePointCount; ++idx) { uint val = mCodePoints.at(idx); if (val > UNICODE_MAX) { if (skipInvalid) continue; else data[i] = QChar::ReplacementCharacter; } else if (val > BMP_MAX) { data[i] = QChar::highSurrogate(val); i++; data[i] = QChar::lowSurrogate(val); } else { data[i] = QChar((ushort)val); } i++; } return QString(data.constData(), i); } qint64 Utf32StringData::read(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining) { const int oldSize = count(); mNonBMPCount = 0; if (mMode == CharCount) { mCodePoints.reserve(mLength.maxChars); } else if (mMode == ByteCount) { mCodePoints.reserve(mLength.maxBytes / 4); } mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, oldSize, 0); mParent->topLevelDataInformation()->_childCountChanged(mParent, oldSize, 0); const uint oldMax = mCodePoints.size(); quint64 remaining = bitsRemaining; Okteta::Address addr = address; uint count = 0; mEofReached = false; if (((mMode & CharCount) && mLength.maxChars == 0) || ((mMode & ByteCount) && mLength.maxBytes < 2)) return 0; bool eofAtStart = false; if (remaining < 32) eofAtStart = true; while (true) { if (remaining < 32) { mEofReached = true; break; } uint codePoint; bool terminate = false; if (mLittleEndian) codePoint = input->byte(addr) | (input->byte(addr + 1) << 8) | (input->byte(addr + 2) << 16) | (input->byte(addr + 3) << 24); else codePoint = (input->byte(addr) << 24) | (input->byte(addr + 1) << 16) | (input->byte(addr + 2) << 8) | input->byte(addr + 3); if (count < oldMax) mCodePoints[count] = codePoint; else mCodePoints.append(codePoint); remaining -= 32; addr += 4; count++; //now check if we have to terminate if (mMode & Sequence) { if (codePoint == mTerminationCodePoint) terminate = true; } if (mMode & ByteCount) { // divide by two in case someone set length to an odd number of bytes if ((addr - address) / 4 >= Okteta::Address(mLength.maxBytes / 4)) terminate = true; } if (mMode & CharCount) { if (count >= mLength.maxChars) terminate = true; } if (mMode == None) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no termination mode set!!"; Q_ASSERT(false); } if (terminate) break; } mCodePoints.resize(count); mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, 0, count); mParent->topLevelDataInformation()->_childCountChanged(mParent, 0, count); if (eofAtStart) return -1; return (addr - address) * 8; } BitCount32 Utf32StringData::size() const { return mCodePoints.size() * 32; } BitCount32 Utf32StringData::sizeAt(uint i) const { Q_ASSERT(i <= count()); Q_UNUSED(i) return 32; } diff --git a/kasten/controllers/view/structures/datatypes/strings/utf8stringdata.cpp b/kasten/controllers/view/structures/datatypes/strings/utf8stringdata.cpp index 86c3a5c6..1b71509f 100644 --- a/kasten/controllers/view/structures/datatypes/strings/utf8stringdata.cpp +++ b/kasten/controllers/view/structures/datatypes/strings/utf8stringdata.cpp @@ -1,356 +1,356 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "utf8stringdata.h" #include "../../structlogging.h" #include #include #include #include "../topleveldatainformation.h" #include "../dummydatainformation.h" #include "stringdatainformation.h" Utf8StringData::Utf8StringData(StringDataInformation* parent) : StringData(parent), mOneByteCount(0), mTwoByteCount(0), mThreeByteCount(0), mFourByteCount(0), mNonBMPCount(0) { } Utf8StringData::~Utf8StringData() { } QString Utf8StringData::charType() const { return i18n("UTF8 char"); } QString Utf8StringData::typeName() const { return i18n("UTF8 string"); } uint Utf8StringData::count() const { return mCodePoints.size(); } QString Utf8StringData::stringValue(int row) const { Q_ASSERT((uint)row < count()); //TODO show invalid values uint val = mCodePoints.at(row); QString number = QString::number(val, 16).toUpper(); if (number.length() == 1) - number = QStringLiteral("0") + number; + number = QLatin1Char('0') + number; if (val > UNICODE_MAX) return i18n("Value too big: 0x%1", number); else if (val > BMP_MAX) { QString ret(2, Qt::Uninitialized); ret[0] = QChar::highSurrogate(val); ret[1] = QChar::lowSurrogate(val); return i18n("%1 (U+%2)", ret, number); } else return i18n("%1 (U+%2)", QString(QChar(mCodePoints.at(row))), number); } QString Utf8StringData::completeString(bool skipInvalid) const { QVarLengthArray data(mCodePoints.size() + mNonBMPCount); int codePointCount = mCodePoints.size(); int i = 0; for (int idx = 0; idx < codePointCount; ++idx) { uint val = mCodePoints.at(idx); //if error at idx is set also skip if (val > UNICODE_MAX || mErrorIndices.value(idx)) { if (skipInvalid) continue; else data[i] = QChar::ReplacementCharacter; } else if (val > BMP_MAX) { data[i] = QChar::highSurrogate(val); i++; data[i] = QChar::lowSurrogate(val); } else { data[i] = QChar((ushort)val); } i++; } return QString(data.constData(), i); } qint64 Utf8StringData::read(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining) { const int oldSize = count(); mNonBMPCount = 0; mOneByteCount = 0; mTwoByteCount = 0; mThreeByteCount = 0; mFourByteCount = 0; if (mMode == CharCount) { mCodePoints.reserve(mLength.maxChars); } else if (mMode == ByteCount) { mCodePoints.reserve(mLength.maxBytes / 1.5); //just a guess, assuming 1.5 bytes per char } mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, oldSize, 0); mParent->topLevelDataInformation()->_childCountChanged(mParent, oldSize, 0); const uint oldMax = mCodePoints.size(); quint64 remaining = bitsRemaining; Okteta::Address addr = address; uint count = 0; mEofReached = false; if (((mMode & CharCount) && mLength.maxChars == 0) || ((mMode & ByteCount) && mLength.maxBytes < 2)) return 0; bool eofAtStart = false; if (bitsRemaining < 8) eofAtStart = true; while (true) { if (remaining < 8) { mEofReached = true; break; } uint codePoint; quint8 byte = input->byte(addr); bool terminate = false; if (byte <= ASCII_MAX) { mOneByteCount++; codePoint = byte; } else if ((byte & 0xe0) == 0xc0) { //two byte sequence if (byte == 0xc0 || byte == 0xc1) { mOneByteCount++; mErrorIndices[count] = 1; codePoint = byte; } else if (remaining < 16) { mOneByteCount++; mEofReached = true; mErrorIndices[count] = 1; codePoint = byte; } else { mTwoByteCount++; remaining -= 8; addr++; quint8 byte2 = input->byte(addr); if ((byte2 & 0xc0) != 0x80) { mErrorIndices[count] = 2; codePoint = (byte << 8) | byte2; //just put the raw bytes in case of error } else { codePoint = (byte2 & 0x3f) | ((byte & 0x1f) << 6); } } } else if ((byte & 0xf0) == 0xe0) { if (remaining < 16) { mEofReached = true; mErrorIndices[count] = 1; codePoint = byte; mOneByteCount++; } else if (remaining < 24) { mEofReached = true; mErrorIndices[count] = 2; remaining -= 8; addr++; codePoint = (byte << 8) | input->byte(addr); mTwoByteCount++; } else { mThreeByteCount++; remaining -= 16; addr++; quint8 byte2 = input->byte(addr); addr++; quint8 byte3 = input->byte(addr); if ((byte2 & 0xc0) != 0x80 || (byte3 & 0xc0) != 0x80) { mErrorIndices[count] = 3; codePoint = (byte << 16) | (byte2 << 8) | byte3; //just put the raw bytes in case of error } else { codePoint = (byte3 & 0x3f) | ((byte2 & 0x3f) << 6) | ((byte & 0x1f) << 12); } } } else if ((byte & 0xf8) == 0xf0) { if (remaining < 16) { mEofReached = true; mErrorIndices[count] = 1; codePoint = byte; mOneByteCount++; } else if (remaining < 24) { mEofReached = true; mErrorIndices[count] = 2; addr++; remaining -= 8; codePoint = (byte << 8) | input->byte(addr); mTwoByteCount++; } else if (remaining < 32) { mEofReached = true; mErrorIndices[count] = 3; codePoint = (byte << 16) | (input->byte(addr + 1) << 8) | input->byte(addr + 2); addr += 2; remaining -= 16; mThreeByteCount++; } else { mFourByteCount++; remaining -= 24; addr++; quint8 byte2 = input->byte(addr); addr++; quint8 byte3 = input->byte(addr); addr++; quint8 byte4 = input->byte(addr); if ((byte2 & 0xc0) != 0x80 || (byte3 & 0xc0) != 0x80 || (byte4 & 0xc0) != 0x80) { mErrorIndices[count] = 3; codePoint = (byte << 16) | (byte2 << 8) | byte3; //just put the raw bytes in case of error } else { codePoint = (byte4 & 0x3f) | ((byte3 & 0x3f) << 6) | ((byte2 & 0x3f) << 12) | ((byte & 0x1f) << 18); if (codePoint > UNICODE_MAX) { mErrorIndices[count] = 4; //just put the raw bytes in case of error codePoint = (byte << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } } } } else { mErrorIndices[count] = 1; codePoint = byte; mOneByteCount++; } if (codePoint > BMP_MAX) mNonBMPCount++; if (count < oldMax) mCodePoints[count] = codePoint; else mCodePoints.append(codePoint); remaining -= 8; addr++; count++; //now check if we have to terminate if (mMode & Sequence) { if (codePoint == mTerminationCodePoint) terminate = true; } if (mMode & ByteCount) { // divide by two in case someone set length to an odd number of bytes if (uint(addr - address) >= mLength.maxBytes) terminate = true; } if (mMode & CharCount) { if (count >= mLength.maxChars) terminate = true; } if (mMode == None) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no termination mode set!!"; Q_ASSERT(false); } if (terminate) break; } mCodePoints.resize(count); mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, 0, count); mParent->topLevelDataInformation()->_childCountChanged(mParent, 0, count); if (eofAtStart) return -1; return (addr - address) * 8; } BitCount32 Utf8StringData::size() const { //add 16 for every non BMP char, since they use 32 bits return (mOneByteCount + mTwoByteCount * 2 + mThreeByteCount * 3 + mFourByteCount * 4) * 8; } BitCount32 Utf8StringData::sizeAt(uint i) const { Q_ASSERT(i <= count()); quint8 isError = mErrorIndices[i]; if (isError) return isError * 8; //error is number of bytes uint val = mCodePoints.at(i); if (val < 0x80) return 8; else if (val < 0x7ff) return 16; else if (val < 0xffff) return 24; else return 32; } diff --git a/kasten/controllers/view/structures/parsers/datainformationfactory.cpp b/kasten/controllers/view/structures/parsers/datainformationfactory.cpp index abe27c6b..d54bf311 100644 --- a/kasten/controllers/view/structures/parsers/datainformationfactory.cpp +++ b/kasten/controllers/view/structures/parsers/datainformationfactory.cpp @@ -1,445 +1,445 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "datainformationfactory.h" #include "../datatypes/primitive/bitfield/boolbitfielddatainformation.h" #include "../datatypes/primitive/bitfield/unsignedbitfielddatainformation.h" #include "../datatypes/primitive/bitfield/signedbitfielddatainformation.h" #include "../datatypes/primitivefactory.h" #include "../script/scriptlogger.h" #include AbstractBitfieldDataInformation* DataInformationFactory::newBitfield(const BitfieldParsedData& pd) { if (!pd.width.isValid) { if (pd.width.string.isEmpty()) pd.error() << "Bitfield is missing width."; else pd.error() << "Width of bitfield is not a valid number: " << pd.width.string; return 0; } if (pd.width.value <= 0 || pd.width.value > 64) { pd.error() << "Width of bitfield is not a value from 1-64:" << pd.width.value; return 0; } AbstractBitfieldDataInformation* bitf = 0; const QString type = pd.type.toLower(); if (type.isEmpty()) { pd.info() << "No bitfield type specified, defaulting to unsigned."; bitf = new UnsignedBitfieldDataInformation(pd.name, pd.width.value, pd.parent); } - else if (type == QStringLiteral("bool")) + else if (type == QLatin1String("bool")) bitf = new BoolBitfieldDataInformation(pd.name, pd.width.value, pd.parent); - else if (type == QStringLiteral("unsigned")) + else if (type == QLatin1String("unsigned")) bitf = new UnsignedBitfieldDataInformation(pd.name, pd.width.value, pd.parent); - else if (type == QStringLiteral("signed")) + else if (type == QLatin1String("signed")) bitf = new SignedBitfieldDataInformation(pd.name, pd.width.value, pd.parent); else { pd.error() << "invalid bitfield type attribute given:" << type; return 0; } return bitf; } PrimitiveDataInformation* DataInformationFactory::newPrimitive(const PrimitiveParsedData& pd) { if (pd.type.isEmpty()) { pd.error() << "Type of primitive not specified, cannot create it!"; return 0; } LoggerWithContext lwc(pd.logger, pd.context()); PrimitiveDataType primitiveType = PrimitiveFactory::typeStringToType(pd.type, lwc); if (primitiveType == Type_Invalid || primitiveType == Type_Bitfield) { pd.error() << "Unrecognized primitive type: " << pd.type; return 0; } return PrimitiveFactory::newInstance(pd.name, primitiveType, lwc, pd.parent); } namespace { template T* newEnumOrFlags(const EnumParsedData& pd) { - LoggerWithContext lwc(pd.logger, pd.context() + QStringLiteral(" (type)")); + LoggerWithContext lwc(pd.logger, pd.context() + QLatin1String(" (type)")); const PrimitiveDataType primitiveType = PrimitiveFactory::typeStringToType(pd.type, lwc); if (primitiveType == Type_Invalid || primitiveType == Type_Bitfield) { pd.error() << "Unrecognized enum type: " << pd.type; return 0; } if (primitiveType == Type_Float || primitiveType == Type_Double) { pd.error() << "Floating-point enums are not allowed since they make little sense."; return 0; } EnumDefinition::Ptr definition = pd.enumDef; if (!definition) { QMap enumValues = EnumDefinition::parseEnumValues(pd.enumValuesObject, lwc, primitiveType); if (enumValues.isEmpty()) { pd.error() << "No enum values specified!"; return 0; } definition = EnumDefinition::Ptr(new EnumDefinition(enumValues, pd.enumName, primitiveType)); } if (definition->type() != primitiveType) { pd.error().nospace() << "Enum type (" << definition->type() << ") and value type (" << primitiveType << ") do not match!"; return 0; } PrimitiveDataInformation* primData = PrimitiveFactory::newInstance(pd.name, primitiveType, lwc); //TODO allow bitfields? if (!primData) { pd.error() << "Could not create a value object for this enum!"; return 0; } return new T(pd.name, primData, definition, pd.parent); } template T* newStructOrUnion(const StructOrUnionParsedData& supd) { T* structOrUnion = new T(supd.name, QVector(), supd.parent); supd.children->setParent(structOrUnion); while (supd.children->hasNext()) { DataInformation* data = supd.children->next(); if (data) structOrUnion->appendChild(data, false); else return 0; //error message should be logged already } if (structOrUnion->childCount() == 0) supd.info() << "No children were found, this is probably a mistake."; return structOrUnion; } QString generateLengthFunction(DataInformation* current, DataInformation* last, QString elemName, QString currentString, const ParserInfo& info) { if (!current) //reached top return QString(); for (int i = current->childCount() - 1; i >= 0; --i) { DataInformation* child = current->childAt(i); if (child == last) return QString(); //don't go down again after going up one level QString childName = child->name(); if (childName == elemName) { - QString function = QStringLiteral("function() { return this.parent.") + currentString - + elemName + QStringLiteral(".value; }"); + QString function = QLatin1String("function() { return this.parent.") + currentString + + elemName + QLatin1String(".value; }"); info.info() << "Found element for dynamic array length: " << child->fullObjectPath() << ", resulting function is: " << function; return function; } else if (child->childCount() > 0) { QString func = generateLengthFunction(child, current, elemName, currentString + childName + QLatin1Char('.'), info); //if func is empty no valid child was found, just continue if (!func.isEmpty()) return func; } //has no children and was not the desired element -> continue loop } //now check parents DataInformationBase* nextBase = current->parent(); if (!nextBase) return QString(); DataInformation* next = nextBase->asDataInformation(); if (next == last) return QString(); //we moved one level down previously, don't move up again else return generateLengthFunction(current->parent()->asDataInformation(), current, elemName, - currentString + QStringLiteral("parent."), info); + currentString + QLatin1String("parent."), info); } } EnumDataInformation* DataInformationFactory::newEnum(const EnumParsedData& pd) { return newEnumOrFlags(pd); } FlagDataInformation* DataInformationFactory::newFlags(const EnumParsedData& pd) { return newEnumOrFlags(pd); } ArrayDataInformation* DataInformationFactory::newArray(const ArrayParsedData& pd) { if (!pd.arrayType) { pd.error() << "Failed to parse array type!"; return 0; } if (!pd.length.isValid()) { pd.error() << "No array length specified!"; return 0; } const ParsedNumber fixedLength = ParserUtils::uintFromScriptValue(pd.length); if (fixedLength.isValid) { return new ArrayDataInformation(pd.name, fixedLength.value, pd.arrayType, pd.parent, QScriptValue()); } else if (pd.length.isFunction()) { return new ArrayDataInformation(pd.name, 0, pd.arrayType, pd.parent, pd.length); } else { //neither integer nor function, must be a string containing the name of another element. const QString lengthStr = pd.length.toString(); if (!pd.parent) { pd.error() << "Toplevel array has length depending on other field (" << lengthStr << "). This is not possible."; return 0; } if (lengthStr.contains(QLatin1Char('.'))) { pd.error() << "Referenced array length element (" << lengthStr << ") contains '.', this is not allowed!"; return 0; //TODO maybe add possible shorthand length="this.parent.length" } QString lengthFunctionString = generateLengthFunction(pd.parent, 0, lengthStr, QString(), pd); if (lengthFunctionString.isEmpty()) { pd.error() << "Could not find element " << lengthStr << " referenced as array length!"; return 0; } QScriptValue lengthFunction = ParserUtils::functionSafeEval(pd.engine, lengthFunctionString); return new ArrayDataInformation(pd.name, 0, pd.arrayType, pd.parent, lengthFunction); } } StringDataInformation* DataInformationFactory::newString(const StringParsedData& pd) { if (pd.maxByteCount.isValid && pd.maxCharCount.isValid) { pd.error() << "Both maxCharCount and maxByteCount are set, only one is allowed."; return 0; } StringDataInformation::StringType encoding = ParserUtils::toStringEncoding(pd.encoding, LoggerWithContext(pd.logger, pd.context())); if (encoding == StringDataInformation::InvalidEncoding) { pd.error() << "Bad string encoding given:" << pd.encoding; return 0; } StringDataInformation* data = new StringDataInformation(pd.name, encoding, pd.parent); bool modeSet = false; if (pd.termination.isValid) { data->setTerminationCodePoint(pd.termination.value); modeSet = true; } if (pd.maxByteCount.isValid) { data->setMaxByteCount(pd.maxByteCount.value); modeSet = true; } if (pd.maxCharCount.isValid) { data->setMaxCharCount(pd.maxCharCount.value); modeSet = true; } //if mode is None, we assume zero terminated strings if (!modeSet) { pd.info() << "No string termination mode set, assuming null terminated strings."; data->setTerminationCodePoint(0); Q_ASSERT(data->terminationMode() == StringData::Sequence); } return data; } UnionDataInformation* DataInformationFactory::newUnion(const StructOrUnionParsedData& pd) { return newStructOrUnion(pd); } StructureDataInformation* DataInformationFactory::newStruct(const StructOrUnionParsedData& pd) { return newStructOrUnion(pd); } bool DataInformationFactory::commonInitialization(DataInformation* data, const CommonParsedData& pd) { data->setByteOrder(pd.endianess); if (data->name().isEmpty()) { pd.warn() << "Name is empty!"; } if (pd.updateFunc.isValid()) { if (!pd.updateFunc.isFunction()) { pd.error() << "Update function is not a function: " << pd.updateFunc.toString(); return false; } else data->setUpdateFunc(pd.updateFunc); } if (pd.validationFunc.isValid()) { if (!pd.validationFunc.isFunction()) { pd.error() << "Validation function is not a function: " << pd.validationFunc.toString(); return false; } else data->setValidationFunc(pd.validationFunc); } if (pd.toStringFunc.isValid()) { if (!pd.toStringFunc.isFunction()) { pd.error() << "To string function is not a function: " << pd.toStringFunc.toString(); return false; } else data->setToStringFunction(pd.toStringFunc); } if (!pd.customTypeName.isEmpty()) { data->setCustomTypeName(pd.customTypeName); } return true; } PointerDataInformation* DataInformationFactory::newPointer(const PointerParsedData& pd) { if (!pd.pointerTarget) { pd.error() << "Missing pointer target"; return 0; } if (!pd.valueType) { pd.error() << "Missing pointer type"; return 0; } if (!pd.valueType->isPrimitive()) { pd.error() << "Bad pointer type, only unsigned integers are allowed"; return 0; } PrimitiveDataInformation* primValue = pd.valueType->asPrimitive(); if (!(primValue->type() == Type_UInt8 || primValue->type() == Type_UInt16 || primValue->type() == Type_UInt32 || primValue->type() == Type_UInt64)) { pd.error() << "Bad pointer type, only unsigned integers are allowed"; //TODO offsets (signed int + bitfields) return 0; } return new PointerDataInformation(pd.name, pd.pointerTarget, primValue, pd.parent); } TaggedUnionDataInformation* DataInformationFactory::newTaggedUnion(const TaggedUnionParsedData& pd) { QScopedPointer tagged(new TaggedUnionDataInformation(pd.name, pd.parent)); pd.children->setParent(tagged.data()); while (pd.children->hasNext()) { DataInformation* data = pd.children->next(); if (data) tagged->appendChild(data, false); else return 0; //error message should be logged already } if (tagged->childCount() == 0) { pd.error() << "No children in tagged union. At least one is required so that tag can be evaluated."; return 0; } //verify alternatives bool alternativesValid = true; QVector altInfo; for(int i = 0; i < pd.alternatives.size(); ++i) { const TaggedUnionParsedData::Alternatives& fi = pd.alternatives.at(i); if (!fi.selectIf.isFunction()) { ParsedNumber number = ParserUtils::uint64FromScriptValue(fi.selectIf); if (!number.isValid) { pd.error() << "Alternative number" << i << "is not valid. SelectIf is neither function nor number!"; alternativesValid = false; } //number is valid -> there must be exactly one field if (tagged->childCount() != 1) { pd.error() << "Alternative number" << i << "is not valid. SelectIf is number," " but there is not exactly one child!"; alternativesValid = false; } } QVector children; while (fi.fields->hasNext()) { DataInformation* next = fi.fields->next(); if (next) children.append(next); else { pd.error() << "Alternative number" << i << "has an invalid field!"; alternativesValid = false; } } altInfo.append(TaggedUnionDataInformation::FieldInfo(fi.name, fi.selectIf, children)); } if (!alternativesValid) { for (int i = 0; i < altInfo.size(); ++i) qDeleteAll(altInfo.at(i).fields); return 0; } tagged->setAlternatives(altInfo, false); pd.defaultFields->setParent(tagged.data()); while (pd.defaultFields->hasNext()) { DataInformation* data = pd.defaultFields->next(); if (data) tagged->appendDefaultField(data, false); else return 0; //error message should be logged already } return tagged.take(); } diff --git a/kasten/controllers/view/structures/parsers/osdparser.cpp b/kasten/controllers/view/structures/parsers/osdparser.cpp index a1863ff3..10670f36 100644 --- a/kasten/controllers/view/structures/parsers/osdparser.cpp +++ b/kasten/controllers/view/structures/parsers/osdparser.cpp @@ -1,619 +1,619 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "osdparser.h" #include "datainformationfactory.h" #include "../datatypes/array/arraydatainformation.h" #include "../datatypes/uniondatainformation.h" #include "../datatypes/structuredatainformation.h" #include "../datatypes/strings/stringdatainformation.h" #include "../datatypes/strings/stringdata.h" #include "../datatypes/primitivefactory.h" #include "../datatypes/topleveldatainformation.h" #include "../datatypes/dummydatainformation.h" #include "../structuredefinitionfile.h" #include "../script/scriptlogger.h" #include "../script/scriptengineinitializer.h" #include "../structlogging.h" #include #include #include #include using namespace ParserStrings; OsdParser::OsdParser(const QString& pluginName, const QString& absolutePath) : AbstractStructureParser(pluginName, absolutePath) { } OsdParser::OsdParser(const QString& xml) : AbstractStructureParser(QString(), QString()), mXmlString(xml) { } OsdParser::~OsdParser() { } QDomDocument OsdParser::openDoc(ScriptLogger* logger) const { return mXmlString.isEmpty() ? openDocFromFile(logger) : openDocFromString(logger); } QDomDocument OsdParser::openDocFromString(ScriptLogger * logger) const { Q_CHECK_PTR(logger); Q_ASSERT(!mXmlString.isEmpty()); int errorLine, errorColumn; QString errorMsg; QDomDocument doc; if (!doc.setContent(mXmlString, false, &errorMsg, &errorLine, &errorColumn)) { const QString errorOutput = QString( QStringLiteral("error reading XML: %1\n error line=%2\nerror column=%3")) .arg(errorMsg, QString::number(errorLine), QString::number(errorColumn)); logger->error() << errorOutput; logger->info() << "XML was:" << mXmlString; return QDomDocument(); } return doc; } QDomDocument OsdParser::openDocFromFile(ScriptLogger* logger) const { Q_CHECK_PTR(logger); QFileInfo fileInfo(mAbsolutePath); if (!fileInfo.exists()) { logger->error() << "File" << mAbsolutePath << "does not exist!"; return QDomDocument(); } QFile file(fileInfo.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) { - const QString errorOutput = QStringLiteral("Could not open file ") + mAbsolutePath; + const QString errorOutput = QLatin1String("Could not open file ") + mAbsolutePath; logger->error() << errorOutput; return QDomDocument(); } int errorLine, errorColumn; QString errorMsg; QDomDocument doc; if (!doc.setContent(&file, false, &errorMsg, &errorLine, &errorColumn)) { const QString errorOutput = QString( QStringLiteral("error reading XML: %1\n error line=%2\nerror column=%3")) .arg(errorMsg, QString::number(errorLine), QString::number(errorColumn)); logger->error() << errorOutput; logger->info() << "File was:" << mAbsolutePath; } file.close(); return doc; } QStringList OsdParser::parseStructureNames() const { QStringList ret; QScopedPointer rootLogger(new ScriptLogger); //only needed if we get an error right now rootLogger->setLogToStdOut(true); //we cannot get our messages into the script console, so do this instead QDomDocument document = openDoc(rootLogger.data()); if (document.isNull()) return QStringList(); QDomElement rootElem = document.firstChildElement(QStringLiteral("data")); if (rootElem.isNull()) return QStringList(); for (QDomElement childElement = rootElem.firstChildElement(); !childElement.isNull(); childElement = childElement.nextSiblingElement()) { QString tag = childElement.tagName(); if (tag == TYPE_STRUCT() || tag == TYPE_ARRAY() || tag == TYPE_BITFIELD() || tag == TYPE_PRIMITIVE() || tag == TYPE_UNION() || tag == TYPE_ENUM() || tag == TYPE_FLAGS() || tag == TYPE_STRING()) { //TODO allow e.g. ret.append(readProperty(childElement, PROPERTY_NAME(), i18n(""))); } else { rootLogger->error(QString()).nospace() << "Unknown tag name in plugin " << mPluginName << " :" << tag; } } return ret; } QVector OsdParser::parseStructures() const { QFileInfo fileInfo(mAbsolutePath); QVector structures; QScopedPointer rootLogger(new ScriptLogger()); //only needed in we get an error right now QDomDocument document = openDoc(rootLogger.data()); if (document.isNull()) { structures.append(new TopLevelDataInformation( new DummyDataInformation(0, fileInfo.fileName()), rootLogger.take(), 0, fileInfo)); return structures; } QDomElement rootElem = document.firstChildElement(QStringLiteral("data")); if (rootElem.isNull()) { rootLogger->error() << "Missing top level element!"; structures.append(new TopLevelDataInformation( new DummyDataInformation(0, fileInfo.fileName()), rootLogger.take(), 0, fileInfo)); return structures; } int count = 1; for (QDomElement elem = rootElem.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.tagName() == TYPE_ENUMDEF()) continue; //skip enum defs QScriptEngine* eng = ScriptEngineInitializer::newEngine(); //we need this for dynamic arrays ScriptLogger* logger = new ScriptLogger(); QVector enums = parseEnums(rootElem, logger); OsdParserInfo info(QString(), logger, 0, eng, enums); DataInformation* data = parseElement(elem, info); if (!data) { QString name = readProperty(elem, PROPERTY_NAME()); if (name.isEmpty()) - name = fileInfo.absoluteFilePath() + QStringLiteral("_element") + QString::number(count); + name = fileInfo.absoluteFilePath() + QLatin1String("_element") + QString::number(count); qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Failed to parse element" << elem.tagName() << name; qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Parsing messages were:" << logger->messages(); data = new DummyDataInformation(0, name); } TopLevelDataInformation* topData = new TopLevelDataInformation(data, logger, eng, fileInfo); QString lockOffsetStr = readProperty(elem, PROPERTY_DEFAULT_LOCK_OFFSET()); if (!lockOffsetStr.isEmpty()) { ParsedNumber offset = ParserUtils::uint64FromString(lockOffsetStr); if (!offset.isValid) data->logError() << "Default lock offset is not a valid number:" << offset.string; else { data->logInfo() << "Default lock offset is " << offset.string; topData->setDefaultLockOffset(offset.value); } } structures.append(topData); count++; } return structures; } //TODO make type depend on the user not the definition QVector OsdParser::parseEnums(const QDomElement& rootElem, ScriptLogger* logger) { QVector ret; for (QDomElement elem = rootElem.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.tagName() != TYPE_ENUMDEF()) continue; QMap defs; const QString enumName = readProperty(elem, PROPERTY_NAME(), i18n("")); const QString typeStr = readProperty(elem, PROPERTY_TYPE()); if (typeStr.isEmpty()) { logger->error(enumName) << "Skipping enum definition, since no type attribute was found."; continue; } - LoggerWithContext lwc(logger, QStringLiteral("enum values (") + enumName + QLatin1Char(')')); + LoggerWithContext lwc(logger, QLatin1String("enum values (") + enumName + QLatin1Char(')')); PrimitiveDataType type = PrimitiveFactory::typeStringToType(typeStr, lwc); //handle all entries for (QDomElement child = elem.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) { - if (child.tagName() != QStringLiteral("entry")) + if (child.tagName() != QLatin1String("entry")) continue; QString name = readProperty(child, PROPERTY_NAME()); if (name.isEmpty()) { lwc.warn() << "Entry is missing name, skipping it!"; continue; } QString value = readProperty(child, PROPERTY_VALUE()); QPair converted = EnumDefinition::convertToEnumEntry(name, value, lwc, type); if (converted == QPair()) continue; defs.insert(converted.first, converted.second); } //now add this enum to the list of enums if (defs.isEmpty()) { lwc.error() << "Enum definition contains no valid elements!"; } else { EnumDefinition::Ptr enumDef = EnumDefinition::Ptr(new EnumDefinition(defs, enumName, type)); ret.append(enumDef); } } return ret; } //Datatypes ArrayDataInformation* OsdParser::arrayFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { ArrayParsedData apd(info); QString lengthStr = readProperty(xmlElem, PROPERTY_LENGTH()); if (lengthStr.isEmpty()) { info.error() << "No array length specified!"; return 0; } //must wrap in parentheses, cannot just evaluate. See https://bugreports.qt-project.org/browse/QTBUG-5757 const QScriptValue lengthFunc = ParserUtils::functionSafeEval(info.engine, lengthStr); if (lengthFunc.isValid()) { apd.length = lengthFunc; } else { apd.length = QScriptValue(lengthStr); } //first check whether there is a element and use the inner element //if that doesn't exist use the first child element as the type, but only if there is only one child apd.arrayType = parseType(xmlElem, info, NAME_ARRAY_TYPE()); if (!apd.arrayType) { //was not specified as element or type="attribute", use first child DummyDataInformation dummy(info.parent, info.name); //dummy so that we have a proper chain OsdChildrenParser typeParser(info, xmlElem.firstChildElement()); typeParser.setParent(&dummy); if (typeParser.hasNext()) { apd.arrayType = typeParser.next(); if (typeParser.hasNext()) { info.error() << "More than one possible type for array!"; delete apd.arrayType; apd.arrayType = 0; return 0; } } } return DataInformationFactory::newArray(apd); } DataInformation* OsdParser::parseChildElement(const QDomElement& xmlElem, const OsdParserInfo& info, const QString& name) { OsdParserInfo newInfo(info); //instantiate a dummy so that a propert chain up to the root element exists DummyDataInformation dummy(info.parent, info.name); newInfo.parent = &dummy; newInfo.name = name; return parseElement(xmlElem, newInfo); } DataInformation* OsdParser::parseType(const QDomElement& xmlElem, const OsdParserInfo& info, const QString& name) { const QString typeAttribute = xmlElem.attribute(PROPERTY_TYPE()); if (!typeAttribute.isEmpty()) { //type was specified as a primitive string LoggerWithContext lwc(info.logger, info.context() + name); DataInformation* ret = PrimitiveFactory::newInstance(name, typeAttribute, lwc); if (!ret) { info.error() << typeAttribute << "is not a valid type identifier"; } return ret; } //we have to parse the first child element of the element const QDomElement toParse = xmlElem.firstChildElement(PROPERTY_TYPE()).firstChildElement(); if (toParse.isNull()) { //don't log an error here, it may be okay (i.e. in arrays can be omitted) return 0; } if (!toParse.nextSiblingElement().isNull()) { info.warn() << " element has more than one child!"; } //TODO have this newInfo code only in one location DataInformation* ret = parseChildElement(toParse, info, name); if (!ret) { info.error() << "Failed to parse element defined in "; } return ret; } PointerDataInformation* OsdParser::pointerFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { PointerParsedData ppd(info); ppd.valueType = parseType(xmlElem, info, NAME_POINTER_VALUE_TYPE()); //first check whether there is a element and use the inner element //if that doesn't exist use the first child element as the type, but only if there is only one child QDomElement childElement = xmlElem.firstChildElement(PROPERTY_TARGET()).firstChildElement(); if (childElement.isNull()) { childElement = xmlElem.firstChildElement(); if (childElement.isNull()) { info.error() << "Pointer target is missing! Please add a child element."; return 0; } else if (childElement != xmlElem.lastChildElement()) { //there is more than one child element info.error() << "There is more than one child element, cannot determine which one " "is the pointer target. Wrap the correct one in a element."; return 0; } } ppd.pointerTarget = parseChildElement(childElement, info, NAME_POINTER_TARGET()); return DataInformationFactory::newPointer(ppd); } PrimitiveDataInformation* OsdParser::primitiveFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { PrimitiveParsedData ppd(info); ppd.type = readProperty(xmlElem, PROPERTY_TYPE()); return DataInformationFactory::newPrimitive(ppd); } AbstractBitfieldDataInformation* OsdParser::bitfieldFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { BitfieldParsedData bpd(info); bpd.type = readProperty(xmlElem, PROPERTY_TYPE()); QString width = readProperty(xmlElem, PROPERTY_WIDTH()); bpd.width = ParserUtils::intFromString(width); return DataInformationFactory::newBitfield(bpd); } inline UnionDataInformation* OsdParser::unionFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); return DataInformationFactory::newUnion(supd); } inline StructureDataInformation* OsdParser::structFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); return DataInformationFactory::newStruct(supd); } EnumDataInformation* OsdParser::enumFromXML(const QDomElement& xmlElem, bool isFlags, const OsdParserInfo& info) { EnumParsedData epd(info); epd.type = readProperty(xmlElem, PROPERTY_TYPE()); epd.enumName = readProperty(xmlElem, PROPERTY_ENUM_NAME()); if (epd.enumName.isEmpty()) epd.enumName = readProperty(xmlElem, TYPE_ENUM()); //used again here as property epd.enumDef = findEnum(epd.enumName, info); if (!epd.enumDef) { info.error().nospace() << "Enum definition '" << epd.enumName << "' does not exist!"; return 0; } if (isFlags) return DataInformationFactory::newFlags(epd); else return DataInformationFactory::newEnum(epd); } StringDataInformation* OsdParser::stringFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StringParsedData spd(info); spd.encoding = readProperty(xmlElem, PROPERTY_ENCODING()); spd.termination = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_TERMINATED_BY())); spd.maxByteCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_BYTE_COUNT())); spd.maxCharCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_CHAR_COUNT())); return DataInformationFactory::newString(spd); } DataInformation* OsdParser::parseElement(const QDomElement& elem, const OsdParserInfo& oldInfo) { Q_ASSERT(!elem.isNull()); DataInformation* data = 0; const QString tag = elem.tagName(); OsdParserInfo info(oldInfo); info.name = readProperty(elem, PROPERTY_NAME(), QStringLiteral("")); if (tag == TYPE_STRUCT()) data = structFromXML(elem, info); else if (tag == TYPE_ARRAY()) data = arrayFromXML(elem, info); else if (tag == TYPE_BITFIELD()) data = bitfieldFromXML(elem, info); else if (tag == TYPE_PRIMITIVE()) data = primitiveFromXML(elem, info); else if (tag == TYPE_UNION()) data = unionFromXML(elem, info); else if (tag == TYPE_ENUM()) data = enumFromXML(elem, false, info); else if (tag == TYPE_FLAGS()) data = enumFromXML(elem, true, info); else if (tag == TYPE_STRING()) data = stringFromXML(elem, info); else if (tag == TYPE_POINTER()) data = pointerFromXML(elem, info); else if (tag == TYPE_TAGGED_UNION()) data = taggedUnionFromXML(elem, info); else { LoggerWithContext lwc(info.logger, info.context()); //use the type tag as a primitive type data = PrimitiveFactory::newInstance(info.name, tag, lwc); if (!data) { info.error() << "Cannot parse unknown tag: " << tag; } } if (data) { CommonParsedData cpd(info); QString byteOrderStr = readProperty(elem, PROPERTY_BYTEORDER()); if (!byteOrderStr.isEmpty()) cpd.endianess = ParserUtils::byteOrderFromString(byteOrderStr, LoggerWithContext(info.logger, info.context())); cpd.updateFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_UPDATE_FUNC())); cpd.validationFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_VALIDATION_FUNC())); cpd.toStringFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_TO_STRING_FUNC())); cpd.customTypeName = readProperty(elem, PROPERTY_CUSTOM_TYPE_NAME()); if (!DataInformationFactory::commonInitialization(data, cpd)) { delete data; //error message has already been logged return 0; } } return data; } EnumDefinition::Ptr OsdParser::findEnum(const QString& defName, const OsdParserInfo& info) { for (int i = 0; i < info.enums.size(); ++i) { const EnumDefinition::Ptr def = info.enums.at(i); if (def->name() == defName) return def; } info.error() << "Could not find enum definition with name" << defName; return EnumDefinition::Ptr(0); } QString OsdParser::readProperty(const QDomElement& elem, const QString& property, const QString& defaultVal) { const QString attrib = elem.attribute(property); if (!attrib.isEmpty()) return attrib; //check for element now const QDomElement childElem = elem.firstChildElement(property); if (!elem.isNull()) return elem.text(); else return defaultVal; } TaggedUnionDataInformation* OsdParser::taggedUnionFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { TaggedUnionParsedData tpd(info); //can be null QDomElement defaultChildren = xmlElem.firstChildElement(PROPERTY_DEFAULT_CHILDREN()).firstChildElement(); if (defaultChildren.isNull()) info.info() << "No default fields specified, defaulting to none."; tpd.defaultFields.reset(new OsdChildrenParser(info, defaultChildren)); tpd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); //now handle alternatives QDomElement alternatives = xmlElem.firstChildElement(PROPERTY_ALTERNATIVES()); if (alternatives.isNull()) { info.error() << "Missing element, tagged union cannot exist without at least one alternative"; return 0; } for (QDomElement elem = alternatives.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { TaggedUnionParsedData::Alternatives alt; alt.name = readProperty(elem, PROPERTY_STRUCT_NAME()); QString selectIfStr = readProperty(elem, PROPERTY_SELECT_IF()); QScriptValue selectIf = ParserUtils::functionSafeEval(info.engine, selectIfStr); if (!selectIf.isValid()) selectIf = selectIfStr; alt.selectIf = selectIf; if (elem.tagName() == TYPE_GROUP()) alt.fields = QSharedPointer(new OsdChildrenParser(info, elem.firstChildElement())); else alt.fields = QSharedPointer(new SingleElementOsdChildrenParser(info, elem)); tpd.alternatives.append(alt); } return DataInformationFactory::newTaggedUnion(tpd); } OsdChildrenParser::OsdChildrenParser(const OsdParserInfo& info, QDomElement firstChild) : mInfo(info), mElem(firstChild) { } DataInformation* OsdChildrenParser::next() { Q_ASSERT(!mElem.isNull()); //skip all known properties const QStringList allProperties = ALL_PROPERTIES(); while (allProperties.contains(mElem.tagName())) mElem = mElem.nextSiblingElement(); if (mElem.isNull()) { mInfo.warn() << "Reached end of fields, but next() was requested!"; return 0; } DataInformation* ret = OsdParser::parseElement(mElem, mInfo); mElem = mElem.nextSiblingElement(); return ret; } OsdChildrenParser::~OsdChildrenParser() { } bool OsdChildrenParser::hasNext() { if (mElem.isNull()) return false; const QStringList allProperties = ALL_PROPERTIES(); while (allProperties.contains(mElem.tagName())) mElem = mElem.nextSiblingElement(); //skip known properties return !mElem.isNull(); } void OsdChildrenParser::setParent(DataInformation* newParent) { mInfo.parent = newParent; } SingleElementOsdChildrenParser::SingleElementOsdChildrenParser(const OsdParserInfo& info, QDomElement element) : OsdChildrenParser(info, element), mParsed(false) { if (mElem.isNull()) info.warn() << "Null Element passed to child parser!"; } SingleElementOsdChildrenParser::~SingleElementOsdChildrenParser() { } DataInformation* SingleElementOsdChildrenParser::next() { Q_ASSERT(!mParsed); mParsed = true; return OsdParser::parseElement(mElem, mInfo); } bool SingleElementOsdChildrenParser::hasNext() { return !mParsed && !mElem.isNull(); } diff --git a/kasten/controllers/view/structures/parsers/parserutils.cpp b/kasten/controllers/view/structures/parsers/parserutils.cpp index 2f223a21..d2c6a601 100644 --- a/kasten/controllers/view/structures/parsers/parserutils.cpp +++ b/kasten/controllers/view/structures/parsers/parserutils.cpp @@ -1,273 +1,273 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * Copyright 2016 Aaron Bishop * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "parserutils.h" #include #include namespace ParserStrings { QString TYPE_ARRAY() { return QStringLiteral("array"); } QString TYPE_BITFIELD() { return QStringLiteral("bitfield"); } QString TYPE_ENUM() { return QStringLiteral("enum"); } QString TYPE_FLAGS() { return QStringLiteral("flags"); } QString TYPE_PRIMITIVE() { return QStringLiteral("primitive"); } QString TYPE_STRING() { return QStringLiteral("string"); } QString TYPE_STRUCT() { return QStringLiteral("struct"); } QString TYPE_UNION() { return QStringLiteral("union"); } QString TYPE_POINTER() { return QStringLiteral("pointer"); } QString TYPE_TAGGED_UNION() { return QStringLiteral("taggedUnion"); } QString TYPE_ENUMDEF() { return QStringLiteral("enumDef"); } QString TYPE_ALTERNATIVES() { return QStringLiteral("alternatives"); } QString TYPE_GROUP() { return QStringLiteral("group"); } QString PROPERTY_DEFAULT_LOCK_OFFSET() { return QStringLiteral("defaultLockOffset"); } QString PROPERTY_NAME() { return QStringLiteral("name"); } QString PROPERTY_BYTEORDER() { return QStringLiteral("byteOrder"); } QString PROPERTY_PARENT() { return QStringLiteral("parent"); } QString PROPERTY_VALIDATION_ERROR() { return QStringLiteral("validationError"); } QString PROPERTY_VALID() { return QStringLiteral("valid"); } QString PROPERTY_ABLE_TO_READ() { return QStringLiteral("wasAbleToRead"); } QString PROPERTY_UPDATE_FUNC() { return QStringLiteral("updateFunc"); } QString PROPERTY_VALIDATION_FUNC() { return QStringLiteral("validationFunc"); } QString PROPERTY_TO_STRING_FUNC() { return QStringLiteral("toStringFunc"); } QString PROPERTY_DATATYPE() { return QStringLiteral("datatype"); } QString PROPERTY_CUSTOM_TYPE_NAME() { return QStringLiteral("typeName"); } QString PROPERTY_ENUM_VALUES() { return QStringLiteral("enumValues"); } QString PROPERTY_ENUM_NAME() { return QStringLiteral("enumName"); } QString PROPERTY_TYPE() { return QStringLiteral("type"); } QString PROPERTY_LENGTH() { return QStringLiteral("length"); } QString PROPERTY_WIDTH() { return QStringLiteral("width"); } QString PROPERTY_CHILDREN() { return QStringLiteral("fields"); } QString PROPERTY_CHILD_COUNT() { return QStringLiteral("childCount"); } QString PROPERTY_CHILD() { return QStringLiteral("child"); } QString PROPERTY_CHAR_COUNT() { return QStringLiteral("charCount"); } QString PROPERTY_BYTE_COUNT() { return QStringLiteral("byteCount"); } QString PROPERTY_MAX_CHAR_COUNT() { return QStringLiteral("maxCharCount"); } QString PROPERTY_MAX_BYTE_COUNT() { return QStringLiteral("maxByteCount"); } QString PROPERTY_TERMINATED_BY() { return QStringLiteral("terminatedBy"); } QString PROPERTY_ENCODING() { return QStringLiteral("encoding"); } //primitive QString PROPERTY_VALUE() { return QStringLiteral("value"); } //pointer QString PROPERTY_TARGET() { return QStringLiteral("target"); } //tagged union QString PROPERTY_ALTERNATIVES() { return QStringLiteral("alternatives"); } QString PROPERTY_DEFAULT_CHILDREN() { return QStringLiteral("defaultFields"); } QString PROPERTY_SELECT_IF() { return QStringLiteral("selectIf"); } QString PROPERTY_STRUCT_NAME() { return QStringLiteral("structName"); } QString PROPERTY_INTERNAL_TYPE() { return QStringLiteral("__type"); } QStringList ALL_PROPERTIES() { return QStringList() << PROPERTY_ABLE_TO_READ() << PROPERTY_ALTERNATIVES() << PROPERTY_BYTEORDER() << PROPERTY_BYTE_COUNT() << PROPERTY_CHAR_COUNT() << PROPERTY_CHAR_COUNT() << PROPERTY_CHILD() << PROPERTY_CHILDREN() << PROPERTY_CHILD_COUNT() << PROPERTY_DATATYPE() << PROPERTY_DEFAULT_CHILDREN() << PROPERTY_ENCODING() << PROPERTY_ENUM_NAME() << PROPERTY_ENUM_VALUES() << PROPERTY_INTERNAL_TYPE() << PROPERTY_LENGTH() << PROPERTY_MAX_BYTE_COUNT() << PROPERTY_MAX_CHAR_COUNT() << PROPERTY_NAME() << PROPERTY_PARENT() << PROPERTY_SELECT_IF() << PROPERTY_STRUCT_NAME() << PROPERTY_TARGET() << PROPERTY_TERMINATED_BY() << PROPERTY_TYPE() << PROPERTY_UPDATE_FUNC() << PROPERTY_VALID() << PROPERTY_VALIDATION_ERROR() << PROPERTY_VALIDATION_FUNC() << PROPERTY_VALUE() << PROPERTY_WIDTH(); } QString NAME_POINTER_VALUE_TYPE() { return QStringLiteral(""); } QString NAME_POINTER_TARGET() { return QStringLiteral(""); } QString NAME_ARRAY_TYPE() { return QStringLiteral(""); } } ParsedNumber ParserUtils::intFromString(const QString& str) { int value = 0; bool okay = false; - if (str.startsWith(QStringLiteral("0x"))) + if (str.startsWith(QLatin1String("0x"))) value = str.mid(2).toInt(&okay, 16); - else if (str.startsWith(QStringLiteral("-0x"))) + else if (str.startsWith(QLatin1String("-0x"))) { //special case for minimum possible value - if (str == QStringLiteral("-0x80000000")) + if (str == QLatin1String("-0x80000000")) return ParsedNumber(-0x80000000, str, true); value = -str.mid(3).toInt(&okay, 16); } else value = str.toInt(&okay, 10); return ParsedNumber(value, str, okay); } ParsedNumber ParserUtils::uintFromString(const QString& str) { uint value = 0; bool okay; - if (str.startsWith(QStringLiteral("0x"))) + if (str.startsWith(QLatin1String("0x"))) value = str.mid(2).toUInt(&okay, 16); else value = str.toUInt(&okay, 10); return ParsedNumber(value, str, okay); } ParsedNumber ParserUtils::uint64FromString(const QString& str) { quint64 value = 0; bool okay; - if (str.startsWith(QStringLiteral("0x"))) + if (str.startsWith(QLatin1String("0x"))) value = str.mid(2).toULongLong(&okay, 16); else value = str.toULongLong(&okay, 10); return ParsedNumber(value, str, okay); } DataInformation::DataInformationEndianess ParserUtils::byteOrderFromString(const QString& string, const LoggerWithContext& logger) { const QString lower = string.toLower(); - if (lower == QStringLiteral("bigendian") || lower == QStringLiteral("big-endian")) + if (lower == QLatin1String("bigendian") || lower == QLatin1String("big-endian")) return DataInformation::EndianessBig; - else if (lower == QStringLiteral("littleendian") || lower == QStringLiteral("little-endian")) + else if (lower == QLatin1String("littleendian") || lower == QLatin1String("little-endian")) return DataInformation::EndianessLittle; - else if (lower == QStringLiteral("fromsettings") || lower == QStringLiteral("from-settings")) + else if (lower == QLatin1String("fromsettings") || lower == QLatin1String("from-settings")) return DataInformation::EndianessFromSettings; - else if (lower == QStringLiteral("inherit")) + else if (lower == QLatin1String("inherit")) return DataInformation::EndianessInherit; else { logger.warn().nospace() << "Unrecognized byte order '" << string << "', defaulting to 'inherit'"; return DataInformation::EndianessInherit; } } ParsedNumber ParserUtils::intFromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const qsreal doubleVal = val.toNumber(); const int value = val.toInt32(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return intFromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } ParsedNumber ParserUtils::uintFromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const uint value = val.toUInt32(); const qsreal doubleVal = val.toNumber(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return uintFromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } ParsedNumber ParserUtils::uint64FromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const uint value = val.toUInt32(); const qsreal doubleVal = val.toNumber(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return uint64FromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } QString ParserUtils::byteOrderToString(DataInformation::DataInformationEndianess order) { if (order == DataInformation::EndianessLittle) return QStringLiteral("littleEndian"); if (order == DataInformation::EndianessBig) return QStringLiteral("bigEndian"); if (order == DataInformation::EndianessFromSettings) return QStringLiteral("fromSettings"); return QStringLiteral("inherit"); } StringDataInformation::StringType ParserUtils::toStringEncoding(const QString& str, const LoggerWithContext& logger) { QString enc = str.toLower(); - if (enc == QStringLiteral("ascii")) + if (enc == QLatin1String("ascii")) return StringDataInformation::ASCII; - else if (enc == QStringLiteral("ebcdic")) + else if (enc == QLatin1String("ebcdic")) return StringDataInformation::EBCDIC; - else if (enc == QStringLiteral("latin1") || enc == QStringLiteral("latin-1")) + else if (enc == QLatin1String("latin1") || enc == QLatin1String("latin-1")) return StringDataInformation::Latin1; - else if (enc.startsWith(QStringLiteral("utf"))) + else if (enc.startsWith(QLatin1String("utf"))) { QStringRef ref = enc.midRef(3); if (ref.at(0) == QLatin1Char('-')) ref = enc.midRef(4); //strip '-' - if (ref == QStringLiteral("8")) + if (ref == QLatin1String("8")) return StringDataInformation::UTF8; - if (ref == QStringLiteral("16") || ref == QStringLiteral("16le") || ref == QStringLiteral("16-le")) + if (ref == QLatin1String("16") || ref == QLatin1String("16le") || ref == QLatin1String("16-le")) { return StringDataInformation::UTF16_LE; } - if (ref == QStringLiteral("16be") || ref == QStringLiteral("16-be")) + if (ref == QLatin1String("16be") || ref == QLatin1String("16-be")) { return StringDataInformation::UTF16_BE; } - if (ref == QStringLiteral("32") || ref == QStringLiteral("32le") || ref == QStringLiteral("32-le")) + if (ref == QLatin1String("32") || ref == QLatin1String("32le") || ref == QLatin1String("32-le")) { return StringDataInformation::UTF32_LE; } - if (ref == QStringLiteral("32be") || ref == QStringLiteral("32-be")) + if (ref == QLatin1String("32be") || ref == QLatin1String("32-be")) { return StringDataInformation::UTF32_BE; } } logger.warn() << "Unrecognized string encoding: " << enc; return StringDataInformation::InvalidEncoding; } QScriptValue ParserUtils::functionSafeEval(QScriptEngine* engine, const QString& str) { if (str.isEmpty()) return QScriptValue(); //must wrap in parentheses, see https://bugreports.qt-project.org/browse/QTBUG-5757 QScriptValue ret = engine->evaluate(QLatin1Char('(') + str + QLatin1Char(')')); if (!ret.isFunction()) return QScriptValue(str); return ret; } diff --git a/kasten/controllers/view/structures/parsers/scriptvalueconverter.cpp b/kasten/controllers/view/structures/parsers/scriptvalueconverter.cpp index dd939132..e8161fa8 100644 --- a/kasten/controllers/view/structures/parsers/scriptvalueconverter.cpp +++ b/kasten/controllers/view/structures/parsers/scriptvalueconverter.cpp @@ -1,68 +1,68 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptvalueconverter.h" #include "scriptvalueconverter_p.h" #include "../script/scriptlogger.h" #include #include #include #include #include namespace ScriptValueConverter { DataInformation* convert(const QScriptValue& value, const QString& name, ScriptLogger* logger, DataInformation* parent) { //TODO Q_CHECK_PTR(parent) const ParserInfo info(name, logger, parent, value.engine()); return toDataInformation(value, info); //could be NULL } QVector convertValues(const QScriptValue& value, ScriptLogger* logger, DataInformation* parent) { //TODO Q_CHECK_PTR(parent); QVector ret; QScriptValueIterator it(value); const bool isArray = value.isArray(); while (it.hasNext()) { it.next(); - if (isArray && it.name() == QStringLiteral("length")) + if (isArray && it.name() == QLatin1String("length")) continue; //skip the length property of arrays const ParserInfo info(it.name(), logger, parent, value.engine()); DataInformation* inf = toDataInformation(it.value(), info); if (inf) ret.append(inf); else //TODO remove the null check once parent must be nonnull logger->info(parent ? parent->fullObjectPath() : QString()).nospace() << "Could not convert property '" << it.name() << "'."; } return ret; } } //namespace ScriptValueConverter diff --git a/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp b/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp index 1912b30c..eeb34461 100644 --- a/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp +++ b/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp @@ -1,319 +1,319 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptvalueconverter.h" #include "scriptvalueconverter_p.h" #include "datainformationfactory.h" #include "parserutils.h" #include "../datatypes/uniondatainformation.h" #include "../datatypes/structuredatainformation.h" #include "../datatypes/strings/stringdata.h" #include "../datatypes/strings/stringdatainformation.h" #include "../script/scriptlogger.h" using namespace ParserStrings; namespace ScriptValueConverter { DataInformation* toDataInformation(const QScriptValue& value, const ParserInfo& oldInfo) { if (!value.isValid()) { oldInfo.error() << "invalid value passed!"; return 0; } ParserInfo info(oldInfo); QString nameOverride = value.property(PROPERTY_NAME()).toString(); if (!nameOverride.isEmpty()) info.name = nameOverride; //check function array and date, since they are objects too if (value.isRegExp()) { //apparently regexp is a function info.error() << "Cannot convert a RegExp object to DataInformation!"; return 0; } if (value.isFunction()) { info.error() << "Cannot convert a Function object to DataInformation!"; return 0; } if (value.isArray()) { info.error() << "Cannot convert a Array object to DataInformation!"; return 0; } if (value.isDate()) { info.error() << "Cannot convert a Date object to DataInformation!"; return 0; } if (value.isError()) { info.error() << "Cannot convert a Error object to DataInformation!"; return 0; } //variant and qobject are also object types, however they cannot appear from user code, no need to check //if it is a string, we convert to primitive type, if not it has to be an object if (value.isString()) return toPrimitive(value, info); //a type string is also okay if (!value.isObject()) { if (value.isBool()) info.error() << "Cannot convert Boolean to DataInformation!"; else if (value.isNull()) info.error() << "Cannot convert null to DataInformation!"; else if (value.isUndefined()) info.error() << "Cannot convert undefined to DataInformation!"; else if (value.isNumber()) info.error() << "Cannot convert Number to DataInformation!"; else info.error() << "Cannot convert object of unknown type to DataInformation!"; return 0; //no point trying to convert } QString type = value.property(PROPERTY_INTERNAL_TYPE()).toString(); if (type.isEmpty()) { info.error() << "Cannot convert object since type of object could not be determined!"; return 0; } DataInformation* returnVal = 0; if (type == TYPE_ARRAY()) returnVal = toArray(value, info); else if (type == TYPE_STRUCT()) returnVal = toStruct(value, info); else if (type == TYPE_UNION()) returnVal = toUnion(value, info); else if (type == TYPE_BITFIELD()) returnVal = toBitfield(value, info); else if (type == TYPE_ENUM()) returnVal = toEnum(value, false, info); else if (type == TYPE_FLAGS()) returnVal = toEnum(value, true, info); else if (type == TYPE_STRING()) returnVal = toString(value, info); else if (type == TYPE_POINTER()) returnVal = toPointer(value, info); else if (type == TYPE_TAGGED_UNION()) returnVal = toTaggedUnion(value, info); else if (type == TYPE_PRIMITIVE()) returnVal = toPrimitive(value, info); else info.error() << "Unknown type:" << type; if (returnVal) { CommonParsedData cpd(info); QString byteOrderStr = value.property(PROPERTY_BYTEORDER()).toString(); if (!byteOrderStr.isEmpty()) cpd.endianess = ParserUtils::byteOrderFromString(byteOrderStr, LoggerWithContext(info.logger, info.context())); cpd.updateFunc = value.property(PROPERTY_UPDATE_FUNC()); cpd.validationFunc = value.property(PROPERTY_VALIDATION_FUNC()); cpd.toStringFunc = value.property(PROPERTY_TO_STRING_FUNC()); cpd.customTypeName = value.property(PROPERTY_CUSTOM_TYPE_NAME()).toString(); if (!DataInformationFactory::commonInitialization(returnVal, cpd)) { delete returnVal; //error message has already been logged return 0; } } return returnVal; } ArrayDataInformation* toArray(const QScriptValue& value, const ParserInfo& info) { ArrayParsedData apd(info); apd.length = value.property(PROPERTY_LENGTH()); QScriptValue childType = value.property(PROPERTY_TYPE()); ParserInfo childInfo(info); DummyDataInformation dummy(info.parent, info.name + QLatin1Char('.') + NAME_ARRAY_TYPE()); childInfo.parent = &dummy; apd.arrayType = toDataInformation(childType, childInfo); return DataInformationFactory::newArray(apd); } AbstractBitfieldDataInformation* toBitfield(const QScriptValue& value, const ParserInfo& info) { BitfieldParsedData bpd(info); bpd.type = value.property(PROPERTY_TYPE()).toString(); bpd.width = ParserUtils::intFromScriptValue(value.property(PROPERTY_WIDTH())); return DataInformationFactory::newBitfield(bpd); } PrimitiveDataInformation* toPrimitive(const QScriptValue& value, const ParserInfo& info) { PrimitiveParsedData ppd(info); ppd.type = value.isString() ? value.toString() : value.property(PROPERTY_TYPE()).toString(); return DataInformationFactory::newPrimitive(ppd); } StructureDataInformation* toStruct(const QScriptValue& value, const ParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); return DataInformationFactory::newStruct(supd); } UnionDataInformation* toUnion(const QScriptValue& value, const ParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); return DataInformationFactory::newUnion(supd);} PointerDataInformation* toPointer(const QScriptValue& value, const ParserInfo& info) { PointerParsedData ppd(info); ParserInfo childInfo(info); DummyDataInformation dummy(info.parent, info.name); childInfo.parent = &dummy; childInfo.name = NAME_POINTER_TARGET(); ppd.pointerTarget = toDataInformation(value.property(PROPERTY_TARGET()), childInfo); childInfo.name = NAME_POINTER_VALUE_TYPE(); ppd.valueType = toDataInformation(value.property(PROPERTY_TYPE()), childInfo); return DataInformationFactory::newPointer(ppd); } EnumDataInformation* toEnum(const QScriptValue& value, bool flags, const ParserInfo& info) { EnumParsedData epd(info); QScriptValue enumType = value.property(PROPERTY_TYPE()); if (enumType.isString()) epd.type = enumType.toString(); else if (enumType.isObject()) epd.type = enumType.property(PROPERTY_TYPE()).toString(); //else it stays empty epd.enumName = value.property(PROPERTY_ENUM_NAME()).toString(); epd.enumValuesObject = value.property(PROPERTY_ENUM_VALUES()); if (flags) return DataInformationFactory::newFlags(epd); else return DataInformationFactory::newEnum(epd); } StringDataInformation* toString(const QScriptValue& value, const ParserInfo& info) { StringParsedData spd(info); spd.encoding = value.property(PROPERTY_ENCODING()).toString(); spd.termination = ParserUtils::uintFromScriptValue(value.property(PROPERTY_TERMINATED_BY())); spd.maxByteCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_BYTE_COUNT())); spd.maxCharCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_CHAR_COUNT())); return DataInformationFactory::newString(spd); } TaggedUnionDataInformation* toTaggedUnion(const QScriptValue& value, const ParserInfo& info) { TaggedUnionParsedData tpd(info); QScriptValue alternatives = value.property(PROPERTY_ALTERNATIVES()); if (!alternatives.isArray()) { info.error() << "Alternatives must be an array!"; return 0; } int length = alternatives.property(PROPERTY_LENGTH()).toInt32(); for (int i = 0; i < length; ++i) { TaggedUnionParsedData::Alternatives alt; QScriptValue current = alternatives.property(i); alt.name = current.property(PROPERTY_STRUCT_NAME()).toString(); alt.selectIf = current.property(PROPERTY_SELECT_IF()); alt.fields = QSharedPointer( new ScriptValueChildrenParser(info, current.property(PROPERTY_CHILDREN()))); tpd.alternatives.append(alt); } tpd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); tpd.defaultFields.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_DEFAULT_CHILDREN()))); return DataInformationFactory::newTaggedUnion(tpd); } } //namespace ScriptValueConverter ScriptValueConverter::ScriptValueChildrenParser::ScriptValueChildrenParser(const ParserInfo& info, const QScriptValue& children) : mValue(children), mIter(children), mInfo(info) { } ScriptValueConverter::ScriptValueChildrenParser::~ScriptValueChildrenParser() { } DataInformation* ScriptValueConverter::ScriptValueChildrenParser::next() { Q_ASSERT(hasNext()); mIter.next(); - if (mValue.isArray() && mIter.name() == QStringLiteral("length")) + if (mValue.isArray() && mIter.name() == QLatin1String("length")) mIter.next(); //skip length property mInfo.name = mIter.name(); return toDataInformation(mIter.value(), mInfo); } bool ScriptValueConverter::ScriptValueChildrenParser::hasNext() { if (!mIter.hasNext()) return false; if (mValue.isArray()) { //check if next element is length property mIter.next(); - if (mIter.name() != QStringLiteral("length")) + if (mIter.name() != QLatin1String("length")) { mIter.previous(); //go back and return true return true; } else { return mIter.hasNext(); //skipped length } } else { return true; } } void ScriptValueConverter::ScriptValueChildrenParser::setParent(DataInformation* newParent) { mInfo.parent = newParent; } diff --git a/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp b/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp index 2c96e0e3..bf9e142e 100644 --- a/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp @@ -1,498 +1,498 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011, 2012, 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "defaultscriptclass.h" #include "../../datatypes/datainformation.h" #include "../../datatypes/topleveldatainformation.h" #include "../../datatypes/uniondatainformation.h" #include "../../datatypes/structuredatainformation.h" #include "../../datatypes/primitive/pointerdatainformation.h" #include "../../parsers/parserutils.h" #include "../../parsers/scriptvalueconverter.h" #include "../scriptlogger.h" #include "../scripthandlerinfo.h" #include "../safereference.h" #include "../../structlogging.h" DefaultScriptClass::DefaultScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : QScriptClass(engine), mHandlerInfo(handlerInfo) { s_valid = engine->toStringHandle(ParserStrings::PROPERTY_VALID()); s_wasAbleToRead = engine->toStringHandle(ParserStrings::PROPERTY_ABLE_TO_READ()); s_validationError = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_ERROR()); s_parent = engine->toStringHandle(ParserStrings::PROPERTY_PARENT()); s_byteOrder = engine->toStringHandle(ParserStrings::PROPERTY_BYTEORDER()); s_name = engine->toStringHandle(ParserStrings::PROPERTY_NAME()); s_datatype = engine->toStringHandle(ParserStrings::PROPERTY_DATATYPE()); s_updateFunc = engine->toStringHandle(ParserStrings::PROPERTY_UPDATE_FUNC()); s_validationFunc = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_FUNC()); s_customTypeName = engine->toStringHandle(ParserStrings::PROPERTY_CUSTOM_TYPE_NAME()); s_asStringFunc = engine->toStringHandle(ParserStrings::PROPERTY_TO_STRING_FUNC()); //TODO remove, every subclass should have proto mDefaultPrototype = engine->newObject(); mDefaultPrototype.setProperty(QStringLiteral("toString"), engine->newFunction(Default_proto_toString)); //add all our properties mIterableProperties.append(qMakePair(s_parent, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_name, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_wasAbleToRead, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_byteOrder, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_valid, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_validationError, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_validationFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_updateFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_datatype, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_customTypeName, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_asStringFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); } DefaultScriptClass::~DefaultScriptClass() { } DataInformation* DefaultScriptClass::toDataInformation(const QScriptValue& obj) { if (!obj.scriptClass()) return 0; Q_ASSERT(obj.data().isVariant()); const QVariant variant = obj.data().toVariant(); if (variant.isValid() && variant.canConvert() && variant.userType() == qMetaTypeId()) { const SafeReference& ref = *reinterpret_cast(variant.constData()); return ref.data(); } return 0; } QScriptClass::QueryFlags DefaultScriptClass::queryProperty(const QScriptValue& object, const QScriptString& name, QScriptClass::QueryFlags flags, uint* id) { const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return 0; } if (name == s_valid || name == s_validationError) { return mode == ScriptHandlerInfo::Validating ? flags : flags & ~HandlesWriteAccess; } if (mode != ScriptHandlerInfo::Updating) { //the only properties that are possibly writable when not updating are valid and validationError //but we checked them before so we remove handlesWriteAccess from the flags flags &= ~HandlesWriteAccess; } if (name == s_byteOrder || name == s_name || name == s_updateFunc || name == s_validationFunc || name == s_datatype || name == s_customTypeName || name == s_asStringFunc) { return flags; } else if (name == s_wasAbleToRead || name == s_parent) { return flags & ~HandlesWriteAccess; } else if (queryAdditionalProperty(data, name, &flags, id)) { return flags; } else { data->logError() << "could not find property with name" << name.toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, - QStringLiteral("Could not find property with name ") + name.toString()); + QLatin1String("Could not find property with name ") + name.toString()); return 0; } } QScriptValue DefaultScriptClass::property(const QScriptValue& object, const QScriptString& name, uint id) { Q_ASSERT(mHandlerInfo->mode() != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); return engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); } if (name == s_valid) { return data->validationSuccessful(); } else if (name == s_wasAbleToRead) { return data->wasAbleToRead(); } else if (name == s_parent) { Q_CHECK_PTR(data->parent()); //parent() cannot be null if (data->parent()->isTopLevel()) return engine()->nullValue(); return data->parent()->asDataInformation()->toScriptValue(engine(), mHandlerInfo); } else if (name == s_datatype) { return data->typeName(); } else if (name == s_updateFunc) { return data->updateFunc(); } else if (name == s_validationFunc) { return data->validationFunc(); } else if (name == s_validationError) { return data->validationError(); } else if (name == s_byteOrder) { return ParserUtils::byteOrderToString(data->byteOrder()); } else if (name == s_name) { return data->name(); } else if (name == s_customTypeName) { return data->typeName(); } else if (name == s_asStringFunc) { return data->toStringFunction(); } QScriptValue other = additionalProperty(data, name, id); if (other.isValid()) return other; else { data->logError() << "could not find property with name" << name.toString(); return engine()->currentContext()->throwError(QScriptContext::ReferenceError, - QStringLiteral("Cannot read property ") + name.toString()); + QLatin1String("Cannot read property ") + name.toString()); } } void DefaultScriptClass::setDataType(const QScriptValue& value, DataInformation* data) { DataInformation* thisObj = toDataInformation(engine()->currentContext()->thisObject()); Q_CHECK_PTR(thisObj); const bool isThisObj = thisObj == data; //this object always has mHasBeenUpdated set just before calling updateFunc, so in that case it is okay if (data->hasBeenUpdated() && !isThisObj) { //this element has already been updated (and probably read, replacing it could cause crazy errors data->logError() << "Attempting to replace an already updated object. This could cause errors." "Current this object: " << (thisObj ? thisObj->fullObjectPath() : QString()); return; } //change the type of the underlying object DataInformation* newType = ScriptValueConverter::convert(value, data->name(), data->logger(), data); if (!newType) { data->logError() << "Failed to set new type, could not convert value!"; return; } DataInformationBase* parent = data->parent(); Q_CHECK_PTR(parent); TopLevelDataInformation* top = data->topLevelDataInformation(); Q_CHECK_PTR(top); //only if parent is toplevel, struct or union, can we replace bool replaced = false; if (parent->isTopLevel()) { Q_ASSERT(isThisObj); //we can only do this if we are currently at the top level element parent->asTopLevel()->setActualDataInformation(newType); replaced = true; } else if (parent->isStruct()) { StructureDataInformation* stru = parent->asStruct(); int index = stru->indexOf(data); Q_ASSERT(index != -1); Q_ASSERT(uint(index) < stru->childCount()); replaced = stru->replaceChildAt(index, newType); if (!replaced) stru->logError() << "failed to replace child at index" << index; } else if (parent->isUnion()) { UnionDataInformation* un = parent->asUnion(); int index = un->indexOf(data); Q_ASSERT(index != -1); Q_ASSERT(uint(index) < un->childCount()); replaced = un->replaceChildAt(index, newType); if (!replaced) un->logError() << "failed to replace child at index" << index; } else if (parent->isPointer()) { parent->asPointer()->setPointerTarget(newType); replaced = true; } else { data->logError() << "Failed to set data type since element is not toplevel and parent" " is neither struct nor union nor pointer."; } if (replaced) { top->setChildDataChanged(); //if the current object was "this" in javascript we have to replace it if (isThisObj) engine()->currentContext()->setThisObject(newType->toScriptValue(engine(), mHandlerInfo)); newType->mHasBeenUpdated = true; } else { delete newType; //could not set new type } } void DefaultScriptClass::setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) { const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return; } if (mode == ScriptHandlerInfo::Validating) { //only way write access is allowed is when validating: valid and validationError if (data->hasBeenValidated()) data->logError() << "Cannot modify this object, it has already been validated!"; else if (name == s_valid) data->mValidationSuccessful = value.toBool(); else if (name == s_validationError) data->setValidationError(value.toString()); else data->logError() << "Cannot write to property" << name.toString() << "while validating!"; return; } if (mode != ScriptHandlerInfo::Updating) { data->logError() << "Writing to property" << name.toString() << "is only allowed when updating."; return; } Q_ASSERT(mode == ScriptHandlerInfo::Updating); if (name == s_byteOrder) { data->setByteOrder(ParserUtils::byteOrderFromString(value.toString(), LoggerWithContext(data->logger(), data->fullObjectPath()))); } else if (name == s_datatype) { //change the type of the underlying object setDataType(value, data); } else if (name == s_updateFunc) { data->setUpdateFunc(value); } else if (name == s_validationFunc) { data->setValidationFunc(value); } else if (name == s_name) { data->setName(value.toString()); } else if (name == s_customTypeName) { if (!value.isValid() || value.isNull() || value.isUndefined()) data->setCustomTypeName(QString()); //unset else data->setCustomTypeName(value.toString()); } else if (name == s_asStringFunc) { data->setToStringFunction(value); } else { bool setAdditional = setAdditionalProperty(data, name, id, value); if (setAdditional) return; else { data->logError() << "could not set property with name" << name.toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, - QStringLiteral("Cannot write property ") + name.toString()); + QLatin1String("Cannot write property ") + name.toString()); } } } QScriptValue::PropertyFlags DefaultScriptClass::propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) { QScriptValue::PropertyFlags result; const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return 0; } if (name == s_valid || name == s_validationError) { if (mode != ScriptHandlerInfo::Validating) result |= QScriptValue::ReadOnly; } else if (mode != ScriptHandlerInfo::Updating) { result |= QScriptValue::ReadOnly; } for (int i = 0, size = mIterableProperties.size(); i < size; ++i) { if (mIterableProperties.at(i).first == name) return result | mIterableProperties.at(i).second; } if (additionalPropertyFlags(data, name, id, &result)) return result; //is a child element else { data->logError() << "could not find flags for property with name" << name.toString(); return 0; } } QScriptValue DefaultScriptClass::prototype() const { return mDefaultPrototype; } QScriptValue DefaultScriptClass::Default_proto_toString(QScriptContext* ctx, QScriptEngine* eng) { DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } return QString(data->typeName() + QLatin1Char(' ') + data->name()); } QScriptClassPropertyIterator* DefaultScriptClass::newIterator(const QScriptValue& object) { return new DefaultscriptClassIterator(object, this); } DefaultscriptClassIterator::DefaultscriptClassIterator(const QScriptValue& object, DefaultScriptClass* cls) : QScriptClassPropertyIterator(object), mCurrent(-1), mClass(cls) { DataInformation* data = DefaultScriptClass::toDataInformation(object); Q_CHECK_PTR(data); mData = data; } DefaultscriptClassIterator::~DefaultscriptClassIterator() { } bool DefaultscriptClassIterator::hasNext() const { return mCurrent < mClass->mIterableProperties.size() - 1; } bool DefaultscriptClassIterator::hasPrevious() const { return mCurrent > 0; } QScriptString DefaultscriptClassIterator::name() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return QScriptString(); if (mCurrent < mClass->mIterableProperties.size()) return mClass->mIterableProperties.at(mCurrent).first; int index = mCurrent - mClass->mIterableProperties.size(); Q_ASSERT(index >= 0); DataInformation* child = mData->childAt(index); return mClass->engine()->toStringHandle(child->name()); } QScriptValue::PropertyFlags DefaultscriptClassIterator::flags() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return 0; if (mCurrent < mClass->mIterableProperties.size()) return mClass->propertyFlags(object(), mClass->mIterableProperties.at(mCurrent).first, id()); return QScriptValue::ReadOnly; } uint DefaultscriptClassIterator::id() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return 0; //only children have an id assigned if (mCurrent < mClass->mIterableProperties.size()) return 0; return mCurrent - mClass->mIterableProperties.size() + 1; } void DefaultscriptClassIterator::next() { Q_ASSERT(mCurrent == -1 || (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); mCurrent++; } void DefaultscriptClassIterator::previous() { Q_ASSERT(mCurrent >= 0); mCurrent--; } void DefaultscriptClassIterator::toBack() { mCurrent = mClass->mIterableProperties.size() + mData->childCount(); } void DefaultscriptClassIterator::toFront() { mCurrent = -1; } diff --git a/kasten/controllers/view/structures/script/scriptengineinitializer.cpp b/kasten/controllers/view/structures/script/scriptengineinitializer.cpp index 7ee16e0e..c973cfee 100644 --- a/kasten/controllers/view/structures/script/scriptengineinitializer.cpp +++ b/kasten/controllers/view/structures/script/scriptengineinitializer.cpp @@ -1,358 +1,358 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012, 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptengineinitializer.h" #include "scriptutils.h" #include "../datatypes/primitivefactory.h" #include "../parsers/parserutils.h" #include #include #include #include #include #include #include namespace ScriptEngineInitializer { void addFuctionsToScriptEngine(QScriptEngine* engine) { engine->globalObject().setProperty(QStringLiteral("uint8"), engine->newFunction(Private::scriptNewUInt8)); engine->globalObject().setProperty(QStringLiteral("uint16"), engine->newFunction(Private::scriptNewUInt16)); engine->globalObject().setProperty(QStringLiteral("uint32"), engine->newFunction(Private::scriptNewUInt32)); engine->globalObject().setProperty(QStringLiteral("uint64"), engine->newFunction(Private::scriptNewUInt64)); engine->globalObject().setProperty(QStringLiteral("int8"), engine->newFunction(Private::scriptNewInt8)); engine->globalObject().setProperty(QStringLiteral("int16"), engine->newFunction(Private::scriptNewInt16)); engine->globalObject().setProperty(QStringLiteral("int32"), engine->newFunction(Private::scriptNewInt32)); engine->globalObject().setProperty(QStringLiteral("int64"), engine->newFunction(Private::scriptNewInt64)); engine->globalObject().setProperty(QStringLiteral("bool8"), engine->newFunction(Private::scriptNewBool8)); engine->globalObject().setProperty(QStringLiteral("bool16"), engine->newFunction(Private::scriptNewBool16)); engine->globalObject().setProperty(QStringLiteral("bool32"), engine->newFunction(Private::scriptNewBool32)); engine->globalObject().setProperty(QStringLiteral("bool64"), engine->newFunction(Private::scriptNewBool64)); engine->globalObject().setProperty(QStringLiteral("float"), engine->newFunction(Private::scriptNewFloat)); engine->globalObject().setProperty(QStringLiteral("double"), engine->newFunction(Private::scriptNewDouble)); engine->globalObject().setProperty(QStringLiteral("char"), engine->newFunction(Private::scriptNewChar)); engine->globalObject().setProperty(QStringLiteral("bitfield"), engine->newFunction(Private::scriptNewBitfield)); engine->globalObject().setProperty(QStringLiteral("array"), engine->newFunction(Private::scriptNewArray)); engine->globalObject().setProperty(QStringLiteral("struct"), engine->newFunction(Private::scriptNewStruct)); engine->globalObject().setProperty(QStringLiteral("union"), engine->newFunction(Private::scriptNewUnion)); //enum is a reserved keyword in JavaScript, cannot use it engine->globalObject().setProperty(QStringLiteral("enumeration"), engine->newFunction(Private::scriptNewEnum)); engine->globalObject().setProperty(QStringLiteral("flags"), engine->newFunction(Private::scriptNewFlags)); engine->globalObject().setProperty(QStringLiteral("string"), engine->newFunction(Private::scriptNewString)); engine->globalObject().setProperty(QStringLiteral("pointer"), engine->newFunction(Private::scriptNewPointer)); engine->globalObject().setProperty(QStringLiteral("taggedUnion"), engine->newFunction(Private::scriptNewTaggedUnion)); engine->globalObject().setProperty(QStringLiteral("alternative"), engine->newFunction(Private::alternativeFunc)); engine->globalObject().setProperty(QStringLiteral("importScript"), engine->newFunction(Private::importScriptFunc)); } QScriptEngine* newEngine() { QScriptEngine* ret = new QScriptEngine(); addFuctionsToScriptEngine(ret); return ret; } namespace Private { QString setUpdatePropertyName() { return QStringLiteral("setUpdate"); } QString setValidationPropertyName() { return QStringLiteral("setValidation"); } QString setPropertyName() { return QStringLiteral("set"); } namespace { QScriptValue scriptNewCommon(QScriptContext* ctx, QScriptEngine* eng, const QString& typeName) { QScriptValue object = ctx->isCalledAsConstructor() ? ctx->thisObject() : eng->newObject(); object.setProperty(ParserStrings::PROPERTY_INTERNAL_TYPE(), typeName); //add the setUpdate() and setValidation() functions object.setProperty(setUpdatePropertyName(), eng->newFunction(addUpdateFunc, 1)); object.setProperty(setValidationPropertyName(), eng->newFunction(addValidationFunc, 1)); object.setProperty(setPropertyName(), eng->newFunction(addCustomPropertiesFunc, 1)); return object; } /** create a new primitive of type @p type */ QScriptValue primitiveConstructor(QScriptContext* ctx, QScriptEngine* eng, const QString& type) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_PRIMITIVE()); object.setProperty(ParserStrings::PROPERTY_TYPE(), type); return object; } } #define PRIMITIVE_CONSTRUCTOR(type) QScriptValue scriptNew##type(QScriptContext* ctx, QScriptEngine* eng) \ { return primitiveConstructor(ctx, eng, QStringLiteral(#type)); } PRIMITIVE_CONSTRUCTOR(UInt8) PRIMITIVE_CONSTRUCTOR(UInt16) PRIMITIVE_CONSTRUCTOR(UInt32) PRIMITIVE_CONSTRUCTOR(UInt64) PRIMITIVE_CONSTRUCTOR(Int8) PRIMITIVE_CONSTRUCTOR(Int16) PRIMITIVE_CONSTRUCTOR(Int32) PRIMITIVE_CONSTRUCTOR(Int64) PRIMITIVE_CONSTRUCTOR(Bool8) PRIMITIVE_CONSTRUCTOR(Bool16) PRIMITIVE_CONSTRUCTOR(Bool32) PRIMITIVE_CONSTRUCTOR(Bool64) PRIMITIVE_CONSTRUCTOR(Float) PRIMITIVE_CONSTRUCTOR(Double) PRIMITIVE_CONSTRUCTOR(Char) #undef PRIMITIVE_CONSTRUCTOR QScriptValue scriptNewBitfield(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_BITFIELD()); object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); //first argument is type object.setProperty(ParserStrings::PROPERTY_WIDTH(), ctx->argument(1)); //second argument is width return object; } //with children: QScriptValue scriptNewStruct(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRUCT()); object.setProperty(ParserStrings::PROPERTY_CHILD(), eng->newFunction(getChild)); object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); //first argument is children return object; } QScriptValue scriptNewUnion(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_UNION()); object.setProperty(ParserStrings::PROPERTY_TYPE(), eng->newFunction(getChild)); object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); //first argument is children return object; } QScriptValue scriptNewArray(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_ARRAY()); object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); //first argument is child type object.setProperty(ParserStrings::PROPERTY_LENGTH(), ctx->argument(1)); //second argument is length return object; } QScriptValue createEnumObject(QScriptContext* ctx, QScriptEngine* eng, const QString& typeName) { QScriptValue object = scriptNewCommon(ctx, eng, typeName); object.setProperty(ParserStrings::PROPERTY_ENUM_NAME(), ctx->argument(0)); //first argument is the name of the underlying enum object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(1)); //second argument is the type of the enum object.setProperty(ParserStrings::PROPERTY_ENUM_VALUES(), ctx->argument(2)); //third argument is the enum values return object; } QScriptValue scriptNewEnum(QScriptContext* ctx, QScriptEngine* eng) { return createEnumObject(ctx, eng, ParserStrings::TYPE_ENUM()); } QScriptValue scriptNewFlags(QScriptContext* ctx, QScriptEngine* eng) { return createEnumObject(ctx, eng, ParserStrings::TYPE_FLAGS()); } QScriptValue scriptNewString(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRING()); object.setProperty(ParserStrings::PROPERTY_ENCODING(), ctx->argument(0)); return object; } QScriptValue scriptNewPointer(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_POINTER()); object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); object.setProperty(ParserStrings::PROPERTY_TARGET(), ctx->argument(1)); return object; } QScriptValue scriptNewTaggedUnion(QScriptContext* ctx, QScriptEngine* eng) { QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_TAGGED_UNION()); object.setProperty(ParserStrings::PROPERTY_CHILD(), eng->newFunction(getChild)); object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); object.setProperty(ParserStrings::PROPERTY_ALTERNATIVES(), ctx->argument(1)); object.setProperty(ParserStrings::PROPERTY_DEFAULT_CHILDREN(), ctx->argument(2)); return object; } QScriptValue getChild(QScriptContext* ctx, QScriptEngine* eng) { Q_UNUSED(eng) if (ctx->argumentCount() < 1) - return ctx->throwError(QStringLiteral("child(): name of child must be passed as first parameter")); + return ctx->throwError(QLatin1String("child(): name of child must be passed as first parameter")); QString nameString = ctx->argument(0).toString(); QScriptValue ret = ctx->thisObject().property(ParserStrings::PROPERTY_CHILDREN()).property(nameString); if (ret.isValid()) return ret; else return ctx->throwError( - QString(QStringLiteral("child(): could not find child with name=") + nameString)); + QString(QLatin1String("child(): could not find child with name=") + nameString)); } QScriptValue addUpdateFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("setUpdate(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue func = ctx->argument(0); if (!func.isFunction()) { return ctx->throwError(QScriptContext::TypeError, QStringLiteral("setUpdate(): argument must be a function!")); } thisObj.setProperty(ParserStrings::PROPERTY_UPDATE_FUNC(), func); return thisObj; } QScriptValue addValidationFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("setValidation(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue func = ctx->argument(0); if (!func.isFunction()) { return ctx->throwError(QScriptContext::TypeError, QStringLiteral("setValidation(): argument must be a function!")); } thisObj.setProperty(ParserStrings::PROPERTY_VALIDATION_FUNC(), func); return thisObj; } QScriptValue addCustomPropertiesFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("set(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue arg = ctx->argument(0); if (!arg.isValid() || !arg.isObject()) return ctx->throwError(QScriptContext::TypeError, QStringLiteral("set(): argument must be an object!")); int count = 0; QScriptValueIterator it(arg); while (it.hasNext()) { it.next(); thisObj.setProperty(it.scriptName(), it.value()); count++; } if (count == 0) return ctx->throwError(QStringLiteral("set(): must set at least one property!")); return thisObj; } QScriptValue alternativeFunc(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() < 2) return ctx->throwError(QStringLiteral("alternative(): needs at least 2 arguments!")); QScriptValue object = ctx->isCalledAsConstructor() ? ctx->thisObject() : eng->newObject(); object.setProperty(ParserStrings::PROPERTY_SELECT_IF(), ctx->argument(0)); object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(1)); if (ctx->argumentCount() > 2) object.setProperty(ParserStrings::PROPERTY_STRUCT_NAME(), ctx->argument(2)); return object; } QScriptValue importScriptFunc(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("importScript(): expected one argument!")); QString arg = ctx->argument(0).toString(); - if (arg.contains(QStringLiteral(".."))) + if (arg.contains(QLatin1String(".."))) return ctx->throwError(QStringLiteral("importScript(): You may only access installed structure files! Path traversal detected.")); - const QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okteta/structures/") + arg); + const QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("okteta/structures/") + arg); if (fileName.isEmpty()) return ctx->throwError(QStringLiteral("importScript(): could not find file to import!")); QFile file(fileName); if (!file.open(QFile::ReadOnly)) return ctx->throwError(QStringLiteral("importScript(): failed to open file!")); QTextStream s(&file); QString code = s.readAll(); file.close(); //now push context so that we don't conflict with the current execution QScriptContext* newCtx = eng->pushContext(); QScriptValue result = eng->evaluate(code); if (result.isError()) - result = QScriptValue(QStringLiteral("importScript(): failed due to exception: ") + result.toString()); + result = QScriptValue(QLatin1String("importScript(): failed due to exception: ") + result.toString()); else result = newCtx->activationObject(); eng->popContext(); return result; } } //namespace Private } //namespace ScriptEngine Initializer diff --git a/kasten/controllers/view/structures/script/scriptutils.cpp b/kasten/controllers/view/structures/script/scriptutils.cpp index 5f78ea83..aa5601ba 100644 --- a/kasten/controllers/view/structures/script/scriptutils.cpp +++ b/kasten/controllers/view/structures/script/scriptutils.cpp @@ -1,92 +1,92 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptutils.h" #include #include #include #include #include #include "../allprimitivetypes.h" QString ScriptUtils::qScriptValueToString(const QScriptValue& val) { if (!val.isValid()) return QStringLiteral("invalid"); if (val.isUndefined()) return QStringLiteral("undefined"); if (val.isNull()) return QStringLiteral("null"); QString ret = val.toString(); if (!val.isQObject()) { return ret; } - ret += QStringLiteral(" ["); + ret += QLatin1String(" ["); QScriptValueIterator it(val); bool first = true; while (it.hasNext()) { - if (it.name().startsWith(QStringLiteral("_"))) + if (it.name().startsWith(QLatin1String("_"))) continue; // skip all names starting with _ like e.g. __proto__ if (!first) - ret += QStringLiteral(", "); + ret += QLatin1String(", "); else first = false; it.next(); QScriptValue loopValue = it.value(); if (!loopValue.isObject()) { - ret += it.name() + QStringLiteral("=") + loopValue.toString(); + ret += it.name() + QLatin1Char('=') + loopValue.toString(); } else { - ret += it.name() + QStringLiteral("=") + qScriptValueToString(loopValue); + ret += it.name() + QLatin1Char('=') + qScriptValueToString(loopValue); } } return ret; } void ScriptUtils::wrapAllPrimitiveTypes(QScriptValue& out, AllPrimitiveTypes allPrim, PrimitiveDataType actualType) { out.setProperty(QStringLiteral("type"), PrimitiveType::standardTypeName(actualType)); out.setProperty(QStringLiteral("char"), QString(allPrim.value() > 127 ? QChar::ReplacementCharacter : QChar(allPrim.value(), 0))); out.setProperty(QStringLiteral("int8"), allPrim.value()); out.setProperty(QStringLiteral("uint8"), allPrim.value()); out.setProperty(QStringLiteral("int16"), allPrim.value()); out.setProperty(QStringLiteral("uint16"), allPrim.value()); out.setProperty(QStringLiteral("int32"), allPrim.value()); out.setProperty(QStringLiteral("uint32"), allPrim.value()); out.setProperty(QStringLiteral("int64"), QString::number(allPrim.value())); out.setProperty(QStringLiteral("uint64"), QString::number(allPrim.value())); //QtScript has no support for 64 bit ints, add another value which contains the higher 32 bits //XXX any better solution for this? out.setProperty(QStringLiteral("int64high32bits"), qint32(allPrim.value() >> 32)); out.setProperty(QStringLiteral("uint64high32bits"), quint32(allPrim.value() >> 32)); out.setProperty(QStringLiteral("float"), allPrim.value()); out.setProperty(QStringLiteral("double"), allPrim.value()); } diff --git a/kasten/controllers/view/structures/settings/structureaddremovewidget.cpp b/kasten/controllers/view/structures/settings/structureaddremovewidget.cpp index fa10d3a4..349d369a 100644 --- a/kasten/controllers/view/structures/settings/structureaddremovewidget.cpp +++ b/kasten/controllers/view/structures/settings/structureaddremovewidget.cpp @@ -1,299 +1,299 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "structureaddremovewidget.h" #include "../structtool.h" #include "../structuresmanager.h" #include "../structuredefinitionfile.h" #include "../structlogging.h" #include #include #include #include #include #include #include #include using namespace Kasten; StructureAddRemoveWidget::StructureAddRemoveWidget(const QStringList& selected, Kasten::StructTool* tool, QWidget* parent) : QWidget(parent), mTool(tool) { QHBoxLayout* baseLayout; QVBoxLayout* tree1Layout; QVBoxLayout* tree2Layout; QVBoxLayout* leftRightLayout; QVBoxLayout* upDownLayout; baseLayout = new QHBoxLayout(); baseLayout->setMargin(0); tree1Layout = new QVBoxLayout(); mTree1Label = new QLabel(i18nc("@info:label", "Installed structures:"), this); tree1Layout->addWidget(mTree1Label); mTreeAvailable = new QTreeWidget(this); mTreeAvailable->setHeaderHidden(true); mTreeAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection); mTreeAvailable->setColumnCount(2); mTreeAvailable->setColumnHidden(1, true); tree1Layout->addWidget(mTreeAvailable); tree2Layout = new QVBoxLayout(); mTree2Label = new QLabel(i18nc("@info:label", "Used structures:"), this); tree2Layout->addWidget(mTree2Label); mTreeSelected = new QTreeWidget(this); mTreeSelected->setHeaderHidden(true); mTreeSelected->setSelectionMode(QAbstractItemView::ExtendedSelection); mTreeSelected->setColumnCount(2); mTreeSelected->setColumnHidden(1, true); tree2Layout->addWidget(mTreeSelected); leftRightLayout = new QVBoxLayout(); leftRightLayout->addStretch(); mRightButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-right")), QString(), this); leftRightLayout->addWidget(mRightButton); mLeftButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-left")), QString(), this); leftRightLayout->addWidget(mLeftButton); leftRightLayout->addStretch(); upDownLayout = new QVBoxLayout(); upDownLayout->addStretch(); mUpButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-up")), QString(), this); upDownLayout->addWidget(mUpButton); mDownButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-down")), QString(), this); upDownLayout->addWidget(mDownButton); upDownLayout->addStretch(); baseLayout->addLayout(tree1Layout); baseLayout->addLayout(leftRightLayout); baseLayout->addLayout(tree2Layout); baseLayout->addLayout(upDownLayout); setLayout(baseLayout); connect(mLeftButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveLeft); connect(mRightButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveRight); connect(mUpButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveUp); connect(mDownButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveDown); buildAvailableList(); //already loaded defs: QRegExp regex(QStringLiteral("'(.+)':'(.+)'")); foreach(const QString& s, selected) { int pos = regex.indexIn(s); if (pos > -1) { QString pluginName = regex.cap(1); QString structName = regex.cap(2); - if (structName == QStringLiteral("*")) { + if (structName == QLatin1String("*")) { //add all of them for (int i = 0; i < mTreeAvailable->topLevelItemCount(); i++) { QTreeWidgetItem* avail = mTreeAvailable->topLevelItem(i); if (avail->text(0) != pluginName) continue; for (int i = 0; i < avail->childCount(); i++) { QTreeWidgetItem* selStruct = avail->child(i); QTreeWidgetItem* item = new QTreeWidgetItem(mTreeSelected, QStringList() << selStruct->text(0) << pluginName); mTreeSelected->addTopLevelItem(item); } break; } } else { QTreeWidgetItem* item = new QTreeWidgetItem(mTreeSelected, QStringList() << structName << pluginName); mTreeSelected->addTopLevelItem(item); } } } syncData(); } StructureAddRemoveWidget::~StructureAddRemoveWidget() { } void StructureAddRemoveWidget::buildAvailableList() { const QList loadedDefs = mTool->manager()->structureDefs(); QList availableItems; foreach(StructureDefinitionFile* def,loadedDefs) { if (!def->isValid()) continue; QString pluginName = def->pluginInfo().pluginName(); if (!def->pluginInfo().isPluginEnabled()) continue; QTreeWidgetItem* item = new QTreeWidgetItem(mTreeAvailable, QStringList() << def->pluginInfo().pluginName() << pluginName); foreach(const QString& name, def->structureNames()) { QTreeWidgetItem* subItem = new QTreeWidgetItem(item, QStringList() << name << pluginName); item->addChild(subItem); } availableItems.append(item); } mTreeAvailable->addTopLevelItems(availableItems); } void StructureAddRemoveWidget::moveLeft() { QList selected = mTreeSelected->selectedItems(); bool changed = false; foreach(QTreeWidgetItem* item,selected) { delete mTreeSelected->takeTopLevelItem( mTreeSelected->indexOfTopLevelItem(item)); changed = true; } if (changed) syncData(); } void StructureAddRemoveWidget::moveRight() { QList selected = mTreeAvailable->selectedItems(); bool changed = false; foreach(const QTreeWidgetItem* item,selected) { if (!item->parent()) continue; //maybe sometime add all subitems QTreeWidgetItem* moveOver = new QTreeWidgetItem(mTreeSelected, QStringList() << item->text(0) << item->text(1)); //item name then parent name then path mTreeSelected->addTopLevelItem(moveOver); changed = true; } if (changed) syncData(); } void StructureAddRemoveWidget::moveUp() { QList selected = mTreeSelected->selectedItems(); bool changed = false; int firstIndex = -1; foreach(QTreeWidgetItem* item,selected) { int idx = mTreeSelected->indexOfTopLevelItem(item); int newIdx = qMax(0, idx - 1); mTreeSelected ->insertTopLevelItem(newIdx, mTreeSelected->takeTopLevelItem(idx)); //only first index firstIndex = firstIndex == -1 ? newIdx : firstIndex; } if (changed) syncData(); if (firstIndex != -1) mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex)); } void StructureAddRemoveWidget::moveDown() { QList selected = mTreeSelected->selectedItems(); bool changed = false; int firstIndex = -1; int maxItmCount = mTreeSelected->topLevelItemCount(); foreach(QTreeWidgetItem* item,selected) { int idx = mTreeSelected->indexOfTopLevelItem(item); int newIdx = qMin(idx + 1, maxItmCount - 1); mTreeSelected ->insertTopLevelItem(newIdx, mTreeSelected->takeTopLevelItem(idx)); //only first index firstIndex = firstIndex == -1 ? newIdx : firstIndex; } if (changed) syncData(); if (firstIndex != -1) mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex)); } void StructureAddRemoveWidget::syncData() { QStringList strings; for (int i = 0; i < mTreeSelected->topLevelItemCount(); ++i) { QTreeWidgetItem* item = mTreeSelected->topLevelItem(i); QString dataStr = QString::fromLatin1("\'%1\':\'%2\'").arg(item->text(1), item->text(0)); strings.append(dataStr); } qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "selection changed to: " << strings; mValues = strings; } void StructureAddRemoveWidget::updateAvailable() { //rebuild available tree mTreeAvailable->clear(); buildAvailableList(); //remove any structs that references not loaded files QStringList plugins; const QList loadedDefs = mTool->manager()->structureDefs(); foreach(const StructureDefinitionFile* def, loadedDefs) { QString pluginName = def->pluginInfo().pluginName(); if (def->pluginInfo().isValid() && !def->pluginInfo().isPluginEnabled()) continue; plugins << pluginName; } bool changed = false; QList toRemove; qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "paths = " << plugins; for (int i = 0; i < mTreeSelected->topLevelItemCount(); ++i) { QTreeWidgetItem* item = mTreeSelected->topLevelItem(i); //text(1) is plugin name if (!plugins.contains(item->text(1))) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "removed item: " << QString::fromLatin1("\'%1\':\'%2\'").arg(item->text(1), item->text(0)); changed = true; toRemove.append(item); } else { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "item " << QString::fromLatin1("\'%1\':\'%2\'").arg(item->text(1), item->text(0)) << "still loaded -> keep"; } } foreach(QTreeWidgetItem* itm,toRemove) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "item " << QString::fromLatin1("\'%1\':\'%2\'").arg(itm->text(1), itm->text(0)) << "removed"; delete mTreeSelected->takeTopLevelItem(mTreeSelected->indexOfTopLevelItem(itm)); } if (changed) syncData(); } diff --git a/kasten/controllers/view/structures/settings/structuresmanagerview.cpp b/kasten/controllers/view/structures/settings/structuresmanagerview.cpp index 0f222516..35f40ad5 100644 --- a/kasten/controllers/view/structures/settings/structuresmanagerview.cpp +++ b/kasten/controllers/view/structures/settings/structuresmanagerview.cpp @@ -1,200 +1,200 @@ /* This file is part of the Okteta Kasten Framework, made within the KDE community. Copyright 2009 Friedrich W. H. Kossebau Copyright 2009, 2012 Alex Richardson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "structuresmanagerview.h" #include "structureaddremovewidget.h" #include "structviewpreferences.h" #include "../structuresmanager.h" #include "../structtool.h" #include "../structlogging.h" // KF5 #include #include #include #include #include // Qt #include #include #include #include #include #include StructuresManagerView::StructuresManagerView(Kasten::StructTool* tool, QWidget* parent) : QWidget(parent), mTool(tool), mStructuresSelector(0), mRebuildingPluginsList(false) { KConfigDialogManager::changedMap()->insert(QStringLiteral("StructuresManagerView"), SIGNAL(changed(QStringList))); setObjectName(QStringLiteral("kcfg_LoadedStructures")); mSelectedStructures = Kasten::StructViewPreferences::loadedStructures(); QVBoxLayout* pageLayout = new QVBoxLayout(); setLayout(pageLayout); rebuildPluginSelectorEntries(); QHBoxLayout* buttonsLayout = new QHBoxLayout(); pageLayout->addLayout(buttonsLayout); mGetNewStructuresButton = new KNS3::Button(i18n("Get New Structures..."), QStringLiteral("okteta-structures.knsrc"), this); connect(mGetNewStructuresButton, &KNS3::Button::dialogFinished, this, &StructuresManagerView::onGetNewStructuresClicked); buttonsLayout->addWidget(mGetNewStructuresButton); mAdvancedSelectionButton = new QPushButton(QIcon::fromTheme(QStringLiteral("configure")), i18n("Advanced Selection..."), this); connect(mAdvancedSelectionButton, &QPushButton::clicked, this, &StructuresManagerView::advancedSelection); buttonsLayout->addWidget(mAdvancedSelectionButton); } void StructuresManagerView::onGetNewStructuresClicked(const KNS3::Entry::List& changedEntries) { foreach (const KNS3::Entry& e, changedEntries) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Changed Entry: " << e.name(); if (e.status() == KNS3::Entry::Installed) { //new element installed qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "installed files:" << e.installedFiles(); } if (e.status() == KNS3::Entry::Deleted) { //element uninstalled qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "deleted files:" << e.uninstalledFiles(); } } if (!changedEntries.isEmpty()) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "installed structures changed -> rebuilding list of installed structures"; mTool->manager()->reloadPaths(); rebuildPluginSelectorEntries(); } } QStringList StructuresManagerView::values() { return mSelectedStructures; } void StructuresManagerView::advancedSelection() { StructureAddRemoveWidget* advancedSelectionWidget = new StructureAddRemoveWidget(mSelectedStructures, mTool, this); QPointer dlg = new QDialog(this); //the dlg-on-heap-variant QVBoxLayout* layout = new QVBoxLayout; QDialogButtonBox* dialogButtonBox = new QDialogButtonBox; dialogButtonBox->addButton(QDialogButtonBox::Ok); connect(dialogButtonBox, &QDialogButtonBox::accepted, dlg.data(), &QDialog::accept); dialogButtonBox->addButton(QDialogButtonBox::Cancel); connect(dialogButtonBox, &QDialogButtonBox::rejected, dlg.data(), &QDialog::reject); layout->addWidget(advancedSelectionWidget); layout->addWidget(dialogButtonBox); dlg->setLayout(layout); if (dlg->exec() == QDialog::Accepted) { QStringList newVals = advancedSelectionWidget->values(); if (newVals != mSelectedStructures) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "selection changed from " << mSelectedStructures << "to" << newVals; mSelectedStructures = newVals; emit changed(newVals); } } delete dlg; } void StructuresManagerView::onPluginSelectorChange(bool change) { if (mRebuildingPluginsList) return; qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "pluginselector changed: " << change; if (!change) return; mStructuresSelector->save(); reloadSelectedItems(); } void StructuresManagerView::reloadSelectedItems() { QStringList newVals; foreach(const Kasten::StructureDefinitionFile* def, mTool->manager()->structureDefs()) { KPluginInfo info = def->pluginInfo(); if (info.isPluginEnabled()) newVals.append(QString(QStringLiteral("\'%1\':\'*\'")).arg(info.pluginName())); } if (newVals != mSelectedStructures) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "selection changed from " << mSelectedStructures << "to" << newVals; mSelectedStructures = newVals; emit changed(newVals); } else { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no change:" << mSelectedStructures; } } void StructuresManagerView::rebuildPluginSelectorEntries() { mRebuildingPluginsList = true; QStringList newVals; KPluginInfo::List plugins; KPluginInfo::List dynamicPlugins; foreach(const Kasten::StructureDefinitionFile* def, mTool->manager()->structureDefs()) { KPluginInfo info = def->pluginInfo(); - if (info.category() == QStringLiteral("structure")) + if (info.category() == QLatin1String("structure")) plugins.append(info); - else if (info.category() == QStringLiteral("structure/js")) + else if (info.category() == QLatin1String("structure/js")) dynamicPlugins.append(info); } //XXX is there any way to clear the plugins selector? QBoxLayout* layoutObj = qobject_cast(layout()); Q_CHECK_PTR(layoutObj); if (mStructuresSelector) { layoutObj->removeWidget(mStructuresSelector); delete mStructuresSelector; } mStructuresSelector = new KPluginSelector(this); connect(mStructuresSelector, &KPluginSelector::changed, this, &StructuresManagerView::onPluginSelectorChange); layoutObj->insertWidget(0, mStructuresSelector); mStructuresSelector->addPlugins(plugins, KPluginSelector::ReadConfigFile, i18n( "Structure Definitions"), QStringLiteral("structure"), mTool->manager()->config()); mStructuresSelector->addPlugins(dynamicPlugins, KPluginSelector::ReadConfigFile, i18n("Dynamic Structure Definitions"), QStringLiteral("structure/js"), mTool->manager()->config()); mStructuresSelector->load(); mStructuresSelector->updatePluginsState(); mRebuildingPluginsList = false; reloadSelectedItems(); } StructuresManagerView::~StructuresManagerView() { } diff --git a/kasten/controllers/view/structures/structtool.cpp b/kasten/controllers/view/structures/structtool.cpp index efcaeff5..a87c35d2 100644 --- a/kasten/controllers/view/structures/structtool.cpp +++ b/kasten/controllers/view/structures/structtool.cpp @@ -1,446 +1,446 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2011, 2012 Alex Richardson * Copyright 2009 Friedrich W. H. Kossebau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "structtool.h" #include "structuredefinitionfile.h" #include "structuresmanager.h" #include "structlogging.h" // lib #include #include // Okteta core #include #include #include // KF5 #include //Qt #include #include "script/scripthandler.h" #include "datatypes/datainformation.h" #include "structviewpreferences.h" namespace Kasten { class StructToolPrivate { public: StructToolPrivate() : mByteArrayView(0), mByteArrayModel(0), mCursorIndex(0), mByteOrder(StructViewPreferences::byteOrder()), mManager(new StructuresManager()), mWritingData(false), mCurrentItemDataChanged(false) {} // source ByteArrayView* mByteArrayView; Okteta::AbstractByteArrayModel* mByteArrayModel; Okteta::Address mCursorIndex; // settings QSysInfo::Endian mByteOrder; QScopedPointer mManager; TopLevelDataInformation::List mData; TopLevelDataInformation::List mInvalidData; bool mWritingData :1; bool mCurrentItemDataChanged :1; }; StructTool::StructTool() : d(new StructToolPrivate()) { //leave mLoadedFiles empty for now, since otherwise loading slot will not work setObjectName(QStringLiteral("StructTool")); d->mManager->reloadPaths(); setSelectedStructuresInView(); // mUtf8Codec = QTextCodec::codecForName("UTF-8"); connect(this, &StructTool::byteOrderChanged, this, &StructTool::onByteOrderChanged); } void StructTool::onByteOrderChanged() { updateData(Okteta::ArrayChangeMetricsList()); } StructTool::~StructTool() { } void StructTool::setByteOrder(QSysInfo::Endian order) { if (order != StructViewPreferences::byteOrder() || order != d->mByteOrder) { emit byteOrderChanged(); StructViewPreferences::setByteOrder(order); d->mByteOrder = order; updateData(Okteta::ArrayChangeMetricsList()); } } QString StructTool::title() const { return i18nc("@title:window", "Structures"); } void StructTool::setTargetModel(AbstractModel* model) { //just a copy of the code in poddecodertool.h if (d->mByteArrayView) d->mByteArrayView->disconnect(this); if (d->mByteArrayModel) d->mByteArrayModel->disconnect(this); d->mByteArrayView = model ? model->findBaseModel() : 0; ByteArrayDocument* document = d->mByteArrayView ? qobject_cast(d->mByteArrayView->baseModel()) : 0; d->mByteArrayModel = document ? document->content() : 0; if (d->mByteArrayModel && d->mByteArrayView) { d->mCursorIndex = d->mByteArrayView->cursorPosition(); connect(d->mByteArrayView, &ByteArrayView::cursorPositionChanged, this, &StructTool::onCursorPositionChange); connect(d->mByteArrayModel, &Okteta::AbstractByteArrayModel::contentsChanged, this, &StructTool::onContentsChange); } emit byteArrayModelChanged(d->mByteArrayModel); updateData(Okteta::ArrayChangeMetricsList()); } void StructTool::onCursorPositionChange(Okteta::Address pos) { if (d->mCursorIndex != pos) { d->mCursorIndex = pos; updateData(Okteta::ArrayChangeMetricsList()); emit cursorIndexChanged(); } } void StructTool::setByteOrder(int order) { if (order == QSysInfo::LittleEndian) setByteOrder(QSysInfo::LittleEndian); else if (order == QSysInfo::BigEndian) setByteOrder(QSysInfo::BigEndian); else { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "invalid byte order set:" << order; } } void StructTool::onContentsChange(const Okteta::ArrayChangeMetricsList& list) { qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "contents changed"; for (int i = 0; i < list.size(); ++i) { const Okteta::ArrayChangeMetrics& acm = list.at(i); qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "change: t=" << acm.type() << "o=" << acm.offset() << "a2=" << acm.removeLength() << "a3=" << acm.insertLength(); } updateData(list); } bool StructTool::setData(const QVariant& value, int role, DataInformation* item, uint row) { Q_UNUSED(row) if (!d->mByteArrayModel) return false; if (role != Qt::EditRole) return false; Q_CHECK_PTR(item); TopLevelDataInformation* topLevel = item->topLevelDataInformation(); const Okteta::Address structureStart = startAddress(topLevel); d->mWritingData = true; bool ret = false; BitCount64 position = item->positionInFile(structureStart); const quint64 remainingBits = qMax(d->mByteArrayModel->size() * 8 - qint64(position), qint64(0)); quint8 bitOffs = position % 8; ret = item->setData(value, d->mByteArrayModel, Okteta::Address(position / 8), remainingBits, bitOffs); d->mWritingData = false; //finished //XXX: this is inefficient, best would be to only update the changed value updateData(Okteta::ArrayChangeMetricsList()); //update once after writing return ret; } void StructTool::updateData(const Okteta::ArrayChangeMetricsList& list) { if (d->mWritingData) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "currently writing data, won't update"; return; } if (!d->mByteArrayModel) return; for (int i = 0; i < d->mData.size(); i++) { const TopLevelDataInformation::Ptr& dat = d->mData.at(i); dat->read(d->mByteArrayModel, d->mCursorIndex, list, false); if (d->mCurrentItemDataChanged) emit dataChanged(i, d->mData.at(i)->actualDataInformation()); d->mCurrentItemDataChanged = false; } } //model interface: QVariant StructTool::headerData(int column, int role) { if (role == Qt::DisplayRole) { switch (column) { case DataInformation::ColumnName: return i18nc("name of a data structure", "Name"); case DataInformation::ColumnType: return i18nc("type of a data structure", "Type"); case DataInformation::ColumnValue: return i18nc("value of a data structure (primitive type)", "Value"); default: return QVariant(); } } return QVariant(); } int StructTool::childCount() const { return d->mData.size(); } DataInformation* StructTool::childAt(int idx) const { if (idx >= d->mData.size() || idx < 0) { return 0; } //don't expose the topLevelDataInformation, since this may cause crashes return d->mData.at(idx)->actualDataInformation(); } void StructTool::addChildItem(TopLevelDataInformation* child) { Q_CHECK_PTR(child); child->setParent(this); if (child->isValid()) { child->setIndex(d->mData.size()); connect(child, &TopLevelDataInformation::dataChanged, this, &StructTool::onChildItemDataChanged); connect(child, &TopLevelDataInformation::childrenAboutToBeInserted, this, &StructTool::childrenAboutToBeInserted); connect(child, &TopLevelDataInformation::childrenInserted, this, &StructTool::childrenInserted); connect(child, &TopLevelDataInformation::childrenAboutToBeRemoved, this, &StructTool::childrenAboutToBeRemoved); connect(child, &TopLevelDataInformation::childrenRemoved, this, &StructTool::childrenRemoved); connect(this, &StructTool::byteArrayModelChanged, child, &TopLevelDataInformation::newModelActivated); d->mData.append(QSharedPointer(child)); //ensure that locking gets set up properly if (d->mByteArrayModel) child->newModelActivated(d->mByteArrayModel); } else { child->setIndex(d->mInvalidData.size()); d->mInvalidData.append(QSharedPointer(child)); } } void StructTool::setSelectedStructuresInView() { d->mData.clear(); d->mInvalidData.clear(); emit dataCleared(); QRegExp regex(QStringLiteral("'(.+)':'(.+)'")); QStringList loadedStructs = StructViewPreferences::loadedStructures(); qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "loadedStructs " << loadedStructs; for (int i = 0; i < loadedStructs.size(); ++i) { const QString& s = loadedStructs.at(i); int pos = regex.indexIn(s); if (pos > -1) { QString pluginName = regex.cap(1); QString name = regex.cap(2); //qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "pluginName=" << path << " structureName=" << name; StructureDefinitionFile* def = d->mManager->definition(pluginName); if (!def) continue; if (!def->isValid()) continue; //should be valid now - if (name == QStringLiteral("*")) + if (name == QLatin1String("*")) { //add all of them QVector structs = def->structures(); for (int i = 0; i < structs.size(); ++i) addChildItem(structs.at(i)); } else { TopLevelDataInformation* data = def->structure(name); if (data) addChildItem(data); else qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Could not find structure with name" << name << "in" << pluginName; } } } for (int i = 0; i < d->mData.count(); ++i) { emit dataChanged(i, d->mData.at(i)->actualDataInformation()); } updateData(Okteta::ArrayChangeMetricsList()); } Okteta::Address StructTool::startAddress(const TopLevelDataInformation* data) { if (data->isLockedFor(d->mByteArrayModel)) return Okteta::Address(data->lockPositionFor(d->mByteArrayModel)); else return d->mCursorIndex; } void StructTool::mark(const QModelIndex& idx) { if (!d->mByteArrayModel || !d->mByteArrayView || !idx.isValid()) return; const DataInformation* data = static_cast(idx.internalPointer()); if (!data) return; Q_CHECK_PTR(data->topLevelDataInformation()); const Okteta::Address baseAddress = startAddress(data->topLevelDataInformation()); //FIXME support marking of partial bytes int length = data->size() / 8; const int maxLen = d->mByteArrayModel->size() - baseAddress; length = qMin(length, maxLen); const Okteta::Address startOffset = Okteta::Address(data->positionInFile(baseAddress) / 8); const Okteta::AddressRange markingRange = Okteta::AddressRange::fromWidth(startOffset, length); d->mByteArrayView->setMarking(markingRange, true); } void StructTool::unmark(/*const QModelIndex& idx*/) { if (d->mByteArrayView) d->mByteArrayView->setMarking(Okteta::AddressRange()); } void StructTool::validateAllStructures() { if (!d->mByteArrayModel) return; //no point validating const int size = d->mData.size(); for (int i = 0; i < size; ++i) { d->mData.at(i)->validate(); } } bool StructTool::isFileLoaded() const { return d->mByteArrayModel != NULL; } void StructTool::lockStructure(const QModelIndex& idx) { if (!d->mByteArrayModel) //no point without ByteArrayModel return; if (!idx.isValid() || !idx.internalPointer()) return; DataInformation* data = static_cast(idx.internalPointer()); TopLevelDataInformation* top = data->topLevelDataInformation(); Q_ASSERT(top); if (top) top->lockPositionToOffset(d->mCursorIndex, d->mByteArrayModel); } void StructTool::unlockStructure(const QModelIndex& idx) { if (!d->mByteArrayModel) //no point without ByteArrayModel return; if (!idx.isValid() || !idx.internalPointer()) return; DataInformation* data = static_cast(idx.internalPointer()); TopLevelDataInformation* top = data->topLevelDataInformation(); Q_CHECK_PTR(top); unmark(); top->unlockPosition(d->mByteArrayModel); //now read from the current position: top->read(d->mByteArrayModel, d->mCursorIndex, Okteta::ArrayChangeMetricsList(), true); mark(idx); //we have to change the marked range, otherwise it stays at the previous locked offset } bool StructTool::isStructureLocked(const QModelIndex& idx) const { if (!d->mByteArrayModel) //no point without ByteArrayModel return false; if (!idx.isValid() || !idx.internalPointer()) return false; DataInformation* data = static_cast(idx.internalPointer()); TopLevelDataInformation* top = data->topLevelDataInformation(); Q_ASSERT(top); if (top) return top->isLockedFor(d->mByteArrayModel); return false; } bool StructTool::canStructureBeLocked(const QModelIndex& idx) const { //we need a valid model and a valid index return d->mByteArrayModel && idx.isValid() && idx.internalPointer(); } void StructTool::onChildItemDataChanged() { d->mCurrentItemDataChanged = true; } Okteta::AbstractByteArrayModel* StructTool::byteArrayModel() const { return d->mByteArrayModel; } StructuresManager* StructTool::manager() const { return d->mManager.data(); } QSysInfo::Endian StructTool::byteOrder() const { return d->mByteOrder; } TopLevelDataInformation::List StructTool::allData() const { TopLevelDataInformation::List ret; ret << d->mData << d->mInvalidData; return ret; } } diff --git a/kasten/controllers/view/structures/structuredefinitionfile.cpp b/kasten/controllers/view/structures/structuredefinitionfile.cpp index 9309fec7..4138eda0 100644 --- a/kasten/controllers/view/structures/structuredefinitionfile.cpp +++ b/kasten/controllers/view/structures/structuredefinitionfile.cpp @@ -1,93 +1,93 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "structuredefinitionfile.h" #include "structlogging.h" #include #include #include #include "datatypes/topleveldatainformation.h" #include "parsers/abstractstructureparser.h" #include "parsers/osdparser.h" #include "parsers/scriptfileparser.h" namespace Kasten { StructureDefinitionFile::StructureDefinitionFile(KPluginInfo info) : mPluginInfo(info) { const QFileInfo tmp(info.entryPath()); const QString absoluteDir = tmp.absolutePath(); QString category = info.category(); - if (category == QStringLiteral("structure/js")) { - const QString filename = absoluteDir + QStringLiteral("/main.js"); + if (category == QLatin1String("structure/js")) { + const QString filename = absoluteDir + QLatin1String("/main.js"); mParser.reset(new ScriptFileParser(mPluginInfo.pluginName(), filename)); } - else if (category == QStringLiteral("structure")) { + else if (category == QLatin1String("structure")) { //by default use main.osd, only if it doesn't exist fall back to old behaviour - QString filename = absoluteDir + QStringLiteral("/main.osd"); + QString filename = absoluteDir + QLatin1String("/main.osd"); if (!QFile::exists(filename)) - filename = absoluteDir + QLatin1Char('/') + mPluginInfo.pluginName() + QStringLiteral(".osd"); + filename = absoluteDir + QLatin1Char('/') + mPluginInfo.pluginName() + QLatin1String(".osd"); mParser.reset(new OsdParser(mPluginInfo.pluginName(), filename)); } else qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no valid parser found for plugin category '" << category << "'"; } StructureDefinitionFile::~StructureDefinitionFile() { } QVector StructureDefinitionFile::structures() const { Q_CHECK_PTR(mParser); return mParser->parseStructures(); } TopLevelDataInformation* StructureDefinitionFile::structure(const QString& name) const { Q_CHECK_PTR(mParser); QVector list = mParser->parseStructures(); TopLevelDataInformation* ret = 0; for (int i = 0; i < list.size(); ++i) { if (list.at(i)->actualDataInformation()->name() == name) ret = list.at(i); else delete list.at(i); //we have no use for this element } if (!ret) qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not find structure with name=" << name; return ret; // not found } QStringList StructureDefinitionFile::structureNames() const { Q_CHECK_PTR(mParser); return mParser->parseStructureNames(); } } diff --git a/kasten/controllers/view/structures/structview.cpp b/kasten/controllers/view/structures/structview.cpp index df121dd9..ad3f3aec 100644 --- a/kasten/controllers/view/structures/structview.cpp +++ b/kasten/controllers/view/structures/structview.cpp @@ -1,307 +1,307 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2012 Alex Richardson * Copyright 2009 Friedrich W. H. Kossebau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "structview.h" // controller #include "structtreemodel.h" #include "structtool.h" #include "structuresmanager.h" #include "structviewitemdelegate.h" #include "structlogging.h" //settings #include "structviewpreferences.h" #include "settings/structviewdisplaysettingswidget.h" #include "settings/structuresmanagerview.h" #include "settings/structureaddremovewidget.h" #include "script/scriptutils.h" #include "script/scriptloggerview.h" //#include "modeltest.h" // KF5 #include #include #include // Qt #include #include #include #include #include #include #include #include namespace Kasten { StructView::StructView(StructTool* tool, QWidget* parent) : QWidget(parent), mTool(tool), mDelegate(new StructViewItemDelegate(this)), mStructTreeViewFocusChild(0) { QBoxLayout* baseLayout = new QVBoxLayout(this); setLayout(baseLayout); baseLayout->setMargin(0); // table mStructTreeModel = new StructTreeModel(mTool, this); // mModeltest = new ModelTest(mStructTreeModel, this); mStructTreeView = new QTreeView(this); mStructTreeView->setObjectName( QStringLiteral("StructTree" )); mStructTreeView->setRootIsDecorated(true); mStructTreeView->setAlternatingRowColors(true); mStructTreeView->setItemsExpandable(true); mStructTreeView->setUniformRowHeights(true); mStructTreeView->setAllColumnsShowFocus(true); mStructTreeView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); mStructTreeView->setItemDelegate(mDelegate); mStructTreeView->setDragEnabled(false); mStructTreeView->setSortingEnabled(false); mStructTreeView->setModel(mStructTreeModel); mStructTreeView->setHeaderHidden(false); mStructTreeView->setSortingEnabled(false); mStructTreeView->installEventFilter(this); QHeaderView* header = mStructTreeView->header(); header->setSectionResizeMode(QHeaderView::Interactive); baseLayout->addWidget(mStructTreeView, 10); // settings QBoxLayout* settingsLayout = new QHBoxLayout(); settingsLayout->setMargin(0); baseLayout->addLayout(settingsLayout); QIcon validateIcon = QIcon::fromTheme(QStringLiteral("document-sign")); mValidateButton = new QPushButton(validateIcon, i18nc("@action:button", "Validate"), this); const QString validationToolTip = i18nc("@info:tooltip", "Validate all structures."); mValidateButton->setToolTip(validationToolTip); mValidateButton->setEnabled(false); //no point validating without file open connect(mValidateButton, &QPushButton::clicked, mTool, &StructTool::validateAllStructures); connect(mTool, &StructTool::byteArrayModelChanged, this, &StructView::onByteArrayModelChanged); //TODO also disable the button if the structure has no validatable members settingsLayout->addWidget(mValidateButton); mLockStructureButton = new QPushButton(this); mLockStructureButton->setCheckable(true); setLockButtonState(false); mLockStructureButton->setEnabled(false); //won't work at beginning connect(mLockStructureButton, &QPushButton::toggled, this, &StructView::lockButtonToggled); settingsLayout->addWidget(mLockStructureButton); settingsLayout->addStretch(); //stretch before the settings button QIcon console = QIcon::fromTheme(QStringLiteral("utilities-terminal")); mScriptConsoleButton = new QPushButton(console, i18nc("@action:button", "Script console"), this); mScriptConsoleButton->setToolTip(i18nc("@info:tooltip", "Open script console.")); connect(mScriptConsoleButton, &QPushButton::pressed, this, &StructView::openScriptConsole); settingsLayout->addWidget(mScriptConsoleButton); QIcon settings = QIcon::fromTheme(QStringLiteral("configure")); mSettingsButton = new QPushButton(settings, i18nc("@action:button", "Settings"), this); const QString settingsTooltip = i18nc("@info:tooltip", "Open settings."); mSettingsButton->setToolTip(settingsTooltip); connect(mSettingsButton, &QPushButton::pressed, this, &StructView::openSettingsDlg); settingsLayout->addWidget(mSettingsButton); connect(mStructTreeView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &StructView::onCurrentRowChanged); connect(mTool, &StructTool::cursorIndexChanged, this, &StructView::onCursorIndexChange); } void StructView::onCursorIndexChange() { QModelIndex idx = mStructTreeView->currentIndex(); if (idx.isValid()) mTool->mark(idx); } void StructView::openSettingsDlg() { //An instance of your dialog could be already created and could be cached, //in which case you want to display the cached dialog instead of creating //another one if (KConfigDialog::showDialog(QStringLiteral("Structures Tool Settings"))) return; //KConfigDialog didn't find an instance of this dialog, so lets create it : KConfigDialog* dialog = new KConfigDialog(this, QStringLiteral("Structures Tool Settings"), StructViewPreferences::self()); StructViewDisplaySettingsWidget* displaySettings = new StructViewDisplaySettingsWidget(); QWidget* structSelectionWrapper = new QWidget(); StructuresManagerView* structureSettings = new StructuresManagerView(mTool, this); KPageWidgetItem* displ = dialog->addPage(displaySettings, i18n("Value Display"), QStringLiteral("configure")); QHBoxLayout* hbox = new QHBoxLayout(); structSelectionWrapper->setLayout(hbox); hbox->addWidget(structureSettings); - Q_ASSERT(structureSettings->objectName() == QStringLiteral("kcfg_LoadedStructures")); + Q_ASSERT(structureSettings->objectName() == QLatin1String("kcfg_LoadedStructures")); dialog->addPage(structSelectionWrapper, i18n("Structures management"), QStringLiteral("preferences-plugin")); //User edited the configuration - update your local copies of the configuration data connect(dialog, &KConfigDialog::settingsChanged, mTool, &StructTool::setSelectedStructuresInView); #pragma message("TODO: kconfig_compiler signals work now, use those signals and not the generic KConfigDialog::settingsChanged") dialog->setCurrentPage(displ); dialog->show(); } bool StructView::eventFilter(QObject* object, QEvent* event) { if (object == mStructTreeView) { if (event->type() == QEvent::FocusIn) { const QModelIndex current = mStructTreeView->selectionModel()->currentIndex(); if (current.isValid()) mTool->mark(current); else mTool->unmark(); setLockButtonState(current); } else if (event->type() == QEvent::FocusOut) { QWidget* treeViewFocusWidget = mStructTreeView->focusWidget(); const bool subChildHasFocus = (treeViewFocusWidget != mStructTreeView); if (subChildHasFocus) { mStructTreeViewFocusChild = treeViewFocusWidget; mStructTreeViewFocusChild->installEventFilter(this); } else mTool->unmark(); } } else if (object == mStructTreeViewFocusChild) { // TODO: it is only assumed the edit widget will be removed if it loses the focus if (event->type() == QEvent::FocusOut) { if (!mStructTreeView->hasFocus()) mTool->unmark(); mStructTreeViewFocusChild->removeEventFilter(this); mStructTreeViewFocusChild = 0; } } return QWidget::eventFilter(object, event); } void StructView::setLockButtonState(const QModelIndex& current) { // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "setLockButtonState() for" << current; // we don't want the toggled signal here, only when the user clicks the button! QSignalBlocker block(mLockStructureButton); setLockButtonState(mTool->isStructureLocked(current)); mLockStructureButton->setEnabled(mTool->canStructureBeLocked(current)); } void StructView::onCurrentRowChanged(const QModelIndex& current, const QModelIndex& previous) { Q_UNUSED( previous ) if (current.isValid() && mTool->byteArrayModel()) { mTool->mark(current); setLockButtonState(current); } else mTool->unmark(); } StructView::~StructView() { } void StructView::lockButtonToggled() { // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Lock button toggled"; setLockButtonState(mLockStructureButton->isChecked()); const QModelIndex current = mStructTreeView->selectionModel()->currentIndex(); if (!current.isValid()) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "it should not be possible to toggle this button when current index is invalid!"; return; } if (mLockStructureButton->isChecked()) mTool->lockStructure(current); else mTool->unlockStructure(current); } void StructView::setLockButtonState(bool structureLocked) { if (structureLocked) { mLockStructureButton->setIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); mLockStructureButton->setText(i18nc("@action:button" " unlock the starting offset of the current structure", "Unlock")); mLockStructureButton->setToolTip(i18nc("@info:tooltip", "Unlock selected structure, i.e. the starting offset is" " always set to the current cursor position.")); } else { mLockStructureButton->setIcon(QIcon::fromTheme(QStringLiteral("object-unlocked"))); mLockStructureButton->setText(i18nc("@action:button" " unlock the starting offset of the current structure", "Lock")); mLockStructureButton->setToolTip(i18nc("@info:tooltip", "Lock selected structure to current offset.")); } mLockStructureButton->setChecked(structureLocked); } void StructView::openScriptConsole() { QDialog* dialog = new QDialog(this); QVBoxLayout* layout = new QVBoxLayout; QDialogButtonBox* dialogButtonBox = new QDialogButtonBox; QPushButton* closeButton = dialogButtonBox->addButton( QDialogButtonBox::Close ); connect( closeButton, &QPushButton::clicked, dialog, &QDialog::accept ); layout->addWidget( new ScriptLoggerView(mTool->allData()) ); layout->addWidget( dialogButtonBox ); dialog->setLayout( layout ); dialog->show(); } void StructView::onByteArrayModelChanged(Okteta::AbstractByteArrayModel* model) { const bool validModel = model != 0; QModelIndex current = mStructTreeView->currentIndex(); mLockStructureButton->setEnabled(mTool->canStructureBeLocked(current)); setLockButtonState(mTool->isStructureLocked(current)); mValidateButton->setEnabled(validModel); } } diff --git a/kasten/core/io/filesystem/externalbookmarkstorage.cpp b/kasten/core/io/filesystem/externalbookmarkstorage.cpp index 5384c2ac..34d85612 100644 --- a/kasten/core/io/filesystem/externalbookmarkstorage.cpp +++ b/kasten/core/io/filesystem/externalbookmarkstorage.cpp @@ -1,133 +1,133 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2009 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "externalbookmarkstorage.h" // lib #include "bytearraydocument.h" // Okteta core #include #include #include #include // KF5 #include // Qt #include namespace Kasten { ExternalBookmarkStorage::ExternalBookmarkStorage() { const QString bookmarksFileName = - QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/okteta/bookmarks.xml"); + QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/okteta/bookmarks.xml"); mBookmarkManager = KBookmarkManager::managerForFile( bookmarksFileName, QStringLiteral("okteta") ); } void ExternalBookmarkStorage::readBookmarks( ByteArrayDocument* document, const QUrl& url ) { Okteta::AbstractByteArrayModel* byteArray = document->content(); Okteta::Bookmarkable* bookmarkable = qobject_cast( byteArray ); bookmarkable->removeAllBookmarks(); const QString urlString = url.toDisplayString(QUrl::PrettyDecoded|QUrl::PreferLocalFile); KBookmarkGroup root = mBookmarkManager->root(); for( KBookmark bm = root.first(); ! bm.isNull(); bm = root.next(bm) ) { if( bm.isSeparator() || ! bm.isGroup() ) continue; if( bm.fullText() == urlString ) { KBookmarkGroup bmGroup = bm.toGroup(); QList bookmarksToBeCreated; Okteta::Bookmark bookmark; for( bm = bmGroup.first(); ! bm.isNull(); bm = bmGroup.next(bm) ) { if( bm.isSeparator() || bm.isGroup() ) continue; bookmark.setOffset( bm.url().fragment().toULongLong() ); bookmark.setName( bm.fullText() ); bookmarksToBeCreated.append( bookmark ); } bookmarkable->addBookmarks( bookmarksToBeCreated ); break; } } } void ExternalBookmarkStorage::writeBookmarks( ByteArrayDocument* document, const QUrl& url ) { Okteta::AbstractByteArrayModel* byteArray = document->content(); Okteta::Bookmarkable* bookmarkable = qobject_cast( byteArray ); if( ! bookmarkable ) return; const QString urlString = url.toDisplayString(QUrl::PrettyDecoded|QUrl::PreferLocalFile); KBookmarkGroup root = mBookmarkManager->root(); // rm old bookmarkable KBookmark bm = root.first(); while( ! bm.isNull() ) { if( bm.isSeparator() || ! bm.isGroup() ) continue; if( bm.fullText() == urlString ) { root.deleteBookmark( bm ); break; } bm = root.next( bm ); } // store current bookmarks KBookmarkGroup bookmarkGroup = root.createNewFolder( urlString ); Okteta::BookmarksConstIterator bit = bookmarkable->createBookmarksConstIterator(); while( bit.hasNext() ) { const Okteta::Bookmark& bookmark = bit.next(); QUrl bookmarkUrl = url; bookmarkUrl.setFragment( QString::number(bookmark.offset()) ); bookmarkGroup.addBookmark( bookmark.name(), bookmarkUrl, QString() ); } mBookmarkManager->save( false ); } ExternalBookmarkStorage::~ExternalBookmarkStorage() {} } diff --git a/kasten/gui/liboktetawidgets/addressvalidator.cpp b/kasten/gui/liboktetawidgets/addressvalidator.cpp index ccb69e06..b19ccc1f 100644 --- a/kasten/gui/liboktetawidgets/addressvalidator.cpp +++ b/kasten/gui/liboktetawidgets/addressvalidator.cpp @@ -1,163 +1,163 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2009 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "addressvalidator.h" // lib #include // Okteta core #include // KF5 #include // Qt #include #include #include #include namespace Okteta { AddressValidator::AddressValidator( QObject* parent, Coding codecId ) : QValidator( parent ), mCodecId( InvalidCoding ), mValueCodec( 0 ) { setCodec( codecId ); } void AddressValidator::setCodec( Coding codecId ) { if( codecId == mCodecId ) return; mCodecId = codecId; delete mValueCodec; mValueCodec = ValueCodec::createCodec( (Okteta::ValueCoding)mCodecId ); } const QRegExp AddressValidator::expressionRegex = QRegExp(QStringLiteral("[0-9a-fx\\+/\\s\\-\\*]+"), Qt::CaseInsensitive, QRegExp::RegExp2); //FIXME this is way too simple, only there to test QValidator::State AddressValidator::validate( QString& string, int& pos ) const { Q_UNUSED( pos ) State result = QValidator::Acceptable; if( mCodecId == ExpressionCoding ) { string = string.trimmed(); if( ! expressionRegex.exactMatch(string) ) result = QValidator::Invalid; //only prefix has been typed: - if( string == QStringLiteral("+") - || string == QStringLiteral("-") + if( string == QLatin1String("+") + || string == QLatin1String("-") || string.endsWith(QLatin1Char('x')) ) // 0x at end result = QValidator::Intermediate; } else { const int stringLength = string.length(); for( int i=0; iisValidDigit( c.toLatin1() ) && !c.isSpace() ) { result = QValidator::Invalid; break; } } } if( string.isEmpty() ) result = QValidator::Intermediate; return result; } Address AddressValidator::toAddress( const QString& string, AddressType* addressType) const { Address address; QString expression = string.trimmed(); if( addressType ) { const AddressType type = expression.startsWith(QLatin1Char('+')) ? RelativeForwards : expression.startsWith(QLatin1Char('-')) ? RelativeBackwards : /* else */ AbsoluteAddress; if( type != AbsoluteAddress ) expression.remove( 0, 1 ); *addressType = type; } if( mCodecId == ExpressionCoding ) { QScriptEngine evaluator; QScriptValue value = evaluator.evaluate( expression ); address = value.toInt32(); qCDebug(LOG_KASTEN_OKTETA_GUI) << "expression " << expression << " evaluated to: " << address; if( evaluator.hasUncaughtException() ) { qCWarning(LOG_KASTEN_OKTETA_GUI) << "evaluation error: " << evaluator.uncaughtExceptionBacktrace(); if( addressType ) *addressType = InvalidAddressType; } } else { const bool isHexadecimal = ( mCodecId == HexadecimalCoding ); const int base = isHexadecimal ? 16 : 10; address = expression.toInt( 0, base ); } return address; } QString AddressValidator::toString( Address address, AddressType addressType ) const { //ExpressionCoding just uses base 10 so no need to adjust this code const int isHexadecimal = ( mCodecId == HexadecimalCoding ); const int base = isHexadecimal ? 16 : 10; QString string = QString::number( address, base ); if( addressType == RelativeForwards ) string.prepend( QLatin1Char('+') ); else if( addressType == RelativeBackwards ) string.prepend( QLatin1Char('-') ); return string; } AddressValidator::~AddressValidator() { delete mValueCodec; } } diff --git a/kasten/gui/system/bytearrayviewprofilelock.cpp b/kasten/gui/system/bytearrayviewprofilelock.cpp index 0b7670c1..628e51bd 100644 --- a/kasten/gui/system/bytearrayviewprofilelock.cpp +++ b/kasten/gui/system/bytearrayviewprofilelock.cpp @@ -1,109 +1,109 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2011-2012 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "bytearrayviewprofilelock.h" // library #include // Qt #include #include namespace Kasten { class ByteArrayViewProfileLockPrivate : public QSharedData { public: ByteArrayViewProfileLockPrivate( const QString& fileName, const ByteArrayViewProfile::Id& viewProfileId ); public: QSharedPointer lockFile; ByteArrayViewProfile::Id viewProfileId; }; static QString viewProfileFileLockPath( const QString& viewProfileFilePath) { // TODO: just ".lock" conflicts with KConfig(?) using the same - return viewProfileFilePath + QStringLiteral(".olock"); + return viewProfileFilePath + QLatin1String(".olock"); } ByteArrayViewProfileLockPrivate::ByteArrayViewProfileLockPrivate( const QString& fileName, const ByteArrayViewProfile::Id& id ) : lockFile(new QLockFile(fileName.isEmpty() ? fileName : viewProfileFileLockPath(fileName))), viewProfileId( id ) { if( !fileName.isEmpty() ) { if ( !lockFile->tryLock( 1000 ) ) qCWarning(LOG_KASTEN_OKTETA_GUI) << "Failed to acquire lock file" << fileName << "error =" << lockFile->error(); } } ByteArrayViewProfileLock::ByteArrayViewProfileLock( const QString& fileName, const ByteArrayViewProfile::Id& viewProfileId ) : d( new ByteArrayViewProfileLockPrivate(fileName, viewProfileId) ) { } ByteArrayViewProfileLock::ByteArrayViewProfileLock( const ByteArrayViewProfileLock& other ) : d( other.d ) { } ByteArrayViewProfileLock& ByteArrayViewProfileLock::operator=( const ByteArrayViewProfileLock& other ) { d = other.d; return *this; } void ByteArrayViewProfileLock::unlock() { d->lockFile->unlock(); } bool ByteArrayViewProfileLock::isLocked() const { return d->lockFile->isLocked(); } ByteArrayViewProfile::Id ByteArrayViewProfileLock::viewProfileId() const { return d->viewProfileId; } ByteArrayViewProfileLock::~ByteArrayViewProfileLock() { } } diff --git a/kasten/gui/system/bytearrayviewprofilemanager.cpp b/kasten/gui/system/bytearrayviewprofilemanager.cpp index 7cb67e7f..4a512a8b 100644 --- a/kasten/gui/system/bytearrayviewprofilemanager.cpp +++ b/kasten/gui/system/bytearrayviewprofilemanager.cpp @@ -1,597 +1,597 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2010,2012 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "bytearrayviewprofilemanager.h" // library #include "bytearrayviewprofilelock.h" #include // KF5 #include #include #include // Qt #include #include #include namespace Kasten { QStringList viewProfileFileNameFilter() { return QStringList() << QStringLiteral( "*.obavp" ) << QStringLiteral( "*.olock" ); } static const QLatin1String viewProfileFileSuffix = QLatin1String( ".obavp" ); static const QLatin1String viewProfileDirSubPath = QLatin1String( "/okteta/viewprofiles" ); static const QLatin1String defaultViewProfileFileSubPath = QLatin1String( "/okteta/defaultviewprofile" ); static const int DefaultNoOfBytesPerLine = 16; static const int DefaultNoOfBytesPerGroup = 4; static const int DefaultLayoutStyle = 0; static const int DefaultViewModus = 0; static const int DefaultVisibleByteArrayCodings = 3; static const int DefaultOffsetCoding = 0; static const int DefaultValueCoding = 0; QString DefaultCharCoding() { return QString(); } static QList lockedViewProfileIds( const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup ) { QList result; ByteArrayViewProfileFileInfoLookup::ConstIterator end = viewProfileFileInfoLookup.constEnd(); for( ByteArrayViewProfileFileInfoLookup::ConstIterator it = viewProfileFileInfoLookup.constBegin(); it != end; ++it ) { if( it.value().isLocked() ) result.append( it.key() ); } return result; } static void updateLockStatus( ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup, const QList& lockedViewProfileIds, const QList& unlockedViewProfileIds ) { if( lockedViewProfileIds.isEmpty() && unlockedViewProfileIds.isEmpty() ) return; ByteArrayViewProfileFileInfoLookup::Iterator end = viewProfileFileInfoLookup.end(); for( ByteArrayViewProfileFileInfoLookup::Iterator it = viewProfileFileInfoLookup.begin(); it != end; ++it ) { bool isLocked; if( lockedViewProfileIds.contains(it.key()) ) isLocked = true; else if( unlockedViewProfileIds.contains(it.key()) ) isLocked = false; else continue; it.value().setLocked( isLocked ); } } static QString defaultViewProfileFilePath() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + defaultViewProfileFileSubPath; } static QString viewProfileFilePath( const ByteArrayViewProfile::Id& viewProfileId ) { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + viewProfileDirSubPath + QLatin1Char('/') + viewProfileId + viewProfileFileSuffix; } static QString viewProfileFileName( const ByteArrayViewProfile::Id& viewProfileId ) { return viewProfileId + viewProfileFileSuffix; } // TODO: add global lock // TODO: make calls async // TODO: only load view profiles on demand ByteArrayViewProfileManager::ByteArrayViewProfileManager() { mViewProfileFileWatcher = new KDirWatch( this ); connect( mViewProfileFileWatcher, &KDirWatch::dirty, this, &ByteArrayViewProfileManager::onViewProfilesFolderChanged ); // get all folder where viewProfiles could be stored const QStringList dataFolderPaths = QStandardPaths::standardLocations( QStandardPaths::GenericDataLocation ); foreach( const QString& dataFolderPath, dataFolderPaths ) { const QString viewProfileFolderPath = dataFolderPath + viewProfileDirSubPath; // watch folder for changes mViewProfileFileWatcher->addDir( viewProfileFolderPath, KDirWatch::WatchDirOnly ); // read current files onViewProfilesFolderChanged( viewProfileFolderPath ); } // default view profile // While there is no proper config syncing offer in the used frameworks, use a // single file with the id as content as workaround and watch for it changing KDirWatch* defaultViewProfileWatcher = new KDirWatch( this ); connect( defaultViewProfileWatcher, &KDirWatch::created, this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged ); connect( defaultViewProfileWatcher, &KDirWatch::dirty, this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged ); const QString _defaultViewProfileFilePath = defaultViewProfileFilePath(); defaultViewProfileWatcher->addFile( _defaultViewProfileFilePath ); onDefaultViewProfileChanged( _defaultViewProfileFilePath ); // report any problems with existing view profiles? } int ByteArrayViewProfileManager::viewProfilesCount() const { return mViewProfiles.count(); } QList ByteArrayViewProfileManager::viewProfiles() const { return mViewProfiles; } ByteArrayViewProfile ByteArrayViewProfileManager::viewProfile( const ByteArrayViewProfile::Id& viewProfileId ) const { ByteArrayViewProfile result; foreach( const ByteArrayViewProfile& viewProfile, mViewProfiles ) { if( viewProfile.id() == viewProfileId ) { result = viewProfile; break; } } return result; } ByteArrayViewProfile::Id ByteArrayViewProfileManager::defaultViewProfileId() const { return mDefaultViewProfileId; } ByteArrayViewProfile ByteArrayViewProfileManager::defaultViewProfile() const { return viewProfile( mDefaultViewProfileId ); } bool ByteArrayViewProfileManager::isViewProfileLocked( const ByteArrayViewProfile::Id& viewProfileId ) const { bool result = false; // search in all folders for the info foreach( const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup, mViewProfileFileInfoLookupPerFolder ) { ByteArrayViewProfileFileInfoLookup::ConstIterator it = viewProfileFileInfoLookup.find( viewProfileId ); if( it != viewProfileFileInfoLookup.constEnd() ) { result = it->isLocked(); break; } } return result; } void ByteArrayViewProfileManager::saveViewProfiles( QList& viewProfiles ) { //TODO: do not save if locked by someone else -> needs passing of our lock? or just registering our own and check? // create and set unique id for( QList::Iterator it = viewProfiles.begin(); it != viewProfiles.end(); ++it ) { ByteArrayViewProfile& viewProfile = *it; const ByteArrayViewProfile::Id viewProfileId = viewProfile.id(); const ByteArrayViewProfile::Id oldViewProfileId = viewProfile.id(); bool needsId = true; if( ! viewProfileId.isEmpty() ) { // already existing? QList::ConstIterator existingIt = mViewProfiles.constBegin(); QList::ConstIterator existingEnd = mViewProfiles.constEnd(); for( ; existingIt != existingEnd; ++existingIt ) { if( viewProfileId == existingIt->id() ) { needsId = false; break; } } } // set new uuid for non-existing if( needsId ) viewProfile.setId( QUuid::createUuid().toString() ); saveViewProfile( viewProfile ); } } void ByteArrayViewProfileManager::removeViewProfiles( const QList& viewProfileIds ) { foreach( const ByteArrayViewProfile::Id& viewProfileId, viewProfileIds ) { removeViewProfile( viewProfileId ); } } void ByteArrayViewProfileManager::setDefaultViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) { QFile defaultViewProfileFile( defaultViewProfileFilePath() ); defaultViewProfileFile.open( QIODevice::WriteOnly ); defaultViewProfileFile.write( viewProfileId.toUtf8() ); defaultViewProfileFile.close(); } ByteArrayViewProfileLock ByteArrayViewProfileManager::createLock( const ByteArrayViewProfile::Id& viewProfileId ) { const QString viewProfileFilePath = filePathOfViewProfile( viewProfileId ); return ByteArrayViewProfileLock( viewProfileFilePath, viewProfileId ); } /* bool ByteArrayViewProfileManager::lockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId ) { bool isSuccessfull; const QString viewProfileFilePath = filePathOfViewProfile( viewProfileId ); // viewProfile known if( not viewProfileFilePath.isEmpty() ) { const QString lockFilePath = viewProfileFileLockPath( viewProfileFilePath ); KLockFile::Ptr lock = new KLockFile( lockFilePath ); const KLockFile::LockResult lockResult = lock->lock(KLockFile::NoBlockFlag | KLockFile::ForceFlag); isSuccessfull = (lockResult == KLockFile::LockOK ); } // if found // try to create lock file return isSuccessfull; } */ // bool // ByteArrayViewProfileManager::unlockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId ) // { // const QString filePath = filePathOfViewProfile( viewProfileId ); // // if( filePath.isEmpty() ) // return false; // } ByteArrayViewProfile ByteArrayViewProfileManager::loadViewProfile( const QString& absoluteFilePath ) const { ByteArrayViewProfile result; KConfig configFile( absoluteFilePath, KConfig::SimpleConfig ); // check version KConfigGroup formatConfigGroup = configFile.group( "OBAVP" ); const QString formatVersion = formatConfigGroup.readEntry( "Version" ); - if( ! formatVersion.startsWith(QStringLiteral( "1." )) ) + if( ! formatVersion.startsWith(QLatin1String( "1." )) ) { return result; } result.setId( QFileInfo(absoluteFilePath).baseName() ); KConfigGroup generalConfigGroup = configFile.group( "General" ); result.setViewProfileTitle( generalConfigGroup.readEntry("Title") ); KConfigGroup layoutConfigGroup = configFile.group( "Layout" ); result.setNoOfBytesPerLine( layoutConfigGroup.readEntry("NoOfBytesPerLine", DefaultNoOfBytesPerLine) ); result.setNoOfGroupedBytes( layoutConfigGroup.readEntry("NoOfBytesPerGroup", DefaultNoOfBytesPerGroup) ); result.setLayoutStyle( layoutConfigGroup.readEntry("LayoutStyle", DefaultLayoutStyle) ); KConfigGroup displayConfigGroup = configFile.group( "Display" ); result.setOffsetColumnVisible( displayConfigGroup.readEntry("OffsetColumnVisible", true) ); result.setOffsetCoding( displayConfigGroup.readEntry("OffsetCoding", DefaultOffsetCoding) ); result.setViewModus( displayConfigGroup.readEntry("ViewModus", DefaultViewModus) ); result.setVisibleByteArrayCodings( displayConfigGroup.readEntry("VisibleByteArrayCodings", DefaultVisibleByteArrayCodings) ); KConfigGroup interpretationConfigGroup = configFile.group( "Interpretation" ); KConfigGroup valuesConfigGroup = interpretationConfigGroup.group( "Values" ); result.setValueCoding( valuesConfigGroup.readEntry("Coding", DefaultValueCoding) ); KConfigGroup charsConfigGroup = interpretationConfigGroup.group( "Chars" ); result.setCharCoding( charsConfigGroup.readEntry("Coding", DefaultCharCoding()) ); result.setShowsNonprinting( charsConfigGroup.readEntry("NonprintingShown", false) ); result.setSubstituteChar( charsConfigGroup.readEntry("SubstituteChar", ".").at(0) ); result.setUndefinedChar( charsConfigGroup.readEntry("UndefinedChar", "?").at(0) ); return result; } void ByteArrayViewProfileManager::saveViewProfile( const ByteArrayViewProfile& viewProfile ) const { const QString fileName = viewProfileFilePath( viewProfile.id() ); KConfig configFile( fileName, KConfig::SimpleConfig ); KConfigGroup formatConfigGroup = configFile.group( "OBAVP" ); formatConfigGroup.writeEntry( "Version", "1.1" ); KConfigGroup generalConfigGroup = configFile.group( "General" ); generalConfigGroup.writeEntry( "Title", viewProfile.viewProfileTitle() ); KConfigGroup layoutConfigGroup = configFile.group( "Layout" ); layoutConfigGroup.writeEntry( "NoOfBytesPerLine", viewProfile.noOfBytesPerLine() ); layoutConfigGroup.writeEntry( "NoOfBytesPerGroup", viewProfile.noOfGroupedBytes() ); layoutConfigGroup.writeEntry( "LayoutStyle", viewProfile.layoutStyle() ); KConfigGroup displayConfigGroup = configFile.group( "Display" ); displayConfigGroup.writeEntry( "OffsetColumnVisible", viewProfile.offsetColumnVisible() ); displayConfigGroup.writeEntry( "OffsetCoding", viewProfile.offsetCoding() ); displayConfigGroup.writeEntry( "ViewModus", viewProfile.viewModus() ); displayConfigGroup.writeEntry( "VisibleByteArrayCodings", viewProfile.visibleByteArrayCodings() ); KConfigGroup interpretationConfigGroup = configFile.group( "Interpretation" ); KConfigGroup valuesConfigGroup = interpretationConfigGroup.group( "Values" ); valuesConfigGroup.writeEntry( "Coding", viewProfile.valueCoding() ); KConfigGroup charsConfigGroup = interpretationConfigGroup.group( "Chars" ); charsConfigGroup.writeEntry( "Coding", viewProfile.charCodingName() ); charsConfigGroup.writeEntry( "NonprintingShown", viewProfile.showsNonprinting() ); charsConfigGroup.writeEntry( "SubstituteChar", QString(viewProfile.substituteChar()) ); charsConfigGroup.writeEntry( "UndefinedChar", QString(viewProfile.undefinedChar()) ); } void ByteArrayViewProfileManager::removeViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) { const QString filePath = filePathOfViewProfile( viewProfileId ); if( ! filePath.isEmpty() ) QFile::remove( filePath ); } QString ByteArrayViewProfileManager::filePathOfViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) const { QString result; for( QHash::ConstIterator foldersIt = mViewProfileFileInfoLookupPerFolder.constBegin(); foldersIt != mViewProfileFileInfoLookupPerFolder.constEnd() && result.isEmpty(); ++foldersIt ) { const ByteArrayViewProfileFileInfoLookup& fileInfoList = foldersIt.value(); for( ByteArrayViewProfileFileInfoLookup::ConstIterator folderIt = fileInfoList.constBegin(); folderIt != fileInfoList.constEnd(); ++folderIt ) { if( folderIt.key() == viewProfileId ) { result = foldersIt.key() + QLatin1Char('/') + viewProfileFileName( viewProfileId ); break; } } } return result; } void ByteArrayViewProfileManager::onViewProfilesFolderChanged( const QString& viewProfileFolderPath ) { ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup = mViewProfileFileInfoLookupPerFolder[viewProfileFolderPath]; // TODO: reparse for new, removed and changed files // assume all are removed and unlocked in the beginning QList removedViewProfileIds = viewProfileFileInfoLookup.keys(); QList newViewProfiles; QList changedViewProfiles; QList newUnlockedViewProfileIds = lockedViewProfileIds(viewProfileFileInfoLookup); QList newLockedViewProfileIds; // iterate all files in folder const QFileInfoList viewProfileFileInfoList = QDir( viewProfileFolderPath ).entryInfoList( viewProfileFileNameFilter(), QDir::Files ); foreach( const QFileInfo& viewProfileFileInfo, viewProfileFileInfoList ) { // a lock file ? - if( viewProfileFileInfo.suffix() == QStringLiteral("olock") ) + if( viewProfileFileInfo.suffix() == QLatin1String("olock") ) { const ByteArrayViewProfile::Id lockedViewProfileId = viewProfileFileInfo.baseName(); // if not in old locks, is a new lock if( ! newUnlockedViewProfileIds.removeOne(lockedViewProfileId) ) newLockedViewProfileIds.append( lockedViewProfileId ); continue; } // not a viewprofile file ? - if( viewProfileFileInfo.suffix() != QStringLiteral("obavp") ) + if( viewProfileFileInfo.suffix() != QLatin1String("obavp") ) continue; // all other files assumed to be viewProfile files const ByteArrayViewProfile::Id viewProfileId = viewProfileFileInfo.baseName(); // load file const ByteArrayViewProfile viewProfile = loadViewProfile( viewProfileFileInfo.absoluteFilePath() ); // loading failed? Treat as not existing if( viewProfile.id().isEmpty() ) continue; const ByteArrayViewProfileFileInfoLookup::Iterator infoIt = viewProfileFileInfoLookup.find( viewProfileId ); const bool isKnown = ( infoIt != viewProfileFileInfoLookup.end() ); const QDateTime fileInfoLastModified = viewProfileFileInfo.lastModified(); // is known? if( isKnown ) { removedViewProfileIds.removeOne( viewProfileId ); // check timestamp if( fileInfoLastModified == infoIt->lastModified() ) continue; // update timestamp infoIt->setLastModified( fileInfoLastModified ); } else { ByteArrayViewProfileFileInfo info( fileInfoLastModified, false ); viewProfileFileInfoLookup.insert( viewProfileId, info ); } if( isKnown ) { QList::Iterator it = mViewProfiles.begin(); QList::Iterator end = mViewProfiles.end(); for( ; it != end; ++it ) { if( it->id() == viewProfileId ) { *it = viewProfile; break; } } } else newViewProfiles.append( viewProfile ); changedViewProfiles.append( viewProfile ); } // remove all removed viewprofiles { QList::Iterator it = mViewProfiles.begin(); while( it != mViewProfiles.end() ) { // contained in removed? if( removedViewProfileIds.contains(it->id()) ) it = mViewProfiles.erase(it); else ++it; } } foreach( const ByteArrayViewProfile::Id& viewProfileId, removedViewProfileIds ) { viewProfileFileInfoLookup.remove( viewProfileId ); if( viewProfileId == mDefaultViewProfileId ) mDefaultViewProfileId.clear(); // TODO: how to select new one? } // add new viewprofiles mViewProfiles.append( newViewProfiles ); // if there was no default viewprofile before, set default to first const bool isDefaultViewProfileChanged = ( mDefaultViewProfileId.isEmpty() && ! mViewProfiles.isEmpty() ); if( isDefaultViewProfileChanged ) mDefaultViewProfileId = mViewProfiles.at(0).id(); // update lock info updateLockStatus( viewProfileFileInfoLookup, newLockedViewProfileIds, newUnlockedViewProfileIds ); // signal changes if( ! changedViewProfiles.isEmpty() ) emit viewProfilesChanged( changedViewProfiles ); if( ! removedViewProfileIds.isEmpty() ) emit viewProfilesRemoved( removedViewProfileIds ); if( ! newUnlockedViewProfileIds.isEmpty() ) emit viewProfilesUnlocked( newUnlockedViewProfileIds ); if( ! newLockedViewProfileIds.isEmpty() ) emit viewProfilesLocked( newLockedViewProfileIds ); if( isDefaultViewProfileChanged ) emit defaultViewProfileChanged( mDefaultViewProfileId ); } void ByteArrayViewProfileManager::onDefaultViewProfileChanged( const QString& path ) { QFile defaultViewProfileFile( path ); if ( !defaultViewProfileFile.open( QIODevice::ReadOnly ) ) { qCDebug(LOG_KASTEN_OKTETA_GUI) << "Failed to open view profiles file " << path; return; } const QByteArray fileContent = defaultViewProfileFile.readAll(); const QString viewProfileId = QString::fromUtf8( fileContent ); defaultViewProfileFile.close(); // no id set? if( viewProfileId.isEmpty() ) return; // no change? if( mDefaultViewProfileId == viewProfileId ) return; bool isExisting = false; foreach( const ByteArrayViewProfile& viewProfile, mViewProfiles ) { if( viewProfile.id() == viewProfileId ) { isExisting = true; break; } } if( isExisting ) { mDefaultViewProfileId = viewProfileId; emit defaultViewProfileChanged( mDefaultViewProfileId ); } } ByteArrayViewProfileManager::~ByteArrayViewProfileManager() { } }