// 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; } } }