nsresult
txExecutionState::init(const txXPathNode& aNode,
                       txOwningExpandedNameMap<txIGlobalParameter>* aGlobalParams)
{
    nsresult rv = NS_OK;

    mGlobalParams = aGlobalParams;

    // Set up initial context
    mEvalContext = new txSingleNodeContext(aNode, this);
    NS_ENSURE_TRUE(mEvalContext, NS_ERROR_OUT_OF_MEMORY);

    mInitialEvalContext = mEvalContext;

    // Set up output and result-handler
    txAXMLEventHandler* handler = 0;
    rv = mOutputHandlerFactory->
        createHandlerWith(mStylesheet->getOutputFormat(), &handler);
    NS_ENSURE_SUCCESS(rv, rv);

    mOutputHandler = handler;
    mResultHandler = handler;
    mOutputHandler->startDocument();

    // Set up loaded-documents-hash
    nsAutoPtr<txXPathNode> document(txXPathNodeUtils::getOwnerDocument(aNode));
    NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);

    rv = mLoadedDocuments.init(document);
    NS_ENSURE_SUCCESS(rv, rv);

    // loaded-documents-hash owns this now
    document.forget();

    // Init members
    rv = mKeyHash.init();
    NS_ENSURE_SUCCESS(rv, rv);
    
    mRecycler = new txResultRecycler;
    NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
    
    rv = mRecycler->init();
    NS_ENSURE_SUCCESS(rv, rv);
    
    // The actual value here doesn't really matter since noone should use this
    // value. But lets put something errorlike in just in case
    mGlobalVarPlaceholderValue = new StringResult(NS_LITERAL_STRING("Error"), nsnull);
    NS_ENSURE_TRUE(mGlobalVarPlaceholderValue, NS_ERROR_OUT_OF_MEMORY);

    // Initiate first instruction. This has to be done last since findTemplate
    // might use us.
    txStylesheet::ImportFrame* frame = 0;
    txExpandedName nullName;
    txInstruction* templ = mStylesheet->findTemplate(aNode, nullName,
                                                     this, nsnull, &frame);
    rv = pushTemplateRule(frame, nullName, nsnull);
    NS_ENSURE_SUCCESS(rv, rv);

    return runTemplate(templ);
}
Ejemplo n.º 2
0
nsresult
txExecutionState::getVariable(int32_t aNamespace, nsIAtom* aLName,
                              txAExprResult*& aResult)
{
    nsresult rv = NS_OK;
    txExpandedName name(aNamespace, aLName);

    // look for a local variable
    if (mLocalVariables) {
        mLocalVariables->getVariable(name, &aResult);
        if (aResult) {
            return NS_OK;
        }
    }

    // look for an evaluated global variable
    mGlobalVariableValues.getVariable(name, &aResult);
    if (aResult) {
        if (aResult == mGlobalVarPlaceholderValue) {
            // XXX ErrorReport: cyclic variable-value
            NS_RELEASE(aResult);
            return NS_ERROR_XSLT_BAD_RECURSION;
        }
        return NS_OK;
    }

    // Is there perchance a global variable not evaluated yet?
    txStylesheet::GlobalVariable* var = mStylesheet->getGlobalVariable(name);
    if (!var) {
        // XXX ErrorReport: variable doesn't exist in this scope
        return NS_ERROR_FAILURE;
    }

    NS_ASSERTION((var->mExpr && !var->mFirstInstruction) ||
                 (!var->mExpr && var->mFirstInstruction),
                 "global variable should have either instruction or expression");

    // Is this a stylesheet parameter that has a value?
    if (var->mIsParam && mGlobalParams) {
        txIGlobalParameter* param = mGlobalParams->get(name);
        if (param) {
            rv = param->getValue(&aResult);
            NS_ENSURE_SUCCESS(rv, rv);

            rv = mGlobalVariableValues.bindVariable(name, aResult);
            if (NS_FAILED(rv)) {
                NS_RELEASE(aResult);
                return rv;
            }

            return NS_OK;
        }
    }

    // Insert a placeholdervalue to protect against recursion
    rv = mGlobalVariableValues.bindVariable(name, mGlobalVarPlaceholderValue);
    NS_ENSURE_SUCCESS(rv, rv);

    // evaluate the global variable
    pushEvalContext(mInitialEvalContext);
    if (var->mExpr) {
        txVariableMap* oldVars = mLocalVariables;
        mLocalVariables = nullptr;
        rv = var->mExpr->evaluate(getEvalContext(), &aResult);
        mLocalVariables = oldVars;

        if (NS_FAILED(rv)) {
          popAndDeleteEvalContextUntil(mInitialEvalContext);
          return rv;
        }
    }
    else {
        nsAutoPtr<txRtfHandler> rtfHandler(new txRtfHandler);

        rv = pushResultHandler(rtfHandler);
        if (NS_FAILED(rv)) {
          popAndDeleteEvalContextUntil(mInitialEvalContext);
          return rv;
        }

        rtfHandler.forget();

        txInstruction* prevInstr = mNextInstruction;
        // set return to nullptr to stop execution
        mNextInstruction = nullptr;
        rv = runTemplate(var->mFirstInstruction);
        if (NS_FAILED(rv)) {
          popAndDeleteEvalContextUntil(mInitialEvalContext);
          return rv;
        }

        pushTemplateRule(nullptr, txExpandedName(), nullptr);
        rv = txXSLTProcessor::execute(*this);
        if (NS_FAILED(rv)) {
          popAndDeleteEvalContextUntil(mInitialEvalContext);
          return rv;
        }

        popTemplateRule();

        mNextInstruction = prevInstr;
        rtfHandler = (txRtfHandler*)popResultHandler();
        rv = rtfHandler->getAsRTF(&aResult);
        if (NS_FAILED(rv)) {
          popAndDeleteEvalContextUntil(mInitialEvalContext);
          return rv;
        }
    }
    popEvalContext();

    // Remove the placeholder and insert the calculated value
    mGlobalVariableValues.removeVariable(name);
    rv = mGlobalVariableValues.bindVariable(name, aResult);
    if (NS_FAILED(rv)) {
        NS_RELEASE(aResult);

        return rv;
    }

    return NS_OK;
}