SOEntityCatalog.cxx revision 7c478bd95313f5f23a4c958a745db2134aa03244
// Copyright (c) 1994, 1995, 1996 James Clark
// See the file COPYING for copying permission.
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __GNUG__
#pragma implementation
#endif
#include "splib.h"
#include "CharsetInfo.h"
#include "MessageArg.h"
#include "CatalogMessages.h"
#include "SOEntityCatalog.h"
#include "EntityDecl.h"
#include "EntityCatalog.h"
#include "Message.h"
#include "StringC.h"
#include "types.h"
#include "HashTable.h"
#include "InputSource.h"
#include "Boolean.h"
#include "SubstTable.h"
#include "CatalogEntry.h"
#include "Vector.h"
#include "StorageManager.h"
#include "macros.h"
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
class CatalogParser;
class SOEntityCatalog;
class SOCatalogManagerImpl : public SOCatalogManager {
public:
SOCatalogManagerImpl(const Vector<StringC> &sysids,
size_t nSysidsMustExist,
const CharsetInfo *sysidCharset,
const CharsetInfo *catalogCharset,
Boolean useDocCatalog);
ConstPtr<EntityCatalog> makeCatalog(StringC &systemId,
const CharsetInfo &charset,
ExtendEntityManager *,
Messenger &) const;
Boolean mapCatalog(ParsedSystemId &systemId,
ExtendEntityManager *em,
Messenger &mgr) const;
private:
void addCatalogsForDocument(CatalogParser &parser,
StringC &sysid,
SOEntityCatalog *,
const CharsetInfo &charset,
Messenger &mgr) const;
size_t nSystemCatalogsMustExist_;
Vector<StringC> systemCatalogs_;
const CharsetInfo *sysidCharset_;
const CharsetInfo *catalogCharset_;
Boolean useDocCatalog_;
};
class SOEntityCatalog : public EntityCatalog {
public:
SOEntityCatalog(Ptr<ExtendEntityManager> em);
typedef EntityDecl::DeclType DeclType;
Boolean document(const CharsetInfo &, Messenger &, StringC &) const;
Boolean sgmlDecl(const CharsetInfo &, Messenger &, StringC &) const;
Boolean lookup(const EntityDecl &entity,
const Syntax &,
const CharsetInfo &,
Messenger &,
StringC &) const;
Boolean lookupPublic(const StringC &,
const CharsetInfo &,
Messenger &,
StringC &) const;
Boolean lookupChar(const StringC &,
const CharsetInfo &,
Messenger &,
UnivChar &) const;
void addPublicId(StringC &publicId, StringC &systemId, const Location &,
Boolean override);
void addDelegate(StringC &prefix, StringC &systemId, const Location &,
Boolean override);
void addSystemId(StringC &systemId, StringC &replSystemId, const Location &);
void addName(StringC &name, DeclType, StringC &systemId, const Location &,
Boolean override);
void setSgmlDecl(StringC &str, const Location &loc);
void setDocument(StringC &str, const Location &loc);
void setBase(const Location &loc);
void endCatalog();
const Ptr<ExtendEntityManager> &entityManager() {
return em_;
}
private:
SOEntityCatalog(const SOEntityCatalog &); // undefined
void operator=(const SOEntityCatalog &); // undefined
Boolean expandCatalogSystemId(const StringC &str,
const Location &loc,
size_t baseNumber,
Boolean isNdata,
const CharsetInfo &charset,
const StringC *lookupPublicId,
Messenger &mgr,
StringC &result) const;
const CatalogEntry *
findBestPublicEntry(const StringC &publicId, Boolean overrideOnly,
const CharsetInfo &charset, Boolean &delegated) const;
class Table {
public:
Table();
const CatalogEntry *lookup(const StringC &, Boolean overrideOnly) const;
const CatalogEntry *lookup(const StringC &key,
const SubstTable<Char> &substTable,
Boolean overrideOnly) const;
void insert(const StringC &, const CatalogEntry &, Boolean override);
size_t count() const;
private:
Table(const Table &); // undefined
void operator=(const Table &); // undefined
// These are entries that are applicable when an explicit system id
// was specified in the external identifier.
HashTable<StringC,CatalogEntry> overrideEntries_;
// This specifies the entries that should substitute for the
// overrideEntries_ when an explicit system identifier was not specified.
HashTable<StringC,CatalogEntry> normalEntries_;
};
Table publicIds_;
Table delegates_;
HashTable<StringC,CatalogEntry> systemIds_;
Table names_[5];
size_t catalogNumber_;
Boolean haveSgmlDecl_;
StringC sgmlDecl_;
Location sgmlDeclLoc_;
size_t sgmlDeclBaseNumber_;
StringC document_;
Boolean haveDocument_;
Location documentLoc_;
size_t documentBaseNumber_;
Boolean haveCurrentBase_;
Vector<Location> base_;
Ptr<ExtendEntityManager> em_;
};
class CatalogParser : private Messenger {
public:
CatalogParser(const CharsetInfo &);
void parseCatalog(const StringC &sysid,
Boolean mustExist,
const CharsetInfo &sysidCharset,
const CharsetInfo &catalogCharset,
InputSourceOrigin *origin,
SOEntityCatalog *catalog,
Messenger &mgr);
public:
// Since it's a return type, it has to be public to keep some
// (broken) compilers happy.
enum Param {
eofParam,
literalParam,
nameParam,
percentParam
};
private:
enum {
data,
eof,
nul,
lit,
lita,
minus,
s,
min // other minimum data characters
};
enum { minimumLiteral = 01 };
Messenger &messenger() { return *this; }
void dispatchMessage(Message &);
void dispatchMessage(const Message &);
void initMessage(Message &);
void parsePublic();
void parseDelegate();
void parseDtddecl();
void parseSystem();
void parseNameMap(EntityDecl::DeclType declType);
void parseOverride();
Param parseParam(unsigned flags = 0);
Boolean parseArg();
void parseLiteral(Char delim, unsigned flags);
void parseName();
void skipComment();
void upcase(StringC &);
Boolean inLoop(const Location &loc);
Boolean isMinimumData(Xchar c) {
int cat = categoryTable_[c];
return (cat == min || (cat == s && c != tab_)
|| cat == minus || cat == lita);
}
Xchar get() { return in_->get(messenger()); }
void unget() { in_->ungetToken(); }
Messenger *mgr_;
InputSource *in_;
SOEntityCatalog *catalog_;
StringC param_;
Location paramLoc_;
Char minus_;
Char tab_;
Char rs_;
Char re_;
Char space_;
StringC publicKey_;
StringC systemKey_;
StringC entityKey_;
StringC doctypeKey_;
StringC linktypeKey_;
StringC notationKey_;
StringC overrideKey_;
StringC sgmlDeclKey_;
StringC documentKey_;
StringC catalogKey_;
StringC yesKey_;
StringC noKey_;
StringC baseKey_;
StringC delegateKey_;
StringC dtddeclKey_;
StringC sgmlKey_;
XcharMap<unsigned char> categoryTable_;
SubstTable<Char> substTable_;
Boolean override_;
};
ExtendEntityManager::CatalogManager *
SOCatalogManager::make(const Vector<StringC> &sysids,
size_t nSysidsMustExist,
const CharsetInfo *sysidCharset,
const CharsetInfo *catalogCharset,
Boolean useDocCatalog)
{
return new SOCatalogManagerImpl(sysids,
nSysidsMustExist,
sysidCharset,
catalogCharset,
useDocCatalog);
}
SOCatalogManagerImpl::SOCatalogManagerImpl(const Vector<StringC> &systemCatalogs,
size_t nSystemCatalogsMustExist,
const CharsetInfo *sysidCharset,
const CharsetInfo *catalogCharset,
Boolean useDocCatalog)
: systemCatalogs_(systemCatalogs),
nSystemCatalogsMustExist_(nSystemCatalogsMustExist),
sysidCharset_(sysidCharset),
catalogCharset_(catalogCharset),
useDocCatalog_(useDocCatalog)
{
}
Boolean SOCatalogManagerImpl::mapCatalog(ParsedSystemId &systemId,
ExtendEntityManager *em,
Messenger &mgr) const
{
Vector<ParsedSystemId::Map> maps;
systemId.maps.swap(maps);
while (maps.size() > 0) {
StringC catalogSystemId;
systemId.unparse(*sysidCharset_, 0, catalogSystemId);
SOEntityCatalog *catalog = new SOEntityCatalog(em);
ConstPtr<EntityCatalog> deleter(catalog);
CatalogParser parser(*catalogCharset_);
parser.parseCatalog(catalogSystemId, 1, *sysidCharset_, *catalogCharset_,
InputSourceOrigin::make(), catalog, mgr);
// FIXME do catalog caching here
StringC s;
if (maps.back().type == ParsedSystemId::Map::catalogDocument) {
if (!catalog->document(*sysidCharset_, mgr, s)) {
mgr.message(CatalogMessages::noDocumentEntry,
StringMessageArg(catalogSystemId));
return 0;
}
}
else {
ASSERT(maps.back().type == ParsedSystemId::Map::catalogPublic);
if (!catalog->lookupPublic(maps.back().publicId, *sysidCharset_, mgr,
s)) {
mgr.message(CatalogMessages::noPublicEntry,
StringMessageArg(maps.back().publicId),
StringMessageArg(catalogSystemId));
return 0;
}
}
ParsedSystemId tem;
if (!em->parseSystemId(s, *sysidCharset_, 0, 0, mgr, tem))
return 0;
systemId = tem;
maps.resize(maps.size() - 1);
for (size_t i = 0; i < systemId.maps.size(); i++)
maps.push_back(systemId.maps[i]);
systemId.maps.clear();
}
return 1;
}
ConstPtr<EntityCatalog>
SOCatalogManagerImpl::makeCatalog(StringC &systemId,
const CharsetInfo &charset,
ExtendEntityManager *em,
Messenger &mgr) const
{
SOEntityCatalog *entityCatalog = new SOEntityCatalog(em);
CatalogParser parser(*catalogCharset_);
size_t i;
for (i = 0; i < nSystemCatalogsMustExist_; i++)
parser.parseCatalog(systemCatalogs_[i], 1,
*sysidCharset_, *catalogCharset_,
InputSourceOrigin::make(), entityCatalog,
mgr);
if (useDocCatalog_)
addCatalogsForDocument(parser, systemId, entityCatalog, charset, mgr);
for (i = nSystemCatalogsMustExist_; i < systemCatalogs_.size(); i++)
parser.parseCatalog(systemCatalogs_[i], 0,
*sysidCharset_, *catalogCharset_,
InputSourceOrigin::make(), entityCatalog,
mgr);
return entityCatalog;
}
void SOCatalogManagerImpl::addCatalogsForDocument(CatalogParser &parser,
StringC &sysid,
SOEntityCatalog *impl,
const CharsetInfo &charset,
Messenger &mgr) const
{
ParsedSystemId v;
if (!impl->entityManager()->parseSystemId(sysid, charset, 0, 0, mgr, v))
return;
if (v.maps.size() > 0) {
if (v.maps[0].type == ParsedSystemId::Map::catalogDocument) {
v.maps.erase(v.maps.begin(), v.maps.begin() + 1);
StringC tem;
v.unparse(charset, 0, tem);
parser.parseCatalog(tem, 1, charset, *catalogCharset_,
InputSourceOrigin::make(), impl, mgr);
if (!impl->document(charset, mgr, sysid)) {
mgr.message(CatalogMessages::noDocumentEntry, StringMessageArg(tem));
sysid.resize(0);
}
}
return;
}
Vector<StringC> catalogs;
size_t i;
for (i = 0; i < v.size(); i++)
if (v[i].storageManager->inheritable()) {
ParsedSystemId catalogId;
catalogId.resize(1);
StorageObjectSpec &spec = catalogId.back();
spec.storageManager = v[i].storageManager;
spec.codingSystemType = v[i].codingSystemType;
spec.codingSystemName = v[i].codingSystemName;
spec.specId = spec.storageManager->idCharset()->execToDesc("catalog");
spec.storageManager->resolveRelative(v[i].specId, spec.specId, 0);
spec.baseId = v[i].baseId;
spec.records = v[i].records;
StringC tem;
catalogId.unparse(charset, 0, tem);
for (size_t j = 0; j < catalogs.size(); j++)
if (tem == catalogs[j]) {
tem.resize(0);
break;
}
if (tem.size() > 0) {
catalogs.resize(catalogs.size() + 1);
tem.swap(catalogs.back());
}
}
for (i = 0; i < catalogs.size(); i++)
parser.parseCatalog(catalogs[i], 0, charset,
*catalogCharset_, InputSourceOrigin::make(), impl,
mgr);
}
SOEntityCatalog::SOEntityCatalog(Ptr<ExtendEntityManager> em)
: em_(em), catalogNumber_(0), haveSgmlDecl_(0), haveDocument_(0),
haveCurrentBase_(0)
{
}
void SOEntityCatalog::endCatalog()
{
catalogNumber_++;
haveCurrentBase_ = 0;
}
Boolean SOEntityCatalog::expandCatalogSystemId(const StringC &str,
const Location &loc,
size_t baseNumber,
Boolean isNdata,
const CharsetInfo &charset,
const StringC *lookupPublicId,
Messenger &mgr,
StringC &result) const
{
return em_->expandSystemId(str,
(baseNumber ? base_[baseNumber - 1] : loc),
isNdata,
charset,
lookupPublicId,
mgr,
result);
}
Boolean SOEntityCatalog::lookup(const EntityDecl &entity,
const Syntax &syntax,
const CharsetInfo &charset,
Messenger &mgr,
StringC &result) const
{
const CatalogEntry *entry = 0;
const CatalogEntry *delegatedEntry = 0;
if (entity.systemIdPointer())
entry = systemIds_.lookup(*entity.systemIdPointer());
if (entity.publicIdPointer()) {
const CatalogEntry *publicEntry;
Boolean delegated;
publicEntry = findBestPublicEntry(*entity.publicIdPointer(),
entity.systemIdPointer() != 0,
charset,
delegated);
if (publicEntry && delegated)
delegatedEntry = publicEntry;
// match for system id has priority over match for public id in same
// catalog
if (publicEntry
&& (!entry || publicEntry->catalogNumber < entry->catalogNumber))
entry = publicEntry;
}
if (entity.name().size() > 0
&& (!entry || entry->catalogNumber > 0)) {
const CatalogEntry *entityEntry;
int tableIndex = (entity.declType() >= EntityDecl::parameterEntity
? int(entity.declType()) - 1
: int(entity.declType()));
StringC name(entity.name());
Boolean subst;
switch (entity.declType()) {
case EntityDecl::parameterEntity:
{
StringC tem(name);
name = syntax.peroDelim();
name += tem;
}
// fall through
case EntityDecl::generalEntity:
subst = syntax.namecaseEntity();
break;
default:
subst = syntax.namecaseGeneral();
break;
}
if (!subst)
entityEntry = names_[tableIndex].lookup(name,
entity.systemIdPointer() != 0);
else
entityEntry = names_[tableIndex].lookup(entity.name(),
syntax.upperSubstTable(),
entity.systemIdPointer() != 0);
// match for public id has priority over match for entity in same
// catalog
if (entityEntry
&& (!entry || entityEntry->catalogNumber < entry->catalogNumber))
entry = entityEntry;
}
if (entry)
return expandCatalogSystemId(entry->to,
entry->loc,
entry->baseNumber,
entity.dataType() == EntityDecl::ndata,
charset,
entry == delegatedEntry
? entity.publicIdPointer()
: 0,
mgr,
result);
if (entity.systemIdPointer())
return em_->expandSystemId(*entity.systemIdPointer(),
entity.defLocation(),
entity.dataType() == EntityDecl::ndata,
charset,
0,
mgr,
result);
return 0;
}
Boolean SOEntityCatalog::lookupPublic(const StringC &publicId,
const CharsetInfo &charset,
Messenger &mgr,
StringC &result) const
{
Boolean delegated;
const CatalogEntry *entry = findBestPublicEntry(publicId, 0, charset,
delegated);
return (entry
&& expandCatalogSystemId(entry->to, entry->loc, entry->baseNumber,
0, charset, delegated ? &publicId : 0,
mgr, result));
}
Boolean SOEntityCatalog::lookupChar(const StringC &name,
const CharsetInfo &charset,
Messenger &mgr,
UnivChar &result) const
{
Boolean delegated;
const CatalogEntry *entry = findBestPublicEntry(name, 0, charset,
delegated);
if (!entry)
return 0;
if (delegated)
return 0; // FIXME
const StringC &number = entry->to;
if (number.size() == 0)
return 0;
UnivChar n = 0;
for (size_t i = 0; i < number.size(); i++) {
int d = charset.digitWeight(number[i]);
if (d < 0)
return 0;
if (n <= UnivChar(-1)/10 && (n *= 10) <= UnivChar(-1) - d)
n += d;
}
result = n;
return 1;
}
const CatalogEntry *
SOEntityCatalog::findBestPublicEntry(const StringC &publicId,
Boolean overrideOnly,
const CharsetInfo &charset,
Boolean &delegated) const
{
Char slash = charset.execToDesc('/');
Char colon = charset.execToDesc(':');
const CatalogEntry *bestEntry = 0;
for (size_t i = 0; i <= publicId.size(); i++) {
if ((i + 1 < publicId.size()
&& (publicId[i] == slash || publicId[i] == colon)
&& publicId[i + 1] == publicId[i])
|| (i >= 2
&& (publicId[i - 1] == slash || publicId[i - 1] == colon)
&& publicId[i - 2] == publicId[i - 1])) {
StringC tem(publicId.data(), i);
const CatalogEntry *entry = delegates_.lookup(tem, overrideOnly);
if (entry
&& (!bestEntry
|| entry->catalogNumber <= bestEntry->catalogNumber)) {
bestEntry = entry;
delegated = 1;
}
}
}
const CatalogEntry *entry = publicIds_.lookup(publicId, overrideOnly);
if (entry
&& (!bestEntry || entry->catalogNumber <= bestEntry->catalogNumber)) {
bestEntry = entry;
delegated = 0;
}
return bestEntry;
}
Boolean SOEntityCatalog::sgmlDecl(const CharsetInfo &charset,
Messenger &mgr,
StringC &result) const
{
return haveSgmlDecl_ && expandCatalogSystemId(sgmlDecl_, sgmlDeclLoc_,
sgmlDeclBaseNumber_,
0, charset, 0, mgr, result);
}
Boolean SOEntityCatalog::document(const CharsetInfo &charset,
Messenger &mgr,
StringC &result) const
{
return haveDocument_ && expandCatalogSystemId(document_, documentLoc_,
documentBaseNumber_,
0, charset, 0, mgr, result);
}
void SOEntityCatalog::addPublicId(StringC &publicId, StringC &systemId,
const Location &loc, Boolean override)
{
CatalogEntry entry;
entry.loc = loc;
entry.catalogNumber = catalogNumber_;
entry.baseNumber = haveCurrentBase_ ? base_.size() : 0;
systemId.swap(entry.to);
publicIds_.insert(publicId, entry, override);
}
void SOEntityCatalog::addDelegate(StringC &prefix, StringC &systemId,
const Location &loc, Boolean override)
{
CatalogEntry entry;
entry.loc = loc;
entry.catalogNumber = catalogNumber_;
entry.baseNumber = haveCurrentBase_ ? base_.size() : 0;
systemId.swap(entry.to);
delegates_.insert(prefix, entry, override);
}
void SOEntityCatalog::addSystemId(StringC &systemId, StringC &toSystemId,
const Location &loc)
{
CatalogEntry entry;
entry.loc = loc;
entry.catalogNumber = catalogNumber_;
entry.baseNumber = haveCurrentBase_ ? base_.size() : 0;
toSystemId.swap(entry.to);
systemIds_.insert(systemId, entry, false);
}
void SOEntityCatalog::addName(StringC &name, DeclType declType,
StringC &systemId, const Location &loc,
Boolean override)
{
CatalogEntry entry;
entry.loc = loc;
entry.catalogNumber = catalogNumber_;
entry.baseNumber = haveCurrentBase_ ? base_.size() : 0;
int tableIndex = (declType >= EntityDecl::parameterEntity
? int(declType) - 1
: int(declType));
entry.serial = names_[tableIndex].count();
systemId.swap(entry.to);
names_[tableIndex].insert(name, entry, override);
}
void SOEntityCatalog::setSgmlDecl(StringC &str, const Location &loc)
{
if (!haveSgmlDecl_) {
haveSgmlDecl_ = true;
str.swap(sgmlDecl_);
sgmlDeclLoc_ = loc;
sgmlDeclBaseNumber_ = haveCurrentBase_ ? base_.size() : 0;
}
}
void SOEntityCatalog::setDocument(StringC &str, const Location &loc)
{
if (!haveDocument_) {
haveDocument_ = true;
str.swap(document_);
documentLoc_ = loc;
documentBaseNumber_ = haveCurrentBase_ ? base_.size() : 0;
}
}
void SOEntityCatalog::setBase(const Location &loc)
{
if (loc.origin().isNull())
haveCurrentBase_ = 0;
else {
haveCurrentBase_ = 1;
base_.push_back(loc);
}
}
SOEntityCatalog::Table::Table()
{
}
void SOEntityCatalog::Table::insert(const StringC &key,
const CatalogEntry &entry,
Boolean override)
{
if (override)
overrideEntries_.insert(key, entry, false);
else {
const CatalogEntry *e = overrideEntries_.lookup(key);
if (!e)
normalEntries_.insert(key, entry, false);
}
}
const CatalogEntry *SOEntityCatalog::Table::lookup(const StringC &key,
Boolean overrideOnly) const
{
if (!overrideOnly) {
const CatalogEntry *e = normalEntries_.lookup(key);
if (e)
return e;
}
return overrideEntries_.lookup(key);
}
const CatalogEntry *
SOEntityCatalog::Table::lookup(const StringC &name,
const SubstTable<Char> &substTable,
Boolean overrideOnly) const
{
HashTableIter<StringC,CatalogEntry> iter1(overrideEntries_);
HashTableIter<StringC,CatalogEntry> iter2(normalEntries_);
HashTableIter<StringC,CatalogEntry> *iters[2];
int nIter = 0;
iters[nIter++] = &iter1;
if (!overrideOnly)
iters[nIter++] = &iter2;
const CatalogEntry *entry = 0;
for (int i = 0; i < nIter; i++) {
HashTableIter<StringC,CatalogEntry> &iter = *iters[i];
const StringC *key;
const CatalogEntry *value;
StringC buffer;
while (iter.next(key, value)) {
buffer = *key;
for (size_t j = 0; j < buffer.size(); j++)
substTable.subst(buffer[j]);
if (buffer == name) {
if (!entry || value->serial < entry->serial)
entry = value;
}
}
}
return entry;
}
size_t SOEntityCatalog::Table::count() const
{
return normalEntries_.count() + overrideEntries_.count();
}
CatalogParser::CatalogParser(const CharsetInfo &charset)
: categoryTable_(data),
entityKey_(charset.execToDesc("ENTITY")),
publicKey_(charset.execToDesc("PUBLIC")),
systemKey_(charset.execToDesc("SYSTEM")),
doctypeKey_(charset.execToDesc("DOCTYPE")),
linktypeKey_(charset.execToDesc("LINKTYPE")),
notationKey_(charset.execToDesc("NOTATION")),
overrideKey_(charset.execToDesc("OVERRIDE")),
sgmlDeclKey_(charset.execToDesc("SGMLDECL")),
documentKey_(charset.execToDesc("DOCUMENT")),
catalogKey_(charset.execToDesc("CATALOG")),
yesKey_(charset.execToDesc("YES")),
noKey_(charset.execToDesc("NO")),
baseKey_(charset.execToDesc("BASE")),
delegateKey_(charset.execToDesc("DELEGATE")),
dtddeclKey_(charset.execToDesc("DTDDECL")),
sgmlKey_(charset.execToDesc("SGML"))
{
static const char lcletters[] = "abcdefghijklmnopqrstuvwxyz";
static const char ucletters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// minimum data other than lcletter, ucletter
static const char minChars[] = "0123456789-.'()+,/:=?";
static const char sChars[] = " \n\r\t";
categoryTable_.setChar(0, nul);
const char *p;
const char *q;
for (p = lcletters, q = ucletters; *p; p++, q++) {
Char lc = charset.execToDesc(*p);
Char uc = charset.execToDesc(*q);
substTable_.addSubst(lc, uc);
categoryTable_.setChar(lc, min);
categoryTable_.setChar(uc, min);
}
for (p = sChars; *p; p++)
categoryTable_.setChar(charset.execToDesc(*p), s);
for (p = minChars; *p; p++)
categoryTable_.setChar(charset.execToDesc(*p), min);
categoryTable_.setChar(charset.execToDesc('\''), lita);
categoryTable_.setChar(charset.execToDesc('"'), lit);
minus_ = charset.execToDesc('-');
categoryTable_.setChar(minus_, minus);
tab_ = charset.execToDesc('\t');
re_ = charset.execToDesc('\r');
rs_ = charset.execToDesc('\n');
space_ = charset.execToDesc(' ');
categoryTable_.setEe(eof);
}
void CatalogParser::parseCatalog(const StringC &sysid,
Boolean mustExist,
const CharsetInfo &sysidCharset,
const CharsetInfo &catalogCharset,
InputSourceOrigin *origin,
SOEntityCatalog *catalog,
Messenger &mgr)
{
const Ptr<ExtendEntityManager> &em = catalog->entityManager();
in_ = em->open(sysid, sysidCharset, origin,
mustExist ? 0 : ExtendEntityManager::mayNotExist, mgr);
if (!in_)
return;
catalog_ = catalog;
mgr_ = &mgr;
override_ = 0;
Boolean recovering = false;
Vector<StringC> subSysids;
Vector<Location> subSysidLocs;
for (;;) {
Param parm = parseParam();
if (parm == nameParam) {
upcase(param_);
Boolean wasRecovering = recovering;
recovering = false;
if (param_ == publicKey_)
parsePublic();
else if (param_ == systemKey_)
parseSystem();
else if (param_ == entityKey_)
parseNameMap(EntityDecl::generalEntity);
else if (param_ == doctypeKey_)
parseNameMap(EntityDecl::doctype);
else if (param_ == linktypeKey_)
parseNameMap(EntityDecl::linktype);
else if (param_ == notationKey_)
parseNameMap(EntityDecl::notation);
else if (param_ == sgmlKey_)
parseNameMap(EntityDecl::sgml);
else if (param_ == sgmlDeclKey_) {
if (parseArg())
catalog_->setSgmlDecl(param_, paramLoc_);
}
else if (param_ == documentKey_) {
if (parseArg())
catalog_->setDocument(param_, paramLoc_);
}
else if (param_ == overrideKey_)
parseOverride();
else if (param_ == catalogKey_) {
if (parseArg()) {
if (inLoop(paramLoc_))
break;
subSysids.resize(subSysids.size() + 1);
param_.swap(subSysids.back());
subSysidLocs.push_back(paramLoc_);
}
}
else if (param_ == baseKey_) {
if (parseArg()) {
StringC tem;
if (em->expandSystemId(param_,
paramLoc_,
0,
catalogCharset,
0,
mgr,
tem)) {
InputSource *in = em->open(tem,
catalogCharset,
InputSourceOrigin::make(paramLoc_),
0,
mgr);
if (in && (in->get(mgr) != InputSource::eE || !in->accessError()))
catalog->setBase(in->currentLocation());
}
}
}
else if (param_ == delegateKey_)
parseDelegate();
else if (param_ == dtddeclKey_)
parseDtddecl();
else {
if (!wasRecovering && parseParam() == eofParam)
break;
recovering = true;
}
}
else if (parm == eofParam)
break;
else if (!recovering) {
recovering = true;
message(CatalogMessages::nameExpected);
}
}
delete in_;
catalog->endCatalog();
for (size_t i = 0; i < subSysids.size(); i++) {
StringC tem;
if (em->expandSystemId(subSysids[i], subSysidLocs[i], 0, catalogCharset,
0, mgr, tem))
parseCatalog(tem, 1, catalogCharset, catalogCharset,
InputSourceOrigin::make(subSysidLocs[i]), catalog, mgr);
}
}
Boolean CatalogParser::inLoop(const Location &loc)
{
const InputSourceOrigin *origin = paramLoc_.origin()->asInputSourceOrigin();
if (!origin)
return 0;
const ExternalInfo *info = origin->externalInfo();
if (!info)
return 0;
StorageObjectLocation soLoc;
if (!ExtendEntityManager::externalize(info,
origin->startOffset(paramLoc_.index()),
soLoc))
return 0;
for (;;) {
const Location &parent = origin->parent();
if (parent.origin().isNull())
break;
origin = parent.origin()->asInputSourceOrigin();
if (!origin)
break;
const ExternalInfo *info1 = origin->externalInfo();
if (info1) {
StorageObjectLocation soLoc1;
if (ExtendEntityManager::externalize(info1,
origin->startOffset(parent.index()),
soLoc1)) {
if (soLoc.storageObjectSpec->storageManager
== soLoc1.storageObjectSpec->storageManager
&& soLoc.actualStorageId == soLoc1.actualStorageId) {
setNextLocation(loc.origin()->parent());
message(CatalogMessages::inLoop);
return 1;
}
}
}
}
return 0;
}
void CatalogParser::parseOverride()
{
if (parseParam() != nameParam) {
message(CatalogMessages::overrideYesOrNo);
return;
}
upcase(param_);
if (param_ == yesKey_)
override_ = 1;
else if (param_ == noKey_)
override_ = 0;
else
message(CatalogMessages::overrideYesOrNo);
}
void CatalogParser::parsePublic()
{
if (parseParam(minimumLiteral) != literalParam) {
message(CatalogMessages::literalExpected);
return;
}
StringC publicId;
param_.swap(publicId);
if (!parseArg())
return;
catalog_->addPublicId(publicId, param_, paramLoc_, override_);
}
void CatalogParser::parseDelegate()
{
if (parseParam(minimumLiteral) != literalParam) {
message(CatalogMessages::literalExpected);
return;
}
StringC publicId;
param_.swap(publicId);
if (!parseArg())
return;
catalog_->addDelegate(publicId, param_, paramLoc_, override_);
}
void CatalogParser::parseDtddecl()
{
message(CatalogMessages::dtddeclNotSupported);
if (parseParam(minimumLiteral) != literalParam) {
message(CatalogMessages::literalExpected);
return;
}
if (!parseArg())
return;
}
void CatalogParser::parseSystem()
{
if (!parseArg())
return;
StringC systemId;
param_.swap(systemId);
Param parm = parseParam();
if (parm == nameParam)
message(CatalogMessages::systemShouldQuote);
else if (parm != literalParam) {
message(CatalogMessages::literalExpected);
return;
}
catalog_->addSystemId(systemId, param_, paramLoc_);
}
void CatalogParser::parseNameMap(EntityDecl::DeclType declType)
{
if (!parseArg())
return;
StringC name;
param_.swap(name);
if (!parseArg())
return;
catalog_->addName(name, declType, param_, paramLoc_, override_);
}
Boolean CatalogParser::parseArg()
{
Param parm = parseParam();
if (parm != nameParam && parm != literalParam) {
message(CatalogMessages::nameOrLiteralExpected);
return false;
}
return true;
}
CatalogParser::Param CatalogParser::parseParam(unsigned flags)
{
for (;;) {
Xchar c = get();
switch (categoryTable_[c]) {
case eof:
return eofParam;
case lit:
case lita:
parseLiteral(c, flags);
return literalParam;
case s:
break;
case nul:
message(CatalogMessages::nulChar);
break;
case minus:
c = get();
if (c == minus_) {
skipComment();
break;
}
unget();
// fall through
default:
parseName();
return nameParam;
}
}
}
void CatalogParser::skipComment()
{
for (;;) {
Xchar c = get();
if (c == minus_) {
c = get();
if (c == minus_)
break;
}
if (c == InputSource::eE) {
message(CatalogMessages::eofInComment);
break;
}
}
}
void CatalogParser::parseLiteral(Char delim, unsigned flags)
{
paramLoc_ = in_->currentLocation();
enum { no, yesBegin, yesMiddle } skipping = yesBegin;
param_.resize(0);
for (;;) {
Xchar c = get();
if (c == InputSource::eE) {
message(CatalogMessages::eofInLiteral);
break;
}
if (Char(c) == delim)
break;
if (flags & minimumLiteral) {
if (!isMinimumData(c))
message(CatalogMessages::minimumData);
if (c == rs_)
;
else if (c == space_ || c == re_) {
if (skipping == no) {
param_ += space_;
skipping = yesMiddle;
}
}
else {
skipping = no;
param_ += Char(c);
}
}
else
param_ += Char(c);
}
if (skipping == yesMiddle)
param_.resize(param_.size() - 1);
}
void CatalogParser::parseName()
{
paramLoc_ = in_->currentLocation();
size_t length;
for (length = 1;; length++) {
Xchar c = in_->tokenChar(messenger());
int cat = categoryTable_[c];
if (cat == eof || cat == s)
break;
// FIXME maybe check for LIT or LITA
if (cat == nul)
message(CatalogMessages::nulChar);
}
in_->endToken(length);
param_.assign(in_->currentTokenStart(), in_->currentTokenLength());
}
void CatalogParser::upcase(StringC &str)
{
for (size_t i = 0; i < str.size(); i++)
substTable_.subst(str[i]);
}
void CatalogParser::dispatchMessage(const Message &msg)
{
mgr_->dispatchMessage(msg);
}
void CatalogParser::dispatchMessage(Message &msg)
{
mgr_->dispatchMessage(msg);
}
void CatalogParser::initMessage(Message &msg)
{
msg.loc = in_->currentLocation();
}
#ifdef SP_NAMESPACE
}
#endif