Logo Search packages:      
Sourcecode: jade version File versions  Download package

SOEntityCatalog.cxx

// Copyright (c) 1994, 1995, 1996 James Clark
// See the file COPYING for copying permission.

#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(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

Generated by  Doxygen 1.6.0   Back to index