CMMLParser.cpp

Go to the documentation of this file.
00001 //===========================================================================
00002 //Copyright (C) 2005 Zentaro Kavanagh
00003 //
00004 //Copyright (C) 2005 Commonwealth Scientific and Industrial Research
00005 //                   Organisation (CSIRO) Australia
00006 //
00007 //Redistribution and use in source and binary forms, with or without
00008 //modification, are permitted provided that the following conditions
00009 //are met:
00010 //
00011 //- Redistributions of source code must retain the above copyright
00012 //  notice, this list of conditions and the following disclaimer.
00013 //
00014 //- Redistributions in binary form must reproduce the above copyright
00015 //  notice, this list of conditions and the following disclaimer in the
00016 //  documentation and/or other materials provided with the distribution.
00017 //
00018 //- Neither the name of Zentaro Kavanagh nor the names of contributors 
00019 //  may be used to endorse or promote products derived from this software 
00020 //  without specific prior written permission.
00021 //
00022 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00025 //PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00026 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00028 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 //===========================================================================
00034 
00035 
00036 #include <libCMMLParse/CMMLParser.h>
00037 #include <libCMMLParse/xtag.h>
00038 
00039 #include <libCMMLTags/libCMMLTags.h>
00040 #include <libilliCore/StringHelper.h>
00041 
00042 #include <fstream>
00043 
00044 
00045 using namespace std;
00046 
00047 
00048 // TODO: i18n?
00049 
00050 
00051 CMMLParser::CMMLParser(void)
00052 {
00053 }
00054 
00055 CMMLParser::~CMMLParser(void)
00056 {
00057 }
00058 
00059 bool CMMLParser::parseDocFromFile(wstring inFilename, C_CMMLDoc* outCMMLDoc)
00060 {
00061         // Assume we are unsuccessful unless we explicitly change that
00062 
00063         bool locReturnValue = false;
00064 
00065         // Sanity check against a NULL output pointer
00066         if (!outCMMLDoc) {
00067                 return false;
00068         }
00069 
00070         // Somebody set us up our file!
00071 
00072         fstream locFile;
00073 
00074         locFile.open(StringHelper::toNarrowStr(inFilename).c_str(), ios_base::in | ios_base::binary);
00075 
00076         if (!locFile.is_open()) {
00077                 //Check if the file is actually open, else if it isn't tellg will return -1 as unsigned.
00078                 // and then we'll try to allocate 4 gigs of memory... which will probably fail :)
00079                 return false;
00080         }
00081 
00082         // Look ma, the world's most portable file-size-getting-function-thing
00083         locFile.seekg(0, ios::end);
00084         size_t locCMMLFileSize = locFile.tellg();
00085         locFile.clear();
00086 
00087         // Read the entirety of the file into the buffer
00088         locFile.seekg(0);
00089 
00090         unsigned short BUFFER_SIZE = 8192;
00091         char *locBuffer = new char[locCMMLFileSize];
00092         size_t locBytesRead = 0;
00093 
00094         while (!locFile.eof()) {
00095                 locFile.read(locBuffer + locBytesRead, BUFFER_SIZE);
00096                 locBytesRead = locFile.gcount();
00097         }
00098 
00099         locFile.close();
00100 
00101         // Widen the file stream
00102         wstring locCMMLFileWString = StringHelper::toWStr(locBuffer);
00103 
00104         // XTag doesn't currently handle preambles, so we'll have to skip until we find
00105         // a <cmml> tag which it can handle ... (note that XML is case-sensitive, so
00106         // we don't need to scan for "<CMML")
00107         size_t locCMMLTagIndex = locCMMLFileWString.find(L"<cmml", 0);
00108         if (locCMMLTagIndex != string::npos) {
00109                 locCMMLFileWString = locCMMLFileWString.substr(locCMMLTagIndex);
00110         }
00111 
00112         // Parse ourselves the CMML
00113         C_CMMLRootTag* locRootTag = new C_CMMLRootTag;
00114         locReturnValue = parseCMMLRootTag(locCMMLFileWString, locRootTag);
00115         if (locReturnValue) {
00116                 // Successfully parsed the CMML
00117                 outCMMLDoc->setRoot(locRootTag);
00118         } else {
00119                 // Parsing CMML failed
00120                 outCMMLDoc = NULL;
00121         }
00122 
00123         // Clean up
00124         delete [] locBuffer;
00125 
00126         return locReturnValue;
00127 }
00128 
00129 
00130 bool CMMLParser::parseCMMLRootTag(wstring inCMMLRootText, C_CMMLRootTag* outCMMLRoot)
00131 {
00132         // Assume we are unsuccessful unless we explicitly change that
00133 
00134         bool locReturnValue = false;
00135 
00136         // Sanity check against a NULL output pointer
00137         if (!outCMMLRoot) {
00138                 return false;
00139         }
00140 
00141         // Narrow the text given us, so we can pass it to XTag
00142         string locCMMLRootText = StringHelper::toNarrowStr(inCMMLRootText);
00143 
00144         // Look for a tag, any tag
00145         XTag *locRootParser = NULL;
00146         locRootParser = xtag_new_parse(locCMMLRootText.c_str(), (int)locCMMLRootText.size());
00147         if (locRootParser) {
00148                 // Is it a <cmml> tag?
00149                 if (strcmp(xtag_get_name(locRootParser), "cmml") == 0) {
00150                         // Found a <cmml> tag
00151                         locReturnValue = parseRootTag(locRootParser, outCMMLRoot);
00152                 }
00153         }
00154 
00155         if (locRootParser) {
00156                 xtag_free(locRootParser);
00157         }
00158 
00159         return locReturnValue;
00160 }
00161 
00162 
00163 bool CMMLParser::parseClipTag(wstring inClipText, C_ClipTag* outClip)
00164 {
00165         // Assume we are unsuccessful unless we explicitly change that
00166 
00167         bool locReturnValue = false;
00168 
00169         // Sanity check against a NULL output pointer
00170         if (!outClip) {
00171                 return false;
00172         }
00173 
00174         // Narrow the text given us, so we can pass it to XTag
00175         string locClipText = StringHelper::toNarrowStr(inClipText);
00176 
00177         // Look for a <clip> tag
00178         XTag *locClipParser = NULL;
00179         locClipParser = xtag_new_parse(locClipText.c_str(), (int)locClipText.size());
00180         if (locClipParser) {
00181                 // Found some sort of tag
00182                 if (strcmp(xtag_get_name(locClipParser), "clip") == 0) {
00183                         // Found a <clip> tag, go parse it
00184                         locReturnValue = parseClipTag(locClipParser, outClip);
00185                 }
00186         }
00187 
00188         if (locClipParser) {
00189                 xtag_free(locClipParser);
00190         }
00191 
00192         return locReturnValue;
00193 }
00194 
00195 
00196 bool CMMLParser::parseHeadTag(wstring inHeadText, C_HeadTag* outHead)
00197 {
00198         // Assume we are unsuccessful unless we explicitly change that
00199 
00200         bool locReturnValue = false;
00201 
00202         // Sanity check against a NULL output pointer
00203         if (!outHead) {
00204                 return false;
00205         }
00206 
00207         // Narrow the text given us, so we can pass it to XTag
00208         string locHeadText = StringHelper::toNarrowStr(inHeadText);
00209 
00210         // Set up an XTag parser
00211         XTag *locHeadParser = NULL;
00212         locHeadParser = xtag_new_parse(locHeadText.c_str(), (int)locHeadText.size());
00213         if (locHeadParser) {
00214                 if (strcmp(xtag_get_name(locHeadParser), "head") == 0) {
00215                         locReturnValue = parseHeadTag(locHeadParser, outHead);
00216                 }
00217         }
00218 
00219         if (locHeadParser) {
00220                 xtag_free(locHeadParser);
00221         }
00222 
00223         return locReturnValue;
00224 }
00225 
00226 
00227 // Macros are evil, macros are evil, can't sleep, clown'll eat me ...
00228 
00229 #define XTAG_PARSE_INTO(tagParser, parseMethod, TagType, parentTagSetter, parentTag) \
00230         { \
00231                 TagType *locTag = new TagType; \
00232                 if (!parseMethod(tagParser, locTag)) { \
00233                         return false; \
00234                 } \
00235                 parentTag->parentTagSetter(locTag); \
00236         };
00237 
00238 #define XTAG_SET_ATTRIBUTE(tagParser, attributeName, tag, attributeSetter) \
00239         { \
00240                 const char *locAttributeCString = xtag_get_attribute(tagParser, attributeName); \
00241                 if (locAttributeCString) { \
00242                         tag->attributeSetter(StringHelper::toWStr(locAttributeCString)); \
00243                         /* free((void *) locAttributeCString); */ \
00244                 } \
00245         };
00246 
00247 #define XTAG_REQUIRED_ATTRIBUTE(tagParser, attributeName, tag) \
00248         { \
00249                 const char *locAttributeCString = xtag_get_attribute(tagParser, attributeName); \
00250                 if (!locAttributeCString) { \
00251                         return false; \
00252                 } else { \
00253                         /* free((void *) locAttributeCString); */ \
00254                 } \
00255         };
00256 
00257 #define XTAG_PARSE_CHILD(parentParser, tagName, tagParser, tagType, setterMethod, parentTag) \
00258         { \
00259                 XTag *locParser = NULL; \
00260                 locParser = xtag_first_child(parentParser, tagName); \
00261                 if (locParser) { \
00262                         XTAG_PARSE_INTO(locParser, tagParser, tagType, setterMethod, parentTag); \
00263                 } \
00264         };
00265 
00266 #define XTAG_EXACTLY_ONE_CHILD(parentParser, tagName) \
00267         { \
00268                 XTag *locParser = xtag_first_child(parentParser, tagName); \
00269                 if (locParser != NULL) { \
00270                         /* Found at least one child */ \
00271                         locParser = xtag_next_child(parentParser, tagName); \
00272                         if (locParser) { \
00273                                 /* Danger will robinson, found more than one child */ \
00274                                 return false; \
00275                         } \
00276                 } else { \
00277                         /* Found no child */ \
00278                         return false; \
00279                 } \
00280         };
00281 
00282 #define XTAG_PARSE_LIST(TagType, listTagName, tagParser, parentParser, parentTag, parentGetListMethod) \
00283         { \
00284                 XTag *locTagListParser = NULL; \
00285                 for (   locTagListParser = xtag_first_child(parentParser, listTagName); \
00286                                 locTagListParser != NULL; \
00287                                 locTagListParser = xtag_next_child(parentParser, listTagName)) { \
00288                         XTAG_PARSE_INTO(locTagListParser, tagParser, TagType, addTag, parentTag->parentGetListMethod()); \
00289                 } \
00290         };
00291 
00292 #define XTAG_SET_CDATA(tagParser, tag) \
00293         { \
00294                 const char *locCData = xtag_get_pcdata(tagParser); \
00295                 if (locCData) { \
00296                         tag->setText(StringHelper::toWStr(locCData)); \
00297                         /* free((void *) locCData); */ \
00298                 } \
00299         };
00300 
00301 
00302 // Look ma, it's declarative programming!
00303 
00304 bool CMMLParser::parseStreamTag(XTag* inStreamParser, C_StreamTag* outStream)
00305 {
00306         XTAG_SET_ATTRIBUTE(inStreamParser, "id", outStream, setId);
00307         XTAG_SET_ATTRIBUTE(inStreamParser, "timebase", outStream, setTimebase);
00308         XTAG_SET_ATTRIBUTE(inStreamParser, "utc", outStream, setUtc);
00309 
00310         XTAG_PARSE_LIST(C_ImportTag, "import", parseImportTag,
00311                 inStreamParser, outStream, importList);
00312 
00313         return true;
00314 }
00315 
00316 
00317 bool CMMLParser::parseRootTag(XTag* inCMMLRootParser, C_CMMLRootTag* outCMMLRoot)
00318 {
00319         XTAG_SET_ATTRIBUTE(inCMMLRootParser, "id", outCMMLRoot, setId);
00320 
00321         XTAG_EXACTLY_ONE_CHILD(inCMMLRootParser, "head");
00322         XTAG_PARSE_CHILD(inCMMLRootParser, "head", parseHeadTag, C_HeadTag, setHead, outCMMLRoot);
00323         XTAG_PARSE_CHILD(inCMMLRootParser, "stream", parseStreamTag, C_StreamTag, setStream, outCMMLRoot);
00324 
00325         XTAG_PARSE_LIST(C_ClipTag, "clip", parseClipTag, inCMMLRootParser, outCMMLRoot, clipList);
00326 
00327         // i18n
00328         XTAG_SET_ATTRIBUTE(inCMMLRootParser, "lang", outCMMLRoot, setLang);
00329         XTAG_SET_ATTRIBUTE(inCMMLRootParser, "dir", outCMMLRoot, setDirn);
00330 
00331         return true;
00332 }
00333 
00334 bool CMMLParser::parseHeadTag(XTag* inHeadParser, C_HeadTag* outHead)
00335 {
00336         XTAG_SET_ATTRIBUTE(inHeadParser, "id", outHead, setId);
00337         XTAG_SET_ATTRIBUTE(inHeadParser, "profile", outHead, setProfile);
00338 
00339         XTAG_EXACTLY_ONE_CHILD(inHeadParser, "title");
00340         XTAG_PARSE_CHILD(inHeadParser, "title", parseTitleTag, C_TitleTag, setTitle, outHead);
00341         XTAG_PARSE_CHILD(inHeadParser, "base", parseBaseTag, C_BaseTag, setBase, outHead);
00342 
00343         XTAG_PARSE_LIST(C_MetaTag, "meta", parseMetaTag, inHeadParser, outHead, metaList);
00344 
00345         // i18n
00346         XTAG_SET_ATTRIBUTE(inHeadParser, "lang", outHead, setLang);
00347         XTAG_SET_ATTRIBUTE(inHeadParser, "dir", outHead, setDirn);
00348 
00349         return true;
00350 }
00351 
00352 bool CMMLParser::parseTitleTag(XTag* inTitleParser, C_TitleTag* outTitle)
00353 {
00354         XTAG_SET_ATTRIBUTE(inTitleParser, "id", outTitle, setId);
00355 
00356         XTAG_SET_CDATA(inTitleParser, outTitle);
00357 
00358         // i18n
00359         XTAG_SET_ATTRIBUTE(inTitleParser, "lang", outTitle, setLang);
00360         XTAG_SET_ATTRIBUTE(inTitleParser, "dir", outTitle, setDirn);
00361 
00362         return true;
00363 }
00364 
00365 bool CMMLParser::parseBaseTag(XTag* inBaseParser, C_BaseTag* outBase)
00366 {
00367         XTAG_SET_ATTRIBUTE(inBaseParser, "id", outBase, setId);
00368         XTAG_SET_ATTRIBUTE(inBaseParser, "href", outBase, setHref);
00369         XTAG_REQUIRED_ATTRIBUTE(inBaseParser, "href", outBase);
00370 
00371         return true;
00372 }
00373 
00374 bool CMMLParser::parseMetaTag(XTag* inMetaParser, C_MetaTag* outMeta)
00375 {
00376         XTAG_SET_ATTRIBUTE(inMetaParser, "scheme", outMeta, setScheme);
00377         XTAG_SET_ATTRIBUTE(inMetaParser, "content", outMeta, setContent);
00378         XTAG_SET_ATTRIBUTE(inMetaParser, "id", outMeta, setId);
00379         XTAG_SET_ATTRIBUTE(inMetaParser, "name", outMeta, setName);
00380 
00381         // i18n
00382         XTAG_SET_ATTRIBUTE(inMetaParser, "lang", outMeta, setLang);
00383         XTAG_SET_ATTRIBUTE(inMetaParser, "dir", outMeta, setDirn);
00384 
00385         return true;
00386 }
00387 
00388 bool CMMLParser::parseClipTag(XTag* inClipParser, C_ClipTag* outClip)
00389 {
00390         XTAG_SET_ATTRIBUTE(inClipParser, "track", outClip, setTrack);
00391         XTAG_SET_ATTRIBUTE(inClipParser, "id", outClip, setId);
00392         XTAG_SET_ATTRIBUTE(inClipParser, "start", outClip, setStart);
00393         XTAG_REQUIRED_ATTRIBUTE(inClipParser, "start", outClip);
00394         XTAG_SET_ATTRIBUTE(inClipParser, "end", outClip, setEnd);
00395 
00396         XTAG_PARSE_LIST(C_MetaTag, "meta", parseMetaTag, inClipParser, outClip, metaList);
00397 
00398         XTAG_PARSE_CHILD(inClipParser, "a", parseAnchorTag, C_AnchorTag, setAnchor, outClip);
00399         XTAG_PARSE_CHILD(inClipParser, "img", parseImageTag, C_ImageTag, setImage, outClip);
00400         XTAG_PARSE_CHILD(inClipParser, "desc", parseDescTag, C_DescTag, setDesc, outClip);
00401 
00402         // i18n
00403         XTAG_SET_ATTRIBUTE(inClipParser, "lang", outClip, setLang);
00404         XTAG_SET_ATTRIBUTE(inClipParser, "dir", outClip, setDirn);
00405 
00406         return true;
00407 }
00408 
00409 bool CMMLParser::parseAnchorTag(XTag* inAnchorParser, C_AnchorTag* outAnchor)
00410 {
00411         XTAG_SET_ATTRIBUTE(inAnchorParser, "id", outAnchor, setId);
00412         XTAG_SET_ATTRIBUTE(inAnchorParser, "class", outAnchor, setCls);
00413         XTAG_SET_ATTRIBUTE(inAnchorParser, "href", outAnchor, setHref);
00414         XTAG_REQUIRED_ATTRIBUTE(inAnchorParser, "href", outAnchor);
00415 
00416         XTAG_SET_CDATA(inAnchorParser, outAnchor);
00417 
00418         // i18n
00419         XTAG_SET_ATTRIBUTE(inAnchorParser, "lang", outAnchor, setLang);
00420         XTAG_SET_ATTRIBUTE(inAnchorParser, "dir", outAnchor, setDirn);
00421 
00422         return true;
00423 }
00424 
00425 bool CMMLParser::parseImageTag(XTag* inImageParser, C_ImageTag* outImage)
00426 {
00427         XTAG_SET_ATTRIBUTE(inImageParser, "id", outImage, setId);
00428         XTAG_SET_ATTRIBUTE(inImageParser, "src", outImage, setSrc);
00429         XTAG_REQUIRED_ATTRIBUTE(inImageParser, "src", outImage);
00430         XTAG_SET_ATTRIBUTE(inImageParser, "alt", outImage, setAlt);
00431 
00432         // i18n
00433         XTAG_SET_ATTRIBUTE(inImageParser, "lang", outImage, setLang);
00434         XTAG_SET_ATTRIBUTE(inImageParser, "dir", outImage, setDirn);
00435 
00436         return true;
00437 }
00438 
00439 bool CMMLParser::parseDescTag(XTag* inDescParser, C_DescTag* outDesc)
00440 {
00441         XTAG_SET_ATTRIBUTE(inDescParser, "id", outDesc, setId);
00442 
00443         XTAG_SET_CDATA(inDescParser, outDesc);
00444 
00445         // i18n
00446         XTAG_SET_ATTRIBUTE(inDescParser, "lang", outDesc, setLang);
00447         XTAG_SET_ATTRIBUTE(inDescParser, "dir", outDesc, setDirn);
00448 
00449         return true;
00450 }
00451 
00452 bool CMMLParser::parseImportTag(XTag* inImportParser, C_ImportTag* outImport)
00453 {
00454         XTAG_SET_ATTRIBUTE(inImportParser, "granulerate", outImport, setGranuleRate);
00455         XTAG_SET_ATTRIBUTE(inImportParser, "contenttype", outImport, setContentType);
00456         XTAG_SET_ATTRIBUTE(inImportParser, "src", outImport, setSrc);
00457         XTAG_SET_ATTRIBUTE(inImportParser, "start", outImport, setStart);
00458         XTAG_SET_ATTRIBUTE(inImportParser, "end", outImport, setEnd);
00459         XTAG_SET_ATTRIBUTE(inImportParser, "title", outImport, setTitle);
00460 
00461         XTAG_PARSE_LIST(C_ParamTag, "param", parseParamTag, inImportParser, outImport, paramList);
00462 
00463         return true;
00464 }
00465 
00466 bool CMMLParser::parseParamTag(XTag* inParamParser, C_ParamTag* outParam)
00467 {
00468         XTAG_SET_ATTRIBUTE(inParamParser, "id", outParam, setId);
00469         XTAG_SET_ATTRIBUTE(inParamParser, "name", outParam, setName);
00470         XTAG_REQUIRED_ATTRIBUTE(inParamParser, "name", outParam);
00471         XTAG_SET_ATTRIBUTE(inParamParser, "value", outParam, setContent);
00472         XTAG_REQUIRED_ATTRIBUTE(inParamParser, "value", outParam);
00473 
00474         return true;
00475 }
00476 
00477 #undef XTAG_REQUIRED_ATTRIBUTE
00478 
00479 #undef XTAG_SET_ATTRIBUTE
00480 
00481 #undef XTAG_PARSE_INTO
00482 
00483 #undef XTAG_SET_CDATA

Generated on Tue Feb 15 14:54:12 2005 for oggdsf by  doxygen 1.3.9