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()); } } }
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 } }