MythTV  0.26-pre
ParseText.cpp
Go to the documentation of this file.
00001 /* ParseText.cpp
00002 
00003    Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU General Public License
00007    as published by the Free Software Foundation; either version 2
00008    of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018    Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00019 
00020 */
00021 
00022 /*
00023 Parser for the textual form of MHEG5.
00024 This is very basic and is only there to enable some test programs to be run.
00025 */
00026 
00027 #include "ParseText.h"
00028 #include "ParseNode.h"
00029 #include "BaseClasses.h"
00030 #include "ASN1Codes.h"
00031 #include "Root.h"
00032 #include "Groups.h"
00033 #include <ctype.h>
00034 #include "Ingredients.h" // For GetEventType
00035 #include "Text.h" // For GetJustification etc
00036 #include "Engine.h"
00037 #include "Logging.h"
00038 
00039 
00040 #ifndef WIN32
00041 #define stricmp strcasecmp
00042 #endif
00043 
00044 
00045 MHParseText::MHParseText(QByteArray &program)
00046 {
00047     m_data = program;
00048     m_lineCount = 1;
00049     m_String = (unsigned char *)malloc(100); // Initial size - may grow.
00050     m_p = 0;
00051 }
00052 
00053 MHParseText::~MHParseText()
00054 {
00055     free(m_String);
00056 }
00057 
00058 // Get the next character.
00059 void MHParseText::GetNextChar()
00060 {
00061     if ((int)m_p >= m_data.size())
00062     {
00063         m_ch = EOF;
00064     }
00065     else
00066     {
00067         m_ch = m_data[m_p++];
00068     }
00069 }
00070 
00071 // Maximum length of a tag (i.e. a symbol beginning with a colon). Actually  the longest is around 22 chars.
00072 #define MAX_TAG_LENGTH  30
00073 
00074 const char *rchTagNames[] =
00075 {
00076     ":Application",
00077     ":Scene",
00078     ":StdID",
00079     ":StdVersion",
00080     ":ObjectInfo",
00081     ":OnStartUp",
00082     ":OnCloseDown",
00083     ":OrigGCPriority",
00084     ":Items",
00085     ":ResidentPrg",
00086     ":RemotePrg",
00087     ":InterchgPrg",
00088     ":Palette",
00089     ":Font",  // Occurs twice.
00090     ":CursorShape",
00091     ":BooleanVar",
00092     ":IntegerVar",
00093     ":OStringVar",
00094     ":ObjectRefVar",
00095     ":ContentRefVar",
00096     ":Link",
00097     ":Stream",
00098     ":Bitmap",
00099     ":LineArt",
00100     ":DynamicLineArt",
00101     ":Rectangle",
00102     ":Hotspot",
00103     ":SwitchButton",
00104     ":PushButton",
00105     ":Text",
00106     ":EntryField",
00107     ":HyperText",
00108     ":Slider",
00109     ":TokenGroup",
00110     ":ListGroup",
00111     ":OnSpawnCloseDown",
00112     ":OnRestart",
00113     "", // Default attributes - encoded as a group in binary
00114     ":CharacterSet",
00115     ":BackgroundColour",
00116     ":TextCHook",
00117     ":TextColour",
00118     ":Font",
00119     ":FontAttributes",
00120     ":InterchgPrgCHook",
00121     ":StreamCHook",
00122     ":BitmapCHook",
00123     ":LineArtCHook",
00124     ":ButtonRefColour",
00125     ":HighlightRefColour",
00126     ":SliderRefColour",
00127     ":InputEventReg",
00128     ":SceneCS",
00129     ":AspectRatio",
00130     ":MovingCursor",
00131     ":NextScenes",
00132     ":InitiallyActive",
00133     ":CHook",
00134     ":OrigContent",
00135     ":Shared",
00136     ":ContentSize",
00137     ":CCPriority",
00138     "" , // Link condition - always replaced by EventSource, EventType and EventData
00139     ":LinkEffect",
00140     ":Name",
00141     ":InitiallyAvailable",
00142     ":ProgramConnectionTag",
00143     ":OrigValue",
00144     ":ObjectRef",
00145     ":ContentRef",
00146     ":MovementTable",
00147     ":TokenGroupItems",
00148     ":NoTokenActionSlots",
00149     ":Positions",
00150     ":WrapAround",
00151     ":MultipleSelection",
00152     ":OrigBoxSize",
00153     ":OrigPosition",
00154     ":OrigPaletteRef",
00155     ":Tiling",
00156     ":OrigTransparency",
00157     ":BBBox",
00158     ":OrigLineWidth",
00159     ":OrigLineStyle",
00160     ":OrigRefLineColour",
00161     ":OrigRefFillColour",
00162     ":OrigFont",
00163     ":HJustification",
00164     ":VJustification",
00165     ":LineOrientation",
00166     ":StartCorner",
00167     ":TextWrapping",
00168     ":Multiplex",
00169     ":Storage",
00170     ":Looping",
00171     ":Audio",
00172     ":Video",
00173     ":RTGraphics",
00174     ":ComponentTag",
00175     ":OrigVolume",
00176     ":Termination",
00177     ":EngineResp",
00178     ":Orientation",
00179     ":MaxValue",
00180     ":MinValue",
00181     ":InitialValue",
00182     ":InitialPortion",
00183     ":StepSize",
00184     ":SliderStyle",
00185     ":InputType",
00186     ":CharList",
00187     ":ObscuredInput",
00188     ":MaxLength",
00189     ":OrigLabel",
00190     ":ButtonStyle",
00191     ":Activate",
00192     ":Add",
00193     ":AddItem",
00194     ":Append",
00195     ":BringToFront",
00196     ":Call",
00197     ":CallActionSlot",
00198     ":Clear",
00199     ":Clone",
00200     ":CloseConnection",
00201     ":Deactivate",
00202     ":DelItem",
00203     ":Deselect",
00204     ":DeselectItem",
00205     ":Divide",
00206     ":DrawArc",
00207     ":DrawLine",
00208     ":DrawOval",
00209     ":DrawPolygon",
00210     ":DrawPolyline",
00211     ":DrawRectangle",
00212     ":DrawSector",
00213     ":Fork",
00214     ":GetAvailabilityStatus",
00215     ":GetBoxSize",
00216     ":GetCellItem",
00217     ":GetCursorPosition",
00218     ":GetEngineSupport",
00219     ":GetEntryPoint",
00220     ":GetFillColour",
00221     ":GetFirstItem",
00222     ":GetHighlightStatus",
00223     ":GetInteractionStatus",
00224     ":GetItemStatus",
00225     ":GetLabel",
00226     ":GetLastAnchorFired",
00227     ":GetLineColour",
00228     ":GetLineStyle",
00229     ":GetLineWidth",
00230     ":GetListItem",
00231     ":GetListSize",
00232     ":GetOverwriteMode",
00233     ":GetPortion",
00234     ":GetPosition",
00235     ":GetRunningStatus",
00236     ":GetSelectionStatus",
00237     ":GetSliderValue",
00238     ":GetTextContent",
00239     ":GetTextData",
00240     ":GetTokenPosition",
00241     ":GetVolume",
00242     ":Launch",
00243     ":LockScreen",
00244     ":Modulo",
00245     ":Move",
00246     ":MoveTo",
00247     ":Multiply",
00248     ":OpenConnection",
00249     ":Preload",
00250     ":PutBefore",
00251     ":PutBehind",
00252     ":Quit",
00253     ":ReadPersistent",
00254     ":Run",
00255     ":ScaleBitmap",
00256     ":ScaleVideo",
00257     ":ScrollItems",
00258     ":Select",
00259     ":SelectItem",
00260     ":SendEvent",
00261     ":SendToBack",
00262     ":SetBoxSize",
00263     ":SetCachePriority",
00264     ":SetCounterEndPosition",
00265     ":SetCounterPosition",
00266     ":SetCounterTrigger",
00267     ":SetCursorPosition",
00268     ":SetCursorShape",
00269     ":SetData",
00270     ":SetEntryPoint",
00271     ":SetFillColour",
00272     ":SetFirstItem",
00273     ":SetFontRef",
00274     ":SetHighlightStatus",
00275     ":SetInteractionStatus",
00276     ":SetLabel",
00277     ":SetLineColour",
00278     ":SetLineStyle",
00279     ":SetLineWidth",
00280     ":SetOverwriteMode",
00281     ":SetPaletteRef",
00282     ":SetPortion",
00283     ":SetPosition",
00284     ":SetSliderValue",
00285     ":SetSpeed",
00286     ":SetTimer",
00287     ":SetTransparency",
00288     ":SetVariable",
00289     ":SetVolume",
00290     ":Spawn",
00291     ":Step",
00292     ":Stop",
00293     ":StorePersistent",
00294     ":Subtract",
00295     ":TestVariable",
00296     ":Toggle",
00297     ":ToggleItem",
00298     ":TransitionTo",
00299     ":Unload",
00300     ":UnlockScreen",
00301     ":GBoolean",
00302     ":GInteger",
00303     ":GOctetString",
00304     ":GObjectRef",
00305     ":GContentRef",
00306     ":NewColourIndex",
00307     ":NewAbsoluteColour",
00308     ":NewFontName",
00309     ":NewFontRef",
00310     ":NewContentSize",
00311     ":NewCCPriority",
00312     ":IndirectRef",
00313     /* UK MHEG */
00314     ":SetBackgroundColour",
00315     ":SetCellPosition",
00316     ":SetInputRegister",
00317     ":SetTextColour",
00318     ":SetFontAttributes",
00319     ":SetVideoDecodeOffset",
00320     ":GetVideoDecodeOffset",
00321     ":GetFocusPosition",
00322     ":SetFocusPosition",
00323     ":SetBitmapDecodeOffset",
00324     ":GetBitmapDecodeOffset",
00325     ":SetSliderParameters",
00326     /* Pseudo-operations.  These are encoded as LinkCondition in binary. */
00327     ":EventSource",
00328     ":EventType",
00329     ":EventData",
00330     ":ActionSlots"
00331 };
00332 
00333 // Some example programs use these colour names
00334 static struct
00335 {
00336     const char *name;
00337     unsigned char r, g, b, t;
00338 } colourTable[] =
00339 {
00340     { "black",          0,  0,  0,  0   },
00341     { "transparent",    0,  0,  0,  255 },
00342     { "gray"/*sic*/,    128, 128, 128, 0 },
00343     { "darkgray"/*sic*/, 192, 192, 192, 0 },
00344     { "red",            255, 0,  0,  0 },
00345     { "darkred",        128, 0,  0,  0 },
00346     { "blue",           0,  0,  255, 0 },
00347     { "darkblue",       0,  0,  128, 0 },
00348     { "green",          0,  255, 0,  0 },
00349     { "darkgreen",      0,  128, 0,  0 },
00350     { "yellow",         255, 255, 0,  0 },
00351     { "cyan",           0,  255, 255, 0 },
00352     { "magenta",        255, 0,  255, 0 }
00353 };
00354 
00355 
00356 // Search for a tag and return it if it exists.  Returns -1 if it isn't found.
00357 static int FindTag(const char *p)
00358 {
00359     for (int i = 0; i < (int)(sizeof(rchTagNames) / sizeof(rchTagNames[0])); i++)
00360     {
00361         if (stricmp(p, rchTagNames[i]) == 0)
00362         {
00363             return i;
00364         }
00365     }
00366 
00367     return -1;
00368 }
00369 
00370 
00371 // Ditto for the enumerated types
00372 #define MAX_ENUM        30
00373 
00374 void MHParseText::Error(const char *str)
00375 {
00376     MHERROR(QString("%1- at line %2\n").arg(str).arg(m_lineCount));
00377 }
00378 
00379 // Lexical analysis.  Get the next symbol.
00380 void MHParseText::NextSym()
00381 {
00382     while (1)
00383     {
00384 
00385         switch (m_ch)
00386         {
00387             case '\n':
00388                 m_lineCount++; // And drop to next
00389             case ' ':
00390             case '\r':
00391             case '\t':
00392             case '\f':
00393                 // Skip white space.
00394                 GetNextChar();
00395                 continue;
00396 
00397             case '/':
00398             {
00399                 // Comment.
00400                 GetNextChar();
00401 
00402                 if (m_ch != '/')
00403                 {
00404                     Error("Malformed comment");
00405                 }
00406 
00407                 do
00408                 {
00409                     GetNextChar();
00410                 }
00411                 while (m_ch != '\n' && m_ch != '\f' && m_ch != '\r');
00412 
00413                 continue; // Next symbol
00414             }
00415 
00416             case ':': // Start of a tag
00417             {
00418                 m_nType = PTTag;
00419                 char buff[MAX_TAG_LENGTH+1];
00420                 char *p = buff;
00421 
00422                 do
00423                 {
00424                     *p++ = m_ch;
00425                     GetNextChar();
00426 
00427                     if (p == buff + MAX_TAG_LENGTH)
00428                     {
00429                         break;
00430                     }
00431                 }
00432                 while ((m_ch >= 'a' && m_ch <= 'z') || (m_ch >= 'A' && m_ch <= 'Z'));
00433 
00434                 *p = 0;
00435 
00436                 // Look it up and return it if it's found.
00437                 m_nTag = FindTag(buff);
00438 
00439                 if (m_nTag >= 0)
00440                 {
00441                     return;
00442                 }
00443 
00444                 // Unrecognised tag.
00445                 Error("Unrecognised tag");
00446             }
00447 
00448             case '"': // Start of a string
00449             {
00450                 m_nType = PTString;
00451                 // MHEG strings can include NULLs.  For the moment we pass back the length and also
00452                 // null-terminate the strings.
00453                 m_nStringLength = 0;
00454 
00455                 while (1)
00456                 {
00457                     GetNextChar();
00458 
00459                     if (m_ch == '"')
00460                     {
00461                         break;    // Finished the string.
00462                     }
00463 
00464                     if (m_ch == '\\')
00465                     {
00466                         GetNextChar();    // Escape character. Include the next char in the string.
00467                     }
00468 
00469                     if (m_ch == '\n' || m_ch == '\r')
00470                     {
00471                         Error("Unterminated string");
00472                     }
00473 
00474                     // We grow the buffer to the largest string in the input.
00475                     unsigned char *str = (unsigned char *)realloc(m_String, m_nStringLength + 2);
00476 
00477                     if (str == NULL)
00478                     {
00479                         Error("Insufficient memory");
00480                     }
00481 
00482                     m_String = str;
00483                     m_String[m_nStringLength++] = m_ch;
00484                 }
00485 
00486                 GetNextChar(); // Skip the closing quote
00487                 m_String[m_nStringLength] = 0;
00488                 return;
00489             }
00490 
00491             case '\'': // Start of a string using quoted printable
00492             {
00493                 m_nType = PTString;
00494                 m_nStringLength = 0;
00495 
00496                 // Quotable printable strings contain escape sequences beginning with the
00497                 // escape character '='.  The strings can span lines but each line must
00498                 // end with an equal sign.
00499                 while (1)
00500                 {
00501                     GetNextChar();
00502 
00503                     if (m_ch == '\'')
00504                     {
00505                         break;
00506                     }
00507 
00508                     if (m_ch == '\n')
00509                     {
00510                         Error("Unterminated string");
00511                     }
00512 
00513                     if (m_ch == '=')   // Special code in quoted-printable.
00514                     {
00515                         // Should be followed by two hex digits or by white space and a newline.
00516                         GetNextChar();
00517 
00518                         if (m_ch == ' ' || m_ch == '\t' || m_ch == '\r' || m_ch == '\n')
00519                         {
00520                             // White space.  Remove everything up to the newline.
00521                             while (m_ch != '\n')
00522                             {
00523                                 if (!(m_ch == ' ' || m_ch == '\t' || m_ch == '\r'))
00524                                 {
00525                                     Error("Malformed quoted printable string");
00526                                 }
00527 
00528                                 GetNextChar();
00529                             }
00530 
00531                             continue; // continue with the first character on the next line
00532                         }
00533                         else
00534                         {
00535                             int byte = 0;
00536 
00537                             if (m_ch >= '0' && m_ch <= '9')
00538                             {
00539                                 byte = m_ch - '0';
00540                             }
00541                             else if (m_ch >= 'A' && m_ch <= 'F')
00542                             {
00543                                 byte = m_ch - 'A' + 10;
00544                             }
00545                             else if (m_ch >= 'a' && m_ch <= 'f')
00546                             {
00547                                 byte = m_ch - 'a' + 10;
00548                             }
00549                             else
00550                             {
00551                                 Error("Malformed quoted printable string");
00552                             }
00553 
00554                             byte *= 16;
00555                             GetNextChar();
00556 
00557                             if (m_ch >= '0' && m_ch <= '9')
00558                             {
00559                                 byte += m_ch - '0';
00560                             }
00561                             else if (m_ch >= 'A' && m_ch <= 'F')
00562                             {
00563                                 byte += m_ch - 'A' + 10;
00564                             }
00565                             else if (m_ch >= 'a' && m_ch <= 'f')
00566                             {
00567                                 byte += m_ch - 'a' + 10;
00568                             }
00569                             else
00570                             {
00571                                 Error("Malformed quoted printable string");
00572                             }
00573 
00574                             m_ch = byte; // Put this into the string.
00575                         }
00576                     }
00577 
00578                     // We grow the buffer to the largest string in the input.
00579                     unsigned char *str = (unsigned char *)realloc(m_String, m_nStringLength + 2);
00580 
00581                     if (str == NULL)
00582                     {
00583                         Error("Insufficient memory");
00584                     }
00585 
00586                     m_String = str;
00587                     m_String[m_nStringLength++] = m_ch;
00588                 }
00589 
00590                 GetNextChar(); // Skip the closing quote
00591                 m_String[m_nStringLength] = 0;
00592                 return;
00593             }
00594 
00595             case '`': // Start of a string using base 64
00596                 // These can, presumably span lines.
00597                 MHERROR("Base 64 string is not implemented");
00598                 break;
00599 
00600             case '#': // Start of 3-byte hex constant.
00601                 MHERROR("3-byte hex constant is not implemented");
00602                 break;
00603 
00604             case '-':
00605             case '0':
00606             case '1':
00607             case '2':
00608             case '3':
00609             case '4':
00610             case '5':
00611             case '6':
00612             case '7':
00613             case '8':
00614             case '9':
00615             {
00616                 m_nType = PTInt;
00617                 bool negative = m_ch == '-';
00618 
00619                 if (negative)
00620                 {
00621                     GetNextChar();
00622 
00623                     if (m_ch < '0' || m_ch > '9')
00624                     {
00625                         Error("Expected digit after '-'");
00626                     }
00627                 }
00628 
00629                 // Start of a number.  Hex can be represented as 0xn.
00630                 // Strictly speaking hex values cannot be preceded by a minus sign.
00631                 m_nInt = m_ch - '0';
00632                 GetNextChar();
00633 
00634                 if (m_nInt == 0 && (m_ch == 'x' || m_ch == 'X'))
00635                 {
00636                     MHERROR("Hex constant is not implemented");
00637                 }
00638 
00639                 while (m_ch >= '0' && m_ch <= '9')
00640                 {
00641                     m_nInt = m_nInt * 10 + m_ch - '0';
00642                     // TODO: What about overflow?
00643                     GetNextChar();
00644                 }
00645 
00646                 if (negative)
00647                 {
00648                     m_nInt = -m_nInt;
00649                 }
00650 
00651                 return;
00652             }
00653 
00654             case 'a':
00655             case 'b':
00656             case 'c':
00657             case 'd':
00658             case 'e':
00659             case 'f':
00660             case 'g':
00661             case 'h':
00662             case 'i':
00663             case 'j':
00664             case 'k':
00665             case 'l':
00666             case 'm':
00667             case 'n':
00668             case 'o':
00669             case 'p':
00670             case 'q':
00671             case 'r':
00672             case 's':
00673             case 't':
00674             case 'u':
00675             case 'v':
00676             case 'w':
00677             case 'x':
00678             case 'y':
00679             case 'z':
00680             case 'A':
00681             case 'B':
00682             case 'C':
00683             case 'D':
00684             case 'E':
00685             case 'F':
00686             case 'G':
00687             case 'H':
00688             case 'I':
00689             case 'J':
00690             case 'K':
00691             case 'L':
00692             case 'M':
00693             case 'N':
00694             case 'O':
00695             case 'P':
00696             case 'Q':
00697             case 'R':
00698             case 'S':
00699             case 'T':
00700             case 'U':
00701             case 'V':
00702             case 'W':
00703             case 'X':
00704             case 'Y':
00705             case 'Z':
00706             {
00707                 // Start of an enumerated type.
00708                 m_nType = PTEnum;
00709                 char buff[MAX_ENUM+1];
00710                 char *p = buff;
00711 
00712                 do
00713                 {
00714                     *p++ = m_ch;
00715                     GetNextChar();
00716 
00717                     if (p == buff + MAX_ENUM)
00718                     {
00719                         break;
00720                     }
00721                 }
00722                 while ((m_ch >= 'a' && m_ch <= 'z') || (m_ch >= 'A' && m_ch <= 'Z') || m_ch == '-');
00723 
00724                 *p = '\0';
00725 
00726                 if (stricmp(buff, "NULL") == 0)
00727                 {
00728                     m_nType = PTNull;
00729                     return;
00730                 }
00731 
00732                 if (stricmp(buff, "true") == 0)
00733                 {
00734                     m_nType = PTBool;
00735                     m_fBool = true;
00736                     return;
00737                 }
00738 
00739                 if (stricmp(buff, "false") == 0)
00740                 {
00741                     m_nType = PTBool;
00742                     m_fBool = false;
00743                     return;
00744                 }
00745 
00746                 // Look up the tag in all the tables.  Fortunately all the enumerations
00747                 // are distinct so we don't need to know the context.
00748                 m_nInt = MHLink::GetEventType(buff);
00749 
00750                 if (m_nInt > 0)
00751                 {
00752                     return;
00753                 }
00754 
00755                 m_nInt = MHText::GetJustification(buff);
00756 
00757                 if (m_nInt > 0)
00758                 {
00759                     return;
00760                 }
00761 
00762                 m_nInt = MHText::GetLineOrientation(buff);
00763 
00764                 if (m_nInt > 0)
00765                 {
00766                     return;
00767                 }
00768 
00769                 m_nInt = MHText::GetStartCorner(buff);
00770 
00771                 if (m_nInt > 0)
00772                 {
00773                     return;
00774                 }
00775 
00776                 m_nInt = MHSlider::GetOrientation(buff);
00777 
00778                 if (m_nInt > 0)
00779                 {
00780                     return;
00781                 }
00782 
00783                 m_nInt = MHSlider::GetStyle(buff);
00784 
00785                 if (m_nInt > 0)
00786                 {
00787                     return;
00788                 }
00789 
00790                 // Check the colour table.  If it's there generate a string containing the colour info.
00791                 for (int i = 0; i < (int)(sizeof(colourTable) / sizeof(colourTable[0])); i++)
00792                 {
00793                     if (stricmp(buff, colourTable[i].name) == 0)
00794                     {
00795                         m_nType = PTString;
00796                         unsigned char *str = (unsigned char *)realloc(m_String, 4 + 1);
00797 
00798                         if (str == NULL)
00799                         {
00800                             Error("Insufficient memory");
00801                         }
00802 
00803                         m_String[0] = colourTable[i].r;
00804                         m_String[1] = colourTable[i].g;
00805                         m_String[2] = colourTable[i].b;
00806                         m_String[3] = colourTable[i].t;
00807                         m_String = str;
00808                         m_nStringLength = 4;
00809                         return;
00810                     }
00811                 }
00812 
00813                 Error("Unrecognised enumeration");
00814                 break;
00815             }
00816 
00817             case '{': // Start of a "section".
00818                 // The standard indicates that open brace followed by a tag should be written
00819                 // as a single word.  We'll be more lenient and allow spaces or comments between them.
00820                 m_nType = PTStartSection;
00821                 GetNextChar();
00822                 return;
00823 
00824             case '}': // End of a "section".
00825                 m_nType = PTEndSection;
00826                 GetNextChar();
00827                 return;
00828 
00829             case '(': // Start of a sequence.
00830                 m_nType = PTStartSeq;
00831                 GetNextChar();
00832                 return;
00833 
00834             case ')': // End of a sequence.
00835                 m_nType = PTEndSeq;
00836                 GetNextChar();
00837                 return;
00838 
00839             case EOF:
00840                 m_nType = PTEOF;
00841                 return;
00842 
00843             default:
00844                 Error("Unknown character");
00845                 GetNextChar();
00846         }
00847     }
00848 }
00849 
00850 MHParseNode *MHParseText::DoParse()
00851 {
00852     MHParseNode *pRes = NULL;
00853 
00854     try
00855     {
00856         switch (m_nType)
00857         {
00858             case PTStartSection: // Open curly bracket
00859             {
00860                 NextSym();
00861 
00862                 // Should be followed by a tag.
00863                 if (m_nType != PTTag)
00864                 {
00865                     Error("Expected ':' after '{'");
00866                 }
00867 
00868                 MHPTagged *pTag = new MHPTagged(m_nTag);
00869                 pRes = pTag;
00870                 NextSym();
00871 
00872                 while (m_nType != PTEndSection)
00873                 {
00874                     pTag->AddArg(DoParse());
00875                 }
00876 
00877                 NextSym(); // Remove the close curly bracket.
00878                 break;
00879             }
00880 
00881             case PTTag: // Tag on its own.
00882             {
00883                 int nTag = m_nTag;
00884                 MHPTagged *pTag = new MHPTagged(nTag);
00885                 pRes = pTag;
00886                 NextSym();
00887 
00888                 switch (nTag)
00889                 {
00890                     case C_ITEMS:
00891                     case C_LINK_EFFECT:
00892                     case C_ACTIVATE:
00893                     case C_ADD:
00894                     case C_ADD_ITEM:
00895                     case C_APPEND:
00896                     case C_BRING_TO_FRONT:
00897                     case C_CALL:
00898                     case C_CALL_ACTION_SLOT:
00899                     case C_CLEAR:
00900                     case C_CLONE:
00901                     case C_CLOSE_CONNECTION:
00902                     case C_DEACTIVATE:
00903                     case C_DEL_ITEM:
00904                     case C_DESELECT:
00905                     case C_DESELECT_ITEM:
00906                     case C_DIVIDE:
00907                     case C_DRAW_ARC:
00908                     case C_DRAW_LINE:
00909                     case C_DRAW_OVAL:
00910                     case C_DRAW_POLYGON:
00911                     case C_DRAW_POLYLINE:
00912                     case C_DRAW_RECTANGLE:
00913                     case C_DRAW_SECTOR:
00914                     case C_FORK:
00915                     case C_GET_AVAILABILITY_STATUS:
00916                     case C_GET_BOX_SIZE:
00917                     case C_GET_CELL_ITEM:
00918                     case C_GET_CURSOR_POSITION:
00919                     case C_GET_ENGINE_SUPPORT:
00920                     case C_GET_ENTRY_POINT:
00921                     case C_GET_FILL_COLOUR:
00922                     case C_GET_FIRST_ITEM:
00923                     case C_GET_HIGHLIGHT_STATUS:
00924                     case C_GET_INTERACTION_STATUS:
00925                     case C_GET_ITEM_STATUS:
00926                     case C_GET_LABEL:
00927                     case C_GET_LAST_ANCHOR_FIRED:
00928                     case C_GET_LINE_COLOUR:
00929                     case C_GET_LINE_STYLE:
00930                     case C_GET_LINE_WIDTH:
00931                     case C_GET_LIST_ITEM:
00932                     case C_GET_LIST_SIZE:
00933                     case C_GET_OVERWRITE_MODE:
00934                     case C_GET_PORTION:
00935                     case C_GET_POSITION:
00936                     case C_GET_RUNNING_STATUS:
00937                     case C_GET_SELECTION_STATUS:
00938                     case C_GET_SLIDER_VALUE:
00939                     case C_GET_TEXT_CONTENT:
00940                     case C_GET_TEXT_DATA:
00941                     case C_GET_TOKEN_POSITION:
00942                     case C_GET_VOLUME:
00943                     case C_LAUNCH:
00944                     case C_LOCK_SCREEN:
00945                     case C_MODULO:
00946                     case C_MOVE:
00947                     case C_MOVE_TO:
00948                     case C_MULTIPLY:
00949                     case C_OPEN_CONNECTION:
00950                     case C_PRELOAD:
00951                     case C_PUT_BEFORE:
00952                     case C_PUT_BEHIND:
00953                     case C_QUIT:
00954                     case C_READ_PERSISTENT:
00955                     case C_RUN:
00956                     case C_SCALE_BITMAP:
00957                     case C_SCALE_VIDEO:
00958                     case C_SCROLL_ITEMS:
00959                     case C_SELECT:
00960                     case C_SELECT_ITEM:
00961                     case C_SEND_EVENT:
00962                     case C_SEND_TO_BACK:
00963                     case C_SET_BOX_SIZE:
00964                     case C_SET_CACHE_PRIORITY:
00965                     case C_SET_COUNTER_END_POSITION:
00966                     case C_SET_COUNTER_POSITION:
00967                     case C_SET_COUNTER_TRIGGER:
00968                     case C_SET_CURSOR_POSITION:
00969                     case C_SET_CURSOR_SHAPE:
00970                     case C_SET_DATA:
00971                     case C_SET_ENTRY_POINT:
00972                     case C_SET_FILL_COLOUR:
00973                     case C_SET_FIRST_ITEM:
00974                     case C_SET_FONT_REF:
00975                     case C_SET_HIGHLIGHT_STATUS:
00976                     case C_SET_INTERACTION_STATUS:
00977                     case C_SET_LABEL:
00978                     case C_SET_LINE_COLOUR:
00979                     case C_SET_LINE_STYLE:
00980                     case C_SET_LINE_WIDTH:
00981                     case C_SET_OVERWRITE_MODE:
00982                     case C_SET_PALETTE_REF:
00983                     case C_SET_PORTION:
00984                     case C_SET_POSITION:
00985                     case C_SET_SLIDER_VALUE:
00986                     case C_SET_SPEED:
00987                     case C_SET_TIMER:
00988                     case C_SET_TRANSPARENCY:
00989                     case C_SET_VARIABLE:
00990                     case C_SET_VOLUME:
00991                     case C_SPAWN:
00992                     case C_STEP:
00993                     case C_STOP:
00994                     case C_STORE_PERSISTENT:
00995                     case C_SUBTRACT:
00996                     case C_TEST_VARIABLE:
00997                     case C_TOGGLE:
00998                     case C_TOGGLE_ITEM:
00999                     case C_TRANSITION_TO:
01000                     case C_UNLOAD:
01001                     case C_UNLOCK_SCREEN:
01002                     case C_CONTENT_REFERENCE:
01003                     case C_TOKEN_GROUP_ITEMS:
01004                     case C_POSITIONS:
01005                     case C_MULTIPLEX:
01006                     {
01007                         // These are parenthesised in the text form.  We have to remove the
01008                         // parentheses otherwise we will return a sequence which will not be
01009                         // be compatible with the binary form.
01010                         if (m_nType != PTStartSeq)
01011                         {
01012                             Error("Expected '('");
01013                         }
01014 
01015                         NextSym();
01016 
01017                         while (m_nType != PTEndSeq)
01018                         {
01019                             pTag->AddArg(DoParse());
01020                         }
01021 
01022                         NextSym(); // Remove the close parenthesis.
01023                         break;
01024                     }
01025                     case C_ORIGINAL_CONTENT:
01026                     case C_NEW_GENERIC_BOOLEAN:
01027                     case C_NEW_GENERIC_INTEGER:
01028                     case C_NEW_GENERIC_OCTETSTRING:
01029                     case C_NEW_GENERIC_OBJECT_REF:
01030                     case C_NEW_GENERIC_CONTENT_REF:
01031                     case C_ORIGINAL_VALUE:
01032                         // These always have an argument which may be a tagged item.
01033                     {
01034                         // Is it always the case that there is at least one argument so if we haven't
01035                         // had any arguments yet we should always process a tag as an argument?
01036                         pTag->AddArg(DoParse());
01037                         break;
01038                     }
01039                     default:
01040 
01041                         // This can be followed by an int, etc but a new tag is dealt with by the caller.
01042                         while (m_nType == PTBool || m_nType == PTInt || m_nType == PTString || m_nType == PTEnum || m_nType == PTStartSeq)
01043                         {
01044                             pTag->AddArg(DoParse());
01045                         }
01046 
01047                 }
01048 
01049                 break;
01050             }
01051 
01052             case PTInt:
01053             {
01054                 pRes = new MHPInt(m_nInt);
01055                 NextSym();
01056                 break;
01057             }
01058 
01059             case PTBool:
01060             {
01061                 pRes = new MHPBool(m_fBool);
01062                 NextSym();
01063                 break;
01064             }
01065 
01066             case PTString:
01067             {
01068                 MHOctetString str;
01069                 str.Copy(MHOctetString((const char *)m_String, m_nStringLength));
01070                 pRes = new MHPString(str);
01071                 NextSym();
01072                 break;
01073             }
01074 
01075             case PTEnum:
01076             {
01077                 pRes = new MHPEnum(m_nInt);
01078                 NextSym();
01079                 break;
01080             }
01081 
01082             case PTNull:
01083             {
01084                 pRes = new MHPNull;
01085                 NextSym();
01086                 break;
01087             }
01088 
01089             case PTStartSeq: // Open parenthesis.
01090             {
01091                 MHParseSequence *pSeq = new MHParseSequence;
01092                 pRes = pSeq;
01093                 NextSym();
01094 
01095                 while (m_nType != PTEndSeq)
01096                 {
01097                     pSeq->Append(DoParse());
01098                 }
01099 
01100                 NextSym(); // Remove the close parenthesis.
01101                 break;
01102             }
01103 
01104             default:
01105                 Error("Unexpected symbol");
01106         }
01107 
01108         return pRes;
01109     }
01110     catch (...)
01111     {
01112         delete(pRes);
01113         throw;
01114     }
01115 }
01116 
01117 
01118 // Run the parser
01119 MHParseNode *MHParseText::Parse()
01120 {
01121     GetNextChar(); // Initialise m_ch
01122     NextSym(); // Initialise the symbol values.
01123     return DoParse();
01124 }
01125 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends