1 #include "compare.hh"
2 #include "compareimpl.hh"
3 #include <sstream>
4 #include <iostream>
5 #include <assert.h>
6 #include <string.h>
7
8 using std::stringstream;
9
10 static int compare_elem(xmlNodePtr m, xmlNodePtr n, bool deep);
11 static int compare_content(xmlNodePtr m, xmlNodePtr n);
12 static int compare_pi(xmlNodePtr m, xmlNodePtr n);
13 static int compare_children(xmlNodePtr m, xmlNodePtr n);
14
15 // A wrapper around xmlGetProp/xmlGetNsProp. Must be passed a valid
16 // attribute (belonging to some node). Throws on error (never returns
17 // NULL); the returned value must be freed (by xmlFree).
18 static xmlChar *get_value(xmlAttrPtr a);
19
20 #if 0
21 #define TRACE(trace_arg) std::cerr << trace_arg << std::endl
22 #else
23 #define TRACE(trace_arg)
24 #endif
25
compare(xmlNodePtr m,xmlNodePtr n,bool deep)26 int compare(xmlNodePtr m, xmlNodePtr n, bool deep)
27 {
28 TRACE("enter compare");
29
30 assert(m);
31 assert(n);
32
33 int type = m->type - n->type;
34 if (type) {
35 return type;
36 }
37
38 switch (m->type) {
39 case XML_ELEMENT_NODE:
40 return compare_elem(m, n, deep);
41 case XML_TEXT_NODE:
42 case XML_COMMENT_NODE:
43 case XML_CDATA_SECTION_NODE:
44 return compare_content(m, n);
45 case XML_PI_NODE:
46 return compare_pi(m, n);
47 }
48
49 stringstream s;
50 s << "unsupported node type " << m->type;
51 throw s.str();
52 }
53
have_nulls(const void * p,const void * q,int & res)54 bool compareimpl::have_nulls(const void *p, const void *q, int &res)
55 {
56 if (!p) {
57 res = q ? -1 : 0;
58 return true;
59 }
60
61 if (!q) {
62 res = 1;
63 return true;
64 }
65
66 return false;
67 }
68
compare_ns(xmlNsPtr a,xmlNsPtr b)69 int compareimpl::compare_ns(xmlNsPtr a, xmlNsPtr b)
70 {
71 assert(a);
72 assert(b);
73 assert(a->href);
74 assert(b->href);
75
76 int href = strcmp(reinterpret_cast<const char *>(a->href),
77 reinterpret_cast<const char *>(b->href));
78 if (href) {
79 return href;
80 }
81
82 int res;
83 if (have_nulls(a->prefix, b->prefix, res)) {
84 return res;
85 } else {
86 return strcmp(reinterpret_cast<const char *>(a->prefix),
87 reinterpret_cast<const char *>(b->prefix));
88 }
89 }
90
compare_attr(xmlAttrPtr a,xmlAttrPtr b)91 int compareimpl::compare_attr(xmlAttrPtr a, xmlAttrPtr b)
92 {
93 int name = compareimpl::compare_name<xmlAttrPtr>(a, b);
94 if (name) {
95 return name;
96 }
97
98 xmlChar *v = get_value(a);
99 xmlChar *w = get_value(b);
100
101 int rv = strcmp(reinterpret_cast<char *>(v),
102 reinterpret_cast<char *>(w));
103
104 xmlFree(w);
105 xmlFree(v);
106
107 return rv;
108 }
109
compare_elem(xmlNodePtr m,xmlNodePtr n,bool deep)110 static int compare_elem(xmlNodePtr m, xmlNodePtr n, bool deep)
111 {
112 int name = compareimpl::compare_name<xmlNodePtr>(m, n);
113 if (name) {
114 return name;
115 }
116
117 int ns_def = compareimpl::compare_set<xmlNsPtr>(m->nsDef,
118 n->nsDef);
119 if (ns_def) {
120 return ns_def;
121 }
122
123 int properties = compareimpl::compare_set<xmlAttrPtr>(
124 m->properties,
125 n->properties);
126 if (properties) {
127 return properties;
128 }
129
130 return deep ? compare_children(m, n) : 0;
131 }
132
get_value(xmlAttrPtr a)133 static xmlChar *get_value(xmlAttrPtr a)
134 {
135 assert(a);
136 assert(a->parent);
137
138 xmlChar *out;
139
140 if (a->ns) {
141 assert(a->ns->href);
142 out = xmlGetNsProp(a->parent, a->name, a->ns->href);
143 } else {
144 out = xmlGetProp(a->parent, a->name);
145 }
146
147 if (!out) {
148 // should be pretty rare, but let's say an allocation might
149 // have failed
150 throw std::string("cannot get attribute value");
151 }
152
153 return out;
154 }
155
compare_pi(xmlNodePtr p,xmlNodePtr q)156 static int compare_pi(xmlNodePtr p, xmlNodePtr q)
157 {
158 assert(p->name);
159 assert(q->name);
160
161 int name = strcmp(reinterpret_cast<const char *>(p->name),
162 reinterpret_cast<const char *>(q->name));
163 if (name) {
164 return name;
165 }
166
167 return compare_content(p, q);
168 }
169
compare_content(xmlNodePtr m,xmlNodePtr n)170 static int compare_content(xmlNodePtr m, xmlNodePtr n)
171 {
172 int res;
173 if (compareimpl::have_nulls(m->content, n->content, res)) {
174 return res;
175 }
176
177 return strcmp(reinterpret_cast<char *>(m->content),
178 reinterpret_cast<char *>(n->content));
179 }
180
compare_children(xmlNodePtr m,xmlNodePtr n)181 static int compare_children(xmlNodePtr m, xmlNodePtr n)
182 {
183 xmlNodePtr mch = m->children;
184 xmlNodePtr nch = n->children;
185
186 while (mch && nch) {
187 int res = compare(mch, nch, true);
188 if (res) {
189 return res;
190 }
191
192 mch = mch->next;
193 nch = nch->next;
194 }
195
196 if (!mch) {
197 return nch ? -1 : 0;
198 } else {
199 assert(!nch);
200 return 1;
201 }
202 }
203
204