#include #include #include HRCParserImpl::HRCParserImpl() : fileTypeHash(200), fileTypeVector(150), schemeHash(4000), regionNamesHash(1000), regionNamesVector(1000, 200) { parseType = null; versionName = null; errorHandler = null; updateStarted = false; } HRCParserImpl::~HRCParserImpl() { int idx; for(FileTypeImpl *ft = fileTypeHash.enumerate(); ft != null; ft = fileTypeHash.next()) delete ft; for(SchemeImpl *scheme = schemeHash.enumerate(); scheme != null; scheme = schemeHash.next()){ delete scheme; }; for(idx = 0; idx < regionNamesVector.size(); idx++) delete regionNamesVector.elementAt(idx); for(String *se = schemeEntitiesHash.enumerate(); se; se = schemeEntitiesHash.next()){ delete se; }; delete versionName; } void HRCParserImpl::setErrorHandler(ErrorHandler *eh){ errorHandler = eh; } void HRCParserImpl::loadSource(InputSource *is){ InputSource *istemp = curInputSource; curInputSource = is; if (is == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("Can't open stream for type without location attribute")); } return; }; try{ parseHRC(is); }catch(Exception &e){ throw e; }; curInputSource = istemp; } void HRCParserImpl::loadFileType(FileType *filetype){ if (filetype == null) return; FileTypeImpl *thisType = (FileTypeImpl*)filetype; if (thisType->typeLoaded || thisType->loadBroken) return; try{ loadSource(thisType->inputSource); }catch(InputSourceException &e){ if (errorHandler != null){ errorHandler->fatalError(StringBuffer("Can't open source stream: ")+e.getMessage()); } thisType->loadBroken = true; }catch(HRCParserException &e){ if (errorHandler != null){ errorHandler->fatalError(StringBuffer(e.getMessage())+" ["+thisType->inputSource->getLocation()+"]"); } thisType->loadBroken = true; }catch(Exception &e){ if (errorHandler != null){ errorHandler->fatalError(StringBuffer(e.getMessage())+" ["+thisType->inputSource->getLocation()+"]"); } thisType->loadBroken = true; }catch(...){ if (errorHandler != null){ errorHandler->fatalError(StringBuffer("Unknown exception while loading ")+thisType->inputSource->getLocation()); } thisType->loadBroken = true; }; } FileType *HRCParserImpl::chooseFileType(const String *fileName, const String *firstLine, int typeNo) { FileTypeImpl *best = null; double max_prior = 0; const double DELTA = 1e-6; for(int idx = 0; idx < fileTypeVector.size(); idx++){ FileTypeImpl *ret = fileTypeVector.elementAt(idx); double prior = ret->getPriority(fileName, firstLine); if (typeNo > 0 && (prior-max_prior < DELTA)){ best = ret; typeNo--; }; if (prior-max_prior > DELTA || best == null){ best = ret; max_prior = prior; }; }; if (typeNo > 0) return null; return best; } FileType *HRCParserImpl::getFileType(const String *name) { if (name == null) return null; return fileTypeHash.get(name); } FileType *HRCParserImpl::enumerateFileTypes(int index) { if (index < fileTypeVector.size()) return fileTypeVector.elementAt(index); return null; } int HRCParserImpl::getRegionCount() { return regionNamesVector.size(); } const Region *HRCParserImpl::getRegion(int id) { return regionNamesVector.elementAt(id); } const Region* HRCParserImpl::getRegion(const String *name) { if (name == null) return null; return getNCRegion(name, false); // regionNamesHash.get(name); } const String *HRCParserImpl::getVersion() { return versionName; } // protected methods void HRCParserImpl::parseHRC(InputSource *is) { Document *xmlDocument = docbuilder.parse(is); Element *types = xmlDocument->getDocumentElement(); if (*types->getNodeName() != "hrc"){ docbuilder.free(xmlDocument); throw HRCParserException(DString("main '' block not found")); }else{ if (versionName == null) versionName = new SString(types->getAttribute(DString("version"))); }; bool globalUpdateStarted = false; if (!updateStarted){ globalUpdateStarted = true; updateStarted = true; }; for (Node *elem = types->getFirstChild(); elem; elem = elem->getNextSibling()){ if (*elem->getNodeName() == "prototype"){ addPrototype((Element*)elem); continue; }; if (*elem->getNodeName() == "package"){ addPrototype((Element*)elem); continue; }; if (*elem->getNodeName() == "type"){ addType((Element*)elem); continue; }; }; docbuilder.free(xmlDocument); structureChanged = true; if (globalUpdateStarted){ updateLinks(); updateStarted = false; }; } void HRCParserImpl::addPrototype(Element *elem) { const String *typeName = elem->getAttribute(DString("name")); const String *typeGroup = elem->getAttribute(DString("group")); const String *typeDescription = elem->getAttribute(DString("description")); if (typeName == null){ if (errorHandler != null) errorHandler->error(DString("unnamed prototype ")); return; } if (typeDescription == null){ typeDescription = typeName; } if (fileTypeHash.get(typeName) != null){ if (errorHandler != null){ errorHandler->error(StringBuffer("Duplicate prototype '")+typeName+"'"); } return; }; FileTypeImpl *type = new FileTypeImpl(this); type->name = new SString(typeName); type->description = new SString(typeDescription); if (typeGroup != null){ type->group = new SString(typeGroup); } if (*elem->getNodeName() == "package"){ type->isPackage = true; } for(Node *content = elem->getFirstChild(); content != null; content = content->getNextSibling()){ if (*content->getNodeName() == "location"){ const String *locationLink = ((Element*)content)->getAttribute(DString("link")); if (locationLink == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("Bad 'location' link attribute in prototype '")+typeName+"'"); } continue; }; type->inputSource = InputSource::newInstance(locationLink, curInputSource); }; if (*content->getNodeName() == "filename" || *content->getNodeName() == "firstline"){ if (content->getFirstChild() == null || content->getFirstChild()->getNodeType() != Node::TEXT_NODE){ if (errorHandler != null) errorHandler->warning(StringBuffer("Bad '")+content->getNodeName()+"' element in prototype '"+typeName+"'"); continue; }; const String *match = ((Text*)content->getFirstChild())->getData(); CRegExp *matchRE = new CRegExp(match); matchRE->setPositionMoves(true); if (!matchRE->isOk()){ if (errorHandler != null){ errorHandler->warning(StringBuffer("Fault compiling chooser RE '")+match+"' in prototype '"+typeName+"'"); } delete matchRE; continue; }; int ctype = *content->getNodeName() == "filename" ? 0 : 1; double prior = *content->getNodeName() == "filename" ? 2 : 1; UnicodeTools::getNumber(((Element*)content)->getAttribute(DString("weight")), &prior); FileTypeChooser *ftc = new FileTypeChooser(ctype, prior, matchRE); type->chooserVector.addElement(ftc); }; if (*content->getNodeName() == "parameters"){ for(Node *param = content->getFirstChild(); param != null; param = param->getNextSibling()){ if (*param->getNodeName() == "param"){ const String *name = ((Element*)param)->getAttribute(DString("name")); const String *value = ((Element*)param)->getAttribute(DString("value")); const String *descr = ((Element*)param)->getAttribute(DString("description")); if (name == null || value == null){ if (errorHandler != null){ errorHandler->warning(StringBuffer("Bad parameter in prototype '")+typeName+"'"); } continue; }; type->paramVector.addElement(new SString(name)); type->paramDescriptionHash.put(name, new SString(descr)); type->paramDefaultHash.put(name, new SString(value)); }; }; }; }; type->protoLoaded = true; fileTypeHash.put(typeName, type); if (!type->isPackage){ fileTypeVector.addElement(type); }; } void HRCParserImpl::addType(Element *elem) { const String *typeName = elem->getAttribute(DString("name")); if (typeName == null){ if (errorHandler != null){ errorHandler->error(DString("Unnamed type found")); } return; }; FileTypeImpl *type_ref = fileTypeHash.get(typeName); if (type_ref == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("type '")+typeName+"' without prototype"); } return; }; FileTypeImpl *type = type_ref; if (type->typeLoaded){ if (errorHandler != null) errorHandler->warning(StringBuffer("type '")+typeName+"' is already loaded"); return; }; type->typeLoaded = true; FileTypeImpl *o_parseType = parseType; parseType = type; for(Node *xmlpar = elem->getFirstChild(); xmlpar; xmlpar = xmlpar->getNextSibling()){ if (*xmlpar->getNodeName() == "region"){ const String *regionName = ((Element*)xmlpar)->getAttribute(DString("name")); const String *regionParent = ((Element*)xmlpar)->getAttribute(DString("parent")); const String *regionDescr = ((Element*)xmlpar)->getAttribute(DString("description")); if (regionName == null){ if (errorHandler != null) errorHandler->error(DString("No 'name' attribute in element")); continue; }; String *qname1 = qualifyOwnName(regionName); if (qname1 == null) continue; String *qname2 = qualifyForeignName(regionParent, QNT_DEFINE, true); if (regionNamesHash.get(qname1) != null){ if (errorHandler != null){ errorHandler->warning(StringBuffer("Duplicate region '") + qname1 + "' definition in type '"+parseType->getName()+"'"); } continue; }; const Region *region = new Region(qname1, regionDescr, getRegion(qname2), regionNamesVector.size()); regionNamesVector.addElement(region); regionNamesHash.put(qname1, region); delete qname1; delete qname2; }; if (*xmlpar->getNodeName() == "entity"){ const String *entityName = ((Element*)xmlpar)->getAttribute(DString("name")); const String *entityValue = ((Element*)xmlpar)->getAttribute(DString("value")); if (entityName == null || entityValue == null){ if (errorHandler != null){ errorHandler->error(DString("Bad entity attributes")); } continue; }; String *qname1 = qualifyOwnName(entityName); String *qname2 = useEntities(entityValue); if (qname1 != null && qname2 != null){ schemeEntitiesHash.put(qname1, qname2); delete qname1; }; }; if (*xmlpar->getNodeName() == "import"){ const String *typeParam = ((Element*)xmlpar)->getAttribute(DString("type")); if (typeParam == null || fileTypeHash.get(typeParam) == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("Import with bad '")+typeParam+"' attribute in type '"+typeName+"'"); } continue; }; type->importVector.addElement(new SString(typeParam)); }; if (*xmlpar->getNodeName() == "scheme"){ addScheme((Element*)xmlpar); continue; }; }; String *baseSchemeName = qualifyOwnName(type->name); if (baseSchemeName != null){ type->baseScheme = schemeHash.get(baseSchemeName); } delete baseSchemeName; if (type->baseScheme == null && !type->isPackage){ if (errorHandler != null){ errorHandler->warning(StringBuffer("type '")+typeName+"' has no default scheme"); } } type->loadDone = true; parseType = o_parseType; } void HRCParserImpl::addScheme(Element *elem) { const String *schemeName = elem->getAttribute(DString("name")); String *qSchemeName = qualifyOwnName(schemeName); if (qSchemeName == null){ if (errorHandler != null) errorHandler->error(StringBuffer("bad scheme name in type '")+parseType->getName()+"'"); return; } if (schemeHash.get(qSchemeName) != null || disabledSchemes.get(qSchemeName) != 0){ if (errorHandler != null) errorHandler->error(StringBuffer("duplicate scheme name '")+qSchemeName+"'"); delete qSchemeName; return; } SchemeImpl *scheme = new SchemeImpl(qSchemeName); delete qSchemeName; scheme->fileType = parseType; schemeHash.put(scheme->schemeName, scheme); const String *condIf = elem->getAttribute(DString("if")); const String *condUnless = elem->getAttribute(DString("unless")); if ((condIf != null && !DString("true").equals(parseType->getParamValue(*condIf))) || (condUnless != null && DString("true").equals(parseType->getParamValue(*condUnless)))){ //disabledSchemes.put(scheme->schemeName, 1); return; } addSchemeNodes(scheme, elem->getFirstChild()); } void HRCParserImpl::addSchemeNodes(SchemeImpl *scheme, Node *elem) { SchemeNode *next = null; for(Node *tmpel = elem; tmpel; tmpel = tmpel->getNextSibling()){ if (!tmpel->getNodeName()) continue; if (next == null){ next = new SchemeNode(); } if (*tmpel->getNodeName() == "inherit"){ const String *nqSchemeName = ((Element*)tmpel)->getAttribute(DString("scheme")); if (nqSchemeName == null || nqSchemeName->length() == 0){ if (errorHandler != null){ errorHandler->error(StringBuffer("empty scheme name in inheritance operator in scheme '")+scheme->schemeName+"'"); } continue; }; next->type = SNT_INHERIT; next->schemeName = new SString(nqSchemeName); String *schemeName = qualifyForeignName(nqSchemeName, QNT_SCHEME, false); if (schemeName == null){ // if (errorHandler != null) errorHandler->warning(StringBuffer("forward inheritance of '")+nqSchemeName+"'. possible inherit loop with '"+scheme->schemeName+"'"); // delete next; // continue; }else next->scheme = schemeHash.get(schemeName); if (schemeName != null){ delete next->schemeName; next->schemeName = schemeName; }; if (tmpel->getFirstChild() != null){ for(Node *vel = tmpel->getFirstChild(); vel; vel = vel->getNextSibling()){ if (*vel->getNodeName() != "virtual"){ continue; } const String *schemeName = ((Element*)vel)->getAttribute(DString("scheme")); const String *substName = ((Element*)vel)->getAttribute(DString("subst-scheme")); if (schemeName == null || substName == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("bad virtualize attributes in scheme '")+scheme->schemeName+"'"); } continue; }; next->virtualEntryVector.addElement(new VirtualEntry(schemeName, substName)); }; }; scheme->nodes.addElement(next); next = null; continue; }; if (*tmpel->getNodeName() == "regexp"){ const String *matchParam = ((Element*)tmpel)->getAttribute(DString("match")); if (matchParam == null && tmpel->getFirstChild() && tmpel->getFirstChild()->getNodeType() == Node::TEXT_NODE){ matchParam = ((Text*)tmpel->getFirstChild())->getData(); } if (matchParam == null){ if (errorHandler != null){ errorHandler->error(StringBuffer("no 'match' in regexp in scheme ")+scheme->schemeName); } delete next; continue; }; String *entMatchParam = useEntities(matchParam); next->lowPriority = DString("low").equals(((Element*)tmpel)->getAttribute(DString("priority"))); next->type = SNT_RE; next->start = new CRegExp(entMatchParam); next->start->setPositionMoves(false); if (!next->start || !next->start->isOk()) if (errorHandler != null) errorHandler->error(StringBuffer("fault compiling regexp '")+entMatchParam+"' in scheme '"+scheme->schemeName+"'"); #ifdef ALLOW_SERIALIZATION next->startString = entMatchParam; #else delete entMatchParam; #endif next->end = 0; loadRegions(next, (Element*)tmpel); scheme->nodes.addElement(next); next = null; continue; }; if (*tmpel->getNodeName() == "block"){ const String *sParam = ((Element*)tmpel)->getAttribute(DString("start")); const String *eParam = ((Element*)tmpel)->getAttribute(DString("end")); if (!sParam && tmpel->getFirstChild() && *tmpel->getFirstChild()->getNodeName() == "start" && tmpel->getFirstChild()->getFirstChild() != null && tmpel->getFirstChild()->getFirstChild()->getNodeType() == Node::TEXT_NODE) { sParam = ((Text*)tmpel->getFirstChild()->getFirstChild())->getData(); } if (!eParam && tmpel->getFirstChild() && tmpel->getFirstChild()->getNextSibling() && *tmpel->getFirstChild()->getNextSibling()->getNodeName() == "end" && tmpel->getFirstChild()->getNextSibling()->getFirstChild() != null && tmpel->getFirstChild()->getNextSibling()->getFirstChild()->getNodeType() == Node::TEXT_NODE) { eParam = ((Text*)tmpel->getFirstChild()->getNextSibling()->getFirstChild())->getData(); } String *startParam; String *endParam; if (!(startParam = useEntities(sParam))){ if (errorHandler != null){ errorHandler->error(StringBuffer("'start' block attribute not found in scheme '")+scheme->schemeName+"'"); } delete next; continue; }; if (!(endParam = useEntities(eParam))){ if (errorHandler != null){ errorHandler->error(StringBuffer("'end' block attribute not found in scheme '")+scheme->schemeName+"'"); } delete next; continue; }; const String *schemeName = ((Element*)tmpel)->getAttribute(DString("scheme")); if (schemeName == null || schemeName->length() == 0){ if (errorHandler != null){ errorHandler->error(StringBuffer("block with bad scheme attribute in scheme '")+scheme->getName()+"'"); } delete startParam; delete endParam; continue; }; next->schemeName = new SString(schemeName); next->lowPriority = DString("low").equals(((Element*)tmpel)->getAttribute(DString("priority"))); next->lowContentPriority = DString("low").equals(((Element*)tmpel)->getAttribute(DString("content-priority"))); next->type = SNT_SCHEME; next->start = new CRegExp(startParam); next->start->setPositionMoves(false); if (!next->start->isOk()){ if (errorHandler != null){ errorHandler->error(StringBuffer("fault compiling regexp '")+startParam+"' in scheme '"+scheme->schemeName+"'"); } } next->end = new CRegExp(); next->end->setPositionMoves(true); next->end->setBackRE(next->start); next->end->setRE(endParam); if (!next->end->isOk()){ if (errorHandler != null){ errorHandler->error(StringBuffer("fault compiling regexp '")+endParam+"' in scheme '"+scheme->schemeName+"'"); } } #ifdef ALLOW_SERIALIZATION next->startString = startParam; next->endString = endParam; #else delete startParam; delete endParam; #endif loadRegions(next, (Element*)tmpel); scheme->nodes.addElement(next); next = null; continue; }; if (*tmpel->getNodeName() == "keywords"){ bool isCase = ((Element*)tmpel)->getAttribute(DString("ignorecase")) ? false : true; next->lowPriority = !DString("normal").equals(((Element*)tmpel)->getAttribute(DString("priority"))); const Region *brgn = getNCRegion((Element*)tmpel, DString("region")); if (brgn == null){ continue; } const String *worddiv = ((Element*)tmpel)->getAttribute(DString("worddiv")); next->worddiv = null; if (worddiv){ String *entWordDiv = useEntities(worddiv); next->worddiv = CharacterClass::createCharClass(*entWordDiv, 0, null); if(next->worddiv == null){ if (errorHandler != null) errorHandler->warning(StringBuffer("fault compiling worddiv regexp '")+entWordDiv+"' in scheme '"+scheme->schemeName+"'"); } #ifdef ALLOW_SERIALIZATION next->worddivString = entWordDiv; #else delete entWordDiv; #endif }; next->kwList = new KeywordList; for(Node *keywrd_count = tmpel->getFirstChild(); keywrd_count; keywrd_count = keywrd_count->getNextSibling()){ if (*keywrd_count->getNodeName() == "word" || *keywrd_count->getNodeName() == "symb") { next->kwList->num++; } } next->kwList->kwList = new KeywordInfo[next->kwList->num]; next->kwList->num = 0; KeywordInfo *pIDs = next->kwList->kwList; next->kwList->matchCase = isCase; next->kwList->kwList = pIDs; next->type = SNT_KEYWORDS; for(Node *keywrd = tmpel->getFirstChild(); keywrd; keywrd = keywrd->getNextSibling()){ int type = 0; if (*keywrd->getNodeName() == "word") type = 1; if (*keywrd->getNodeName() == "symb") type = 2; if (!type){ continue; } const String *param; if (!(param = ((Element*)keywrd)->getAttribute(DString("name"))) || !param->length()){ continue; } const Region *rgn = brgn; if (((Element*)keywrd)->getAttribute(DString("region"))) rgn = getNCRegion((Element*)keywrd, DString("region")); int pos = next->kwList->num; pIDs[pos].keyword = new SString(param); pIDs[pos].region = rgn; pIDs[pos].isSymbol = (type == 2); next->kwList->firstChar->addChar((*param)[0]); if (!isCase){ next->kwList->firstChar->addChar(Character::toLowerCase((*param)[0])); next->kwList->firstChar->addChar(Character::toUpperCase((*param)[0])); next->kwList->firstChar->addChar(Character::toTitleCase((*param)[0])); }; next->kwList->num++; if (next->kwList->minKeywordLength > pIDs[pos].keyword->length()) next->kwList->minKeywordLength = pIDs[pos].keyword->length(); }; next->kwList->sortList(); next->kwList->substrIndex(); scheme->nodes.addElement(next); next = null; continue; }; }; // drop last unused node if (next != null) delete next; }; void HRCParserImpl::loadRegions(SchemeNode *node, Element *el) { int i; static char rg_tmpl[0x10] = "region"; node->region = getNCRegion(el, DString("region")); for (i = 0; i < REGIONS_NUM; i++){ if (node->type == SNT_SCHEME){ rg_tmpl[6] = '0'; rg_tmpl[7] = (i<0xA?i:i+7)+'0'; rg_tmpl[8] = 0; node->regions[i] = getNCRegion(el, DString(rg_tmpl)); rg_tmpl[6] = '1'; node->regione[i] = getNCRegion(el, DString(rg_tmpl)); rg_tmpl[6] = (i<0xA?i:i+7+32)+'0'; rg_tmpl[7] = 0; if (el->getFirstChild() && *el->getFirstChild()->getNodeName() == "start"){ node->regions[i] = getNCRegion((Element*)el->getFirstChild(), DString(rg_tmpl)); }; if (el->getFirstChild() && el->getFirstChild()->getNextSibling() && *el->getFirstChild()->getNextSibling()->getNodeName() == "end"){ node->regione[i] = getNCRegion((Element*)el->getFirstChild()->getNextSibling(), DString(rg_tmpl)); }; }else if (node->type == SNT_RE){ rg_tmpl[6] = (i<0xA?i:i+7+32)+'0'; rg_tmpl[7] = 0; node->regions[i] = getNCRegion(el, DString(rg_tmpl)); }; }; for (i = 0; i < NAMED_REGIONS_NUM; i++){ node->regionsn[i] = getNCRegion(node->start->getBracketName(i), false); if (node->type == SNT_SCHEME) node->regionen[i] = getNCRegion(node->end->getBracketName(i), false); }; if (node->type == SNT_RE && node->region) node->regions[0] = node->region; }; void HRCParserImpl::updateLinks() { while(structureChanged){ structureChanged = false; for(SchemeImpl *scheme = schemeHash.enumerate(); scheme != null; scheme = schemeHash.next()){ if (!scheme->fileType->loadDone) continue; FileTypeImpl *old_parseType = parseType; parseType = scheme->fileType; for (int sni = 0; sni < scheme->nodes.size(); sni++){ SchemeNode *snode = scheme->nodes.elementAt(sni); if (snode->schemeName != null && (snode->type == SNT_SCHEME || snode->type == SNT_INHERIT) && snode->scheme == null){ String *schemeName = qualifyForeignName(snode->schemeName, QNT_SCHEME, true); if (schemeName != null){ snode->scheme = schemeHash.get(schemeName); }else{ if (errorHandler != null) errorHandler->error(StringBuffer("cannot resolve scheme name '")+snode->schemeName+"' in scheme '"+scheme->schemeName+"'"); }; delete schemeName; delete snode->schemeName; snode->schemeName = null; }; if (snode->type == SNT_INHERIT){ for(int vti = 0; vti < snode->virtualEntryVector.size(); vti++){ VirtualEntry *vt = snode->virtualEntryVector.elementAt(vti); if (vt->virtScheme == null && vt->virtSchemeName != null){ String *vsn = qualifyForeignName(vt->virtSchemeName, QNT_SCHEME, true); if (vsn) vt->virtScheme = schemeHash.get(vsn); if (!vsn) if (errorHandler != null) errorHandler->error(StringBuffer("cannot virtualize scheme '")+vt->virtSchemeName+"' in scheme '"+scheme->schemeName+"'"); delete vsn; delete vt->virtSchemeName; vt->virtSchemeName = null; }; if (vt->substScheme == null && vt->substSchemeName != null){ String *vsn = qualifyForeignName(vt->substSchemeName, QNT_SCHEME, true); if (vsn) vt->substScheme = schemeHash.get(vsn); else if (errorHandler != null) errorHandler->error(StringBuffer("cannot virtualize using subst-scheme scheme '")+vt->substSchemeName+"' in scheme '"+scheme->schemeName+"'"); delete vsn; delete vt->substSchemeName; vt->substSchemeName = null; }; }; }; }; parseType = old_parseType; if (structureChanged) break; }; }; }; String *HRCParserImpl::qualifyOwnName(const String *name) { if (name == null) return null; int colon = name->indexOf(':'); if (colon != -1){ if (parseType && DString(name, 0, colon) != *parseType->name){ if (errorHandler != null) errorHandler->error(StringBuffer("type name qualifer in '")+name+"' doesn't match type '"+parseType->name+"'"); return null; }else return new SString(name); }else{ if (parseType == null) return null; StringBuffer *sbuf = new StringBuffer(parseType->name); sbuf->append(DString(":")).append(name); return sbuf; }; }; bool HRCParserImpl::checkNameExist(const String *name, FileTypeImpl *parseType, QualifyNameType qntype, bool logErrors) { if (qntype == QNT_DEFINE && regionNamesHash.get(name) == null){ if (logErrors) if (errorHandler != null) errorHandler->error(StringBuffer("region '")+name+"', referenced in type '"+parseType->name+"', is not defined"); return false; }else if (qntype == QNT_ENTITY && schemeEntitiesHash.get(name) == null){ if (logErrors) if (errorHandler != null) errorHandler->error(StringBuffer("entity '")+name+"', referenced in type '"+parseType->name+"', is not defined"); return false; }else if (qntype == QNT_SCHEME && schemeHash.get(name) == null){ if (logErrors) if (errorHandler != null) errorHandler->error(StringBuffer("scheme '")+name+"', referenced in type '"+parseType->name+"', is not defined"); return false; }; return true; }; String *HRCParserImpl::qualifyForeignName(const String *name, QualifyNameType qntype, bool logErrors){ if (name == null) return null; int colon = name->indexOf(':'); if (colon != -1){ // qualified name DString prefix(name, 0, colon); FileTypeImpl *prefType = fileTypeHash.get(&prefix); if (prefType == null){ if (logErrors && errorHandler != null) errorHandler->error(StringBuffer("type name qualifer in '")+name+"' doesn't match any type"); return null; }else if (!prefType->typeLoaded) loadFileType(prefType); if (prefType == parseType || prefType->typeLoaded) return checkNameExist(name, prefType, qntype, logErrors)?(new SString(name)):null; }else{ // unqualified name for(int idx = -1; parseType != null && idx < parseType->importVector.size(); idx++){ const String *tname = parseType->name; if (idx > -1) tname = parseType->importVector.elementAt(idx); FileTypeImpl *importer = fileTypeHash.get(tname); if (!importer->typeLoaded) loadFileType(importer); StringBuffer *qname = new StringBuffer(tname); qname->append(DString(":")).append(name); if (checkNameExist(qname, importer, qntype, false)) return qname; delete qname; }; if (logErrors && errorHandler != null){ errorHandler->error(StringBuffer("unqualified name '")+name+"' doesn't belong to any imported type ["+curInputSource->getLocation()+"]"); } }; return null; }; String *HRCParserImpl::useEntities(const String *name) { int copypos = 0; int epos = 0; if (!name) return null; StringBuffer *newname = new StringBuffer(); while(true){ epos = name->indexOf('%', epos); if (epos == -1){ epos = name->length(); break; }; if (epos && (*name)[epos-1] == '\\'){ epos++; continue; }; int elpos = name->indexOf(';', epos); if (elpos == -1){ epos = name->length(); break; }; DString enname(name, epos+1, elpos-epos-1); String *qEnName = qualifyForeignName(&enname, QNT_ENTITY, true); const String *enval = null; if (qEnName != null){ enval = schemeEntitiesHash.get(qEnName); delete qEnName; }; if (enval == null){ epos++; continue; }; newname->append(DString(name, copypos, epos-copypos)); newname->append(enval); epos = elpos+1; copypos = epos; }; if (epos > copypos) newname->append(DString(name, copypos, epos-copypos)); return newname; }; const Region* HRCParserImpl::getNCRegion(const String *name, bool logErrors){ if (name == null) return null; const Region *reg = null; String *qname = qualifyForeignName(name, QNT_DEFINE, logErrors); if (qname == null) return null; reg = regionNamesHash.get(qname); delete qname; /** Check for 'default' region request. Regions with this name are always transparent */ if (reg != null){ const String *name = reg->getName(); int idx = name->indexOf(DString(":default")); if (idx != -1 && idx+8 == name->length()) return null; }; return reg; }; const Region* HRCParserImpl::getNCRegion(Element *el, const String &tag){ const String *par = el->getAttribute(tag); if (par == null) return null; return getNCRegion(par, true); }; /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Colorer Library. * * The Initial Developer of the Original Code is * Cail Lomecb . * Portions created by the Initial Developer are Copyright (C) 1999-2003 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */