20
20
#include <libxml/xmlmemory.h>
21
21
#include <libxml/xmlsave.h>
22
22
#include <libxml/xpath.h>
23
+ #include <libxml/xpathInternals.h>
23
24
#include <libxml/dict.h>
24
25
#include "CFInternal.h"
25
26
@@ -57,6 +58,7 @@ CFIndex _kCFXMLTypeElement = XML_ELEMENT_NODE;
57
58
CFIndex _kCFXMLTypeAttribute = XML_ATTRIBUTE_NODE ;
58
59
CFIndex _kCFXMLTypeDTD = XML_DTD_NODE ;
59
60
CFIndex _kCFXMLDocTypeHTML = XML_DOC_HTML ;
61
+ CFIndex _kCFXMLTypeNamespace = 22 ; // libxml2 does not define namespaces as nodes, so we have to fake it
60
62
61
63
CFIndex _kCFXMLDTDNodeTypeEntity = XML_ENTITY_DECL ;
62
64
CFIndex _kCFXMLDTDNodeTypeAttribute = XML_ATTRIBUTE_DECL ;
@@ -360,10 +362,6 @@ _CFXMLNodePtr _CFXMLNewProperty(_CFXMLNodePtr node, const unsigned char* name, c
360
362
return xmlNewProp (node , name , value );
361
363
}
362
364
363
- _CFXMLNamespacePtr _CFXMLNewNamespace (_CFXMLNodePtr node , const unsigned char * uri , const unsigned char * prefix ) {
364
- return xmlNewNs (node , uri , prefix );
365
- }
366
-
367
365
CF_RETURNS_RETAINED CFStringRef _CFXMLNodeURI (_CFXMLNodePtr node ) {
368
366
xmlNodePtr nodePtr = (xmlNodePtr )node ;
369
367
switch (nodePtr -> type ) {
@@ -447,8 +445,44 @@ CFIndex _CFXMLNodeGetType(_CFXMLNodePtr node) {
447
445
return ((xmlNodePtr )node )-> type ;
448
446
}
449
447
450
- const char * _CFXMLNodeGetName (_CFXMLNodePtr node ) {
451
- return (const char * )(((xmlNodePtr )node )-> name );
448
+ static inline xmlChar * _getQName (xmlNodePtr node ) {
449
+ const xmlChar * prefix = NULL ;
450
+ const xmlChar * ncname = node -> name ;
451
+
452
+ switch (node -> type ) {
453
+ case XML_NOTATION_NODE :
454
+ case XML_DTD_NODE :
455
+ case XML_ELEMENT_DECL :
456
+ case XML_ATTRIBUTE_DECL :
457
+ case XML_ENTITY_DECL :
458
+ case XML_NAMESPACE_DECL :
459
+ case XML_XINCLUDE_START :
460
+ case XML_XINCLUDE_END :
461
+ break ;
462
+
463
+ default :
464
+ if (node -> ns != NULL ) {
465
+ prefix = node -> ns -> prefix ;
466
+ }
467
+ }
468
+
469
+ return xmlBuildQName (ncname , prefix , NULL , 0 );
470
+ }
471
+
472
+ CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLNodeGetName (_CFXMLNodePtr node ) {
473
+ xmlNodePtr xmlNode = (xmlNodePtr )node ;
474
+
475
+ xmlChar * qName = _getQName (xmlNode );
476
+
477
+ if (qName != NULL ) {
478
+ CFStringRef result = CFStringCreateWithCString (NULL , (const char * )qName , kCFStringEncodingUTF8 );
479
+ if (qName != xmlNode -> name ) {
480
+ xmlFree (qName );
481
+ }
482
+ return result ;
483
+ } else {
484
+ return NULL ;
485
+ }
452
486
}
453
487
454
488
void _CFXMLNodeSetName (_CFXMLNodePtr node , const char * name ) {
@@ -497,7 +531,7 @@ void _CFXMLNodeSetContent(_CFXMLNodePtr node, const unsigned char* _Nullable co
497
531
// xmlElementContent structures, let's leverage what we've already got.
498
532
CFMutableStringRef xmlString = CFStringCreateMutable (NULL , 0 );
499
533
CFStringAppend (xmlString , CFSTR ("<!ELEMENT " ));
500
- CFStringAppendCString (xmlString , _CFXMLNodeGetName ( node ) , kCFStringEncodingUTF8 );
534
+ CFStringAppendCString (xmlString , ( const char * ) element -> name , kCFStringEncodingUTF8 );
501
535
CFStringAppend (xmlString , CFSTR (" " ));
502
536
CFStringAppendCString (xmlString , (const char * )content , kCFStringEncodingUTF8 );
503
537
CFStringAppend (xmlString , CFSTR (">" ));
@@ -837,12 +871,21 @@ CF_RETURNS_RETAINED CFArrayRef _CFXMLNodesForXPath(_CFXMLNodePtr node, const uns
837
871
if (((xmlNodePtr )node )-> doc == NULL ) {
838
872
return NULL ;
839
873
}
840
-
874
+
875
+ if (((xmlNodePtr )node )-> type == XML_DOCUMENT_NODE ) {
876
+ node = ((xmlDocPtr )node )-> children ;
877
+ }
878
+
841
879
xmlXPathContextPtr context = xmlXPathNewContext (((xmlNodePtr )node )-> doc );
880
+ xmlNsPtr ns = ((xmlNodePtr )node )-> ns ;
881
+ while (ns != NULL ) {
882
+ xmlXPathRegisterNs (context , ns -> prefix , ns -> href );
883
+ ns = ns -> next ;
884
+ }
842
885
xmlXPathObjectPtr evalResult = xmlXPathNodeEval (node , xpath , context );
843
886
844
887
xmlNodeSetPtr nodes = evalResult -> nodesetval ;
845
-
888
+
846
889
int count = nodes -> nodeNr ;
847
890
848
891
CFMutableArrayRef results = CFArrayCreateMutable (NULL , count , NULL );
@@ -856,8 +899,15 @@ CF_RETURNS_RETAINED CFArrayRef _CFXMLNodesForXPath(_CFXMLNodePtr node, const uns
856
899
return results ;
857
900
}
858
901
859
- _CFXMLNodePtr _CFXMLNodeHasProp (_CFXMLNodePtr node , const unsigned char * propertyName ) {
860
- return xmlHasProp (node , propertyName );
902
+ CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLPathForNode (_CFXMLNodePtr node ) {
903
+ xmlChar * path = xmlGetNodePath (node );
904
+ CFStringRef result = CFStringCreateWithCString (NULL , (const char * )path , kCFStringEncodingUTF8 );
905
+ xmlFree (path );
906
+ return result ;
907
+ }
908
+
909
+ _CFXMLNodePtr _CFXMLNodeHasProp (_CFXMLNodePtr node , const char * propertyName ) {
910
+ return xmlHasProp (node , (const xmlChar * )propertyName );
861
911
}
862
912
863
913
_CFXMLDocPtr _CFXMLDocPtrFromDataWithOptions (CFDataRef data , int options ) {
@@ -876,19 +926,26 @@ _CFXMLDocPtr _CFXMLDocPtrFromDataWithOptions(CFDataRef data, int options) {
876
926
if (options & _kCFXMLNodeLoadExternalEntitiesAlways ) {
877
927
xmlOptions |= XML_PARSE_DTDLOAD ;
878
928
}
879
-
929
+
930
+ xmlOptions |= XML_PARSE_RECOVER ;
931
+ xmlOptions |= XML_PARSE_NSCLEAN ;
932
+
880
933
return xmlReadMemory ((const char * )CFDataGetBytePtr (data ), CFDataGetLength (data ), NULL , NULL , xmlOptions );
881
934
}
882
935
883
936
CF_RETURNS_RETAINED CFStringRef _CFXMLNodeLocalName (_CFXMLNodePtr node ) {
884
- int length = 0 ;
885
- const xmlChar * result = xmlSplitQName3 (((xmlNodePtr )node )-> name , & length );
937
+ xmlChar * prefix = NULL ;
938
+ const xmlChar * result = xmlSplitQName2 (_getQName ((xmlNodePtr )node ), & prefix );
939
+ if (result == NULL ) {
940
+ result = ((xmlNodePtr )node )-> name ;
941
+ }
942
+
886
943
return CFStringCreateWithCString (NULL , (const char * )result , kCFStringEncodingUTF8 );
887
944
}
888
945
889
946
CF_RETURNS_RETAINED CFStringRef _CFXMLNodePrefix (_CFXMLNodePtr node ) {
890
947
xmlChar * result = NULL ;
891
- xmlChar * unused = xmlSplitQName2 (((xmlNodePtr )node )-> name , & result );
948
+ xmlChar * unused = xmlSplitQName2 (_getQName ((xmlNodePtr )node ), & result );
892
949
893
950
CFStringRef resultString = CFStringCreateWithCString (NULL , (const char * )result , kCFStringEncodingUTF8 );
894
951
xmlFree (result );
@@ -1179,6 +1236,131 @@ void _CFXMLDTDNodeSetPublicID(_CFXMLDTDNodePtr node, const unsigned char* public
1179
1236
}
1180
1237
}
1181
1238
1239
+ // Namespaces
1240
+ CF_RETURNS_RETAINED _CFXMLNodePtr _Nonnull * _Nullable _CFXMLNamespaces (_CFXMLNodePtr node , CFIndex * count ) {
1241
+ * count = 0 ;
1242
+ xmlNs * ns = ((xmlNode * )node )-> ns ;
1243
+ while (ns != NULL ) {
1244
+ (* count )++ ;
1245
+ ns = ns -> next ;
1246
+ }
1247
+
1248
+ _CFXMLNodePtr * result = calloc (* count , sizeof (_CFXMLNodePtr ));
1249
+ ns = ((xmlNode * )node )-> ns ;
1250
+ for (int i = 0 ; i < * count ; i ++ ) {
1251
+ xmlNode * temp = xmlNewNode (ns , (unsigned char * )"" );
1252
+
1253
+ temp -> type = _kCFXMLTypeNamespace ;
1254
+ result [i ] = temp ;
1255
+ ns = ns -> next ;
1256
+ }
1257
+ return result ;
1258
+ }
1259
+
1260
+ static inline void _removeAllNamespaces (xmlNodePtr node );
1261
+ static inline void _removeAllNamespaces (xmlNodePtr node ) {
1262
+ xmlNsPtr ns = node -> ns ;
1263
+ if (ns != NULL ) {
1264
+ xmlFreeNsList (ns );
1265
+ node -> ns = NULL ;
1266
+ }
1267
+ }
1268
+
1269
+ void _CFXMLSetNamespaces (_CFXMLNodePtr node , _CFXMLNodePtr * _Nullable nodes , CFIndex count ) {
1270
+ _removeAllNamespaces (node );
1271
+
1272
+ if (nodes == NULL || count == 0 ) {
1273
+ return ;
1274
+ }
1275
+
1276
+ xmlNodePtr nsNode = (xmlNodePtr )nodes [0 ];
1277
+ ((xmlNodePtr )node )-> ns = xmlCopyNamespace (nsNode -> ns );
1278
+ xmlNsPtr currNs = ((xmlNodePtr )node )-> ns ;
1279
+ for (CFIndex i = 1 ; i < count ; i ++ ) {
1280
+ currNs -> next = xmlCopyNamespace (((xmlNodePtr )nodes [i ])-> ns );
1281
+ currNs = currNs -> next ;
1282
+ }
1283
+ }
1284
+
1285
+ CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLNamespaceGetValue (_CFXMLNodePtr node ) {
1286
+ xmlNsPtr ns = ((xmlNode * )node )-> ns ;
1287
+
1288
+ if (ns -> href == NULL ) {
1289
+ return NULL ;
1290
+ }
1291
+
1292
+ return CFStringCreateWithCString (NULL , (const char * )ns -> href , kCFStringEncodingUTF8 );
1293
+ }
1294
+
1295
+ void _CFXMLNamespaceSetValue (_CFXMLNodePtr node , const char * value , int64_t length ) {
1296
+ xmlNsPtr ns = ((xmlNodePtr )node )-> ns ;
1297
+ ns -> href = xmlStrndup ((const xmlChar * )value , length );
1298
+ }
1299
+
1300
+ CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLNamespaceGetPrefix (_CFXMLNodePtr node ) {
1301
+ xmlNsPtr ns = ((xmlNodePtr )node )-> ns ;
1302
+
1303
+ if (ns -> prefix == NULL ) {
1304
+ return NULL ;
1305
+ }
1306
+
1307
+ return CFStringCreateWithCString (NULL , (const char * )ns -> prefix , kCFStringEncodingUTF8 );
1308
+ }
1309
+
1310
+ void _CFXMLNamespaceSetPrefix (_CFXMLNodePtr node , const char * prefix , int64_t length ) {
1311
+ xmlNsPtr ns = ((xmlNodePtr )node )-> ns ;
1312
+
1313
+ ns -> prefix = xmlStrndup ((const xmlChar * )prefix , length );
1314
+ }
1315
+
1316
+ _CFXMLNodePtr _CFXMLNewNamespace (const char * name , const char * stringValue ) {
1317
+ xmlNsPtr ns = xmlNewNs (NULL , (const xmlChar * )stringValue , (const xmlChar * )name );
1318
+ xmlNodePtr node = xmlNewNode (ns , (const xmlChar * )"" );
1319
+
1320
+ node -> type = _kCFXMLTypeNamespace ;
1321
+
1322
+ return node ;
1323
+ }
1324
+
1325
+ void _CFXMLAddNamespace (_CFXMLNodePtr node , _CFXMLNodePtr nsNode ) {
1326
+ xmlNodePtr nodePtr = (xmlNodePtr )node ;
1327
+ xmlNsPtr ns = xmlCopyNamespace (((xmlNodePtr )nsNode )-> ns );
1328
+ ns -> context = nodePtr -> doc ;
1329
+
1330
+ xmlNsPtr currNs = nodePtr -> ns ;
1331
+ if (currNs == NULL ) {
1332
+ nodePtr -> ns = ns ;
1333
+ return ;
1334
+ }
1335
+
1336
+ while (currNs -> next != NULL ) {
1337
+ currNs = currNs -> next ;
1338
+ }
1339
+
1340
+ currNs -> next = ns ;
1341
+ }
1342
+
1343
+ void _CFXMLRemoveNamespace (_CFXMLNodePtr node , const char * prefix ) {
1344
+ xmlNodePtr nodePtr = (xmlNodePtr )node ;
1345
+ xmlNsPtr ns = nodePtr -> ns ;
1346
+ if (ns != NULL && xmlStrcmp ((const xmlChar * )prefix , ns -> prefix ) == 0 ) {
1347
+ nodePtr -> ns = ns -> next ;
1348
+ xmlFreeNs (ns );
1349
+ return ;
1350
+ }
1351
+
1352
+ while (ns -> next != NULL ) {
1353
+ if (xmlStrcmp (ns -> next -> prefix , (const xmlChar * )prefix ) == 0 ) {
1354
+ xmlNsPtr next = ns -> next ;
1355
+ ns -> next = ns -> next -> next ;
1356
+ xmlFreeNs (next );
1357
+ return ;
1358
+ }
1359
+
1360
+ ns = ns -> next ;
1361
+ }
1362
+ }
1363
+
1182
1364
void _CFXMLFreeNode (_CFXMLNodePtr node ) {
1183
1365
if (!node ) {
1184
1366
return ;
@@ -1231,6 +1413,13 @@ void _CFXMLFreeNode(_CFXMLNodePtr node) {
1231
1413
}
1232
1414
1233
1415
default :
1416
+ // we first need to check if this node is one of our custom
1417
+ // namespace nodes, which don't actually exist in libxml2
1418
+ if (((xmlNodePtr )node )-> type == _kCFXMLTypeNamespace ) {
1419
+ // resetting its type to XML_ELEMENT_NODE will cause the enclosed namespace
1420
+ // to be properly freed by libxml2
1421
+ ((xmlNodePtr )node )-> type = XML_ELEMENT_NODE ;
1422
+ }
1234
1423
xmlFreeNode (node );
1235
1424
}
1236
1425
}
0 commit comments