File indexing completed on 2024-04-28 15:35:14

0001 /***************************************************************************
0002  *   Copyright (C) 2004 by Tomas Mecir                                     *
0003  *   kmuddy@kmuddy.org                                                     *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU Library General Public License as       *
0007  *   published by the Free Software Foundation; either version 2 of the    *
0008  *   License, or (at your option) any later version.                       *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU Library General Public License for more details.                  *
0014  ***************************************************************************/
0015 
0016 #include "centitymanager.h"
0017 
0018 #include "entitylist.h"
0019 
0020 cEntityManager::cEntityManager (bool noStdEntities)
0021 {
0022   reset (noStdEntities);
0023 }
0024 
0025 cEntityManager::~cEntityManager ()
0026 {
0027   entities.clear ();
0028 }
0029 
0030 void cEntityManager::reset (bool noStdEntities)
0031 {
0032   partent = "";
0033   entities.clear ();
0034   inEntity = false;
0035   
0036   if (noStdEntities)
0037     return;
0038   
0039   char s[2];
0040   s[1] = 0;
0041   //restore standard HTML entities
0042   for (int i = 0; i < NUM_MXP_ENTITIES; i++)
0043   {
0044     s[0] = ENTITY_DEF[i];
0045     entities[ENTITY_NAMES[i]] = s;
0046   }
0047 }
0048 
0049 //can this be the first letter of an entity?
0050 inline bool correct1 (char l)
0051 {
0052   return (((l >= 'a') && (l <= 'z')) || ((l >= 'A') && (l <= 'Z')) || (l == '#'));
0053 }
0054 
0055 //can this be a letter of entity?
0056 inline bool correctN (char l)
0057 {
0058   return (((l >= 'a') && (l <= 'z')) || ((l >= 'A') && (l <= 'Z')) || (l == '_') ||
0059       ((l >= '0') && (l <= '9')));
0060 }
0061 
0062 void cEntityManager::addEntity (const string &name, const string &value)
0063 {
0064   if (name.empty()) return;
0065 
0066   //add or modify the entity
0067   entities[name] = value;
0068 }
0069 
0070 void cEntityManager::deleteEntity (const string &name)
0071 {
0072   entities.erase (name);
0073 }
0074 
0075 string cEntityManager::entity (const string &name)
0076 {
0077   if (exists (name))
0078     return entities[name];
0079   //return empty string otherwise
0080   return empty_string;
0081 }
0082 
0083 string cEntityManager::expandEntities (const string &s, bool finished)
0084 {
0085   string s1;
0086 
0087   if (!partent.empty ())  //some unfinished entity is waiting...
0088     inEntity = true;
0089 
0090   string::const_iterator it;
0091   for (it = s.begin(); it != s.end(); ++it)
0092     if (inEntity)
0093     {
0094       char ch = *it;
0095       if (ch == ';')  //end of entity
0096       {
0097         inEntity = false;
0098         if (partent.empty()) //received &;
0099         {
0100           s1 += "&;";
0101         }
0102         else
0103         if (partent[0] == '_')  //invalid entity name - IGNORED
0104         {
0105           partent = "";
0106         }
0107         else
0108         if (partent[0] == '#')  //&#nnn; entity
0109         {
0110           //compute number
0111           int n = 0;
0112           string::iterator it2 = partent.begin();
0113           it2++;  //starting from second character
0114           for (; it2 != partent.end(); ++it2)
0115           {
0116             int x = *it2 - 48;
0117             if ((x < 0) || (x > 9)) //WRONG
0118             {
0119               n = 0;
0120               break;
0121             }
0122             n = n * 10 + x;
0123             if (n > 255)  //number too big!
0124             {
0125               n = 0;
0126               break;
0127             }
0128           }
0129           //verify number, IGNORE entity if it's wrong
0130           if ((n >= 32) && (n <= 255))
0131             s1 += (unsigned char) n;
0132           partent = "";
0133         }
0134         else
0135         {
0136           //now we have correct entity name, let's expand it, if possible :)
0137           if (entities.count (partent))
0138             s1 += entities[partent];
0139           else
0140             //keep the same string if the entity doesn't exist...
0141             s1 += "&" + partent + ";";
0142           partent = "";
0143         }
0144       }
0145       else if (ch == '&')
0146       //unterminated entity, new entity may start here
0147       {
0148         s1 += "&" + partent;
0149         partent = "";
0150         //isEntity remains set
0151       }
0152       else if ((partent.empty() && correct1(ch)) || ((!partent.empty()) && correctN(ch)))
0153       {
0154         partent += ch;
0155       }
0156       //this wasn't an entity after all
0157       else
0158       {
0159         inEntity = false;
0160         s1 += "&" + partent + ch;
0161         partent = "";
0162       }
0163     }
0164     else
0165     {
0166       if (*it == '&')
0167         inEntity = true;
0168       else
0169         //copy without change
0170         s1 += *it;
0171     }
0172   //string ends in an unterminated entity, but only if the string is finished
0173   if (inEntity && finished)
0174   {
0175     s1 += "&" + partent;
0176     partent = "";
0177     inEntity = false;
0178   }
0179 
0180   //return the resulting string
0181   return s1;
0182 }
0183 
0184 bool cEntityManager::needMoreText()
0185 {
0186   return partent.empty() ? false : true;
0187 }