10 #define NS_CHAR_SEPARATOR '>'
14 const XML_Char
**elements
; /* NULL terminated array of elements */
18 int depth
; /* Current parser depth, root element is 0 */
19 int element_depth
; /* elements[element_depth] we are in,
20 -1 if we are not in any (root mismatch)*/
24 /* Check for expat compile-time configuration
25 * @current_version is static string describing current expat version */
26 _hidden isds_error
_isds_init_expat(const char **current_version
) {
27 XML_Expat_Version current
;
28 const int min_major
= 2;
29 const int min_minor
= 0;
30 const int min_micro
= 0;
31 const XML_Feature
*features
; /* Static array stored in expat BSS */
32 _Bool ns_supported
= 0;
34 if (current_version
) *current_version
= XML_ExpatVersion();
37 * Max(XML_Size) <= Max(size_t)
38 * XML_Char is char, not a wchar_t
39 * XML_UNICODE is undefined (i.e. strings in UTF-8)
42 /* Check minimal expat version */
43 current
= XML_ExpatVersionInfo();
44 if ( (current
.major
< min_major
) ||
45 (current
.major
== min_major
&& current
.minor
< min_minor
) ||
46 (current
.major
== min_major
&& current
.minor
== min_minor
&&
47 current
.micro
< min_micro
) ) {
48 isds_log(ILF_ISDS
, ILL_CRIT
,
49 _("Minimal %d.%d.%d Expat version required. "
50 "Current version is %d.%d.%d\n"),
51 min_major
, min_minor
, min_micro
,
52 current
.major
, current
.minor
, current
.micro
);
56 /* XML_Char must be char, not a wchar_t */
57 features
= XML_GetFeatureList();
58 while (features
->feature
!= XML_FEATURE_END
) {
59 switch (features
->feature
) {
60 case XML_FEATURE_UNICODE_WCHAR_T
:
61 case XML_FEATURE_UNICODE
:
62 isds_log(ILF_ISDS
, ILL_CRIT
,
63 _("Expat compiled with UTF-16 (wide) characters\n"));
66 case XML_FEATURE_SIZEOF_XML_CHAR
:
67 if (features
->value
!= sizeof(char)) {
68 isds_log(ILF_ISDS
, ILL_CRIT
,
69 "Expat compiled with XML_Chars incompatible "
83 isds_log(ILF_ISDS
, ILL_CRIT
,
84 _("Expat not compiled with name space support\n"));
92 /* Breaks element path address into NULL terminated array of elements in
93 * preserved order. Zeroth array element will be first path element.
94 * @path element address, content will be damaged
95 * @return array of elements, NULL in case of error */
96 static const XML_Char
**path2elements(XML_Char
*path
) {
97 const XML_Char
**elements
= NULL
;
101 unsigned int depth
= 0;
103 if (!path
) return NULL
;
105 elements
= malloc(sizeof(elements
[0]) * (strlen(path
) + 1));
106 if (!elements
) return NULL
;
111 while ((element
= (XML_Char
*) strtok_r(tmp_path
,
112 PHYSXML_ELEMENT_SEPARATOR
, &saveptr
))) {
114 elements
[depth
++] = element
;
117 elements
[depth
] = NULL
;
122 /* Examine start and empty element tag.
123 * @name is expanded name */
124 static void XMLCALL
element_start(void *userData
, const XML_Char
*name
,
125 const XML_Char
**atts
) {
126 struct expat_data
*data
= (struct expat_data
*) userData
;
129 const XML_Index index
= XML_GetCurrentByteIndex(data
->parser
);
130 /* XXX: Because document length is stored as size_t, index always fits
132 const size_t boundary
= index
;
134 /* Silent warning about unused argument.
135 * This protype is expat's XML_StartElementHandler type. */
138 isds_log(ILF_XML
, ILL_DEBUG
, _("Start: name=%s, depth=%zd, offset=%#jx "
139 "=> boundary=%#zx\n"),
140 name
, data
->depth
, (uintmax_t)index
, boundary
);
142 if ((!data
->found
) &&
143 (data
->depth
== data
->element_depth
+ 1) &&
144 (!strcmp(data
->elements
[data
->element_depth
+ 1], name
))) {
145 data
->element_depth
++;
147 isds_log(ILF_XML
, ILL_DEBUG
,
148 _("\tStart tag for element `%s' found\n"),
149 data
->elements
[data
->element_depth
]);
151 if (!data
->elements
[data
->element_depth
+ 1]) {
153 *data
->start
= boundary
;
159 /* Examine end and empty element tag.
160 * @name is expanded name */
161 static void XMLCALL
element_end(void *userData
, const XML_Char
*name
) {
163 struct expat_data
*data
= (struct expat_data
*) userData
;
164 enum XML_Status xerr
;
166 const XML_Index index
= (uintmax_t) XML_GetCurrentByteIndex(data
->parser
);
167 const int count
= XML_GetCurrentByteCount(data
->parser
);
168 /* XXX: Because document length is stored as size_t, index + count always
170 const size_t boundary
= index
+ count
- 1;
172 isds_log(ILF_XML
, ILL_DEBUG
, _("End: name=%s, depth=%zd, offset=%#jx "
173 "count=%u => boundary=%#zx\n"),
174 name
, data
->depth
, (uintmax_t)index
, count
, boundary
);
176 if (data
->element_depth
== data
->depth
) {
178 isds_log(ILF_XML
, ILL_DEBUG
,
179 _("\tEnd tag for element `%s' found\n"),
180 data
->elements
[data
->element_depth
]);
181 *data
->end
= boundary
;
183 /* Here we can stop parser
184 * XXX: requires Expat 1.95.8 */
185 xerr
= XML_StopParser(data
->parser
, XML_FALSE
);
186 if (xerr
!= XML_STATUS_OK
) {
187 PANIC("Error while stopping parser");
191 data
->element_depth
--;
198 /* Locate element specified by element path in XML stream.
199 * TODO: Support other encodings than UTF-8
200 * @document is XML document as bit stream
201 * @length is size of @document in bytes. Zero length is forbidden.
202 * @path is special path (e.g. "|html|head|title",
203 * qualified element names are specified as
204 * NSURI '>' LOCALNAME, ommit NSURI and '>' separator if no namespace
205 * should be addressed (i.e. use only locale name)
206 * You can use PHYSXML_ELEMENT_SEPARATOR and PHYSXML_NS_SEPARATOR string
208 * @start outputs start of the element location in @document (inclusive,
210 * @end outputs end of element (inclusive, counts from 0)
211 * @return 0 if element found */
212 _hidden isds_error
_isds_find_element_boundary(void *document
, size_t length
,
213 char *path
, size_t *start
, size_t *end
) {
216 enum XML_Status xerr
;
217 struct expat_data user_data
;
219 if (!document
|| !path
|| !start
|| !end
|| length
<= 0)
222 isds_log(ILF_XML
, ILL_DEBUG
, _("Searching boundary of element: %s\n"),
226 user_data
.elements
= path2elements(path
);
227 if (!user_data
.elements
) return IE_NOMEM
;
229 /* No element means whole document */
230 if (!user_data
.elements
[0]) {
231 free(user_data
.elements
);
238 parser
= XML_ParserCreateNS(NULL
, NS_CHAR_SEPARATOR
);
240 XML_SetStartElementHandler(parser
, element_start
);
241 XML_SetEndElementHandler(parser
, element_end
);
243 user_data
.parser
= parser
;
245 user_data
.start
= start
;
247 user_data
.depth
= -1;
248 user_data
.element_depth
= -1;
249 XML_SetUserData(parser
, &user_data
);
252 xerr
= XML_Parse(parser
, (const char *) document
, length
, 1);
253 if (xerr
!= XML_STATUS_OK
&&
254 !( (xerr
== XML_STATUS_ERROR
&&
255 XML_GetErrorCode(parser
) == XML_ERROR_ABORTED
))) {
256 free(user_data
.elements
);
257 isds_log(ILF_ISDS
, ILL_CRIT
, _("XML_Parse failed\n"));
260 free(user_data
.elements
);
262 XML_ParserFree(parser
);
263 if (user_data
.found
) return IE_SUCCESS
;
264 else return IE_NOEXIST
;