00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <QStringList>
00023 #include <QRegExp>
00024
00025 #include "Engine.h"
00026 #include "ParseNode.h"
00027 #include "ParseBinary.h"
00028 #include "ParseText.h"
00029 #include "Root.h"
00030 #include "Groups.h"
00031 #include "ASN1Codes.h"
00032 #include "Logging.h"
00033 #include "freemheg.h"
00034 #include "Visible.h"
00035
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <stdarg.h>
00039
00040
00041 MHEG *MHCreateEngine(MHContext *context)
00042 {
00043 return new MHEngine(context);
00044 }
00045
00046 MHEngine::MHEngine(MHContext *context): m_Context(context)
00047 {
00048 m_fInTransition = false;
00049 m_fBooting = true;
00050 m_Interacting = 0;
00051 }
00052
00053 MHEngine::~MHEngine()
00054 {
00055 while (!m_ApplicationStack.isEmpty())
00056 {
00057 delete m_ApplicationStack.pop();
00058 }
00059
00060 while (!m_EventQueue.isEmpty())
00061 {
00062 delete m_EventQueue.dequeue();
00063 }
00064
00065 while (!m_ExternContentTable.isEmpty())
00066 {
00067 delete m_ExternContentTable.takeFirst();
00068 }
00069 }
00070
00071
00072 #define CONTENT_CHECK_TIME 2000
00073
00074
00075 int MHEngine::RunAll()
00076 {
00077
00078 if (m_fBooting)
00079 {
00080
00081 while (!m_ApplicationStack.isEmpty())
00082 {
00083 delete m_ApplicationStack.pop();
00084 }
00085
00086 while (!m_EventQueue.isEmpty())
00087 {
00088 delete m_EventQueue.dequeue();
00089 }
00090
00091 while (!m_ExternContentTable.isEmpty())
00092 {
00093 delete m_ExternContentTable.takeFirst();
00094 }
00095
00096 m_LinkTable.clear();
00097
00098
00099
00100 MHObjectRef startObj;
00101 startObj.m_nObjectNo = 0;
00102 startObj.m_GroupId.Copy(MHOctetString("~//a"));
00103
00104
00105
00106
00107
00108 if (! Launch(startObj))
00109 {
00110 startObj.m_GroupId.Copy(MHOctetString("~//startup"));
00111
00112 if (! Launch(startObj))
00113 {
00114 MHLOG(MHLogWarning, "MHEG engine auto-boot failed");
00115 return -1;
00116 }
00117 }
00118
00119 m_fBooting = false;
00120 }
00121
00122 int nNextTime = 0;
00123
00124 do
00125 {
00126
00127 if (m_Context->CheckStop())
00128 {
00129 return 0;
00130 }
00131
00132
00133 RunActions();
00134
00135
00136
00137
00138
00139 CheckContentRequests();
00140
00141
00142 nNextTime = CurrentScene() ? CurrentScene()->CheckTimers(this) : 0;
00143
00144 if (CurrentApp())
00145 {
00146
00147 int nAppTime = CurrentApp()->CheckTimers(this);
00148
00149 if (nAppTime != 0 && (nNextTime == 0 || nAppTime < nNextTime))
00150 {
00151 nNextTime = nAppTime;
00152 }
00153 }
00154
00155 if (! m_ExternContentTable.isEmpty())
00156 {
00157
00158 if (nNextTime == 0 || nNextTime > CONTENT_CHECK_TIME)
00159 {
00160 nNextTime = CONTENT_CHECK_TIME;
00161 }
00162 }
00163
00164 if (! m_EventQueue.isEmpty())
00165 {
00166 MHAsynchEvent *pEvent = m_EventQueue.dequeue();
00167 MHLOG(MHLogLinks, QString("Asynchronous event dequeued - %1 from %2")
00168 .arg(MHLink::EventTypeToString(pEvent->eventType))
00169 .arg(pEvent->pEventSource->m_ObjectReference.Printable()));
00170 CheckLinks(pEvent->pEventSource->m_ObjectReference, pEvent->eventType, pEvent->eventData);
00171 delete pEvent;
00172 }
00173 }
00174 while (! m_EventQueue.isEmpty() || ! m_ActionStack.isEmpty());
00175
00176
00177 if (! m_redrawRegion.isEmpty())
00178 {
00179 m_Context->RequireRedraw(m_redrawRegion);
00180 m_redrawRegion = QRegion();
00181 }
00182
00183 return nNextTime;
00184 }
00185
00186
00187
00188 MHGroup *MHEngine::ParseProgram(QByteArray &text)
00189 {
00190 if (text.size() == 0)
00191 {
00192 return NULL;
00193 }
00194
00195
00196
00197
00198
00199 unsigned char ch = text[0];
00200 MHParseBase *parser = NULL;
00201 MHParseNode *pTree = NULL;
00202 MHGroup *pRes = NULL;
00203
00204 if (ch >= 128)
00205 {
00206 parser = new MHParseBinary(text);
00207 }
00208 else
00209 {
00210 parser = new MHParseText(text);
00211 }
00212
00213 try
00214 {
00215
00216 pTree = parser->Parse();
00217
00218 switch (pTree->GetTagNo())
00219 {
00220 case C_APPLICATION:
00221 pRes = new MHApplication;
00222 break;
00223 case C_SCENE:
00224 pRes = new MHScene;
00225 break;
00226 default:
00227 pTree->Failure("Expected Application or Scene");
00228 }
00229
00230 pRes->Initialise(pTree, this);
00231 delete(pTree);
00232 delete(parser);
00233 }
00234 catch (...)
00235 {
00236 delete(parser);
00237 delete(pTree);
00238 delete(pRes);
00239 throw;
00240 }
00241
00242 return pRes;
00243 }
00244
00245
00246 bool MHEngine::Launch(const MHObjectRef &target, bool fIsSpawn)
00247 {
00248 QString csPath = GetPathName(target.m_GroupId);
00249
00250 if (csPath.length() == 0)
00251 {
00252 return false;
00253 }
00254
00255 if (m_fInTransition)
00256 {
00257 MHLOG(MHLogWarning, "Launch during transition - ignoring");
00258 return false;
00259 }
00260
00261 QByteArray text;
00262
00263
00264
00265 if (! m_Context->GetCarouselData(csPath, text))
00266 {
00267 if (CurrentApp())
00268 {
00269 EventTriggered(CurrentApp(), EventEngineEvent, 2);
00270 }
00271
00272 return false;
00273 }
00274
00275
00276 m_ActionStack.clear();
00277
00278 m_fInTransition = true;
00279
00280 try
00281 {
00282 if (CurrentApp())
00283 {
00284 if (fIsSpawn)
00285 {
00286 AddActions(CurrentApp()->m_CloseDown);
00287 RunActions();
00288 }
00289
00290 if (CurrentScene())
00291 {
00292 CurrentScene()->Destruction(this);
00293 }
00294
00295 CurrentApp()->Destruction(this);
00296
00297 if (!fIsSpawn)
00298 {
00299 delete m_ApplicationStack.pop();
00300 }
00301 }
00302
00303 MHApplication *pProgram = (MHApplication *)ParseProgram(text);
00304
00305 if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0)
00306 {
00307 pProgram->PrintMe(__mhlogStream, 0);
00308 }
00309
00310 if (! pProgram->m_fIsApp)
00311 {
00312 MHERROR("Expected an application");
00313 }
00314
00315
00316 pProgram->m_Path = csPath;
00317 int nPos = pProgram->m_Path.lastIndexOf('/');
00318
00319 if (nPos < 0)
00320 {
00321 pProgram->m_Path = "";
00322 }
00323 else
00324 {
00325 pProgram->m_Path = pProgram->m_Path.left(nPos);
00326 }
00327
00328
00329 m_ApplicationStack.push(pProgram);
00330
00331
00332
00333 while (!m_EventQueue.isEmpty())
00334 {
00335 delete m_EventQueue.dequeue();
00336 }
00337
00338
00339 CurrentApp()->Activation(this);
00340 m_fInTransition = false;
00341 return true;
00342 }
00343 catch (...)
00344 {
00345 m_fInTransition = false;
00346 return false;
00347 }
00348 }
00349
00350 void MHEngine::Quit()
00351 {
00352 if (m_fInTransition)
00353 {
00354 MHLOG(MHLogWarning, "Quit during transition - ignoring");
00355 return;
00356 }
00357
00358 m_fInTransition = true;
00359
00360 if (CurrentScene())
00361 {
00362 CurrentScene()->Destruction(this);
00363 }
00364
00365 CurrentApp()->Destruction(this);
00366
00367
00368
00369 while (!m_EventQueue.isEmpty())
00370 {
00371 delete m_EventQueue.dequeue();
00372 }
00373
00374 delete m_ApplicationStack.pop();
00375
00376
00377 if (m_ApplicationStack.isEmpty())
00378 {
00379 m_fBooting = true;
00380 }
00381 else
00382 {
00383 CurrentApp()->m_fRestarting = true;
00384 CurrentApp()->Activation(this);
00385
00386 }
00387
00388 m_fInTransition = false;
00389 }
00390
00391 void MHEngine::TransitionToScene(const MHObjectRef &target)
00392 {
00393 int i;
00394
00395 if (m_fInTransition)
00396 {
00397
00398 MHLOG(MHLogWarning, "TransitionTo during transition - ignoring");
00399 return;
00400 }
00401
00402 if (target.m_GroupId.Size() == 0)
00403 {
00404 return;
00405 }
00406
00407 QString csPath = GetPathName(target.m_GroupId);
00408 QByteArray text;
00409
00410
00411 if (! m_Context->GetCarouselData(csPath, text))
00412 {
00413 EventTriggered(CurrentApp(), EventEngineEvent, 2);
00414 return;
00415 }
00416
00417
00418 MHGroup *pProgram = ParseProgram(text);
00419
00420 if (pProgram->m_fIsApp)
00421 {
00422 MHERROR("Expected a scene");
00423 }
00424
00425
00426 m_ActionStack.clear();
00427
00428
00429
00430 MHApplication *pApp = CurrentApp();
00431
00432 for (i = pApp->m_Items.Size(); i > 0; i--)
00433 {
00434 MHIngredient *pItem = pApp->m_Items.GetAt(i - 1);
00435
00436 if (! pItem->IsShared())
00437 {
00438 pItem->Deactivation(this);
00439 }
00440 }
00441
00442 m_fInTransition = true;
00443
00444 if (pApp->m_pCurrentScene)
00445 {
00446 pApp->m_pCurrentScene->Deactivation(this);
00447 pApp->m_pCurrentScene->Destruction(this);
00448 }
00449
00450
00451
00452
00453
00454
00455
00456
00457 MHAsynchEvent *pEvent;
00458 QQueue<MHAsynchEvent *>::iterator it = m_EventQueue.begin();
00459
00460 while (it != m_EventQueue.end())
00461 {
00462 pEvent = *it;
00463
00464 if (!pEvent->pEventSource->IsShared())
00465 {
00466 delete pEvent;
00467 it = m_EventQueue.erase(it);
00468 }
00469 else
00470 {
00471 ++it;
00472 }
00473 }
00474
00475
00476 if (pApp->m_pCurrentScene)
00477 {
00478 delete(pApp->m_pCurrentScene);
00479 pApp->m_pCurrentScene = NULL;
00480 }
00481
00482 m_Interacting = 0;
00483
00484
00485 CurrentApp()->m_pCurrentScene = (MHScene *) pProgram;
00486 SetInputRegister(CurrentScene()->m_nEventReg);
00487 m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY);
00488
00489 if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0)
00490 {
00491 pProgram->PrintMe(__mhlogStream, 0);
00492 }
00493
00494 pProgram->Preparation(this);
00495 pProgram->Activation(this);
00496 m_fInTransition = false;
00497 }
00498
00499 void MHEngine::SetInputRegister(int nReg)
00500 {
00501 m_Context->SetInputRegister(nReg);
00502 }
00503
00504
00505 QString MHEngine::GetPathName(const MHOctetString &str)
00506 {
00507 QString csPath;
00508
00509 if (str.Size() != 0)
00510 {
00511 csPath = QString::fromUtf8((const char *)str.Bytes(), str.Size());
00512 }
00513
00514 if (csPath.left(4) == "DSM:")
00515 {
00516 csPath = csPath.mid(4);
00517 }
00518
00519
00520 int firstColon = csPath.indexOf(':'), firstSlash = csPath.indexOf('/');
00521
00522 if (firstColon > 0 && firstSlash > 0 && firstColon < firstSlash)
00523 {
00524 return QString();
00525 }
00526
00527 if (csPath.left(1) == "~")
00528 {
00529 csPath = csPath.mid(1);
00530 }
00531
00532
00533 if (csPath.left(2) != "//")
00534 {
00535
00536 if (CurrentApp())
00537 {
00538 csPath = CurrentApp()->m_Path + csPath;
00539 }
00540 }
00541
00542
00543 int nPos;
00544
00545 while ((nPos = csPath.indexOf("/../")) >= 0)
00546 {
00547 int nEnd = nPos + 4;
00548
00549 while (nPos >= 1 && csPath[nPos-1] != '/')
00550 {
00551 nPos--;
00552 }
00553
00554 csPath = csPath.left(nPos) + csPath.mid(nEnd);
00555 }
00556
00557 return csPath;
00558 }
00559
00560
00561 MHRoot *MHEngine::FindObject(const MHObjectRef &oRef, bool failOnNotFound)
00562 {
00563
00564 MHGroup *pSearch = NULL;
00565 MHGroup *pScene = CurrentScene(), *pApp = CurrentApp();
00566
00567 if (pScene && GetPathName(pScene->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
00568 {
00569 pSearch = pScene;
00570 }
00571 else if (pApp && GetPathName(pApp->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
00572 {
00573 pSearch = pApp;
00574 }
00575
00576 if (pSearch)
00577 {
00578 MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);
00579
00580 if (pItem)
00581 {
00582 return pItem;
00583 }
00584 }
00585
00586 if (failOnNotFound)
00587 {
00588
00589
00590
00591
00592 MHLOG(MHLogWarning, QString("Reference %1 not found").arg(oRef.m_nObjectNo));
00593 throw "FindObject failed";
00594 }
00595
00596 return NULL;
00597 }
00598
00599
00600 void MHEngine::RunActions()
00601 {
00602 while (! m_ActionStack.isEmpty())
00603 {
00604
00605 MHElemAction *pAction = m_ActionStack.pop();
00606
00607
00608 try
00609 {
00610 if ((__mhlogoptions & MHLogActions) && __mhlogStream != 0)
00611 {
00612 fprintf(__mhlogStream, "Action - ");
00613 pAction->PrintMe(__mhlogStream, 0);
00614 fflush(__mhlogStream);
00615 }
00616
00617 pAction->Perform(this);
00618 }
00619 catch (char const *)
00620 {
00621 }
00622 }
00623 }
00624
00625
00626 void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
00627 {
00628 MHLOG(MHLogLinks, QString("Event - %1 from %2")
00629 .arg(MHLink::EventTypeToString(ev)).arg(pSource->m_ObjectReference.Printable()));
00630
00631 switch (ev)
00632 {
00633 case EventFirstItemPresented:
00634 case EventHeadItems:
00635 case EventHighlightOff:
00636 case EventHighlightOn:
00637 case EventIsAvailable:
00638 case EventIsDeleted:
00639 case EventIsDeselected:
00640 case EventIsRunning:
00641 case EventIsSelected:
00642 case EventIsStopped:
00643 case EventItemDeselected:
00644 case EventItemSelected:
00645 case EventLastItemPresented:
00646 case EventTailItems:
00647 case EventTestEvent:
00648 case EventTokenMovedFrom:
00649 case EventTokenMovedTo:
00650
00651
00652
00653
00654
00655 CheckLinks(pSource->m_ObjectReference, ev, evData);
00656 break;
00657 case EventAnchorFired:
00658 case EventAsyncStopped:
00659 case EventContentAvailable:
00660 case EventCounterTrigger:
00661 case EventCursorEnter:
00662 case EventCursorLeave:
00663 case EventEngineEvent:
00664 case EventEntryFieldFull:
00665 case EventInteractionCompleted:
00666 case EventStreamEvent:
00667 case EventStreamPlaying:
00668 case EventStreamStopped:
00669 case EventTimerFired:
00670 case EventUserInput:
00671 case EventFocusMoved:
00672 case EventSliderValueChanged:
00673 {
00674
00675 MHAsynchEvent *pEvent = new MHAsynchEvent;
00676 pEvent->pEventSource = pSource;
00677 pEvent->eventType = ev;
00678 pEvent->eventData = evData;
00679 m_EventQueue.enqueue(pEvent);
00680 }
00681 }
00682 }
00683
00684
00685
00686
00687
00688
00689
00690 void MHEngine::CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
00691 {
00692 for (int i = 0; i < m_LinkTable.size(); i++)
00693 {
00694 m_LinkTable.at(i)->MatchEvent(sourceRef, ev, un, this);
00695 }
00696 }
00697
00698
00699 void MHEngine::AddLink(MHLink *pLink)
00700 {
00701 m_LinkTable.append(pLink);
00702 }
00703
00704 void MHEngine::RemoveLink(MHLink *pLink)
00705 {
00706 m_LinkTable.removeAll(pLink);
00707 }
00708
00709
00710 void MHEngine::AddActions(const MHActionSequence &actions)
00711 {
00712
00713 for (int i = actions.Size(); i > 0; i--)
00714 {
00715 m_ActionStack.push(actions.GetAt(i - 1));
00716 }
00717 }
00718
00719
00720 void MHEngine::AddToDisplayStack(MHVisible *pVis)
00721 {
00722 if (CurrentApp()->FindOnStack(pVis) != -1)
00723 {
00724 return;
00725 }
00726
00727 CurrentApp()->m_DisplayStack.Append(pVis);
00728 Redraw(pVis->GetVisibleArea());
00729 }
00730
00731
00732 void MHEngine::RemoveFromDisplayStack(MHVisible *pVis)
00733 {
00734 int nPos = CurrentApp()->FindOnStack(pVis);
00735
00736 if (nPos == -1)
00737 {
00738 return;
00739 }
00740
00741 CurrentApp()->m_DisplayStack.RemoveAt(nPos);
00742 Redraw(pVis->GetVisibleArea());
00743 }
00744
00745
00746 void MHEngine::BringToFront(const MHRoot *p)
00747 {
00748 int nPos = CurrentApp()->FindOnStack(p);
00749
00750 if (nPos == -1)
00751 {
00752 return;
00753 }
00754
00755 MHVisible *pVis = (MHVisible *)p;
00756 CurrentApp()->m_DisplayStack.RemoveAt(nPos);
00757 CurrentApp()->m_DisplayStack.Append((MHVisible *)pVis);
00758 Redraw(pVis->GetVisibleArea());
00759 }
00760
00761 void MHEngine::SendToBack(const MHRoot *p)
00762 {
00763 int nPos = CurrentApp()->FindOnStack(p);
00764
00765 if (nPos == -1)
00766 {
00767 return;
00768 }
00769
00770 MHVisible *pVis = (MHVisible *)p;
00771 CurrentApp()->m_DisplayStack.RemoveAt(nPos);
00772 CurrentApp()->m_DisplayStack.InsertAt(pVis, 0);
00773 Redraw(pVis->GetVisibleArea());
00774 }
00775
00776 void MHEngine::PutBefore(const MHRoot *p, const MHRoot *pRef)
00777 {
00778 int nPos = CurrentApp()->FindOnStack(p);
00779
00780 if (nPos == -1)
00781 {
00782 return;
00783 }
00784
00785 MHVisible *pVis = (MHVisible *)p;
00786 int nRef = CurrentApp()->FindOnStack(pRef);
00787
00788 if (nRef == -1)
00789 {
00790 return;
00791 }
00792
00793 CurrentApp()->m_DisplayStack.RemoveAt(nPos);
00794
00795 if (nRef >= nPos)
00796 {
00797 nRef--;
00798 }
00799
00800 CurrentApp()->m_DisplayStack.InsertAt(pVis, nRef + 1);
00801
00802
00803
00804 Redraw(pVis->GetVisibleArea());
00805 }
00806
00807 void MHEngine::PutBehind(const MHRoot *p, const MHRoot *pRef)
00808 {
00809 int nPos = CurrentApp()->FindOnStack(p);
00810
00811 if (nPos == -1)
00812 {
00813 return;
00814 }
00815
00816 int nRef = CurrentApp()->FindOnStack(pRef);
00817
00818 if (nRef == -1)
00819 {
00820 return;
00821 }
00822
00823 MHVisible *pVis = (MHVisible *)p;
00824 CurrentApp()->m_DisplayStack.RemoveAt(nPos);
00825
00826 if (nRef >= nPos)
00827 {
00828 nRef--;
00829 }
00830
00831 CurrentApp()->m_DisplayStack.InsertAt((MHVisible *)pVis, nRef);
00832 Redraw(pVis->GetVisibleArea());
00833 }
00834
00835
00836
00837
00838 void MHEngine::DrawRegion(QRegion toDraw, int nStackPos)
00839 {
00840 if (toDraw.isEmpty())
00841 {
00842 return;
00843 }
00844
00845 while (nStackPos >= 0)
00846 {
00847 MHVisible *pItem = CurrentApp()->m_DisplayStack.GetAt(nStackPos);
00848
00849
00850 QRegion drawArea = pItem->GetVisibleArea() & toDraw;
00851
00852 if (! drawArea.isEmpty())
00853 {
00854
00855
00856 QRegion newDraw = toDraw - pItem->GetOpaqueArea();
00857 DrawRegion(newDraw, nStackPos - 1);
00858
00859 pItem->Display(this);
00860 return;
00861 }
00862
00863 nStackPos--;
00864 }
00865
00866
00867
00868 m_Context->DrawBackground(toDraw);
00869 }
00870
00871
00872 void MHEngine::DrawDisplay(QRegion toDraw)
00873 {
00874 if (m_fBooting)
00875 {
00876 return;
00877 }
00878
00879 int nTopStack = CurrentApp() == NULL ? -1 : CurrentApp()->m_DisplayStack.Size() - 1;
00880 DrawRegion(toDraw, nTopStack);
00881 }
00882
00883
00884
00885 void MHEngine::Redraw(QRegion region)
00886 {
00887 m_redrawRegion += region;
00888 }
00889
00890
00891 void MHEngine::UnlockScreen()
00892 {
00893 if (CurrentApp()->m_nLockCount > 0)
00894 {
00895 CurrentApp()->m_nLockCount--;
00896 }
00897 }
00898
00899
00900
00901 void MHEngine::GenerateUserAction(int nCode)
00902 {
00903 MHScene *pScene = CurrentScene();
00904
00905 if (! pScene)
00906 {
00907 return;
00908 }
00909
00910
00911
00912
00913 switch (nCode)
00914 {
00915 case 104:
00916 case 105:
00917 EventTriggered(pScene, EventEngineEvent, 4);
00918 break;
00919 case 16:
00920 case 100:
00921 case 101:
00922 case 102:
00923 case 103:
00924 EventTriggered(pScene, EventEngineEvent, nCode);
00925 break;
00926 }
00927
00928
00929
00930 if (m_Interacting)
00931 {
00932 m_Interacting->KeyEvent(this, nCode);
00933 }
00934 else
00935 {
00936 EventTriggered(pScene, EventUserInput, nCode);
00937 }
00938 }
00939
00940 void MHEngine::EngineEvent(int nCode)
00941 {
00942 EventTriggered(CurrentApp(), EventEngineEvent, nCode);
00943 }
00944
00945
00946 void MHEngine::RequestExternalContent(MHIngredient *pRequester)
00947 {
00948
00949
00950 if (! pRequester->m_ContentRef.IsSet())
00951 {
00952 return;
00953 }
00954
00955
00956 CancelExternalContentRequest(pRequester);
00957 QString csPath = GetPathName(pRequester->m_ContentRef.m_ContentRef);
00958
00959
00960
00961 if (csPath.isEmpty())
00962 {
00963 MHLOG(MHLogWarning, "RequestExternalContent empty path");
00964 return;
00965 }
00966
00967 QByteArray text;
00968
00969 if (m_Context->CheckCarouselObject(csPath) && m_Context->GetCarouselData(csPath, text))
00970 {
00971
00972 pRequester->ContentArrived((const unsigned char *)text.data(), text.size(), this);
00973 }
00974 else
00975 {
00976
00977 MHLOG(MHLogLinks, QString("RequestExternalContent %1 pending").arg(csPath));
00978 MHExternContent *pContent = new MHExternContent;
00979 pContent->m_FileName = csPath;
00980 pContent->m_pRequester = pRequester;
00981 pContent->m_time.start();
00982 m_ExternContentTable.append(pContent);
00983 }
00984 }
00985
00986
00987 void MHEngine::CancelExternalContentRequest(MHIngredient *pRequester)
00988 {
00989 QList<MHExternContent *>::iterator it = m_ExternContentTable.begin();
00990 MHExternContent *pContent;
00991
00992 while (it != m_ExternContentTable.end())
00993 {
00994 pContent = *it;
00995
00996 if (pContent->m_pRequester == pRequester)
00997 {
00998 delete pContent;
00999 it = m_ExternContentTable.erase(it);
01000 return;
01001 }
01002 else
01003 {
01004 ++it;
01005 }
01006 }
01007 }
01008
01009
01010 void MHEngine::CheckContentRequests()
01011 {
01012 QList<MHExternContent *>::iterator it = m_ExternContentTable.begin();
01013 MHExternContent *pContent;
01014
01015 while (it != m_ExternContentTable.end())
01016 {
01017 pContent = *it;
01018 QByteArray text;
01019
01020 if (m_Context->CheckCarouselObject(pContent->m_FileName) &&
01021 m_Context->GetCarouselData(pContent->m_FileName, text))
01022 {
01023
01024 try
01025 {
01026 MHLOG(MHLogLinks, QString("CheckContentRequests %1 arrived")
01027 .arg(pContent->m_FileName));
01028 pContent->m_pRequester->ContentArrived((const unsigned char *)text.data(),
01029 text.size(), this);
01030 }
01031 catch (char const *)
01032 {
01033 }
01034
01035
01036 delete pContent;
01037 it = m_ExternContentTable.erase(it);
01038 }
01039 else if (pContent->m_time.elapsed() > 60000)
01040 {
01041 MHLOG(MHLogWarning, QString("CheckContentRequests %1 timed out")
01042 .arg(pContent->m_FileName));
01043 delete pContent;
01044 it = m_ExternContentTable.erase(it);
01045 EventTriggered(CurrentApp(), EventEngineEvent, 3);
01046 }
01047 else
01048 {
01049 ++it;
01050 }
01051 }
01052 }
01053
01054 bool MHEngine::LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence<MHObjectRef *> &variables)
01055 {
01056
01057 MHPSEntry *pEntry = NULL;
01058 int i;
01059
01060 for (i = 0; i < m_PersistentStore.Size(); i++)
01061 {
01062 pEntry = m_PersistentStore.GetAt(i);
01063
01064 if (pEntry->m_FileName.Equal(fileName))
01065 {
01066 break;
01067 }
01068 }
01069
01070 if (i == m_PersistentStore.Size())
01071 {
01072
01073 if (fIsLoad)
01074 {
01075 return false;
01076 }
01077
01078
01079 pEntry = new MHPSEntry;
01080 pEntry->m_FileName.Copy(fileName);
01081 m_PersistentStore.Append(pEntry);
01082 }
01083
01084 if (fIsLoad)
01085 {
01086
01087 if (pEntry->m_Data.Size() < variables.Size())
01088 {
01089 return false;
01090 }
01091
01092 for (i = 0; i < variables.Size(); i++)
01093 {
01094 FindObject(*(variables.GetAt(i)))->SetVariableValue(*(pEntry->m_Data.GetAt(i)));
01095 }
01096 }
01097
01098 else
01099 {
01100
01101 while (pEntry->m_Data.Size() != 0)
01102 {
01103 pEntry->m_Data.RemoveAt(0);
01104 }
01105
01106
01107 for (i = 0; i < variables.Size(); i++)
01108 {
01109 MHUnion *pValue = new MHUnion;
01110 pEntry->m_Data.Append(pValue);
01111 FindObject(*(variables.GetAt(i)))->GetVariableValue(*pValue, this);
01112 }
01113 }
01114
01115 return true;
01116 }
01117
01118
01119 bool MHEngine::GetEngineSupport(const MHOctetString &feature)
01120 {
01121 QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
01122 QStringList strings = csFeat.split(QRegExp("[\\(\\,\\)]"));
01123
01124 if (strings[0] == "ApplicationStacking" || strings[0] == "ASt")
01125 {
01126 return true;
01127 }
01128
01129
01130 if (strings[0] == "Cloning" || strings[0] == "Clo")
01131 {
01132 return true;
01133 }
01134
01135 if (strings[0] == "SceneCoordinateSystem" || strings[0] == "SCS")
01136 {
01137 if (strings.count() >= 3 && strings[1] == "720" && strings[2] == "576")
01138 {
01139 return true;
01140 }
01141 else
01142 {
01143 return false;
01144 }
01145
01146
01147 }
01148
01149 if (strings[0] == "MultipleAudioStreams" || strings[0] == "MAS")
01150 {
01151 if (strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1"))
01152 {
01153 return true;
01154 }
01155 else
01156 {
01157 return false;
01158 }
01159 }
01160
01161 if (strings[0] == "MultipleVideoStreams" || strings[0] == "MVS")
01162 {
01163 if (strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1"))
01164 {
01165 return true;
01166 }
01167 else
01168 {
01169 return false;
01170 }
01171 }
01172
01173
01174 if (strings[0] == "OverlappingVisibles" || strings[0] == "OvV")
01175 {
01176 return true;
01177 }
01178
01179 if (strings[0] == "SceneAspectRatio" || strings[0] == "SAR")
01180 {
01181 if (strings.count() < 3)
01182 {
01183 return false;
01184 }
01185 else if ((strings[1] == "4" && strings[2] == "3") || (strings[1] == "16" && strings[2] == "9"))
01186 {
01187 return true;
01188 }
01189 else
01190 {
01191 return false;
01192 }
01193 }
01194
01195
01196 if (strings[0] == "VideoScaling" || strings[0] == "VSc")
01197 {
01198 if (strings.count() < 4 || strings[1] != "10")
01199 {
01200 return false;
01201 }
01202 else if ((strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288"))
01203 {
01204 return true;
01205 }
01206 else
01207 {
01208 return false;
01209 }
01210 }
01211
01212 if (strings[0] == "BitmapScaling" || strings[0] == "BSc")
01213 {
01214 if (strings.count() < 4 || strings[1] != "2")
01215 {
01216 return false;
01217 }
01218 else if ((strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288"))
01219 {
01220 return true;
01221 }
01222 else
01223 {
01224 return false;
01225 }
01226 }
01227
01228
01229 if (strings[0] == "VideoDecodeOffset" || strings[0] == "VDO")
01230 {
01231 if (strings.count() >= 3 && strings[1] == "10" && strings[1] == "0")
01232 {
01233 return true;
01234 }
01235 else
01236 {
01237 return false;
01238 }
01239 }
01240
01241
01242 if (strings[0] == "BitmapDecodeOffset" || strings[0] == "BDO")
01243 {
01244 if (strings.count() >= 3 && strings[1] == "10" && (strings[2] == "0" || strings[2] == "1"))
01245 {
01246 return true;
01247 }
01248 else
01249 {
01250 return false;
01251 }
01252 }
01253
01254 if (strings[0] == "UKEngineProfile" || strings[0] == "UniversalEngineProfile" || strings[0] == "UEP")
01255 {
01256 if (strings.count() < 2)
01257 {
01258 return false;
01259 }
01260
01261 if (strings[1] == MHEGEngineProviderIdString)
01262 {
01263 return true;
01264 }
01265
01266 if (strings[1] == m_Context->GetReceiverId())
01267 {
01268 return true;
01269 }
01270
01271 if (strings[1] == m_Context->GetDSMCCId())
01272 {
01273 return true;
01274 }
01275
01276
01277
01278 if (strings[1] == "2")
01279 {
01280 return true;
01281 }
01282 else
01283 {
01284 return false;
01285 }
01286 }
01287
01288
01289 return false;
01290 }
01291
01292
01293 int MHEngine::GetDefaultCharSet()
01294 {
01295 MHApplication *pApp = CurrentApp();
01296
01297 if (pApp && pApp->m_nCharSet > 0)
01298 {
01299 return pApp->m_nCharSet;
01300 }
01301 else
01302 {
01303 return 10;
01304 }
01305 }
01306
01307 void MHEngine::GetDefaultBGColour(MHColour &colour)
01308 {
01309 MHApplication *pApp = CurrentApp();
01310
01311 if (pApp && pApp->m_BGColour.IsSet())
01312 {
01313 colour.Copy(pApp->m_BGColour);
01314 }
01315 else
01316 {
01317 colour.SetFromString("\000\000\000\377", 4);
01318 }
01319 }
01320
01321 void MHEngine::GetDefaultTextColour(MHColour &colour)
01322 {
01323 MHApplication *pApp = CurrentApp();
01324
01325 if (pApp && pApp->m_TextColour.IsSet())
01326 {
01327 colour.Copy(pApp->m_TextColour);
01328 }
01329 else
01330 {
01331 colour.SetFromString("\377\377\377\000", 4);
01332 }
01333 }
01334
01335 void MHEngine::GetDefaultButtonRefColour(MHColour &colour)
01336 {
01337 MHApplication *pApp = CurrentApp();
01338
01339 if (pApp && pApp->m_ButtonRefColour.IsSet())
01340 {
01341 colour.Copy(pApp->m_ButtonRefColour);
01342 }
01343 else
01344 {
01345 colour.SetFromString("\377\377\377\000", 4);
01346 }
01347 }
01348
01349 void MHEngine::GetDefaultHighlightRefColour(MHColour &colour)
01350 {
01351 MHApplication *pApp = CurrentApp();
01352
01353 if (pApp && pApp->m_HighlightRefColour.IsSet())
01354 {
01355 colour.Copy(pApp->m_HighlightRefColour);
01356 }
01357 else
01358 {
01359 colour.SetFromString("\377\377\377\000", 4);
01360 }
01361 }
01362
01363 void MHEngine::GetDefaultSliderRefColour(MHColour &colour)
01364 {
01365 MHApplication *pApp = CurrentApp();
01366
01367 if (pApp && pApp->m_SliderRefColour.IsSet())
01368 {
01369 colour.Copy(pApp->m_SliderRefColour);
01370 }
01371 else
01372 {
01373 colour.SetFromString("\377\377\377\000", 4);
01374 }
01375 }
01376
01377 int MHEngine::GetDefaultTextCHook()
01378 {
01379 MHApplication *pApp = CurrentApp();
01380
01381 if (pApp && pApp->m_nTextCHook > 0)
01382 {
01383 return pApp->m_nTextCHook;
01384 }
01385 else
01386 {
01387 return 10;
01388 }
01389 }
01390
01391 int MHEngine::GetDefaultStreamCHook()
01392 {
01393 MHApplication *pApp = CurrentApp();
01394
01395 if (pApp && pApp->m_nStrCHook > 0)
01396 {
01397 return pApp->m_nStrCHook;
01398 }
01399 else
01400 {
01401 return 10;
01402 }
01403 }
01404
01405 int MHEngine::GetDefaultBitmapCHook()
01406 {
01407 MHApplication *pApp = CurrentApp();
01408
01409 if (pApp && pApp->m_nBitmapCHook > 0)
01410 {
01411 return pApp->m_nBitmapCHook;
01412 }
01413 else
01414 {
01415 return 4;
01416 }
01417 }
01418
01419 void MHEngine::GetDefaultFontAttrs(MHOctetString &str)
01420 {
01421 MHApplication *pApp = CurrentApp();
01422
01423 if (pApp && pApp->m_FontAttrs.Size() > 0)
01424 {
01425 str.Copy(pApp->m_FontAttrs);
01426 }
01427 else
01428 {
01429 str.Copy("plain.24.24.0");
01430 }
01431 }
01432
01433
01434 const char *MHEngine::MHEGEngineProviderIdString = "MHGGNU001";
01435
01436
01437 int __mhlogoptions = MHLogError;
01438
01439 FILE *__mhlogStream = NULL;
01440
01441
01442 void __mhlog(QString logtext)
01443 {
01444 QByteArray tmp = logtext.toAscii();
01445 fprintf(__mhlogStream, "%s\n", tmp.constData());
01446 }
01447
01448
01449 void MHSetLogging(FILE *logStream, unsigned int logLevel)
01450 {
01451 __mhlogStream = logStream;
01452 __mhlogoptions = logLevel;
01453 }