1 /*
2  *      Copyright (C) 2016 Jean-Luc Barriere
3  *
4  *  This library is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU Lesser General Public License as published
6  *  by the Free Software Foundation; either version 3, or (at your option)
7  *  any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  *  GNU Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with this library; see the file COPYING.  If not, write to
16  *  the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17  *  MA 02110-1301 USA
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21 
22 #include "xmldict.h"
23 #include <string.h>
24 
25 using namespace thumbnailer;
26 
27 #define ZERO      '\0'
28 
PrefixEqual(const char * qname,const char * prefix)29 bool XMLNS::PrefixEqual(const char* qname, const char* prefix)
30 {
31   unsigned n = 0;
32   const char* p = qname;
33   while (*p != ZERO)
34     if (*(++p) == ':')
35     {
36       n = p - qname;
37       break;
38     }
39   return (strlen(prefix) == n && strncmp(qname, prefix, n) == 0);
40 }
41 
NameEqual(const char * qname,const char * name)42 bool XMLNS::NameEqual(const char* qname, const char* name)
43 {
44   const char* n = qname;
45   const char* p = qname;
46   while (*p != ZERO)
47     if (*(++p) == ':')
48     {
49       n = p + 1;
50       break;
51     }
52   return (strcmp(n, name) == 0);
53 }
54 
LocalName(const char * qname)55 const char* XMLNS::LocalName(const char* qname)
56 {
57   const char* n = qname;
58   const char* p = qname;
59   while (*p != ZERO)
60     if (*(++p) == ':')
61     {
62       n = p + 1;
63       break;
64     }
65   return n;
66 }
67 
68 ///////////////////////////////////////////////////////////////////////////////
69 ////
70 //// XMLDict
71 ////
72 
XMLDict()73 XMLDict::XMLDict()
74 {
75 }
76 
DefineNS(const char * key,const char * name)77 void XMLDict::DefineNS(const char* key, const char* name)
78 {
79   // remove ending colon from key
80   std::string _key;
81   const char* p = key;
82   while (*p != ZERO && *p != ':') ++p;
83   if (p > key)
84     _key.assign(key, p - key);
85 
86   XMLNS* ns = FindKey(_key.c_str());
87   if (ns)
88   {
89     ns->name.assign(name);
90     // rebuild xml string
91     m_xmlstring.assign(" ");
92     for (XMLNSList::iterator it = m_nsout.begin(); it != m_nsout.end(); ++it)
93     {
94       if (it->key.empty())
95         m_xmlstring.append("xmlns");
96       else
97         m_xmlstring.append("xmlns:").append(it->key);
98       m_xmlstring.append("=\"").append(it->name).append("\" ");
99     }
100   }
101   else
102   {
103     m_nsout.push_back(XMLNS(_key.c_str(), name));
104     // update xml string
105     XMLNS& xmlns = m_nsout.back();
106     if (m_xmlstring.empty())
107       m_xmlstring.assign(" ");
108     if (xmlns.key.empty())
109       m_xmlstring.append("xmlns");
110     else
111       m_xmlstring.append("xmlns:").append(xmlns.key);
112     m_xmlstring.append("=\"").append(xmlns.name).append("\" ");
113   }
114 }
115 
KeyForName(const char * name)116 const char* XMLDict::KeyForName(const char* name)
117 {
118   XMLNSList::iterator it;
119   for (it = m_nsout.begin(); it != m_nsout.end(); ++it)
120     if (it->name.compare(name) == 0)
121       return it->key.c_str();
122   return 0;
123 }
124 
TranslateQName(const XMLNames & names,const char * qname)125 std::string XMLDict::TranslateQName(const XMLNames& names, const char* qname)
126 {
127   unsigned l = 0;
128   const char* n = qname;
129   const char* p = qname;
130   while (*p != ZERO)
131     if (*(++p) == ':')
132     {
133       l = p - qname;
134       n = p + 1;
135       break;
136     }
137   std::string prefix(qname, l);
138   const XMLNS* in = names.FindKey(prefix.c_str());
139   if (in)
140   {
141     XMLNSList::const_iterator it;
142     for (it = m_nsout.begin(); it != m_nsout.end(); ++it)
143       if (it->name.compare(in->name) == 0)
144       {
145         if (it->key.empty())
146           return std::string(n); // return local name without qualifier
147         return std::string(it->key).append(":").append(n);
148       }
149   }
150   // cannot translate qualified name
151   return std::string(qname);
152 }
153 
FindKey(const char * key)154 XMLNS* XMLDict::FindKey(const char* key)
155 {
156   XMLNSList::iterator it;
157   for (it = m_nsout.begin(); it != m_nsout.end(); ++it)
158     if (it->key.compare(key) == 0)
159       return &(*it);
160   return 0;
161 }
162 
163 ///////////////////////////////////////////////////////////////////////////////
164 ////
165 //// XMLNames
166 ////
167 
AddXMLNS(const tinyxml2::XMLElement * e)168 void XMLNames::AddXMLNS(const tinyxml2::XMLElement* e)
169 {
170   const tinyxml2::XMLAttribute* attr = e->FirstAttribute();
171   while (attr)
172   {
173     const char* key = 0;
174     if (XMLNS::PrefixEqual(attr->Name(), "xmlns"))
175       key = XMLNS::LocalName(attr->Name());
176     else if (XMLNS::NameEqual(attr->Name(), "xmlns"))
177       key = "";
178     if (key)
179       AddXMLNS(key, attr->Value());
180     attr = attr->Next();
181   }
182 }
183 
AddXMLNS(const char * key,const char * name)184 void XMLNames::AddXMLNS(const char* key, const char* name)
185 {
186   XMLNS* ns = FindKey(key);
187   if (ns)
188     ns->name.assign(name);
189   else
190     m_names.push_back(XMLNS(key, name));
191 }
192 
FindKey(const char * key)193 XMLNS* XMLNames::FindKey(const char* key)
194 {
195   XMLNSList::iterator it;
196   for (it = m_names.begin(); it != m_names.end(); ++it)
197     if (it->key.compare(key) == 0)
198       return &(*it);
199   return 0;
200 }
201 
FindKey(const char * key) const202 const XMLNS* XMLNames::FindKey(const char* key) const
203 {
204   XMLNSList::const_iterator it;
205   for (it = m_names.begin(); it != m_names.end(); ++it)
206     if (it->key.compare(key) == 0)
207       return &(*it);
208   return 0;
209 }
210 
FindName(const char * name)211 XMLNS* XMLNames::FindName(const char* name)
212 {
213   XMLNSList::iterator it;
214   for (it = m_names.begin(); it != m_names.end(); ++it)
215     if (it->name.compare(name) == 0)
216       return &(*it);
217   return 0;
218 }
219 
FindName(const char * name) const220 const XMLNS* XMLNames::FindName(const char* name) const
221 {
222   XMLNSList::const_iterator it;
223   for (it = m_names.begin(); it != m_names.end(); ++it)
224     if (it->name.compare(name) == 0)
225       return &(*it);
226   return 0;
227 }
228