20
20
#if HAVE_LIBXML && HAVE_XML
21
21
#include "expat_compat.h"
22
22
23
+ typedef struct _php_xml_ns {
24
+ xmlNsPtr nsptr ;
25
+ int ref_count ;
26
+ void * next ;
27
+ void * prev ;
28
+ } php_xml_ns ;
29
+
23
30
#ifdef LIBXML_EXPAT_COMPAT
24
31
25
32
#define IS_NS_DECL (__ns ) \
@@ -34,51 +41,111 @@ _find_namespace_decl(XML_Parser parser, const xmlChar *tagname, const xmlChar **
34
41
xmlChar * value ;
35
42
xmlChar * partial ;
36
43
xmlChar * namespace ;
44
+ php_xml_ns * cur_ns_scope = NULL ;
45
+ php_xml_ns * exist_ns_scope ;
46
+ xmlNsPtr nsptr , curnsptr ;
47
+
48
+ exist_ns_scope = xmlHashLookup (parser -> _reverse_ns_map , tagname );
49
+
50
+ if (exist_ns_scope ) {
51
+ while (exist_ns_scope -> next != NULL )
52
+ exist_ns_scope = exist_ns_scope -> next ;
53
+ }
37
54
38
55
while (attr_p && * attr_p ) {
39
56
name = attr_p [0 ];
40
57
value = xmlStrdup (attr_p [1 ]);
41
58
42
59
partial = xmlSplitQName (parser -> parser , name , & namespace );
60
+
43
61
if (IS_NS_DECL (namespace )) {
62
+
44
63
if (parser -> h_start_ns ) {
45
64
parser -> h_start_ns (parser -> user , partial , (const XML_Char * ) value );
46
65
}
47
- xmlHashAddEntry (parser -> _ns_map , partial , value );
48
- xmlHashAddEntry (parser -> _reverse_ns_map , tagname , xmlStrdup (partial ));
49
- break ;
66
+ if (xmlHashLookup (parser -> _ns_map , partial ) == NULL ) {
67
+ xmlHashAddEntry (parser -> _ns_map , partial , value );
68
+ } else {
69
+ xmlFree (value );
70
+ }
71
+
72
+ nsptr = (xmlNsPtr ) xmlMalloc (sizeof (xmlNs ));
73
+
74
+ if (nsptr ) {
75
+ memset (nsptr , 0 , sizeof (xmlNs ));
76
+ nsptr -> type = XML_LOCAL_NAMESPACE ;
77
+
78
+ if (value != NULL )
79
+ nsptr -> href = xmlStrdup (value );
80
+ if (partial != NULL )
81
+ nsptr -> prefix = xmlStrdup (partial );
82
+
83
+ if (cur_ns_scope == NULL ) {
84
+ cur_ns_scope = emalloc (sizeof (php_xml_ns ));
85
+ cur_ns_scope -> next = NULL ;
86
+ cur_ns_scope -> prev = NULL ;
87
+ cur_ns_scope -> nsptr = nsptr ;
88
+ cur_ns_scope -> ref_count = 0 ;
89
+
90
+ if (exist_ns_scope ) {
91
+ exist_ns_scope -> next = cur_ns_scope ;
92
+ cur_ns_scope -> prev = exist_ns_scope ;
93
+ } else {
94
+ xmlHashAddEntry (parser -> _reverse_ns_map , tagname , cur_ns_scope );
95
+ }
96
+
97
+ exist_ns_scope = cur_ns_scope ;
98
+ } else {
99
+ curnsptr = cur_ns_scope -> nsptr ;
100
+ while (curnsptr -> next != NULL ) {
101
+ curnsptr = curnsptr -> next ;
102
+ }
103
+ curnsptr -> next = nsptr ;
104
+ }
105
+ }
106
+
107
+ } else {
108
+ xmlFree (value );
109
+ }
110
+
111
+ xmlFree (partial );
112
+ if (namespace != NULL ) {
113
+ xmlFree (namespace );
50
114
}
51
115
52
- xmlFree (value );
53
116
attr_p += 2 ;
54
117
}
118
+
119
+ if (exist_ns_scope ) {
120
+ exist_ns_scope -> ref_count ++ ;
121
+ }
55
122
}
56
123
57
124
static void
58
125
_qualify_namespace (XML_Parser parser , const xmlChar * name , xmlChar * * qualified )
59
126
{
60
127
xmlChar * partial ;
61
128
xmlChar * namespace ;
62
- int len ;
63
129
64
130
partial = xmlSplitQName (parser -> parser , name , & namespace );
65
131
if (namespace ) {
66
132
xmlChar * nsvalue ;
67
133
68
134
nsvalue = xmlHashLookup (parser -> _ns_map , namespace );
69
135
if (nsvalue ) {
70
- len = strlen (nsvalue ) + strlen (partial ) + 1 ; /* colon */
71
- * qualified = malloc (len + 1 );
72
- memcpy (* qualified , nsvalue , strlen (nsvalue ));
73
- memcpy (* qualified + strlen (nsvalue ), ":" , 1 );
74
- memcpy (* qualified + strlen (nsvalue ) + 1 , partial , strlen (partial ));
75
- (* qualified )[len ] = '\0' ;
136
+ /* Use libxml functions otherwise its memory deallocation is screwed up */
137
+ * qualified = xmlStrdup (nsvalue );
138
+ * qualified = xmlStrncat (* qualified , parser -> _ns_seperator , 1 );
139
+ * qualified = xmlStrncat (* qualified , partial , strlen (partial ));
76
140
} else {
77
141
* qualified = xmlStrdup (name );
78
142
}
143
+ xmlFree (namespace );
79
144
} else {
80
145
* qualified = xmlStrdup (name );
81
146
}
147
+
148
+ xmlFree (partial );
82
149
}
83
150
84
151
static void
@@ -103,6 +170,15 @@ _start_element_handler(void *user, const xmlChar *name, const xmlChar **attribut
103
170
xmlFree (qualified_name );
104
171
}
105
172
173
+ static void
174
+ _namespace_handler (XML_Parser parser , xmlNsPtr nsptr )
175
+ {
176
+ if (nsptr != NULL ) {
177
+ _namespace_handler (parser , nsptr -> next );
178
+ parser -> h_end_ns (parser -> user , nsptr -> prefix );
179
+ }
180
+ }
181
+
106
182
static void
107
183
_end_element_handler (void * user , const xmlChar * name )
108
184
{
@@ -114,20 +190,40 @@ _end_element_handler(void *user, const xmlChar *name)
114
190
}
115
191
116
192
if (parser -> use_namespace ) {
117
- xmlChar * nsname ;
118
-
119
- nsname = xmlHashLookup (parser -> _reverse_ns_map , name );
120
- if (nsname && parser -> h_end_ns ) {
121
- parser -> h_end_ns (parser -> user , nsname );
122
- }
123
-
124
193
_qualify_namespace (parser , name , & qualified_name );
125
194
} else {
126
195
qualified_name = xmlStrdup (name );
127
196
}
128
197
129
198
parser -> h_end_element (parser -> user , (const XML_Char * ) qualified_name );
130
199
200
+ if (parser -> use_namespace ) {
201
+ int tag_counter ;
202
+ php_xml_ns * cur_ns_scope , * prev_ns_scope ;
203
+ xmlNsPtr nsptr ;
204
+
205
+ cur_ns_scope = xmlHashLookup (parser -> _reverse_ns_map , name );
206
+ if (cur_ns_scope ) {
207
+ while (cur_ns_scope -> next != NULL ) {
208
+ cur_ns_scope = cur_ns_scope -> next ;
209
+ }
210
+ tag_counter = -- cur_ns_scope -> ref_count ;
211
+ if (tag_counter == 0 ) {
212
+ nsptr = cur_ns_scope -> nsptr ;
213
+ if (nsptr && parser -> h_end_ns ) {
214
+ _namespace_handler (parser , nsptr );
215
+ }
216
+ xmlFreeNsList (nsptr );
217
+ cur_ns_scope -> nsptr = NULL ;
218
+ prev_ns_scope = cur_ns_scope -> prev ;
219
+ if (prev_ns_scope != NULL ) {
220
+ efree (cur_ns_scope );
221
+ prev_ns_scope -> next = NULL ;
222
+ }
223
+ }
224
+ }
225
+ }
226
+
131
227
xmlFree (qualified_name );
132
228
}
133
229
@@ -304,6 +400,8 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
304
400
parser = (XML_Parser ) emalloc (sizeof (struct _XML_Parser ));
305
401
memset (parser , 0 , sizeof (struct _XML_Parser ));
306
402
parser -> use_namespace = 0 ;
403
+ parser -> _ns_seperator = NULL ;
404
+
307
405
parser -> parser = xmlCreatePushParserCtxt ((xmlSAXHandlerPtr ) & php_xml_compat_handlers , (void * ) parser , NULL , 0 , NULL );
308
406
if (parser -> parser == NULL ) {
309
407
efree (parser );
@@ -318,6 +416,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
318
416
parser -> use_namespace = 1 ;
319
417
parser -> _ns_map = xmlHashCreate (10 );
320
418
parser -> _reverse_ns_map = xmlHashCreate (10 );
419
+ parser -> _ns_seperator = xmlStrdup (sep );
321
420
}
322
421
return parser ;
323
422
}
@@ -544,12 +643,32 @@ _free_ns_name(void *ptr, xmlChar *name)
544
643
xmlFree (ptr );
545
644
}
546
645
646
+ static void
647
+ _free_ns_pointer (void * ptr , xmlChar * name )
648
+ {
649
+ php_xml_ns * cur_ns_scope ;
650
+
651
+ /* Child scopes should already be removed, but in the event
652
+ of malformed xml, they may still be resident and need to be cleaned */
653
+ cur_ns_scope = ((php_xml_ns * ) ptr )-> next ;
654
+ if (cur_ns_scope != NULL ) {
655
+ _free_ns_pointer (cur_ns_scope , NULL );
656
+ }
657
+
658
+ xmlFreeNsList (((php_xml_ns * ) ptr )-> nsptr );
659
+
660
+ efree (ptr );
661
+ }
662
+
547
663
void
548
664
XML_ParserFree (XML_Parser parser )
549
665
{
550
666
if (parser -> use_namespace ) {
551
667
xmlHashFree (parser -> _ns_map , _free_ns_name );
552
- xmlHashFree (parser -> _reverse_ns_map , _free_ns_name );
668
+ xmlHashFree (parser -> _reverse_ns_map , _free_ns_pointer );
669
+ if (parser -> _ns_seperator ) {
670
+ xmlFree (parser -> _ns_seperator );
671
+ }
553
672
}
554
673
xmlFreeParserCtxt (parser -> parser );
555
674
efree (parser );
0 commit comments