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,11 +362,7 @@ _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
- CF_RETURNS_RETAINED CFStringRef _CFXMLNodeURI (_CFXMLNodePtr node ) {
365
+ CFStringRef _CFXMLNodeCopyURI (_CFXMLNodePtr node ) {
368
366
xmlNodePtr nodePtr = (xmlNodePtr )node ;
369
367
switch (nodePtr -> type ) {
370
368
case XML_ATTRIBUTE_NODE :
@@ -447,15 +445,51 @@ 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
+ CFStringRef _Nullable _CFXMLNodeCopyName (_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 ) {
455
489
xmlNodeSetName (node , (const xmlChar * )name );
456
490
}
457
491
458
- CFStringRef _CFXMLNodeGetContent (_CFXMLNodePtr node ) {
492
+ CFStringRef _CFXMLNodeCopyContent (_CFXMLNodePtr node ) {
459
493
switch (((xmlNodePtr )node )-> type ) {
460
494
case XML_ELEMENT_DECL :
461
495
{
@@ -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 (">" ));
@@ -647,7 +681,7 @@ void _CFXMLDocSetRootElement(_CFXMLDocPtr doc, _CFXMLNodePtr node) {
647
681
xmlDocSetRootElement (doc , node );
648
682
}
649
683
650
- CF_RETURNS_RETAINED CFStringRef _CFXMLDocCharacterEncoding (_CFXMLDocPtr doc ) {
684
+ CFStringRef _CFXMLDocCopyCharacterEncoding (_CFXMLDocPtr doc ) {
651
685
return CFStringCreateWithCString (NULL , (const char * )((xmlDocPtr )doc )-> encoding , kCFStringEncodingUTF8 );
652
686
}
653
687
@@ -661,7 +695,7 @@ void _CFXMLDocSetCharacterEncoding(_CFXMLDocPtr doc, const unsigned char* _Null
661
695
docPtr -> encoding = xmlStrdup (encoding );
662
696
}
663
697
664
- CF_RETURNS_RETAINED CFStringRef _CFXMLDocVersion (_CFXMLDocPtr doc ) {
698
+ CFStringRef _CFXMLDocCopyVersion (_CFXMLDocPtr doc ) {
665
699
return CFStringCreateWithCString (NULL , (const char * )((xmlDocPtr )doc )-> version , kCFStringEncodingUTF8 );
666
700
}
667
701
@@ -748,7 +782,7 @@ _CFXMLEntityPtr _CFXMLGetParameterEntity(_CFXMLDocPtr doc, const char* entity) {
748
782
return xmlGetParameterEntity (doc , (const xmlChar * )entity );
749
783
}
750
784
751
- CFStringRef _CFXMLGetEntityContent (_CFXMLEntityPtr entity ) {
785
+ CFStringRef _CFXMLCopyEntityContent (_CFXMLEntityPtr entity ) {
752
786
const xmlChar * content = ((xmlEntityPtr )entity )-> content ;
753
787
if (!content ) {
754
788
return NULL ;
@@ -760,7 +794,7 @@ CFStringRef _CFXMLGetEntityContent(_CFXMLEntityPtr entity) {
760
794
return result ;
761
795
}
762
796
763
- CFStringRef _CFXMLStringWithOptions (_CFXMLNodePtr node , uint32_t options ) {
797
+ CFStringRef _CFXMLCopyStringWithOptions (_CFXMLNodePtr node , uint32_t options ) {
764
798
if (((xmlNodePtr )node )-> type == XML_ENTITY_DECL &&
765
799
((xmlEntityPtr )node )-> etype == XML_INTERNAL_PREDEFINED_ENTITY ) {
766
800
// predefined entities need special handling, libxml2 just tosses an error and returns a NULL string
@@ -832,17 +866,26 @@ CFStringRef _CFXMLStringWithOptions(_CFXMLNodePtr node, uint32_t options) {
832
866
return result ;
833
867
}
834
868
835
- CF_RETURNS_RETAINED CFArrayRef _CFXMLNodesForXPath (_CFXMLNodePtr node , const unsigned char * xpath ) {
869
+ CFArrayRef _CFXMLNodesForXPath (_CFXMLNodePtr node , const unsigned char * xpath ) {
836
870
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
+ CFStringRef _Nullable _CFXMLCopyPathForNode (_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
- CF_RETURNS_RETAINED CFStringRef _CFXMLNodeLocalName (_CFXMLNodePtr node ) {
884
- int length = 0 ;
885
- const xmlChar * result = xmlSplitQName3 (((xmlNodePtr )node )-> name , & length );
936
+ CFStringRef _CFXMLNodeCopyLocalName (_CFXMLNodePtr node ) {
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
- CF_RETURNS_RETAINED CFStringRef _CFXMLNodePrefix (_CFXMLNodePtr node ) {
946
+ CFStringRef _CFXMLNodeCopyPrefix (_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 );
@@ -983,7 +1040,7 @@ _CFXMLDTDPtr _Nullable _CFXMLParseDTDFromData(CFDataRef data, CFErrorRef _Nullab
983
1040
return dtd ;
984
1041
}
985
1042
986
- CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDExternalID (_CFXMLDTDPtr dtd ) {
1043
+ CFStringRef _Nullable _CFXMLDTDCopyExternalID (_CFXMLDTDPtr dtd ) {
987
1044
const unsigned char * externalID = ((xmlDtdPtr )dtd )-> ExternalID ;
988
1045
if (externalID ) {
989
1046
return CFStringCreateWithCString (NULL , (const char * )externalID , kCFStringEncodingUTF8 );
@@ -1008,7 +1065,7 @@ void _CFXMLDTDSetExternalID(_CFXMLDTDPtr dtd, const unsigned char* externalID) {
1008
1065
dtdPtr -> ExternalID = xmlStrdup (externalID );
1009
1066
}
1010
1067
1011
- CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDSystemID (_CFXMLDTDPtr dtd ) {
1068
+ CFStringRef _Nullable _CFXMLDTDCopySystemID (_CFXMLDTDPtr dtd ) {
1012
1069
const unsigned char * systemID = ((xmlDtdPtr )dtd )-> SystemID ;
1013
1070
if (systemID ) {
1014
1071
return CFStringCreateWithCString (NULL , (const char * )systemID , kCFStringEncodingUTF8 );
@@ -1095,7 +1152,7 @@ CFIndex _CFXMLDTDAttributeNodeGetType(_CFXMLDTDNodePtr node) {
1095
1152
return ((xmlAttributePtr )node )-> atype ;
1096
1153
}
1097
1154
1098
- CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDNodeGetSystemID (_CFXMLDTDNodePtr node ) {
1155
+ CFStringRef _Nullable _CFXMLDTDNodeCopySystemID (_CFXMLDTDNodePtr node ) {
1099
1156
switch (((xmlNodePtr )node )-> type ) {
1100
1157
case XML_ENTITY_DECL :
1101
1158
return CFStringCreateWithCString (NULL , (const char * )((xmlEntityPtr )node )-> SystemID , kCFStringEncodingUTF8 );
@@ -1137,7 +1194,7 @@ void _CFXMLDTDNodeSetSystemID(_CFXMLDTDNodePtr node, const unsigned char* system
1137
1194
}
1138
1195
}
1139
1196
1140
- CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDNodeGetPublicID (_CFXMLDTDNodePtr node ) {
1197
+ CFStringRef _Nullable _CFXMLDTDNodeCopyPublicID (_CFXMLDTDNodePtr node ) {
1141
1198
switch (((xmlNodePtr )node )-> type ) {
1142
1199
case XML_ENTITY_DECL :
1143
1200
return CFStringCreateWithCString (NULL , (const char * )((xmlEntityPtr )node )-> ExternalID , kCFStringEncodingUTF8 );
@@ -1179,6 +1236,131 @@ void _CFXMLDTDNodeSetPublicID(_CFXMLDTDNodePtr node, const unsigned char* public
1179
1236
}
1180
1237
}
1181
1238
1239
+ // Namespaces
1240
+ _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
+ CFStringRef _Nullable _CFXMLNamespaceCopyValue (_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
+ CFStringRef _Nullable _CFXMLNamespaceCopyPrefix (_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