public void EventTriggered(MHRoot pSource, int ev, MHUnion evData) { Logging.Log(Logging.MHLogLinks, "Event - " + MHLink.EventTypeToString(ev) + " from " + pSource.ObjectIdentifier.Printable()); switch (ev) { case MHRoot.EventFirstItemPresented: case MHRoot.EventHeadItems: case MHRoot.EventHighlightOff: case MHRoot.EventHighlightOn: case MHRoot.EventIsAvailable: case MHRoot.EventIsDeleted: case MHRoot.EventIsDeselected: case MHRoot.EventIsRunning: case MHRoot.EventIsSelected: case MHRoot.EventIsStopped: case MHRoot.EventItemDeselected: case MHRoot.EventItemSelected: case MHRoot.EventLastItemPresented: case MHRoot.EventTailItems: case MHRoot.EventTestEvent: case MHRoot.EventTokenMovedFrom: case MHRoot.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.ObjectIdentifier, ev, evData); break; case MHRoot.EventAnchorFired: case MHRoot.EventAsyncStopped: case MHRoot.EventContentAvailable: case MHRoot.EventCounterTrigger: case MHRoot.EventCursorEnter: case MHRoot.EventCursorLeave: case MHRoot.EventEngineEvent: case MHRoot.EventEntryFieldFull: case MHRoot.EventInteractionCompleted: case MHRoot.EventStreamEvent: case MHRoot.EventStreamPlaying: case MHRoot.EventStreamStopped: case MHRoot.EventTimerFired: case MHRoot.EventUserInput: case MHRoot.EventFocusMoved: // UK MHEG. Generated by HyperText class case MHRoot.EventSliderValueChanged: // UK MHEG. Generated by Slider class { // Asynchronous events. Add to the event queue. MHAsynchEvent pEvent = new MHAsynchEvent(); pEvent.EventSource = pSource; pEvent.EventType = ev; pEvent.EventData = evData; m_EventQueue.Add(pEvent); } break; } }
protected override void PrintArgs(TextWriter writer, int nTabs) { m_EventSource.Print(writer, 0); writer.Write(MHLink.EventTypeToString(m_EventType)); writer.Write(" "); if (m_EventData.Type != MHParameter.P_Null) { m_EventData.Print(writer, 0); } }
// Add and remove links to and from the active link table. public void AddLink(MHLink pLink) { #if DEBUG // Should not be there already. for (int i = 0; i < m_LinkTable.Count; i++) { Logging.Assert(pLink != m_LinkTable[i]); } #endif m_LinkTable.Add(pLink); }
// Set this up from the parse tree. public override void Initialise(MHParseNode p, MHEngine engine) { // Set to empty before we start (just in case). engine.GetGroupId().Copy(""); base.Initialise(p, engine); // Must be an external reference with an object number of zero. Logging.Assert(m_ObjectIdentifier.ObjectNo == 0 && m_ObjectIdentifier.GroupId.Size != 0); // Set the group id for the rest of the group to this. engine.GetGroupId().Copy(m_ObjectIdentifier.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(ASN1Codes.C_ON_START_UP); if (pOnStartUp != null) { m_StartUp.Initialise(pOnStartUp, engine); } MHParseNode pOnCloseDown = p.GetNamedArg(ASN1Codes.C_ON_CLOSE_DOWN); if (pOnCloseDown != null) { m_CloseDown.Initialise(pOnCloseDown, engine); } MHParseNode pOriginalGCPrio = p.GetNamedArg(ASN1Codes.C_ORIGINAL_GC_PRIORITY); if (pOriginalGCPrio != null) { m_nOrigGroupCachePriority = pOriginalGCPrio.GetArgN(0).GetIntValue(); } // Ignore the other stuff at the moment. MHParseNode pItems = p.GetNamedArg(ASN1Codes.C_ITEMS); if (pItems == null) { p.Failure("Missing :Items block"); } for (int i = 0; i < pItems.GetArgCount(); i++) { MHParseNode pItem = pItems.GetArgN(i); MHIngredient pIngredient = null; // Generate the particular kind of ingredient. switch (pItem.GetTagNo()) { case ASN1Codes.C_RESIDENT_PROGRAM: pIngredient = new MHResidentProgram(); break; // NOT UK case ASN1Codes.C_REMOTE_PROGRAM: pIngredient = new MHRemoteProgram(); break; // NOT UK case ASN1Codes.C_INTERCHANGED_PROGRAM: pIngredient = new MHInterChgProgram(); break; // NOT UK case ASN1Codes.C_PALETTE: pIngredient = new MHPalette(); break; // NOT UK case ASN1Codes.C_FONT: pIngredient = new MHFont(); break; // NOT UK case ASN1Codes.C_CURSOR_SHAPE: pIngredient = new MHCursorShape(); break; case ASN1Codes.C_BOOLEAN_VARIABLE: pIngredient = new MHBooleanVar(); break; case ASN1Codes.C_INTEGER_VARIABLE: pIngredient = new MHIntegerVar(); break; case ASN1Codes.C_OCTET_STRING_VARIABLE: pIngredient = new MHOctetStrVar(); break; case ASN1Codes.C_OBJECT_REF_VARIABLE: pIngredient = new MHObjectRefVar(); break; case ASN1Codes.C_CONTENT_REF_VARIABLE: pIngredient = new MHContentRefVar(); break; case ASN1Codes.C_LINK: pIngredient = new MHLink(); break; case ASN1Codes.C_STREAM: pIngredient = new MHStream(); break; case ASN1Codes.C_BITMAP: pIngredient = new MHBitmap(); break; case ASN1Codes.C_LINE_ART: pIngredient = new MHLineArt(); break; case ASN1Codes.C_DYNAMIC_LINE_ART: pIngredient = new MHDynamicLineArt(); break; case ASN1Codes.C_RECTANGLE: pIngredient = new MHRectangle(); break; // NOT UK case ASN1Codes.C_HOTSPOT: pIngredient = new MHHotSpot(); break; // NOT UK case ASN1Codes.C_SWITCH_BUTTON: pIngredient = new MHSwitchButton(); break; // NOT UK case ASN1Codes.C_PUSH_BUTTON: pIngredient = new MHPushButton(); break; case ASN1Codes.C_TEXT: pIngredient = new MHText(); break; case ASN1Codes.C_ENTRY_FIELD: pIngredient = new MHEntryField(); break; case ASN1Codes.C_HYPER_TEXT: pIngredient = new MHHyperText(); break; case ASN1Codes.C_SLIDER: pIngredient = new MHSlider(); break; case ASN1Codes.C_TOKEN_GROUP: pIngredient = new MHTokenGroup(); break; case ASN1Codes.C_LIST_GROUP: pIngredient = new MHListGroup(); break; default: // So we find out about these when debugging. Logging.Log(Logging.MHLogError, "'" + pItem.GetTagNo() + "' tag not in switch"); Logging.Assert(false); // Future proofing: ignore any ingredients that we don't know about. // Obviously these can only arise in the binary coding. break; } if (pIngredient != null) { // Initialise it from its argments. pIngredient.Initialise(pItem, engine); // Remember the highest numbered ingredient if (pIngredient.ObjectIdentifier.ObjectNo > m_nLastId) { m_nLastId = pIngredient.ObjectIdentifier.ObjectNo; } // Add it to the ingedients of this group. m_Items.Append(pIngredient); } } }
private void NextSym() { while (true) { switch (m_ch) { case '\n': m_lineCount++; // And drop to next goto case ' '; case ' ': case '\r': case '\t': case '\f': // Skip white space. GetNextChar(); continue; case '/': { // Comment. GetNextChar(); if (m_ch != '/') { Error("Malformed comment"); } do { GetNextChar(); } while (m_ch != '\n' && m_ch != '\f' && m_ch != '\r'); continue; // Next symbol } case ':': // Start of a tag { m_nType = PTTag; char[] buff = new char[MAX_TAG_LENGTH + 1]; int p = 0; do { buff[p++] = (char)m_ch; GetNextChar(); if (p == MAX_TAG_LENGTH) { break; } } while ((m_ch >= 'a' && m_ch <= 'z') || (m_ch >= 'A' && m_ch <= 'Z')); // Look it up and return it if it's found. m_nTag = FindTag(new string(buff, 0, p)); if (m_nTag >= 0) { return; } // Unrecognised tag. Error("Unrecognised tag"); break; } case '"': // Start of a string { m_nType = PTString; // MHEG strings can include NULLs. For the moment we pass back the length and also // null-terminate the strings. StringBuilder sb = new StringBuilder(); while (true) { GetNextChar(); if (m_ch == '"') { break; // Finished the string. } if (m_ch == '\\') { GetNextChar(); // Escape character. Include the next char in the string. } if (m_ch == '\n' || m_ch == '\r') { Error("Unterminated string"); } sb.Append((char)m_ch); } GetNextChar(); // Skip the closing quote m_String = sb.ToString(); m_nStringLength = sb.Length; return; } case '\'': // Start of a string using quoted printable { m_nType = PTString; StringBuilder sb = new StringBuilder(); // Quotable printable strings contain escape sequences beginning with the // escape character '='. The strings can span lines but each line must // end with an equal sign. while (true) { GetNextChar(); if (m_ch == '\'') { break; } if (m_ch == '\n') { Error("Unterminated string"); } if (m_ch == '=') // Special code in quoted-printable. // Should be followed by two hex digits or by white space and a newline. { GetNextChar(); if (m_ch == ' ' || m_ch == '\t' || m_ch == '\r' || m_ch == '\n') { // White space. Remove everything up to the newline. while (m_ch != '\n') { if (!(m_ch == ' ' || m_ch == '\t' || m_ch == '\r')) { Error("Malformed quoted printable string"); } GetNextChar(); } continue; // continue with the first character on the next line } else { int nByte = 0; if (m_ch >= '0' && m_ch <= '9') { nByte = m_ch - '0'; } else if (m_ch >= 'A' && m_ch <= 'F') { nByte = m_ch - 'A' + 10; } else if (m_ch >= 'a' && m_ch <= 'f') { nByte = m_ch - 'a' + 10; } else { Error("Malformed quoted printable string"); } nByte *= 16; GetNextChar(); if (m_ch >= '0' && m_ch <= '9') { nByte += m_ch - '0'; } else if (m_ch >= 'A' && m_ch <= 'F') { nByte += m_ch - 'A' + 10; } else if (m_ch >= 'a' && m_ch <= 'f') { nByte += m_ch - 'a' + 10; } else { Error("Malformed quoted printable string"); } m_ch = nByte; // Put this into the string. } } // We grow the buffer to the largest string in the input. sb.Append((char)m_ch); } GetNextChar(); // Skip the closing quote m_String = sb.ToString(); m_nStringLength = sb.Length; return; } case '`': // Start of a string using base 64 // These can, presumably span lines. Logging.Assert(false); // TODO break; case '#': // Start of 3-byte hex constant. Logging.Assert(false); // TODO break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { m_nType = PTInt; bool negative = m_ch == '-'; if (negative) { GetNextChar(); if (m_ch < '0' || m_ch > '9') { Error("Expected digit after '-'"); } } // Start of a number. Hex can be represented as 0xn. // Strictly speaking hex values cannot be preceded by a minus sign. m_nInt = m_ch - '0'; GetNextChar(); if (m_nInt == 0 && (m_ch == 'x' || m_ch == 'X')) { throw new MHEGException("TODO"); // ASSERT(FALSE); // TODO } while (m_ch >= '0' && m_ch <= '9') { m_nInt = m_nInt * 10 + m_ch - '0'; // TODO: What about overflow? GetNextChar(); } if (negative) { m_nInt = -m_nInt; } return; } case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': { // Start of an enumerated type. m_nType = PTEnum; char[] buff = new char[MAX_ENUM + 1]; int p = 0; do { buff[p++] = (char)m_ch; GetNextChar(); if (p == MAX_ENUM) { break; } }while ((m_ch >= 'a' && m_ch <= 'z') || (m_ch >= 'A' && m_ch <= 'Z') || m_ch == '-'); string b = new string(buff, 0, p); if (b.Equals("NULL")) { m_nType = PTNull; return; } if (b.Equals("true")) { m_nType = PTBool; m_fBool = true; return; } if (b.Equals("false")) { m_nType = PTBool; m_fBool = false; return; } // Look up the tag in all the tables. Fortunately all the enumerations // are distinct so we don't need to know the context. m_nInt = MHLink.GetEventType(b); if (m_nInt > 0) { return; } m_nInt = MHText.GetJustification(b); if (m_nInt > 0) { return; } m_nInt = MHText.GetLineOrientation(b); if (m_nInt > 0) { return; } m_nInt = MHText.GetStartCorner(b); if (m_nInt > 0) { return; } // Check the colour table. If it's there generate a string containing the colour info. for (int i = 0; i < colourTable.Length; i++) { if (b.ToLower().Equals(colourTable[i].name)) { m_nType = PTString; string str = new string((char)colourTable[i].red, 1); str += (char)colourTable[i].green; str += (char)colourTable[i].blue; str += (char)colourTable[i].alpha; m_String = str; m_nStringLength = 4; return; } } Error("Unrecognised enumeration"); break; } case '{': // Start of a "section". // The standard indicates that open brace followed by a tag should be written // as a single word. We'll be more lenient and allow spaces or comments between them. m_nType = PTStartSection; GetNextChar(); return; case '}': // End of a "section". m_nType = PTEndSection; GetNextChar(); return; case '(': // Start of a sequence. m_nType = PTStartSeq; GetNextChar(); return; case ')': // End of a sequence. m_nType = PTEndSeq; GetNextChar(); return; case -1: m_nType = PTEOF; return; default: Error("Unknown character"); GetNextChar(); break; } } }
public void RemoveLink(MHLink pLink) { bool fRes = m_LinkTable.Remove(pLink); Logging.Assert(fRes); // The link should have been there. }
public int RunAll() { // Request to boot or reboot if (m_fBooting) { // Reset everything m_ApplicationStack.Clear(); m_EventQueue.Clear(); m_ExternContentTable.Clear(); m_LinkTable.Clear(); // UK MHEG applications boot from ~//a or ~//startup. Actually the initial // object can also be explicitly given in the MHObjectRef startObj = new MHObjectRef(); startObj.ObjectNo = 0; startObj.GroupId.Copy(new 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.GroupId.Copy(new MHOctetString("~//startup")); if (!Launch(startObj)) { //Logging.Log(Logging.MHLogError, "Unable to launch application"); 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. if (CurrentScene() != null) { int next = CurrentScene().CheckTimers(this); if (nNextTime == 0 || nNextTime > next) { nNextTime = next; } } if (CurrentApp() != null) { // 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.Count != 0) { // 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.Count != 0) { MHAsynchEvent pEvent = m_EventQueue[0]; Logging.Log(Logging.MHLogLinks, "Asynchronous event dequeued - " + MHLink.EventTypeToString(pEvent.EventType) + " from " + pEvent.EventSource.ObjectIdentifier.Printable()); CheckLinks(pEvent.EventSource.ObjectIdentifier, pEvent.EventType, pEvent.EventData); m_EventQueue.Remove(pEvent); } } while (m_EventQueue.Count != 0 || m_ActionStack.Count != 0); // Redraw the display if necessary. if (!IsRegionEmpty(m_redrawRegion)) { m_Context.RequireRedraw(m_redrawRegion); m_redrawRegion = new Region(); m_redrawRegion.MakeEmpty(); } return(nNextTime); }