//
// Check a CodeDirectory for basic integrity. This should ensure that the
// version is understood by our code, and that the internal structure
// (offsets etc.) is intact. In particular, it must make sure that no offsets
// point outside the CodeDirectory.
// Throws if the directory is corrupted or out of versioning bounds.
// Returns if the version is usable (perhaps with degraded features due to
// compatibility hacks).
//
// Note: There are some things we don't bother checking because they won't
// cause crashes, and will just be flagged as nonsense later. For example,
// a Bad Guy could overlap the identifier and hash fields, which is nonsense
// but not dangerous.
//
void CodeDirectory::checkIntegrity() const
{
	// check version for support
	if (!this->validateBlob())
		MacOSError::throwMe(errSecCSSignatureInvalid);	// busted
	if (version > compatibilityLimit)
		MacOSError::throwMe(errSecCSSignatureUnsupported);	// too new - no clue
	if (version < earliestVersion)
		MacOSError::throwMe(errSecCSSignatureUnsupported);	// too old - can't support
	if (version > currentVersion)
		secdebug("codedir", "%p version 0x%x newer than current 0x%x",
			this, uint32_t(version), currentVersion);
	
	// now check interior offsets for validity
	if (!stringAt(identOffset))
		MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range
	if (version >= supportsTeamID && teamIDOffset != 0 && !stringAt(teamIDOffset))
			MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range
	if (!contains(hashOffset - int64_t(hashSize) * nSpecialSlots, hashSize * (int64_t(nSpecialSlots) + nCodeSlots)))
		MacOSError::throwMe(errSecCSSignatureFailed); // hash array out of blob range
	if (const Scatter *scatter = this->scatterVector()) {
		// the optional scatter vector is terminated with an element having (count == 0)
		unsigned int pagesConsumed = 0;
		for (;; scatter++) {
			if (!contains(scatter, sizeof(Scatter)))
				MacOSError::throwMe(errSecCSSignatureFailed);
			if (scatter->count == 0)
				break;
			pagesConsumed += scatter->count;
		}
		if (!contains((*this)[pagesConsumed-1], hashSize))	// referenced too many main hash slots
			MacOSError::throwMe(errSecCSSignatureFailed);
	}
}
Beispiel #2
0
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
    Q_D(Compiler);
    const QString &importUri = stringAt(import->uriIndex);
    const QString &importQualifier = stringAt(import->qualifierIndex);

    if (import->type == QV4::CompiledData::Import::ImportScript) {
        // TBD: qqmltypeloader.cpp:1320
        QmlCompilation::ScriptReference scriptRef;
        scriptRef.location = import->location;
        scriptRef.qualifier = importQualifier;
        scriptRef.compilation = NULL;
        d->compilation->scripts.append(scriptRef);
    } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
        QString qmldirFilePath;
        QString qmldirUrl;
        if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) {
            //Locked modules are checked first, to save on filesystem checks
            if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion,
                                          import->minorVersion, QString(), QString(), false, errors))
                return false;

        } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion,
                                 &qmldirFilePath, &qmldirUrl)) {
            // This is a local library import
            if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion,
                                          import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
                return false;

            if (!importQualifier.isEmpty()) {
                // Does this library contain any qualified scripts?
                QUrl libraryUrl(qmldirUrl);
                QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader;
                const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl);
                foreach (const QQmlDirParser::Script &script, qmldir->scripts()) {
                    // TBD: qqmltypeloader.cpp:1343
                    qDebug() << "Library contains scripts";
                    QQmlError error;
                    error.setDescription("Libraries with scripts not supported");
                    appendError(error);
                    return false;
                }
            }
        } else {
bool PropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
{
    const QmlIR::Object *obj = qmlObjects.at(objectIndex);

    QQmlPropertyCache *baseTypeCache = 0;
    QQmlPropertyData *instantiatingProperty = 0;
    if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
        Q_ASSERT(referencingObjectIndex >= 0);
        QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex);
        Q_ASSERT(parentCache);
        Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);

        bool notInRevision = false;
        instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
        if (instantiatingProperty) {
            if (instantiatingProperty->isQObject()) {
                baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
                Q_ASSERT(baseTypeCache);
            } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) {
                baseTypeCache = enginePrivate->cache(vt->metaObject());
                Q_ASSERT(baseTypeCache);
            }
        }
    }

    bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
    if (!needVMEMetaObject) {
        for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
            if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {

                // On assignments are implemented using value interceptors, which require a VME meta object.
                needVMEMetaObject = true;

                // If the on assignment is inside a group property, we need to distinguish between QObject based
                // group properties and value type group properties. For the former the base type is derived from
                // the property that references us, for the latter we only need a meta-object on the referencing object
                // because interceptors can't go to the shared value type instances.
                if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) {
                    needVMEMetaObject = false;
                    if (!ensureMetaObject(referencingObjectIndex))
                        return false;
                }
                break;
            }
        }
    }

    if (obj->inheritedTypeNameIndex != 0) {
        QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
        Q_ASSERT(typeRef);

        if (typeRef->isFullyDynamicType) {
            if (obj->propertyCount() > 0) {
                compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new properties."));
                return false;
            }
            if (obj->signalCount() > 0) {
                compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new signals."));
                return false;
            }
            if (obj->functionCount() > 0) {
                compiler->recordError(obj->location, tr("Fully Dynamic types cannot declare new functions."));
                return false;
            }
        }

        baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
        Q_ASSERT(baseTypeCache);
    } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) {
        QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex);
        Q_ASSERT(typeRef);
        const QMetaObject *attachedMo = typeRef->type ? typeRef->type->attachedPropertiesType() : 0;
        if (!attachedMo) {
            compiler->recordError(instantiatingBinding->location, tr("Non-existent attached object"));
            return false;
        }
        baseTypeCache = enginePrivate->cache(attachedMo);
        Q_ASSERT(baseTypeCache);
    }

    if (needVMEMetaObject) {
        if (!createMetaObject(objectIndex, obj, baseTypeCache))
            return false;
    } else if (baseTypeCache) {
        propertyCaches[objectIndex] = baseTypeCache;
        baseTypeCache->addref();
    }

    if (propertyCaches.at(objectIndex)) {
        for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next)
            if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
                if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
                    return false;
            }
    }

    return true;
}
bool PropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache)
{
    QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
                                                             obj->propertyCount(),
                                                             obj->functionCount() + obj->propertyCount() + obj->signalCount(),
                                                             obj->signalCount() + obj->propertyCount());
    propertyCaches[objectIndex] = cache;

    struct TypeData {
        QV4::CompiledData::Property::Type dtype;
        int metaType;
    } builtinTypes[] = {
        { QV4::CompiledData::Property::Var, qMetaTypeId<QJSValue>() },
        { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
        { QV4::CompiledData::Property::Int, QMetaType::Int },
        { QV4::CompiledData::Property::Bool, QMetaType::Bool },
        { QV4::CompiledData::Property::Real, QMetaType::Double },
        { QV4::CompiledData::Property::String, QMetaType::QString },
        { QV4::CompiledData::Property::Url, QMetaType::QUrl },
        { QV4::CompiledData::Property::Color, QMetaType::QColor },
        { QV4::CompiledData::Property::Font, QMetaType::QFont },
        { QV4::CompiledData::Property::Time, QMetaType::QTime },
        { QV4::CompiledData::Property::Date, QMetaType::QDate },
        { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
        { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
        { QV4::CompiledData::Property::Point, QMetaType::QPointF },
        { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
        { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
        { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
        { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
        { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
        { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
    };
    static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);

    QByteArray newClassName;

    if (objectIndex == compiler->rootObjectIndex()) {
        QString path = compiler->data()->url.path();
        int lastSlash = path.lastIndexOf(QLatin1Char('/'));
        if (lastSlash > -1) {
            QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
            if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
                newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
                               QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
        }
    }
    if (newClassName.isEmpty()) {
        newClassName = QQmlMetaObject(baseTypeCache).className();
        newClassName.append("_QML_");
        newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
    }

    cache->_dynamicClassName = newClassName;

    int aliasCount = 0;
    int varPropCount = 0;

    QmlIR::PropertyResolver resolver(baseTypeCache);

    for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
        if (p->type == QV4::CompiledData::Property::Alias)
            aliasCount++;
        else if (p->type == QV4::CompiledData::Property::Var)
            varPropCount++;

        // No point doing this for both the alias and non alias cases
        bool notInRevision = false;
        QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
        if (d && d->isFinal()) {
            compiler->recordError(p->location, tr("Cannot override FINAL property"));
            return false;
        }
    }

    typedef QQmlVMEMetaData VMD;

    QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData)
                                                              + obj->propertyCount() * sizeof(VMD::PropertyData)
                                                              + obj->functionCount() * sizeof(VMD::MethodData)
                                                              + aliasCount * sizeof(VMD::AliasData), 0);

    int effectivePropertyIndex = cache->propertyIndexCacheStart;
    int effectiveMethodIndex = cache->methodIndexCacheStart;

    // For property change signal override detection.
    // We prepopulate a set of signal names which already exist in the object,
    // and throw an error if there is a signal/method defined as an override.
    QSet<QString> seenSignals;
    seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
    QQmlPropertyCache *parentCache = cache;
    while ((parentCache = parentCache->parent())) {
        if (int pSigCount = parentCache->signalCount()) {
            int pSigOffset = parentCache->signalOffset();
            for (int i = pSigOffset; i < pSigCount; ++i) {
                QQmlPropertyData *currPSig = parentCache->signal(i);
                // XXX TODO: find a better way to get signal name from the property data :-/
                for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
                        iter != parentCache->stringCache.end(); ++iter) {
                    if (currPSig == (*iter).second) {
                        seenSignals.insert(iter.key());
                        break;
                    }
                }
            }
        }
    }

    // First set up notify signals for properties - first normal, then var, then alias
    enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
    for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias

        if (ii == NSS_Var && varPropCount == 0) continue;
        else if (ii == NSS_Alias && aliasCount == 0) continue;

        for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
            if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias ||
                                      p->type == QV4::CompiledData::Property::Var)) ||
                ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) ||
                ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias)))
                continue;

            quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
                            QQmlPropertyData::IsVMESignal;

            QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
            seenSignals.insert(changedSigName);

            cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
        }
    }

    // Dynamic signals
    for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) {
        const int paramCount = s->parameters->count;

        QList<QByteArray> names;
        QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);

        if (paramCount) {
            paramTypes[0] = paramCount;

            QmlIR::SignalParameter *param = s->parameters->first;
            for (int i = 0; i < paramCount; ++i, param = param->next) {
                names.append(stringAt(param->nameIndex).toUtf8());
                if (param->type < builtinTypeCount) {
                    // built-in type
                    paramTypes[i + 1] = builtinTypes[param->type].metaType;
                } else {
                    // lazily resolved type
                    Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
                    const QString customTypeName = stringAt(param->customTypeNameIndex);
                    QQmlType *qmltype = 0;
                    if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0)) {
                        compiler->recordError(s->location, tr("Invalid signal parameter type: %1").arg(customTypeName));
                        return false;
                    }

                    if (qmltype->isComposite()) {
                        // Composite type usage
                        qDebug() << "Composite type usage2" << qmltype->sourceUrl() << "Line" << param->location.line << "Col" << param->location.column;
                        QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(param->customTypeNameIndex);
                        Q_ASSERT(typeRef->component->compiledData != NULL);
                        paramTypes[i + 1] = typeRef->component->compiledData->metaTypeId;
                    } else {
                        paramTypes[i + 1] = qmltype->typeId();
                    }
                }
            }
        }

        ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;

        quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
                        QQmlPropertyData::IsVMESignal;
        if (paramCount)
            flags |= QQmlPropertyData::HasArguments;

        QString signalName = stringAt(s->nameIndex);
        if (seenSignals.contains(signalName)) {
            compiler->recordError(s->location, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
            return false;
        }
        seenSignals.insert(signalName);

        cache->appendSignal(signalName, flags, effectiveMethodIndex++,
                            paramCount?paramTypes.constData():0, names);
    }


    // Dynamic slots
    for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
        QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;

        quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;

        if (astFunction->formals)
            flags |= QQmlPropertyData::HasArguments;

        QString slotName = astFunction->name.toString();
        if (seenSignals.contains(slotName)) {
            compiler->recordError(s->location, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
            return false;
        }

        // Note: we don't append slotName to the seenSignals list, since we don't
        // protect against overriding change signals or methods with properties.

        QList<QByteArray> parameterNames;
        QQmlJS::AST::FormalParameterList *param = astFunction->formals;
        while (param) {
            parameterNames << param->name.toUtf8();
            param = param->next;
        }

        cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
    }


    // Dynamic properties (except var and aliases)
    int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
    int propertyIdx = 0;
    for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {

        if (p->type == QV4::CompiledData::Property::Alias ||
            p->type == QV4::CompiledData::Property::Var)
            continue;

        int propertyType = 0;
        int vmePropertyType = 0;
        quint32 propertyFlags = 0;

        if (p->type < builtinTypeCount) {
            propertyType = builtinTypes[p->type].metaType;
            vmePropertyType = propertyType;

            if (p->type == QV4::CompiledData::Property::Variant)
                propertyFlags |= QQmlPropertyData::IsQVariant;
        } else {
            Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
                     p->type == QV4::CompiledData::Property::Custom);

            QQmlType *qmltype = 0;
            if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
                compiler->recordError(p->location, tr("Invalid property type"));
                return false;
            }

            Q_ASSERT(qmltype);
            if (qmltype->isComposite()) {
                // Composite type usage
                QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(p->customTypeNameIndex);
                Q_ASSERT(typeRef->component->compiledData != NULL);
                QQmlCompiledData *data = typeRef->component->compiledData;

                if (p->type == QV4::CompiledData::Property::Custom) {
                    propertyType = data->metaTypeId;
                    vmePropertyType = QMetaType::QObjectStar;
                } else {
                    propertyType = data->listMetaTypeId;
                    vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
                }

            } else {
                if (p->type == QV4::CompiledData::Property::Custom) {
                    propertyType = qmltype->typeId();
                    vmePropertyType = QMetaType::QObjectStar;
                } else {
                    propertyType = qmltype->qListTypeId();
                    vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
                }
            }

            if (p->type == QV4::CompiledData::Property::Custom)
                propertyFlags |= QQmlPropertyData::IsQObjectDerived;
            else
                propertyFlags |= QQmlPropertyData::IsQList;
        }

        if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
            propertyFlags |= QQmlPropertyData::IsWritable;


        QString propertyName = stringAt(p->nameIndex);
        if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
        cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
                              propertyType, effectiveSignalIndex);

        effectiveSignalIndex++;

        VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
        (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
        vmd->propertyCount++;
    }

    // Now do var properties
    propertyIdx = 0;
    for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {

        if (p->type != QV4::CompiledData::Property::Var)
            continue;

        quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
        if (!p->flags & QV4::CompiledData::Property::IsReadOnly)
            propertyFlags |= QQmlPropertyData::IsWritable;

        VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
        (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
        vmd->propertyCount++;
        ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;

        QString propertyName = stringAt(p->nameIndex);
        if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
        cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
                              QMetaType::QVariant, effectiveSignalIndex);

        effectiveSignalIndex++;
    }

    // Alias property count.  Actual data is setup in buildDynamicMetaAliases
    ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;

    // Dynamic slot data - comes after the property data
    for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
        QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
        int formalsCount = 0;
        QQmlJS::AST::FormalParameterList *param = astFunction->formals;
        while (param) {
            formalsCount++;
            param = param->next;
        }

        VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
                                       formalsCount,
                                       /* s->location.start.line */0 }; // ###

        VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
        VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
        vmd->methodCount++;
        md = methodData;
    }

    return true;
}
bool QmcTypeUnitComponentAndAliasResolver::addAliases()
{
    // add aliases
    //QmcUnitAlias al = {0, 0, 0, 8, 0, 0, 24};
    //qmcTypeUnit->unit->aliases.append(al);
    // see QQmlComponentAndAliasResolver::resolve
    int effectiveAliasIndex = -1;
    int effectivePropertyIndex = -1;
    int effectiveSignalIndex = -1;
    int currentObjectIndex = -1;
    QQmlPropertyCache *propertyCache = NULL;
    foreach (const QmcUnitAlias &alias, qmcTypeUnit->unit->aliases) {
        if ((int)alias.objectIndex != currentObjectIndex) {
            currentObjectIndex = alias.objectIndex;
            effectiveAliasIndex = 0;
            propertyCache = qmcTypeUnit->propertyCaches.at(alias.objectIndex);
            effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
            effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
        }
        Q_ASSERT(propertyCache);
        QQmlVMEMetaData::AliasData aliasData;
        aliasData.contextIdx = alias.contextIndex;
        aliasData.propertyIdx = alias.targetPropertyIndex;
        aliasData.propType = alias.propertyType;
        aliasData.flags = alias.flags;
        aliasData.notifySignal = alias.notifySignal;

        typedef QQmlVMEMetaData VMD;
        QByteArray &dynamicData = qmcTypeUnit->vmeMetaObjects[alias.objectIndex];
        Q_ASSERT(!dynamicData.isEmpty());
        VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
        *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;

        Q_ASSERT(dynamicData.isDetached());

        // TBD: propertyCache
        const QV4::CompiledData::Object *obj = qmcTypeUnit->compiledData->qmlUnit->objectAt(alias.objectIndex);
        Q_ASSERT(obj);
        Q_ASSERT(alias.propertyIndex < obj->nProperties);
        const QV4::CompiledData::Property *p = &obj->propertyTable()[alias.propertyIndex];
        Q_ASSERT(p);
        QString propertyName = qmcTypeUnit->stringAt(p->nameIndex);
        const QString aliasPropertyValue = qmcTypeUnit->stringAt(p->aliasPropertyValueIndex);

        //const int idIndex = p->aliasIdValueIndex;
        const int targetObjectIndex = alias.targetObjectIndex;
#if 0
        const int idIndex = p->aliasIdValueIndex;
        const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
        if (targetObjectIndex == -1) {
            recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
            return false;
        }
#endif
        QStringRef property;
        QStringRef subProperty;

        const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
        if (propertySeparator != -1) {
            property = aliasPropertyValue.leftRef(propertySeparator);
            subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
        } else
            property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());

        quint32 propertyFlags = QQmlPropertyData::IsAlias;
        int type = 0;
        bool writable = false;
        bool resettable = false;

        if (property.isEmpty()) {
            const QV4::CompiledData::Object *targetObject = qmcTypeUnit->compiledData->qmlUnit->objectAt(targetObjectIndex);
            QQmlCompiledData::TypeReference *typeRef = qmcTypeUnit->compiledData->resolvedTypes.value(targetObject->inheritedTypeNameIndex);
            Q_ASSERT(typeRef);

            if (typeRef->type)
                type = typeRef->type->typeId();
            else
                type = typeRef->component->metaTypeId;

            //flags |= QML_ALIAS_FLAG_PTR;
            propertyFlags |= QQmlPropertyData::IsQObjectDerived;
        } else {
            QQmlPropertyCache *targetCache = qmcTypeUnit->propertyCaches.at(targetObjectIndex);
            Q_ASSERT(targetCache);
            QmlIR::PropertyResolver resolver(targetCache);

            QQmlPropertyData *targetProperty = resolver.property(property.toString());
            if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
                return false;
            }

            //propIdx = targetProperty->coreIndex;
            type = targetProperty->propType;

            writable = targetProperty->isWritable();
            resettable = targetProperty->isResettable();
            //notifySignal = targetProperty->notifyIndex;

            if (!subProperty.isEmpty()) {
                QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
                if (!valueType) {
                    return false;
                }

                //propType = type;

                int valueTypeIndex =
                    valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
                if (valueTypeIndex == -1) {
                    return false;
                }
                Q_ASSERT(valueTypeIndex <= 0x0000FFFF);

                //propIdx |= (valueTypeIndex << 16);
                if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
                    type = QVariant::Int;
                else
                    type = valueType->metaObject()->property(valueTypeIndex).userType();

            } else {
                if (targetProperty->isEnum()) {
                    type = QVariant::Int;
                } else {
                    // Copy type flags
                    propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;

                    if (targetProperty->isVarProperty())
                        propertyFlags |= QQmlPropertyData::IsQVariant;

#if 0
                    if (targetProperty->isQObject())
                        flags |= QML_ALIAS_FLAG_PTR;
#endif
                }
            }
        }

        if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
            propertyFlags |= QQmlPropertyData::IsWritable;
        else
            propertyFlags &= ~QQmlPropertyData::IsWritable;

        if (resettable)
            propertyFlags |= QQmlPropertyData::IsResettable;
        else
            propertyFlags &= ~QQmlPropertyData::IsResettable;

        if ((int)alias.propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName;
        propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
                                      type, effectiveSignalIndex++);
    }

    return true;
}
Beispiel #6
0
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
    Q_D(Compiler);
    const QString &importUri = stringAt(import->uriIndex);
    const QString &importQualifier = stringAt(import->qualifierIndex);

    if (import->type == QV4::CompiledData::Import::ImportScript) {
        // TBD: qqmltypeloader.cpp:1320
        QmlCompilation::ScriptReference scriptRef;
        scriptRef.location = import->location;
        scriptRef.qualifier = importQualifier;
        scriptRef.compilation = NULL;
        d->compilation->scripts.append(scriptRef);
    } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
        QString qmldirFilePath;
        QString qmldirUrl;
        if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) {
            //Locked modules are checked first, to save on filesystem checks
            if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion,
                                          import->minorVersion, QString(), QString(), false, errors))
                return false;

        } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion,
                                 &qmldirFilePath, &qmldirUrl)) {
            // This is a local library import
            if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion,
                                          import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
                return false;

            if (!importQualifier.isEmpty()) {
                // Does this library contain any qualified scripts?
                QUrl libraryUrl(qmldirUrl);
                QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader;
                const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl);
                // File loading will import the dependency and takes care of
                // everything there. Adding a script reference here just seems
                // to add an unnecessary reference that might actually be a bug.
                // In case something is needed, see: qqmltypeloader.cpp:1343
            }
        } else {
            // Is this a module?
            qDebug() << "Importing local module" << importUri;
            if (QQmlMetaType::isAnyModule(importUri)) {
                if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion,
                                              import->minorVersion, QString(), QString(), false, errors))
                    return false;
            } else {
                QQmlError error;
                error.setDescription("Unresolved import " + importUri);
                error.setLine(import->location.line);
                error.setColumn(import->location.column);
                error.setUrl(d->compilation->url);
                appendError(error);
                return false;
                // TBD: else add to unresolved imports qqmltypeloader.cpp:1356
            }
        }
    } else {
        // qqmltypeloader.cpp:1383
        Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile);

        QUrl qmldirUrl;
        if (importQualifier.isEmpty()) {
            qmldirUrl = compilation()->loadUrl.resolved(QUrl(importUri + QLatin1String("/qmldir")));
            if (!QQmlImports::isLocal(qmldirUrl)) {
                qDebug() << "File import from network not supported";
                QQmlError error;
                error.setDescription("File import from network not supported");
                errors->append(error);
                return false;
            }
        }

        if (!compilation()->importCache->addFileImport(compilation()->importDatabase, importUri, importQualifier, import->majorVersion,
                                   import->minorVersion, /*incomplete*/ false, errors))
            return false;
    }
    return true;
}