Esempio n. 1
0
// See if we can satisfy any of the outstanding requests.
void MHEngine::CheckContentRequests()
{
    QList<MHExternContent*>::iterator it = m_ExternContentTable.begin();
    while (it != m_ExternContentTable.end())
    {
        MHExternContent *pContent = *it;
        if (m_Context->CheckCarouselObject(pContent->m_FileName))
        {
            // Remove from the list.
            it = m_ExternContentTable.erase(it);

            QByteArray text;
            if (m_Context->GetCarouselData(pContent->m_FileName, text))
            {
                MHLOG(MHLogNotifications, QString("Received %1 len %2")
                    .arg(pContent->m_pRequester->m_ObjectReference.Printable())
                    .arg(text.size()) );
                // If the content is not recognized catch the exception and continue
                try
                {
                    pContent->m_pRequester->ContentArrived(
                        reinterpret_cast< const unsigned char * >(text.constData()),
                        text.size(), this);
                }
                catch (char const *)
                {}
            }
            else
            {
                MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
                    .arg(pContent->m_pRequester->m_ObjectReference.Printable())
                    .arg(pContent->m_FileName));
                if (kProtoHTTP == PathProtocol(pContent->m_FileName))
                    EngineEvent(203); // 203=RemoteNetworkError if 404 reply
                EngineEvent(3); // ContentRefError
            }

            delete pContent;
        }
        else if (pContent->m_time.elapsed() > 60000) // TODO Get this from carousel
        {
            // Remove from the list.
            it = m_ExternContentTable.erase(it);

            MHLOG(MHLogWarning, QString("WARN File timed out %1 <= %2")
                .arg(pContent->m_pRequester->m_ObjectReference.Printable())
                .arg(pContent->m_FileName));

            if (kProtoHTTP == PathProtocol(pContent->m_FileName))
                EngineEvent(203); // 203=RemoteNetworkError if 404 reply
            EngineEvent(3); // ContentRefError

            delete pContent;
        }
        else
        {
            ++it;
        }
    }
}
Esempio n. 2
0
// Called by an ingredient wanting external content.
void MHEngine::RequestExternalContent(MHIngredient *pRequester)
{
    // It seems that some MHEG applications contain active ingredients with empty contents
    // This isn't correct but we simply ignore that.
    if (! pRequester->m_ContentRef.IsSet())
    {
        return;
    }

    // Remove any existing content requests for this ingredient.
    CancelExternalContentRequest(pRequester);

    QString csPath = GetPathName(pRequester->m_ContentRef.m_ContentRef);

    if (csPath.isEmpty())
    {
        MHLOG(MHLogWarning, "RequestExternalContent empty path");
        return;
    }
    
    if (m_Context->CheckCarouselObject(csPath))
    {
        // Available now - pass it to the ingredient.
        QByteArray text;
        if (m_Context->GetCarouselData(csPath, text))
        {
            // If the content is not recognized catch the exception and continue
            try
            {
                pRequester->ContentArrived(
                    reinterpret_cast< const unsigned char * >(text.constData()),
                    text.size(), this);
            }
            catch (char const *)
            {}
        }
        else
        {
            MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
                .arg(pRequester->m_ObjectReference.Printable()).arg(csPath));
            if (kProtoHTTP == PathProtocol(csPath))
                EngineEvent(203); // 203=RemoteNetworkError if 404 reply
            EngineEvent(3); // ContentRefError
        }
    }
    else
    {
        // Need to record this and check later.
        MHLOG(MHLogNotifications, QString("Waiting for %1 <= %2")
            .arg(pRequester->m_ObjectReference.Printable()).arg(csPath.left(128)) );
        MHExternContent *pContent = new MHExternContent;
        pContent->m_FileName = csPath;
        pContent->m_pRequester = pRequester;
        pContent->m_time.start();
        m_ExternContentTable.append(pContent);
    }
}
Esempio n. 3
0
// Implement the TestVariable action.  Triggers a TestEvent event on the result.
void MHOctetStrVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
{
    parm.CheckType(MHUnion::U_String);
    int nRes = m_Value.Compare(parm.m_StrVal);
    bool fRes = false;

    switch (nOp)
    {
        case TC_Equal:
            fRes = nRes == 0;
            break;
        case TC_NotEqual:
            fRes = nRes != 0;
            break;
            /*  case TC_Less: fRes = nRes < 0; break;
                case TC_LessOrEqual: fRes = nRes <= 0; break;
                case TC_Greater: fRes = nRes > 0; break;
                case TC_GreaterOrEqual: fRes = nRes >= 0; break;*/
        default:
            MHERROR("Invalid comparison for string"); // Shouldn't ever happen
    }

    MHOctetString sample1(m_Value, 0, 10);
    MHOctetString sample2(parm.m_StrVal, 0, 10);
    MHLOG(MHLogDetail, QString("Comparison %1 %2 and %3 => %4").arg(TestToText(nOp))
          .arg(sample1.Printable()).arg(sample2.Printable()).arg(fRes ? "true" : "false"));
    engine->EventTriggered(this, EventTestEvent, fRes);
}
Esempio n. 4
0
// Return the colour, looking up in the palette if necessary.  Used by the sub-classes
MHRgba MHVisible::GetColour(const MHColour &colour)
{
    int red = 0, green = 0, blue = 0, alpha = 0;
    int cSize = colour.m_ColStr.Size();

    if (cSize != 4)
    {
        MHLOG(MHLogWarning, QString("Colour string has length %1 not 4.").arg(cSize));
    }

    // Just in case the length is short we handle those properly.
    if (cSize > 0)
    {
        red = colour.m_ColStr.GetAt(0);
    }

    if (cSize > 1)
    {
        green = colour.m_ColStr.GetAt(1);
    }

    if (cSize > 2)
    {
        blue = colour.m_ColStr.GetAt(2);
    }

    if (cSize > 3)
    {
        alpha = 255 - colour.m_ColStr.GetAt(3);    // Convert transparency to alpha
    }

    return MHRgba(red, green, blue, alpha);
}
Esempio n. 5
0
void MHEngine::EngineEvent(int nCode)
{
    if (CurrentApp())
        EventTriggered(CurrentApp(), EventEngineEvent, nCode);
    else if (!m_fBooting)
        MHLOG(MHLogWarning, QString("WARN EngineEvent %1 but no app").arg(nCode));
}
Esempio n. 6
0
// Implement the TestVariable action.  Triggers a TestEvent event on the result.
void MHIntegerVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
{
    parm.CheckType(MHUnion::U_Int);
    bool fRes = false;

    switch (nOp)
    {
        case TC_Equal:
            fRes = m_nValue == parm.m_nIntVal;
            break;
        case TC_NotEqual:
            fRes = m_nValue != parm.m_nIntVal;
            break;
        case TC_Less:
            fRes = m_nValue < parm.m_nIntVal;
            break;
        case TC_LessOrEqual:
            fRes = m_nValue <= parm.m_nIntVal;
            break;
        case TC_Greater:
            fRes = m_nValue > parm.m_nIntVal;
            break;
        case TC_GreaterOrEqual:
            fRes = m_nValue >= parm.m_nIntVal;
            break;
        default:
            MHERROR("Invalid comparison for int"); // Shouldn't ever happen
    }

    MHLOG(MHLogDetail, QString("Comparison %1 between %2 and %3 => %4").arg(TestToText(nOp))
          .arg(m_nValue).arg(parm.m_nIntVal).arg(fRes ? "true" : "false"));
    engine->EventTriggered(this, EventTestEvent, fRes);
}
Esempio n. 7
0
// Called when an event is triggered.  Either queues the event or finds a link that matches.
void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
{
    MHLOG(MHLogLinks, QString("Event - %1 from %2")
          .arg(MHLink::EventTypeToString(ev)).arg(pSource->m_ObjectReference.Printable()));

    switch (ev)
    {
        case EventFirstItemPresented:
        case EventHeadItems:
        case EventHighlightOff:
        case EventHighlightOn:
        case EventIsAvailable:
        case EventIsDeleted:
        case EventIsDeselected:
        case EventIsRunning:
        case EventIsSelected:
        case EventIsStopped:
        case EventItemDeselected:
        case EventItemSelected:
        case EventLastItemPresented:
        case EventTailItems:
        case EventTestEvent:
        case EventTokenMovedFrom:
        case EventTokenMovedTo:
            // Synchronous events.  Fire any links that are waiting.
            // The UK MHEG describes this as the preferred interpretation.  We are checking the link
            // at the time we generate the event rather than queuing the synchronous events until
            // this elementary action is complete.  That matters if we are processing an elementary action
            // which will activate or deactivate links.
            CheckLinks(pSource->m_ObjectReference, ev, evData);
            break;
        case EventAnchorFired:
        case EventAsyncStopped:
        case EventContentAvailable:
        case EventCounterTrigger:
        case EventCursorEnter:
        case EventCursorLeave:
        case EventEngineEvent:
        case EventEntryFieldFull:
        case EventInteractionCompleted:
        case EventStreamEvent:
        case EventStreamPlaying:
        case EventStreamStopped:
        case EventTimerFired:
        case EventUserInput:
        case EventFocusMoved: // UK MHEG.  Generated by HyperText class
        case EventSliderValueChanged: // UK MHEG.  Generated by Slider class
        default:
        {
            // Asynchronous events.  Add to the event queue.
            MHAsynchEvent *pEvent = new MHAsynchEvent;
            pEvent->pEventSource = pSource;
            pEvent->eventType = ev;
            pEvent->eventData = evData;
            m_EventQueue.enqueue(pEvent);
        }
        break;
    }
}
Esempio n. 8
0
void MHStream::Initialise(MHParseNode *p, MHEngine *engine)
{
    MHPresentable::Initialise(p, engine);
    MHParseNode *pMultiplex = p->GetNamedArg(C_MULTIPLEX);

    if (pMultiplex)
    {
        for (int i = 0; i < pMultiplex->GetArgCount(); i++)
        {
            MHParseNode *pItem = pMultiplex->GetArgN(i);

            if (pItem->GetTagNo() == C_AUDIO)
            {
                MHAudio *pAudio = new MHAudio;
                m_Multiplex.Append(pAudio);
                pAudio->Initialise(pItem, engine);
            }
            else if (pItem->GetTagNo() == C_VIDEO)
            {
                MHVideo *pVideo = new MHVideo;
                m_Multiplex.Append(pVideo);
                pVideo->Initialise(pItem, engine);
            }
            else if (pItem->GetTagNo() == C_RTGRAPHICS)
            {
                MHRTGraphics *pRtGraph = new MHRTGraphics;
                m_Multiplex.Append(pRtGraph);
                pRtGraph->Initialise(pItem, engine);
            }
            else
            {
                // Ignore unknown items
                MHLOG(MHLogWarning, QString("WARN unknown stream type %1")
                    .arg(pItem->GetTagNo()));
            }
        }
    }

    MHParseNode *pStorage = p->GetNamedArg(C_STORAGE);

    if (pStorage)
    {
        m_nStorage = (enum Storage) pStorage->GetArgN(0)->GetEnumValue();
    }

    MHParseNode *pLooping = p->GetNamedArg(C_LOOPING);

    if (pLooping)
    {
        m_nLooping = pLooping->GetArgN(0)->GetIntValue();
    }
}
Esempio n. 9
0
// Implement the TestVariable action.  Triggers a TestEvent event on the result.
void MHBooleanVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
{
    parm.CheckType(MHUnion::U_Bool);
    bool fRes = false;
    switch (nOp) {
    case TC_Equal: fRes = m_fValue == parm.m_fBoolVal; break;
    case TC_NotEqual: fRes = m_fValue != parm.m_fBoolVal; break;
    default: MHERROR("Invalid comparison for bool");
    }
    MHLOG(MHLogDetail, QString("Comparison %1 between %2 and %3 => %4").arg(TestToText(nOp))
        .arg(m_fValue ? "true" : "false").arg(parm.m_fBoolVal ? "true" : "false").arg(fRes ? "true" : "false"));
    engine->EventTriggered(this, EventTestEvent, fRes);
}
Esempio n. 10
0
// Implement the SetVariable action.
void MHOctetStrVar::SetVariableValue(const MHUnion &value)
{
    if (value.m_Type == MHUnion::U_Int) {
        // Implicit conversion of int to string.
        char buff[30]; // 30 chars is more than enough.
        snprintf(buff, sizeof(buff), "%0d", value.m_nIntVal);
        m_Value.Copy(buff);
    }
    else {
        value.CheckType(MHUnion::U_String);
        m_Value.Copy(value.m_StrVal);
    }
    // Debug
    MHOctetString sample(m_Value, 0, 10);
    MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable())
        .arg(sample.Printable()));
}
Esempio n. 11
0
// Implement the SetVariable action.  Also used as part of Add, Subtract etc
void MHIntegerVar::SetVariableValue(const MHUnion &value)
{
    if (value.m_Type == MHUnion::U_String)
    {
        // Implicit conversion of string to integer.
        int v = 0;
        int p = 0;
        bool fNegative = false;

        if (value.m_StrVal.Size() > 0 && value.m_StrVal.GetAt(0) == '-')
        {
            p++;
            fNegative = true;
        }

        for (; p < value.m_StrVal.Size(); p++)
        {
            unsigned char ch =  value.m_StrVal.GetAt(p);

            if (ch < '0' || ch > '9')
            {
                break;
            }

            v = v * 10 + ch - '0';
        }

        if (fNegative)
        {
            m_nValue = -v;
        }
        else
        {
            m_nValue = v;
        }
    }
    else
    {
        value.CheckType(MHUnion::U_Int);
        m_nValue = value.m_nIntVal;
    }

    MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_nValue));
}
Esempio n. 12
0
void MHEngine::Quit()
{
    if (m_fInTransition)
    {
        MHLOG(MHLogWarning, "WARN Quit during transition - ignoring");
        return;
    }

    m_fInTransition = true; // Starting a transition

    if (CurrentScene())
    {
        CurrentScene()->Destruction(this);
    }

    CurrentApp()->Destruction(this);

    // This isn't in the standard as far as I can tell but we have to do this because
    // we may have events referring to the old application.
    while (!m_EventQueue.isEmpty())
    {
        delete m_EventQueue.dequeue();
    }

    delete m_ApplicationStack.pop();

    // If the stack is now empty we return to boot mode.
    if (m_ApplicationStack.isEmpty())
    {
        m_fBooting = true;
    }
    else
    {
        CurrentApp()->m_fRestarting = true;
        CurrentApp()->Activation(this); // This will do any OnRestart actions.
        // Note - this doesn't activate the previously active scene.
    }

    m_fInTransition = false; // The transition is complete
}
Esempio n. 13
0
// Provide updated content.
void MHIngredient::SetData(const MHOctetString &included, MHEngine *engine)
{
    // If the content is currently Included then the data should be Included
    // and similarly for Referenced content.  I've seen cases where SetData
    // with included content has been used erroneously with the intention that
    // this should be the file name for referenced content.
    if (m_ContentType == IN_ReferencedContent)
    {
        m_ContentRef.m_ContentRef.Copy(included);
    }
    else if (m_ContentType == IN_IncludedContent)
    {
        m_IncludedContent.Copy(included);

    }
    else
    {
        MHLOG(MHLogWarning, "SetData with no content");    // MHEG Error
    }

    ContentPreparation(engine);
}
Esempio n. 14
0
// Remove any pending requests from the queue.
void MHEngine::CancelExternalContentRequest(MHIngredient *pRequester)
{
    QList<MHExternContent *>::iterator it = m_ExternContentTable.begin();
    MHExternContent *pContent;

    while (it != m_ExternContentTable.end())
    {
        pContent = *it;

        if (pContent->m_pRequester == pRequester)
        {
            MHLOG(MHLogNotifications, QString("Cancelled wait for %1")
                .arg(pRequester->m_ObjectReference.Printable()) );
            it = m_ExternContentTable.erase(it);
            delete pContent;
            return;
        }
        else
        {
            ++it;
        }
    }
}
Esempio n. 15
0
// Look up an object. In most cases we just want to fail if the object isn't found.
MHRoot *MHEngine::FindObject(const MHObjectRef &oRef, bool failOnNotFound)
{
    // It should match either the application or the scene.
    MHGroup *pSearch = NULL;
    MHGroup *pScene = CurrentScene(), *pApp = CurrentApp();

    if (pScene && GetPathName(pScene->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
    {
        pSearch = pScene;
    }
    else if (pApp && GetPathName(pApp->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
    {
        pSearch = pApp;
    }

    if (pSearch)
    {
        MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);

        if (pItem)
        {
            return pItem;
        }
    }

    if (failOnNotFound)
    {
        // I've seen at least one case where MHEG code has quite deliberately referred to
        // an object that may or may not exist at a particular time.
        // Another case was a call to CallActionSlot with an object reference variable
        // that had been initialised to zero.
        MHLOG(MHLogWarning, QString("WARN Reference %1 not found").arg(oRef.m_nObjectNo));
        throw "FindObject failed";
    }

    return NULL; // If we don't generate an error.
}
Esempio n. 16
0
// This is the main loop of the engine.
int MHEngine::RunAll()
{
    // Request to boot or reboot
    if (m_fBooting)
    {
        // Reset everything
        while (!m_ApplicationStack.isEmpty())
        {
            delete m_ApplicationStack.pop();
        }

        while (!m_EventQueue.isEmpty())
        {
            delete m_EventQueue.dequeue();
        }

        while (!m_ExternContentTable.isEmpty())
        {
            delete m_ExternContentTable.takeFirst();
        }

        m_LinkTable.clear();

        // UK MHEG applications boot from ~//a or ~//startup.  Actually the initial
        // object can also be explicitly given in the
        MHObjectRef startObj;
        startObj.m_nObjectNo = 0;
        startObj.m_GroupId.Copy(MHOctetString("~//a"));

        // Launch will block until either it finds the appropriate object and
        // begins the application or discovers that the file definitely isn't
        // present in the carousel.  It is possible that the object might appear
        // if one of the containing directories is updated.
        if (! Launch(startObj))
        {
            startObj.m_GroupId.Copy(MHOctetString("~//startup"));

            if (! Launch(startObj))
            {
                MHLOG(MHLogNotifications, "NOTE Engine auto-boot failed");
                return -1;
            }
        }

        m_fBooting = false;
    }

    int nNextTime = 0;

    do
    {
        // Check to see if we need to close.
        if (m_Context->CheckStop())
        {
            return 0;
        }

        // Run queued actions.
        RunActions();
        // Now the action stack is empty process the next asynchronous event.
        // Processing one event may affect how subsequent events are handled.

        // Check to see if some files we're waiting for have arrived.
        // This could result in ContentAvailable events.
        CheckContentRequests();

        // Check the timers.  This may result in timer events being raised.
        nNextTime = CurrentScene() ? CurrentScene()->CheckTimers(this) : 0;

        if (CurrentApp())
        {
            // The UK MHEG profile allows applications to have timers.
            int nAppTime = CurrentApp()->CheckTimers(this);

            if (nAppTime != 0 && (nNextTime == 0 || nAppTime < nNextTime))
            {
                nNextTime = nAppTime;
            }
        }

        if (! m_ExternContentTable.isEmpty())
        {
            // If we have an outstanding request for external content we need to set a timer.
            if (nNextTime == 0 || nNextTime > CONTENT_CHECK_TIME)
            {
                nNextTime = CONTENT_CHECK_TIME;
            }
        }

        if (! m_EventQueue.isEmpty())
        {
            MHAsynchEvent *pEvent = m_EventQueue.dequeue();
            MHLOG(MHLogLinks, QString("Asynchronous event dequeued - %1 from %2")
                  .arg(MHLink::EventTypeToString(pEvent->eventType))
                  .arg(pEvent->pEventSource->m_ObjectReference.Printable()));
            CheckLinks(pEvent->pEventSource->m_ObjectReference, pEvent->eventType, pEvent->eventData);
            delete pEvent;
        }
    }
    while (! m_EventQueue.isEmpty() || ! m_ActionStack.isEmpty());

    // Redraw the display if necessary.
    if (! m_redrawRegion.isEmpty())
    {
        m_Context->RequireRedraw(m_redrawRegion);
        m_redrawRegion = QRegion();
    }

    return nNextTime;
}
Esempio n. 17
0
void MHEngine::TransitionToScene(const MHObjectRef &target)
{
    int i;

    if (m_fInTransition)
    {
        // TransitionTo is not allowed in OnStartUp or OnCloseDown actions.
        MHLOG(MHLogWarning, "WARN TransitionTo during transition - ignoring");
        return;
    }

    if (target.m_GroupId.Size() == 0)
    {
        return;    // No file name.
    }

    QString csPath = GetPathName(target.m_GroupId);

    // Check that the file exists before we commit to the transition.
    // This may block if we cannot be sure whether the object is present.
    QByteArray text;
    if (! m_Context->GetCarouselData(csPath, text)) {
        EngineEvent(2); // GroupIDRefError
        return;
    }

    // Parse and run the file.
    MHGroup *pProgram = ParseProgram(text);

    if (!pProgram )
        MHERROR("Empty scene");

    if (pProgram->m_fIsApp)
    {
        delete pProgram;
        MHERROR("Expected a scene");
    }

    // Clear the action queue of anything pending.
    m_ActionStack.clear();

    // At this point we have managed to load the scene.
    // Deactivate any non-shared ingredients in the application.
    MHApplication *pApp = CurrentApp();

    for (i = pApp->m_Items.Size(); i > 0; i--)
    {
        MHIngredient *pItem = pApp->m_Items.GetAt(i - 1);

        if (! pItem->IsShared())
        {
            pItem->Deactivation(this);    // This does not remove them from the display stack.
        }
    }

    m_fInTransition = true; // TransitionTo etc are not allowed.

    if (pApp->m_pCurrentScene)
    {
        pApp->m_pCurrentScene->Deactivation(this); // This may involve a call to RunActions
        pApp->m_pCurrentScene->Destruction(this);
    }

    // Everything that belongs to the previous scene should have been removed from the display stack.

    // At this point we may have added actions to the queue as a result of synchronous
    // events during the deactivation.

    // Remove any events from the asynch event queue unless they derive from
    // the application itself or a shared ingredient.
    MHAsynchEvent *pEvent;
    QQueue<MHAsynchEvent *>::iterator it = m_EventQueue.begin();

    while (it != m_EventQueue.end())
    {
        pEvent = *it;

        if (!pEvent->pEventSource->IsShared())
        {
            delete pEvent;
            it = m_EventQueue.erase(it);
        }
        else
        {
            ++it;
        }
    }

    // Can now actually delete the old scene.
    if (pApp->m_pCurrentScene)
    {
        delete(pApp->m_pCurrentScene);
        pApp->m_pCurrentScene = NULL;
    }

    m_Interacting = 0;

    // Switch to the new scene.
    CurrentApp()->m_pCurrentScene = static_cast< MHScene* >(pProgram);
    SetInputRegister(CurrentScene()->m_nEventReg);
    m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY); // Redraw the whole screen

    if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0)   // Print it so we know what's going on.
    {
        pProgram->PrintMe(__mhlogStream, 0);
    }

    pProgram->Preparation(this);
    pProgram->Activation(this);
    m_fInTransition = false; // The transition is complete
}
Esempio n. 18
0
// Launch and Spawn
bool MHEngine::Launch(const MHObjectRef &target, bool fIsSpawn)
{
    if (m_fInTransition)
    {
        MHLOG(MHLogWarning, "WARN Launch during transition - ignoring");
        return false;
    }

    if (target.m_GroupId.Size() == 0) return false; // No file name.
    QString csPath = GetPathName(target.m_GroupId); // Get path relative to root.

    // Check that the file exists before we commit to the transition.
    // This may block if we cannot be sure whether the object is present.
    QByteArray text;
    if (! m_Context->GetCarouselData(csPath, text))
    {
        if (!m_fBooting)
            EngineEvent(2); // GroupIDRefError
        return false;
    }

    MHApplication *pProgram = (MHApplication*)ParseProgram(text);
    if (! pProgram)
    {
        MHLOG(MHLogWarning, "Empty application");
        return false;
    }
    if (! pProgram->m_fIsApp)
    {
        MHLOG(MHLogWarning, "Expected an application");
        delete pProgram;
        return false;
    }
    if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0)   // Print it so we know what's going on.
    {
        pProgram->PrintMe(__mhlogStream, 0);
    }

    // Clear the action queue of anything pending.
    m_ActionStack.clear();

    m_fInTransition = true; // Starting a transition

    try
    {
        if (CurrentApp())
        {
            if (fIsSpawn)   // Run the CloseDown actions.
            {
                AddActions(CurrentApp()->m_CloseDown);
                RunActions();
            }

            if (CurrentScene())
            {
                CurrentScene()->Destruction(this);
            }

            CurrentApp()->Destruction(this);

            if (!fIsSpawn)
            {
                delete m_ApplicationStack.pop();    // Pop and delete the current app.
            }
        }

        // Save the path we use for this app.
        pProgram->m_Path = csPath; // Record the path
        int nPos = pProgram->m_Path.lastIndexOf('/');

        if (nPos < 0)
        {
            pProgram->m_Path = "";
        }
        else
        {
            pProgram->m_Path = pProgram->m_Path.left(nPos);
        }

        // Have now got the application.
        m_ApplicationStack.push(pProgram);

        // This isn't in the standard as far as I can tell but we have to do this because
        // we may have events referring to the old application.
        while (!m_EventQueue.isEmpty())
        {
            delete m_EventQueue.dequeue();
        }

        // Activate the application. ....
        CurrentApp()->Activation(this);
        m_fInTransition = false; // The transition is complete
        return true;
    }
    catch (...)
    {
        m_fInTransition = false; // The transition is complete
        return false;
    }
}
Esempio n. 19
0
// Implement the SetVariable action.
void MHBooleanVar::SetVariableValue(const MHUnion &value)
{
    value.CheckType(MHUnion::U_Bool);
    m_fValue = value.m_fBoolVal;
    MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_fValue ? "true" : "false"));
}
Esempio n. 20
0
void MHResidentProgram::CallProgram(bool fIsFork, const MHObjectRef &success, const MHSequence<MHParameter *> &args, MHEngine *engine)
{
    if (! m_fAvailable)
    {
        Preparation(engine);
    }

    //  if (m_fRunning) return; // Strictly speaking there should be only one instance of a program running at a time.
    Activation(engine);
    MHLOG(MHLogDetail, QString("Calling program %1").arg(m_Name.Printable()));

    try
    {
        // Run the code.
        if (m_Name.Equal("GCD"))   // GetCurrentDate - returns local time.
        {
            if (args.Size() == 2)
            {
                time_t epochSeconds = 0;
                short int timeZone = 0;
#if HAVE_GETTIMEOFDAY
                struct timeval   time;
                struct timezone  zone;

                if (gettimeofday(&time, &zone) == -1)
                {
                    MHLOG(MHLogDetail, QString("gettimeofday() failed"));
                }

                epochSeconds     = time.tv_sec;
                timeZone = zone.tz_minuteswest;
#elif HAVE_FTIME
                struct timeb timebuffer;
                if (ftime(&timebuffer) == -1)
                {
                    MHLOG(MHLogDetail, QString("ftime() failed"));
                }
                epochSeconds = timebuffer.time;
                timeZone = timebuffer.timezone;
#else
#error Configuration error? No ftime() or gettimeofday()?
#endif
                // Adjust the time to local.  TODO: Check this.
                epochSeconds -= timeZone * 60;
                // Time as seconds since midnight.
                int nTimeAsSecs = epochSeconds % (24 * 60 * 60);
                // Modified Julian date as number of days since 17th November 1858.
                // 1st Jan 1970 was date 40587.
                int nModJulianDate = 40587 + epochSeconds / (24 * 60 * 60);

                engine->FindObject(*(args.GetAt(0)->GetReference()))->SetVariableValue(nModJulianDate);
                engine->FindObject(*(args.GetAt(1)->GetReference()))->SetVariableValue(nTimeAsSecs);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("FDa"))   // FormatDate
        {
            if (args.Size() == 4)
            {
                // This is a bit like strftime but not quite.
                MHOctetString format;
                GetString(args.GetAt(0), format, engine);
                int date = GetInt(args.GetAt(1), engine); // As produced in GCD
                int time = GetInt(args.GetAt(2), engine);
                // Convert to a Unix date (secs since 1st Jan 1970) but adjusted for time zone.
                time_t timet = (date - 40587) * (24 * 60 * 60) + time;
                struct tm *timeStr = gmtime(&timet);
                MHOctetString result;

                for (int i = 0; i < format.Size(); i++)
                {
                    unsigned char ch = format.GetAt(i);
                    char buffer[5]; // Largest text is 4 chars for a year + null terminator

                    if (ch == '%')
                    {
                        i++;

                        if (i == format.Size())
                        {
                            break;
                        }

                        ch = format.GetAt(i);
                        buffer[0] = 0;

                        switch (ch)
                        {
                            case 'Y':
                                sprintf(buffer, "%04d", timeStr->tm_year + 1900);
                                break;
                            case 'y':
                                sprintf(buffer, "%02d", timeStr->tm_year % 100);
                                break;
                            case 'X':
                                sprintf(buffer, "%02d", timeStr->tm_mon + 1);
                                break;
                            case 'x':
                                sprintf(buffer, "%1d", timeStr->tm_mon + 1);
                                break;
                            case 'D':
                                sprintf(buffer, "%02d", timeStr->tm_mday);
                                break;
                            case 'd':
                                sprintf(buffer, "%1d", timeStr->tm_mday);
                                break;
                            case 'H':
                                sprintf(buffer, "%02d", timeStr->tm_hour);
                                break;
                            case 'h':
                                sprintf(buffer, "%1d", timeStr->tm_hour);
                                break;
                            case 'I':

                                if (timeStr->tm_hour == 12 || timeStr->tm_hour == 0)
                                {
                                    strcpy(buffer, "12");
                                }
                                else
                                {
                                    sprintf(buffer, "%02d", timeStr->tm_hour % 12);
                                }

                                break;
                            case 'i':

                                if (timeStr->tm_hour == 12 || timeStr->tm_hour == 0)
                                {
                                    strcpy(buffer, "12");
                                }
                                else
                                {
                                    sprintf(buffer, "%1d", timeStr->tm_hour % 12);
                                }

                                break;
                            case 'M':
                                sprintf(buffer, "%02d", timeStr->tm_min);
                                break;
                            case 'm':
                                sprintf(buffer, "%1d", timeStr->tm_min);
                                break;
                            case 'S':
                                sprintf(buffer, "%02d", timeStr->tm_sec);
                                break;
                            case 's':
                                sprintf(buffer, "%1d", timeStr->tm_sec);
                                break;
                                // TODO: These really should be localised.
                            case 'A':

                                if (timeStr->tm_hour < 12)
                                {
                                    strcpy(buffer, "AM");
                                }
                                else
                                {
                                    strcpy(buffer, "PM");
                                }

                                break;
                            case 'a':

                                if (timeStr->tm_hour < 12)
                                {
                                    strcpy(buffer, "am");
                                }
                                else
                                {
                                    strcpy(buffer, "pm");
                                }

                                break;
                            default:
                                buffer[0] = ch;
                                buffer[1] = 0;
                        }

                        result.Append(buffer);
                    }
                    else
                    {
                        result.Append(MHOctetString(&ch, 1));
                    }
                }

                MHParameter *pResString = args.GetAt(3);
                engine->FindObject(*(pResString->GetReference()))->SetVariableValue(result);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("GDW"))   // GetDayOfWeek - returns the day of week that the date occurred on.
        {
            if (args.Size() == 2)
            {
                int date = GetInt(args.GetAt(0), engine); // Date as produced in GCD
                // Convert to a Unix date (secs since 1st Jan 1970) but adjusted for time zone.
                time_t timet = (date - 40587) * (24 * 60 * 60);
                struct tm *timeStr = gmtime(&timet);
                // 0 => Sunday, 1 => Monday etc.
                engine->FindObject(*(args.GetAt(1)->GetReference()))->SetVariableValue(timeStr->tm_wday);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("Rnd"))   // Random
        {
            if (args.Size() == 2)
            {
                int nLimit = GetInt(args.GetAt(0), engine);
                MHParameter *pResInt = args.GetAt(1);
                int r = random() % (nLimit + 1);
                engine->FindObject(
                    *(pResInt->GetReference()))->SetVariableValue(r);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("CTC"))   // CastToContentRef
        {
            // Converts a string to a ContentRef.
            if (args.Size() == 2)
            {
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                MHContentRef result;
                result.m_ContentRef.Copy(string);
                engine->FindObject(*(args.GetAt(1)->GetReference()))->SetVariableValue(result);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("CTO"))   // CastToObjectRef
        {
            // Converts a string and an integer to an ObjectRef.
            if (args.Size() == 3)
            {
                MHObjectRef result;
                GetString(args.GetAt(0), result.m_GroupId, engine);
                result.m_nObjectNo = GetInt(args.GetAt(1), engine);
                engine->FindObject(*(args.GetAt(2)->GetReference()))->SetVariableValue(result);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("GSL"))   // GetStringLength
        {
            if (args.Size() == 2)
            {
                // Find a substring within a string and return an index to the position.
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                MHParameter *pResInt = args.GetAt(1);
                SetSuccessFlag(success, true, engine);
                engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(string.Size());
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("GSS"))   // GetSubString
        {
            if (args.Size() == 4)   // Extract a sub-string from a string.
            {
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                int nBeginExtract = GetInt(args.GetAt(1), engine);
                int nEndExtract = GetInt(args.GetAt(2), engine);

                if (nBeginExtract < 1)
                {
                    nBeginExtract = 1;
                }

                if (nBeginExtract > string.Size())
                {
                    nBeginExtract = string.Size();
                }

                if (nEndExtract < 1)
                {
                    nEndExtract = 1;
                }

                if (nEndExtract > string.Size())
                {
                    nEndExtract = string.Size();
                }

                MHParameter *pResString = args.GetAt(3);
                // Returns beginExtract to endExtract inclusive.
                engine->FindObject(*(pResString->GetReference()))->SetVariableValue(
                    MHOctetString(string, nBeginExtract - 1, nEndExtract - nBeginExtract + 1));
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("SSS"))   // SearchSubString
        {
            if (args.Size() == 4)
            {
                // Find a substring within a string and return an index to the position.
                MHOctetString string, searchString;
                GetString(args.GetAt(0), string, engine);
                int nStart = GetInt(args.GetAt(1), engine);

                if (nStart < 1)
                {
                    nStart = 1;
                }

                GetString(args.GetAt(2), searchString, engine);
                // Strings are indexed from one.
                int nPos;

                for (nPos = nStart - 1; nPos <= string.Size() - searchString.Size(); nPos++)
                {
                    int i;

                    for (i = 0; i < searchString.Size(); i++)
                    {
                        if (searchString.GetAt(i) != string.GetAt(i + nPos))
                        {
                            break;
                        }
                    }

                    if (i == searchString.Size())
                    {
                        break;    // Found a match.
                    }
                }

                // Set the result.
                MHParameter *pResInt = args.GetAt(3);
                SetSuccessFlag(success, true, engine); // Set this first.

                if (nPos <= string.Size() - searchString.Size())   // Found
                {
                    // Set the index to the position of the string, counting from 1.
                    engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(nPos + 1);
                }
                else   // Not found.  Set the result index to -1
                {
                    engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(-1);
                }
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("SES"))   // SearchAndExtractSubString
        {
            if (args.Size() == 5)
            {
                // Find a substring within a string and return an index to the position
                // and the prefix to the substring.
                MHOctetString string, searchString;
                GetString(args.GetAt(0), string, engine);
                int nStart = GetInt(args.GetAt(1), engine);

                if (nStart < 1)
                {
                    nStart = 1;
                }

                GetString(args.GetAt(2), searchString, engine);
                // Strings are indexed from one.
                int nPos;

                for (nPos = nStart - 1; nPos <= string.Size() - searchString.Size(); nPos++)
                {
                    int i;

                    for (i = 0; i < searchString.Size(); i++)
                    {
                        if (searchString.GetAt(i) != string.GetAt(i + nPos))
                        {
                            break;    // Doesn't match
                        }
                    }

                    if (i == searchString.Size())
                    {
                        break;    // Found a match.
                    }
                }

                // Set the results.
                MHParameter *pResString = args.GetAt(3);
                MHParameter *pResInt = args.GetAt(4);
                SetSuccessFlag(success, true, engine); // Set this first.

                if (nPos <= string.Size() - searchString.Size())   // Found
                {
                    // Set the index to the position AFTER the string, counting from 1.
                    engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(nPos + 1 + searchString.Size());
                    // Return the sequence from nStart-1 of length nPos-nStart+1
                    MHOctetString resultString(string, nStart - 1, nPos - nStart + 1);
                    engine->FindObject(*(pResString->GetReference()))->SetVariableValue(resultString);
                }
                else   // Not found.  Set the result string to empty and the result index to -1
                {
                    engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(-1);
                    engine->FindObject(*(pResString->GetReference()))->SetVariableValue(MHOctetString(""));
                }
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("GSI"))   // SI_GetServiceIndex
        {
            // Returns an index indicating the service
            if (args.Size() == 2)
            {
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                MHParameter *pResInt = args.GetAt(1);
                // The format of the service is dvb://netID.[transPortID].serviceID
                // where the IDs are in hex.
                // or rec://svc/lcn/N where N is the "logical channel number" i.e. the Freeview channel.
                QString str = QString::fromUtf8((const char *)string.Bytes(), string.Size());
                int nResult = engine->GetContext()->GetChannelIndex(str);
                engine->FindObject(*(pResInt->GetReference()))->SetVariableValue(nResult);
                SetSuccessFlag(success, nResult >= 0, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("TIn"))   // SI_TuneIndex - Fork not allowed
        {
            // Tunes to an index returned by GSI
            if (args.Size() == 1)
            {
                int nChannel = GetInt(args.GetAt(0), engine);
                bool res = nChannel >= 0 ? engine->GetContext()->TuneTo(
                               nChannel, engine->GetTuneInfo()) : false;
                SetSuccessFlag(success, res, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }
        else if (m_Name.Equal("TII"))   // SI_TuneIndexInfo
        {
            // Indicates whether to perform a subsequent TIn quietly or normally.
            if (args.Size() == 1)
            {
                int tuneinfo = GetInt(args.GetAt(0), engine);
                engine->SetTuneInfo(tuneinfo);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }
        else if (m_Name.Equal("BSI"))   // SI_GetBasicSI
        {
            // Returns basic SI information about the service indicated by an index
            // returned by GSI.
            // Returns networkID, origNetworkID, transportStreamID, serviceID
            if (args.Size() == 5)
            {
                int channelId = GetInt(args.GetAt(0), engine);
                int netId, origNetId, transportId, serviceId;
                // Look the information up in the database.
                bool res = engine->GetContext()->GetServiceInfo(channelId, netId, origNetId,
                                                                transportId, serviceId);

                if (res)
                {
                    engine->FindObject(*(args.GetAt(1)->GetReference()))->SetVariableValue(netId);
                    engine->FindObject(*(args.GetAt(2)->GetReference()))->SetVariableValue(origNetId);
                    engine->FindObject(*(args.GetAt(3)->GetReference()))->SetVariableValue(transportId);
                    engine->FindObject(*(args.GetAt(4)->GetReference()))->SetVariableValue(serviceId);
                }

                SetSuccessFlag(success, res, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }
        else if (m_Name.Equal("GBI"))   // GetBootInfo
        {
            // Gets the NB_info field.
            MHERROR("GetBootInfo ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("CCR"))   // CheckContentRef
        {
            // Sees if an item with a particular content reference is available
            // in the carousel.  This looks like it should block until the file
            // is available.  The profile recommends that this should be forked
            // rather than called.
            if (args.Size() == 3)
            {
                MHUnion un;
                un.GetValueFrom(*(args.GetAt(0)), engine);
                un.CheckType(MHUnion::U_ContentRef);
                MHContentRef fileName;
                fileName.Copy(un.m_ContentRefVal);
                QString csPath = engine->GetPathName(fileName.m_ContentRef);
                bool result = false;
                QByteArray text;

                // Try to load the object.
                if (! csPath.isEmpty())
                {
                    result = engine->GetContext()->GetCarouselData(csPath, text);
                }

                // Set the result variable.
                MHParameter *pResFlag = args.GetAt(1);
                engine->FindObject(*(pResFlag->GetReference()))->SetVariableValue(result);
                MHParameter *pResCR = args.GetAt(2);
                // Copy the file name to the resulting content ref.
                engine->FindObject(*(pResCR->GetReference()))->SetVariableValue(fileName);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }
        else if (m_Name.Equal("CGR"))   // CheckGroupIDRef
        {
            // Sees if an application or scene with a particular group id
            // is available in the carousel.
            MHERROR("CheckGroupIDRef ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("VTG"))   // VideoToGraphics
        {
            // Video to graphics transformation.
            MHERROR("VideoToGraphics ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("SWA"))   // SetWidescreenAlignment
        {
            // Sets either LetterBox or Centre-cut-out mode.
            // Seems to be concerned with aligning a 4:3 scene with an underlying 16:9 video
            MHERROR("SetWidescreenAlignment ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("GDA"))   // GetDisplayAspectRatio
        {
            // Returns the aspcet ratio.  4:3 => 1, 16:9 => 2
            MHERROR("GetDisplayAspectRatio ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("CIS"))   // CI_SendMessage
        {
            // Sends a message to a DVB CI application
            MHERROR("CI_SendMessage ResidentProgram is not implemented");
        }
        else if (m_Name.Equal("SSM"))   // SetSubtitleMode
        {
            // Enable or disable subtitles in addition to MHEG.
            if (args.Size() == 1) {
                bool status = GetBool(args.GetAt(0), engine);
                MHLOG(MHLogNotifications, QString("NOTE SetSubtitleMode %1")
                    .arg(status ? "enabled" : "disabled"));
                // TODO Notify player
                SetSuccessFlag(success, true, engine);
            }
            else SetSuccessFlag(success, false, engine);
        }

        else if (m_Name.Equal("WAI"))   // WhoAmI
        {
            // Return a concatenation of the strings we respond to in
            // GetEngineSupport(UKEngineProfile(X))
            if (args.Size() == 1)
            {
                MHOctetString result;
                result.Copy(engine->MHEGEngineProviderIdString);
                result.Append(" ");
                result.Append(engine->GetContext()->GetReceiverId());
                result.Append(" ");
                result.Append(engine->GetContext()->GetDSMCCId());
                engine->FindObject(*(args.GetAt(0)->GetReference()))->SetVariableValue(result);
                SetSuccessFlag(success, true, engine);
            }
            else
            {
                SetSuccessFlag(success, false, engine);
            }
        }

        else if (m_Name.Equal("DBG"))   // Debug - optional
        {
            QString message = "DEBUG: ";

            for (int i = 0; i < args.Size(); i++)
            {
                MHUnion un;
                un.GetValueFrom(*(args.GetAt(i)), engine);

                switch (un.m_Type)
                {
                    case MHUnion::U_Int:
                        message.append(QString("%1").arg(un.m_nIntVal));
                        break;
                    case MHParameter::P_Bool:
                        message.append(un.m_fBoolVal ? "True" : "False");
                        break;
                    case MHParameter::P_String:
                        message.append(QString::fromUtf8((const char *)un.m_StrVal.Bytes(), un.m_StrVal.Size()));
                        break;
                    case MHParameter::P_ObjRef:
                        message.append(un.m_ObjRefVal.Printable());
                        break;
                    case MHParameter::P_ContentRef:
                        message.append(un.m_ContentRefVal.Printable());
                        break;
                    case MHParameter::P_Null:
                        break;
                }
            }

            MHLOG(MHLogNotifications, message);
        }

        else if (m_Name.Equal("SBI"))   // SetBroadcastInterrupt
        {
            // Required for NativeApplicationExtension
            // En/dis/able program interruptions e.g. green button
            if (args.Size() == 1) {
                bool status = GetBool(args.GetAt(0), engine);
                MHLOG(MHLogNotifications, QString("NOTE SetBroadcastInterrupt %1")
                    .arg(status ? "enabled" : "disabled"));
                // Nothing todo at present
                SetSuccessFlag(success, true, engine);
            }
            else SetSuccessFlag(success, false, engine);
        }

        // InteractionChannelExtension
        else if (m_Name.Equal("GIS")) { // GetICStatus
            if (args.Size() == 1)
            {
                int ICstatus = engine->GetContext()->GetICStatus();
                MHLOG(MHLogNotifications, "NOTE InteractionChannel " + QString(
                    ICstatus == 0 ? "active" : ICstatus == 1 ? "inactive" :
                    ICstatus == 2 ? "disabled" : "undefined"));
                engine->FindObject(*(args.GetAt(0)->GetReference()))->SetVariableValue(ICstatus);
                SetSuccessFlag(success, true, engine);
            }
            else SetSuccessFlag(success, false, engine);
        }
        else if (m_Name.Equal("RDa")) { // ReturnData
            if (args.Size() >= 3)
            {
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                QString url = QString::fromUtf8((const char *)string.Bytes(), string.Size());

                // Variable name/value pairs
                QStringList params;
                int i = 1;
                for (; i + 2 < args.Size(); i += 2)
                {
                    GetString(args.GetAt(i), string, engine);
                    QString name = QString::fromUtf8((const char *)string.Bytes(), string.Size());
                    QString val;
                    MHUnion un;
                    un.GetValueFrom(*(args.GetAt(i+1)), engine);
                    switch (un.m_Type) {
                    case MHUnion::U_Int:
                        val = QString::number(un.m_nIntVal);
                        break;
                    case MHParameter::P_Bool:
                        val = un.m_fBoolVal ? "true" : "false";
                        break;
                    case MHParameter::P_String:
                        val = QString::fromUtf8((const char*)un.m_StrVal.Bytes(), un.m_StrVal.Size());
                        break;
                    case MHParameter::P_ObjRef:
                        val = un.m_ObjRefVal.Printable();
                        break;
                    case MHParameter::P_ContentRef:
                        val = un.m_ContentRefVal.Printable();
                        break;
                    case MHParameter::P_Null:
                        val = "<NULL>";
                        break;
                    default:
                        val = QString("<type %1>").arg(un.m_Type);
                        break;
                    }
                    params += name + "=" + val;
                }
                // TODO
                MHLOG(MHLogNotifications, "NOTE ReturnData '" + url + "' { " + params.join(" ") + " }");
                // HTTP response code, 0= none
                engine->FindObject(*(args.GetAt(i)->GetReference()))->SetVariableValue(0);
                // HTTP response data
                string = "";
                engine->FindObject(*(args.GetAt(i+1)->GetReference()))->SetVariableValue(string);
                SetSuccessFlag(success, false, engine);
            }
            else SetSuccessFlag(success, false, engine);
        }
        else if (m_Name.Equal("SHF")) { // SetHybridFileSystem
            if (args.Size() == 2)
            {
                MHOctetString string;
                GetString(args.GetAt(0), string, engine);
                QString str = QString::fromUtf8((const char *)string.Bytes(), string.Size());
                GetString(args.GetAt(1), string, engine);
                QString str2 = QString::fromUtf8((const char *)string.Bytes(), string.Size());
                // TODO
                MHLOG(MHLogNotifications, QString("NOTE SetHybridFileSystem %1=%2")
                    .arg(str).arg(str2));
                SetSuccessFlag(success, false, engine);
            }
            else SetSuccessFlag(success, false, engine);
        }

        else
        {
            MHERROR(QString("Unknown ResidentProgram %1").arg(m_Name.Printable()));
        }
    }
    catch (char const *)
    {
        // If something went wrong set the succeeded flag to false
        SetSuccessFlag(success, false, engine);
        // And continue on.  In particular we need to deactivate.
    }

    Deactivation(engine);

    // At the moment we always treat Fork as Call.  If we do get a Fork we should signal that we're done.
    if (fIsFork)
    {
        engine->EventTriggered(this, EventAsyncStopped);
    }
}
Esempio n. 21
0
// Recreate the image.
void MHText::Redraw()
{
    if (! m_fRunning || !m_pDisplay)
    {
        return;
    }

    if (m_nBoxWidth == 0 || m_nBoxHeight == 0)
    {
        return;    // Can't draw zero sized boxes.
    }

    m_pDisplay->SetSize(m_nBoxWidth, m_nBoxHeight);
    m_pDisplay->Clear();

    MHRgba textColour = GetColour(m_textColour);
    // Process any escapes in the text and construct the text arrays.
    MHSequence <MHTextLine *> theText;
    // Set up the first item on the first line.
    MHTextItem *pCurrItem = new MHTextItem;
    MHTextLine *pCurrLine = new MHTextLine;
    pCurrLine->m_Items.Append(pCurrItem);
    theText.Append(pCurrLine);
    MHStack <MHRgba> m_ColourStack; // Stack to handle nested colour codes.
    m_ColourStack.Push(textColour);
    pCurrItem->m_Colour = textColour;

//  FILE *fd=stdout; fprintf(fd, "Redraw Text "); m_Content.PrintMe(fd, 0); fprintf(fd, "\n");
    int i = 0;

    while (i < m_Content.Size())
    {
        unsigned char ch = m_Content.GetAt(i++);

        if (ch == 0x09) // Tab - start a new item if we have any text in the existing one.
        {
            if (pCurrItem->m_Text.Size() != 0)
            {
                pCurrItem = pCurrItem->NewItem();
                pCurrLine->m_Items.Append(pCurrItem);
            }
            if (m_HorizJ == Start)
                pCurrItem->m_nTabCount++;
        }

        else if (ch == 0x0d)    // CR - line break.
        {
            // TODO: Two CRs next to one another are treated as </P> rather than <BR><BR>
            // This should also include the sequence CRLFCRLF.
            pCurrLine = new MHTextLine;
            theText.Append(pCurrLine);
            pCurrItem = pCurrItem->NewItem();
            pCurrLine->m_Items.Append(pCurrItem);
        }

        else if (ch == 0x1b)   // Escape - special codes.
        {
            if (i == m_Content.Size())
            {
                break;
            }

            unsigned char code = m_Content.GetAt(i);
            // The only codes we are interested in are the start and end of colour.
            // TODO: We may also need "bold" and some hypertext colours.

            if (code >= 0x40 && code <= 0x5e)   // Start code
            {
                // Start codes are followed by a parameter count and a number of parameter bytes.
                if (++i == m_Content.Size())
                {
                    break;
                }

                unsigned char paramCount = m_Content.GetAt(i);
                i++;

                if (code == 0x43 && paramCount == 4 && i + paramCount <= m_Content.Size())
                {
                    // Start of colour.
                    if (pCurrItem->m_Text.Size() != 0)
                    {
                        pCurrItem = pCurrItem->NewItem();
                        pCurrLine->m_Items.Append(pCurrItem);
                    }

                    pCurrItem->m_Colour = MHRgba(m_Content.GetAt(i), m_Content.GetAt(i + 1),
                                                 m_Content.GetAt(i + 2), 255 - m_Content.GetAt(i + 3));
                    // Push this colour onto the colour stack.
                    m_ColourStack.Push(pCurrItem->m_Colour);
                }
                else
                {
                    MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code, 2, 16));
                }

                i += paramCount; // Skip the parameters
            }
            else if (code >= 0x60 && code <= 0x7e)   // End code.
            {
                i++;

                if (code == 0x63)
                {
                    if (m_ColourStack.Size() > 1)
                    {
                        m_ColourStack.Pop();

                        // Start a new item since we're using a new colour.
                        if (pCurrItem->m_Text.Size() != 0)
                        {
                            pCurrItem = pCurrItem->NewItem();
                            pCurrLine->m_Items.Append(pCurrItem);
                        }

                        // Set the subsequent text in the colour we're using now.
                        pCurrItem->m_Colour = m_ColourStack.Top();
                    }
                }
                else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
            }
            else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
        }

        else if (ch <= 0x1f)
        {
            // Certain characters including LF and the marker codes between 0x1c and 0x1f are
            // explicitly intended to be ignored.  Include all the other codes.
        }

        else   // Add to the current text.
        {
            int nStart = i - 1;

            while (i < m_Content.Size() && m_Content.GetAt(i) >= 0x20)
            {
                i++;
            }

            pCurrItem->m_Text.Append(MHOctetString(m_Content, nStart, i - nStart));
        }
    }

    // Set up the initial attributes.
    int style, size, lineSpace, letterSpace;
    InterpretAttributes(m_fontAttrs, style, size, lineSpace, letterSpace);
    // Create a font with this information.
    m_pDisplay->SetFont(size, (style & 2) != 0, (style & 1) != 0);

    // Calculate the layout of each section.
    for (i = 0; i < theText.Size(); i++)
    {
        MHTextLine *pLine = theText.GetAt(i);
        pLine->m_nLineWidth = 0;

        for (int j = 0; j < pLine->m_Items.Size(); j++)
        {
            MHTextItem *pItem = pLine->m_Items.GetAt(j);

            // Set any tabs.
            pLine->m_nLineWidth = Tabs(pLine->m_nLineWidth, pItem->m_nTabCount);

            if (pItem->m_Unicode.isEmpty())   // Convert UTF-8 to Unicode.
            {
                int s = pItem->m_Text.Size();
                pItem->m_Unicode = QString::fromUtf8((const char *)pItem->m_Text.Bytes(), s);
                pItem->m_nUnicode = pItem->m_Unicode.length();
            }

            // Fit the text onto the line.
            int nFullText = pItem->m_nUnicode;
            // Get the box size and update pItem->m_nUnicode to the number that will fit.
            QRect rect = m_pDisplay->GetBounds(pItem->m_Unicode, pItem->m_nUnicode, m_nBoxWidth - pLine->m_nLineWidth);

            if (nFullText != pItem->m_nUnicode && m_fTextWrap)   // Doesn't fit, we have to word-wrap.
            {
                int nTruncated = pItem->m_nUnicode; // Just in case.
                // Now remove characters until we find a word-break character.
                while (pItem->m_nUnicode > 0 && pItem->m_Unicode[pItem->m_nUnicode] != ' ')
                {
                    pItem->m_nUnicode--;
                }

                // If there are now word-break characters we truncate the text.
                if (pItem->m_nUnicode == 0)
                {
                    pItem->m_nUnicode = nTruncated;
                }

                // Special case to avoid infinite loop if the box is very narrow.
                if (pItem->m_nUnicode == 0)
                {
                    pItem->m_nUnicode = 1;
                }

                // We need to move the text we've cut off this line into a new line.
                int nNewWidth = nFullText - pItem->m_nUnicode;
                int nNewStart = pItem->m_nUnicode;

                // Remove any spaces at the start of the new section.
                while (nNewWidth != 0 && pItem->m_Unicode[nNewStart] == ' ')
                {
                    nNewStart++;
                    nNewWidth--;
                }

                if (nNewWidth != 0)
                {
                    // Create a new line from the extra text.
                    MHTextLine *pNewLine = new MHTextLine;
                    theText.InsertAt(pNewLine, i + 1);
                    // The first item on the new line is the rest of the text.
                    MHTextItem *pNewItem = pItem->NewItem();
                    pNewLine->m_Items.Append(pNewItem);
                    pNewItem->m_Unicode = pItem->m_Unicode.mid(nNewStart, nNewWidth);
                    pNewItem->m_nUnicode = nNewWidth;

                    // Move any remaining items, e.g. in a different colour, from this line onto the new line.
                    while (pLine->m_Items.Size() > j + 1)
                    {
                        pNewLine->m_Items.Append(pLine->m_Items.GetAt(j + 1));
                        pLine->m_Items.RemoveAt(j + 1);
                    }
                }

                // Remove any spaces at the end of the old section.  If we don't do that and
                // we are centering or right aligning the text we'll get it wrong.
                while (pItem->m_nUnicode > 1 && pItem->m_Unicode[pItem->m_nUnicode-1] == ' ')
                {
                    pItem->m_nUnicode--;
                }

                rect = m_pDisplay->GetBounds(pItem->m_Unicode, pItem->m_nUnicode);
            }

            pItem->m_Width = rect.width();
            pLine->m_nLineWidth += rect.width();

            if (rect.height() > pLine->m_nLineHeight)
            {
                pLine->m_nLineHeight = rect.height();
            }

            if (rect.bottom() > pLine->m_nDescent)
            {
                pLine->m_nDescent = rect.bottom();
            }
        }
    }

    // Now output the text.
    int yOffset = 0;
    // If there isn't space for all the lines we should drop extra lines.
    int nNumLines = theText.Size();

    do
    {
        if (m_VertJ == End)
        {
            yOffset = m_nBoxHeight - nNumLines * lineSpace;
        }
        else if (m_VertJ == Centre)
        {
            yOffset = (m_nBoxHeight - nNumLines * lineSpace) / 2;
        }

        if (yOffset < 0)
        {
            nNumLines--;
        }
    }
    while (yOffset < 0);

    for (i = 0; i < nNumLines; i++)
    {
        MHTextLine *pLine = theText.GetAt(i);
        int xOffset = 0;

        if (m_HorizJ == End)
        {
            xOffset = m_nBoxWidth - pLine->m_nLineWidth;
        }
        else if (m_HorizJ == Centre)
        {
            xOffset = (m_nBoxWidth - pLine->m_nLineWidth) / 2;
        }

        for (int j = 0; j < pLine->m_Items.Size(); j++)
        {
            MHTextItem *pItem = pLine->m_Items.GetAt(j);

            // Tab across if necessary.
            xOffset = Tabs(xOffset, pItem->m_nTabCount);

            if (! pItem->m_Unicode.isEmpty())   // We may have blank lines.
            {
                m_pDisplay->AddText(xOffset, yOffset + (pLine->m_nLineHeight + lineSpace) / 2 - pLine->m_nDescent,
                                    pItem->m_Unicode.left(pItem->m_nUnicode), pItem->m_Colour);
            }

            xOffset += pItem->m_Width;
        }

        yOffset += lineSpace;

        if (yOffset + lineSpace > m_nBoxHeight)
        {
            break;
        }
    }

    // Clean up.
    for (int k = 0; k < theText.Size(); k++)
    {
        delete(theText.GetAt(k));
    }
}
Esempio n. 22
0
// Process the action set and create the action values.
void MHActionSequence::Initialise(MHParseNode *p, MHEngine *engine)
{
    // Depending on the caller we may have a tagged argument list or a sequence.
    for (int i = 0; i < p->GetArgCount(); i++)
    {
        MHParseNode *pElemAction = p->GetArgN(i);
        MHElemAction *pAction;

        switch (pElemAction->GetTagNo())
        {
            case C_ACTIVATE:
                pAction = new MHActivate(":Activate", true);
                break;
            case C_ADD:
                pAction = new MHAdd;
                break;
            case C_ADD_ITEM:
                pAction = new MHAddItem;
                break;
            case C_APPEND:
                pAction = new MHAppend;
                break;
            case C_BRING_TO_FRONT:
                pAction = new MHBringToFront;
                break;
            case C_CALL:
                pAction = new MHCall(":Call", false);
                break;
            case C_CALL_ACTION_SLOT:
                pAction = new MHCallActionSlot;
                break;
            case C_CLEAR:
                pAction = new MHClear;
                break;
            case C_CLONE:
                pAction = new MHClone;
                break;
            case C_CLOSE_CONNECTION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ??
            case C_DEACTIVATE:
                pAction = new MHActivate(":Deactivate", false);
                break;
            case C_DEL_ITEM:
                pAction = new MHDelItem;
                break;
            case C_DESELECT:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Button
            case C_DESELECT_ITEM:
                pAction = new MHDeselectItem;
                break;
            case C_DIVIDE:
                pAction = new MHDivide;
                break;
            case C_DRAW_ARC:
                pAction = new MHDrawArcSector(":DrawArc", false);
                break;
            case C_DRAW_LINE:
                pAction = new MHDrawLine;
                break;
            case C_DRAW_OVAL:
                pAction = new MHDrawOval;
                break;
            case C_DRAW_POLYGON:
                pAction = new MHDrawPoly(":DrawPolygon", true);
                break;
            case C_DRAW_POLYLINE:
                pAction = new MHDrawPoly(":DrawPolyline", false);
                break;
            case C_DRAW_RECTANGLE:
                pAction = new MHDrawRectangle;
                break;
            case C_DRAW_SECTOR:
                pAction = new MHDrawArcSector(":DrawSector", true);
                break;
            case C_FORK:
                pAction = new MHCall(":Fork", true);
                break;
            case C_GET_AVAILABILITY_STATUS:
                pAction = new MHGetAvailabilityStatus;
                break;
            case C_GET_BOX_SIZE:
                pAction = new MHGetBoxSize;
                break;
            case C_GET_CELL_ITEM:
                pAction = new MHGetCellItem;
                break;
            case C_GET_CURSOR_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_GET_ENGINE_SUPPORT:
                pAction = new MHGetEngineSupport;
                break;
            case C_GET_ENTRY_POINT:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // EntryField
            case C_GET_FILL_COLOUR:
                pAction = new MHGetFillColour;
                break;
            case C_GET_FIRST_ITEM:
                pAction = new MHGetFirstItem;
                break;
            case C_GET_HIGHLIGHT_STATUS:
                pAction = new MHGetHighlightStatus;
                break;
            case C_GET_INTERACTION_STATUS:
                pAction = new MHGetInteractionStatus;
                break;
            case C_GET_ITEM_STATUS:
                pAction = new MHGetItemStatus;
                break;
            case C_GET_LABEL:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break;// PushButton
            case C_GET_LAST_ANCHOR_FIRED:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break;// HyperText
            case C_GET_LINE_COLOUR:
                pAction = new MHGetLineColour;
                break;
            case C_GET_LINE_STYLE:
                pAction = new MHGetLineStyle;
                break;
            case C_GET_LINE_WIDTH:
                pAction = new MHGetLineWidth;
                break;
            case C_GET_LIST_ITEM:
                pAction = new MHGetListItem;
                break;
            case C_GET_LIST_SIZE:
                pAction = new MHGetListSize;
                break;
            case C_GET_OVERWRITE_MODE:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break;// ?
            case C_GET_PORTION:
                pAction = new MHGetPortion;
                break;
            case C_GET_POSITION:
                pAction = new MHGetPosition;
                break;
            case C_GET_RUNNING_STATUS:
                pAction = new MHGetRunningStatus;
                break;
            case C_GET_SELECTION_STATUS:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break;// ?
            case C_GET_SLIDER_VALUE:
                pAction = new MHGetSliderValue;
                break;
            case C_GET_TEXT_CONTENT:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break;// Text
            case C_GET_TEXT_DATA:
                pAction = new MHGetTextData;
                break;
            case C_GET_TOKEN_POSITION:
                pAction = new MHGetTokenPosition;
                break;
            case C_GET_VOLUME:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_LAUNCH:
                pAction = new MHLaunch;
                break;
            case C_LOCK_SCREEN:
                pAction = new MHLockScreen;
                break;
            case C_MODULO:
                pAction = new MHModulo;
                break;
            case C_MOVE:
                pAction = new MHMove;
                break;
            case C_MOVE_TO:
                pAction = new MHMoveTo;
                break;
            case C_MULTIPLY:
                pAction = new MHMultiply;
                break;
            case C_OPEN_CONNECTION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_PRELOAD:
                pAction = new MHPreload;
                break;
            case C_PUT_BEFORE:
                pAction = new MHPutBefore;
                break;
            case C_PUT_BEHIND:
                pAction = new MHPutBehind;
                break;
            case C_QUIT:
                pAction = new MHQuit;
                break;
            case C_READ_PERSISTENT:
                pAction = new MHPersistent(":ReadPersistent", true);
                break;
            case C_RUN:
                pAction = new MHRun;
                break;
            case C_SCALE_BITMAP:
                pAction = new MHScaleBitmap;
                break;
            case C_SCALE_VIDEO:
                pAction = new MHScaleVideo;
                break;
            case C_SCROLL_ITEMS:
                pAction = new MHScrollItems;
                break;
            case C_SELECT:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Button
            case C_SELECT_ITEM:
                pAction = new MHSelectItem;
                break;
            case C_SEND_EVENT:
                pAction = new MHSendEvent;
                break;
            case C_SEND_TO_BACK:
                pAction = new MHSendToBack;
                break;
            case C_SET_BOX_SIZE:
                pAction = new MHSetBoxSize;
                break;
            case C_SET_CACHE_PRIORITY:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_SET_COUNTER_END_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Stream
            case C_SET_COUNTER_POSITION:
                pAction = new MHSetCounterPosition;
                break; // Stream
            case C_SET_COUNTER_TRIGGER:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Stream
            case C_SET_CURSOR_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_SET_CURSOR_SHAPE:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_SET_DATA:
                pAction = new MHSetData;
                break;
            case C_SET_ENTRY_POINT:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // EntryField
            case C_SET_FILL_COLOUR:
                pAction = new MHSetFillColour;
                break;
            case C_SET_FIRST_ITEM:
                pAction = new MHSetFirstItem;
                break;
            case C_SET_FONT_REF:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Text
            case C_SET_HIGHLIGHT_STATUS:
                pAction = new MHSetHighlightStatus;
                break;
            case C_SET_INTERACTION_STATUS:
                pAction = new MHSetInteractionStatus;
                break;
            case C_SET_LABEL:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // PushButton
            case C_SET_LINE_COLOUR:
                pAction = new MHSetLineColour;
                break;
            case C_SET_LINE_STYLE:
                pAction = new MHSetLineStyle;
                break;
            case C_SET_LINE_WIDTH:
                pAction = new MHSetLineWidth;
                break;
            case C_SET_OVERWRITE_MODE:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // EntryField
            case C_SET_PALETTE_REF:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Visible
            case C_SET_PORTION:
                pAction = new MHSetPortion;
                break;
            case C_SET_POSITION:
                pAction = new MHSetPosition;
                break;
            case C_SET_SLIDER_VALUE:
                pAction = new MHSetSliderValue;
                break;
            case C_SET_SPEED:
                pAction = new MHSetSpeed;
                break; // ?
            case C_SET_TIMER:
                pAction = new MHSetTimer;
                break;
            case C_SET_TRANSPARENCY:
                pAction = new MHSetTransparency;
                break;
            case C_SET_VARIABLE:
                pAction = new MHSetVariable;
                break;
            case C_SET_VOLUME:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_SPAWN:
                pAction = new MHSpawn;
                break;
            case C_STEP:
                pAction = new MHStep;
                break;
            case C_STOP:
                pAction = new MHStop;
                break;
            case C_STORE_PERSISTENT:
                pAction = new MHPersistent(":StorePersistent", false);
                break;
            case C_SUBTRACT:
                pAction = new MHSubtract;
                break;
            case C_TEST_VARIABLE:
                pAction = new MHTestVariable;
                break;
            case C_TOGGLE:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // Button
            case C_TOGGLE_ITEM:
                pAction = new MHToggleItem;
                break;
            case C_TRANSITION_TO:
                pAction = new MHTransitionTo;
                break;
            case C_UNLOAD:
                pAction = new MHUnload;
                break;
            case C_UNLOCK_SCREEN:
                pAction = new MHUnlockScreen;
                break;
                // UK MHEG added actions.
            case C_SET_BACKGROUND_COLOUR:
                pAction = new MHSetBackgroundColour;
                break;
            case C_SET_CELL_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // ?
            case C_SET_INPUT_REGISTER:
                pAction = new MHSetInputRegister;
                break;
            case C_SET_TEXT_COLOUR:
                pAction = new MHSetTextColour;
                break;
            case C_SET_FONT_ATTRIBUTES:
                pAction = new MHSetFontAttributes;
                break;
            case C_SET_VIDEO_DECODE_OFFSET:
                pAction = new MHSetVideoDecodeOffset;
                break;
            case C_GET_VIDEO_DECODE_OFFSET:
                pAction = new MHGetVideoDecodeOffset;
                break;
            case C_GET_FOCUS_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // HyperText
            case C_SET_FOCUS_POSITION:
                pAction = new MHUnimplementedAction(pElemAction->GetTagNo());
                break; // HyperText
            case C_SET_BITMAP_DECODE_OFFSET:
                pAction = new MHSetBitmapDecodeOffset;
                break;
            case C_GET_BITMAP_DECODE_OFFSET:
                pAction = new MHGetBitmapDecodeOffset;
                break;
            case C_SET_SLIDER_PARAMETERS:
                pAction = new MHSetSliderParameters;
                break;

            // Added in ETSI ES 202 184 V2.1.1 (2010-01)
            case C_GET_COUNTER_POSITION: // Stream position
                pAction = new MHGetCounterPosition;
                break;
            case C_GET_COUNTER_MAX_POSITION: // Stream total size
                pAction = new MHGetCounterMaxPosition;
                break;

            default:
                MHLOG(MHLogWarning, QString("WARN Unknown action %1").arg(pElemAction->GetTagNo()));
                // Future proofing: ignore any actions that we don't know about.
                // Obviously these can only arise in the binary coding.
                pAction = NULL;
        }

        if (pAction)
        {
            Append(pAction); // Add to the sequence.
            pAction->Initialise(pElemAction, engine);
        }
    }
}
Esempio n. 23
0
 MHUnimplementedAction(int nTag): MHElemAction(""), m_nTag(nTag)
 {
     MHLOG(MHLogWarning, QString("WARN Unimplemented action %1").arg(m_nTag) );
 }
Esempio n. 24
0
// Implement the SetVariable action.
void MHContentRefVar::SetVariableValue(const MHUnion &value)
{
    value.CheckType(MHUnion::U_ContentRef);
    m_Value.Copy(value.m_ContentRefVal);
    MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_Value.Printable()));
}
Esempio n. 25
0
void MHGroup::Initialise(MHParseNode *p, MHEngine *engine)
{
    engine->GetGroupId().Copy(""); // Set to empty before we start (just in case).
    MHRoot::Initialise(p, engine);

    // Must be an external reference with an object number of zero.
    if (m_ObjectReference.m_nObjectNo != 0 || m_ObjectReference.m_GroupId.Size() == 0)
    {
        MHERROR("Object reference for a group object must be zero and external");
    }

    // Set the group id for the rest of the group to this.
    engine->GetGroupId().Copy(m_ObjectReference.m_GroupId);
    // Some of the information is irrelevant.
    //  MHParseNode *pStdId = p->GetNamedArg(C_STANDARD_IDENTIFIER);
    //  MHParseNode *pStdVersion = p->GetNamedArg(C_STANDARD_VERSION);
    //  MHParseNode *pObjectInfo = p->GetNamedArg(C_OBJECT_INFORMATION);

    MHParseNode *pOnStartUp = p->GetNamedArg(C_ON_START_UP);

    if (pOnStartUp)
    {
        m_StartUp.Initialise(pOnStartUp, engine);
    }

    MHParseNode *pOnCloseDown = p->GetNamedArg(C_ON_CLOSE_DOWN);

    if (pOnCloseDown)
    {
        m_CloseDown.Initialise(pOnCloseDown, engine);
    }

    MHParseNode *pOriginalGCPrio = p->GetNamedArg(C_ORIGINAL_GC_PRIORITY);

    if (pOriginalGCPrio)
    {
        m_nOrigGCPriority = pOriginalGCPrio->GetArgN(0)->GetIntValue();
    }

    // Ignore the other stuff at the moment.
    MHParseNode *pItems = p->GetNamedArg(C_ITEMS);

    if (pItems == NULL)
    {
        p->Failure("Missing :Items block");
        return;
    }

    for (int i = 0; i < pItems->GetArgCount(); i++)
    {
        MHParseNode *pItem = pItems->GetArgN(i);
        MHIngredient *pIngredient = NULL;

        try
        {
            // Generate the particular kind of ingredient.
            switch (pItem->GetTagNo())
            {
                case C_RESIDENT_PROGRAM:
                    pIngredient = new MHResidentProgram;
                    break;
                case C_REMOTE_PROGRAM:
                    pIngredient = new MHRemoteProgram;
                    break;
                case C_INTERCHANGED_PROGRAM:
                    pIngredient = new MHInterChgProgram;
                    break;
                case C_PALETTE:
                    pIngredient = new MHPalette;
                    break;
                case C_FONT:
                    pIngredient = new MHFont;
                    break;
                case C_CURSOR_SHAPE:
                    pIngredient = new MHCursorShape;
                    break;
                case C_BOOLEAN_VARIABLE:
                    pIngredient = new MHBooleanVar;
                    break;
                case C_INTEGER_VARIABLE:
                    pIngredient = new MHIntegerVar;
                    break;
                case C_OCTET_STRING_VARIABLE:
                    pIngredient = new MHOctetStrVar;
                    break;
                case C_OBJECT_REF_VARIABLE:
                    pIngredient = new MHObjectRefVar;
                    break;
                case C_CONTENT_REF_VARIABLE:
                    pIngredient = new MHContentRefVar;
                    break;
                case C_LINK:
                    pIngredient = new MHLink;
                    break;
                case C_STREAM:
                    pIngredient = new MHStream;
                    break;
                case C_BITMAP:
                    pIngredient = new MHBitmap;
                    break;
                case C_LINE_ART:
                    pIngredient = new MHLineArt;
                    break;
                case C_DYNAMIC_LINE_ART:
                    pIngredient = new MHDynamicLineArt;
                    break;
                case C_RECTANGLE:
                    pIngredient = new MHRectangle;
                    break;
                case C_HOTSPOT:
                    pIngredient = new MHHotSpot;
                    break;
                case C_SWITCH_BUTTON:
                    pIngredient = new MHSwitchButton;
                    break;
                case C_PUSH_BUTTON:
                    pIngredient = new MHPushButton;
                    break;
                case C_TEXT:
                    pIngredient = new MHText;
                    break;
                case C_ENTRY_FIELD:
                    pIngredient = new MHEntryField;
                    break;
                case C_HYPER_TEXT:
                    pIngredient = new MHHyperText;
                    break;
                case C_SLIDER:
                    pIngredient = new MHSlider;
                    break;
                case C_TOKEN_GROUP:
                    pIngredient = new MHTokenGroup;
                    break;
                case C_LIST_GROUP:
                    pIngredient = new MHListGroup;
                    break;
                default:
                    MHLOG(MHLogWarning, QString("Unknown ingredient %1").arg(pItem->GetTagNo()));
                    // Future proofing: ignore any ingredients that we don't know about.
                    // Obviously these can only arise in the binary coding.
            }

            if (pIngredient)
            {
                // Initialise it from its argments.
                pIngredient->Initialise(pItem, engine);

                // Remember the highest numbered ingredient
                if (pIngredient->m_ObjectReference.m_nObjectNo > m_nLastId)
                {
                    m_nLastId = pIngredient->m_ObjectReference.m_nObjectNo;
                }

                // Add it to the ingedients of this group.
                m_Items.Append(pIngredient);
            }
        }
        catch (...)
        {
            delete(pIngredient);
            throw;
        }
    }
}
Esempio n. 26
0
// Find out what we support.
bool MHEngine::GetEngineSupport(const MHOctetString &feature)
{
    QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
    QStringList strings = csFeat.split(QRegExp("[\\(\\,\\)]"));

    MHLOG(MHLogNotifications, "NOTE GetEngineSupport " + csFeat);

    if (strings[0] == "ApplicationStacking" || strings[0] == "ASt")
    {
        return true;
    }

    // We're required to support cloning for Text, Bitmap and Rectangle.
    if (strings[0] == "Cloning" || strings[0] == "Clo")
    {
        return true;
    }

    if (strings[0] == "SceneCoordinateSystem" || strings[0] == "SCS")
    {
        if (strings.count() >= 3 && strings[1] == "720" && strings[2] == "576")
        {
            return true;
        }
        else
        {
            return false;
        }

        // I've also seen SceneCoordinateSystem(1,1)
    }

    if (strings[0] == "MultipleAudioStreams" || strings[0] == "MAS")
    {
        if (strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    if (strings[0] == "MultipleVideoStreams" || strings[0] == "MVS")
    {
        if (strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // We're supposed to return true for all values of N
    if (strings[0] == "OverlappingVisibles" || strings[0] == "OvV")
    {
        return true;
    }

    if (strings[0] == "SceneAspectRatio" || strings[0] == "SAR")
    {
        if (strings.count() < 3)
        {
            return false;
        }
        else if ((strings[1] == "4" && strings[2] == "3") || (strings[1] == "16" && strings[2] == "9"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // We're supposed to support these at least.  May also support(10,1440,1152)
    if (strings[0] == "VideoScaling" || strings[0] == "VSc")
    {
        if (strings.count() < 4 || strings[1] != "10")
        {
            return false;
        }
        else if ((strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    if (strings[0] == "BitmapScaling" || strings[0] == "BSc")
    {
        if (strings.count() < 4 || strings[1] != "2")
        {
            return false;
        }
        else if ((strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // I think we only support the video fully on screen
    if (strings[0] == "VideoDecodeOffset" || strings[0] == "VDO")
    {
        if (strings.count() >= 3 && strings[1] == "10" && strings[1] == "0")
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // We support bitmaps that are partially off screen (don't we?)
    if (strings[0] == "BitmapDecodeOffset" || strings[0] == "BDO")
    {
        if (strings.count() >= 3 && strings[1] == "2" && (strings[2] == "0" || strings[2] == "1"))
        {
            return true;
        }
        else if (strings.count() >= 2 && (strings[1] == "4" || strings[1] == "6"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    if (strings[0] == "UKEngineProfile" || strings[0] == "UniversalEngineProfile" || strings[0] == "UEP")
    {
        if (strings.count() < 2)
        {
            return false;
        }

        if (strings[1] == MHEGEngineProviderIdString)
        {
            return true;
        }

        if (strings[1] == m_Context->GetReceiverId())
        {
            return true;
        }

        if (strings[1] == m_Context->GetDSMCCId())
        {
            return true;
        }

        // The UK profile 1.06 seems a bit confused on this point.  It is not clear whether
        // we are supposed to return true for UKEngineProfile(2) or not.
        if (strings[1] == "2")
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // InteractionChannelExtension.
    if (strings[0] == "ICProfile" || strings[0] == "ICP") {
        if (strings.count() != 2) return false;
        if (strings[1] == "0")
            return true; // // InteractionChannelExtension.
        if (strings[1] == "1")
            return false; // ICStreamingExtension.
        return false;
    }

    // Otherwise return false.
    return false;
}