Skip to content

Commit ddcbfec

Browse files
authored
Merge pull request #1052 from rothomp3/master
2 parents 5ea6461 + 675e1cb commit ddcbfec

File tree

8 files changed

+505
-146
lines changed

8 files changed

+505
-146
lines changed

CoreFoundation/Parsing.subproj/CFXMLInterface.c

Lines changed: 217 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <libxml/xmlmemory.h>
2121
#include <libxml/xmlsave.h>
2222
#include <libxml/xpath.h>
23+
#include <libxml/xpathInternals.h>
2324
#include <libxml/dict.h>
2425
#include "CFInternal.h"
2526

@@ -57,6 +58,7 @@ CFIndex _kCFXMLTypeElement = XML_ELEMENT_NODE;
5758
CFIndex _kCFXMLTypeAttribute = XML_ATTRIBUTE_NODE;
5859
CFIndex _kCFXMLTypeDTD = XML_DTD_NODE;
5960
CFIndex _kCFXMLDocTypeHTML = XML_DOC_HTML;
61+
CFIndex _kCFXMLTypeNamespace = 22; // libxml2 does not define namespaces as nodes, so we have to fake it
6062

6163
CFIndex _kCFXMLDTDNodeTypeEntity = XML_ENTITY_DECL;
6264
CFIndex _kCFXMLDTDNodeTypeAttribute = XML_ATTRIBUTE_DECL;
@@ -360,11 +362,7 @@ _CFXMLNodePtr _CFXMLNewProperty(_CFXMLNodePtr node, const unsigned char* name, c
360362
return xmlNewProp(node, name, value);
361363
}
362364

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) {
368366
xmlNodePtr nodePtr = (xmlNodePtr)node;
369367
switch (nodePtr->type) {
370368
case XML_ATTRIBUTE_NODE:
@@ -447,15 +445,51 @@ CFIndex _CFXMLNodeGetType(_CFXMLNodePtr node) {
447445
return ((xmlNodePtr)node)->type;
448446
}
449447

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+
}
452486
}
453487

454488
void _CFXMLNodeSetName(_CFXMLNodePtr node, const char* name) {
455489
xmlNodeSetName(node, (const xmlChar*)name);
456490
}
457491

458-
CFStringRef _CFXMLNodeGetContent(_CFXMLNodePtr node) {
492+
CFStringRef _CFXMLNodeCopyContent(_CFXMLNodePtr node) {
459493
switch (((xmlNodePtr)node)->type) {
460494
case XML_ELEMENT_DECL:
461495
{
@@ -497,7 +531,7 @@ void _CFXMLNodeSetContent(_CFXMLNodePtr node, const unsigned char* _Nullable co
497531
// xmlElementContent structures, let's leverage what we've already got.
498532
CFMutableStringRef xmlString = CFStringCreateMutable(NULL, 0);
499533
CFStringAppend(xmlString, CFSTR("<!ELEMENT "));
500-
CFStringAppendCString(xmlString, _CFXMLNodeGetName(node), kCFStringEncodingUTF8);
534+
CFStringAppendCString(xmlString, (const char*)element->name, kCFStringEncodingUTF8);
501535
CFStringAppend(xmlString, CFSTR(" "));
502536
CFStringAppendCString(xmlString, (const char*)content, kCFStringEncodingUTF8);
503537
CFStringAppend(xmlString, CFSTR(">"));
@@ -647,7 +681,7 @@ void _CFXMLDocSetRootElement(_CFXMLDocPtr doc, _CFXMLNodePtr node) {
647681
xmlDocSetRootElement(doc, node);
648682
}
649683

650-
CF_RETURNS_RETAINED CFStringRef _CFXMLDocCharacterEncoding(_CFXMLDocPtr doc) {
684+
CFStringRef _CFXMLDocCopyCharacterEncoding(_CFXMLDocPtr doc) {
651685
return CFStringCreateWithCString(NULL, (const char*)((xmlDocPtr)doc)->encoding, kCFStringEncodingUTF8);
652686
}
653687

@@ -661,7 +695,7 @@ void _CFXMLDocSetCharacterEncoding(_CFXMLDocPtr doc, const unsigned char* _Null
661695
docPtr->encoding = xmlStrdup(encoding);
662696
}
663697

664-
CF_RETURNS_RETAINED CFStringRef _CFXMLDocVersion(_CFXMLDocPtr doc) {
698+
CFStringRef _CFXMLDocCopyVersion(_CFXMLDocPtr doc) {
665699
return CFStringCreateWithCString(NULL, (const char*)((xmlDocPtr)doc)->version, kCFStringEncodingUTF8);
666700
}
667701

@@ -748,7 +782,7 @@ _CFXMLEntityPtr _CFXMLGetParameterEntity(_CFXMLDocPtr doc, const char* entity) {
748782
return xmlGetParameterEntity(doc, (const xmlChar*)entity);
749783
}
750784

751-
CFStringRef _CFXMLGetEntityContent(_CFXMLEntityPtr entity) {
785+
CFStringRef _CFXMLCopyEntityContent(_CFXMLEntityPtr entity) {
752786
const xmlChar* content = ((xmlEntityPtr)entity)->content;
753787
if (!content) {
754788
return NULL;
@@ -760,7 +794,7 @@ CFStringRef _CFXMLGetEntityContent(_CFXMLEntityPtr entity) {
760794
return result;
761795
}
762796

763-
CFStringRef _CFXMLStringWithOptions(_CFXMLNodePtr node, uint32_t options) {
797+
CFStringRef _CFXMLCopyStringWithOptions(_CFXMLNodePtr node, uint32_t options) {
764798
if (((xmlNodePtr)node)->type == XML_ENTITY_DECL &&
765799
((xmlEntityPtr)node)->etype == XML_INTERNAL_PREDEFINED_ENTITY) {
766800
// 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) {
832866
return result;
833867
}
834868

835-
CF_RETURNS_RETAINED CFArrayRef _CFXMLNodesForXPath(_CFXMLNodePtr node, const unsigned char* xpath) {
869+
CFArrayRef _CFXMLNodesForXPath(_CFXMLNodePtr node, const unsigned char* xpath) {
836870

837871
if (((xmlNodePtr)node)->doc == NULL) {
838872
return NULL;
839873
}
840-
874+
875+
if (((xmlNodePtr)node)->type == XML_DOCUMENT_NODE) {
876+
node = ((xmlDocPtr)node)->children;
877+
}
878+
841879
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+
}
842885
xmlXPathObjectPtr evalResult = xmlXPathNodeEval(node, xpath, context);
843886

844887
xmlNodeSetPtr nodes = evalResult->nodesetval;
845-
888+
846889
int count = nodes->nodeNr;
847890

848891
CFMutableArrayRef results = CFArrayCreateMutable(NULL, count, NULL);
@@ -856,8 +899,15 @@ CF_RETURNS_RETAINED CFArrayRef _CFXMLNodesForXPath(_CFXMLNodePtr node, const uns
856899
return results;
857900
}
858901

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);
861911
}
862912

863913
_CFXMLDocPtr _CFXMLDocPtrFromDataWithOptions(CFDataRef data, int options) {
@@ -876,19 +926,26 @@ _CFXMLDocPtr _CFXMLDocPtrFromDataWithOptions(CFDataRef data, int options) {
876926
if (options & _kCFXMLNodeLoadExternalEntitiesAlways) {
877927
xmlOptions |= XML_PARSE_DTDLOAD;
878928
}
879-
929+
930+
xmlOptions |= XML_PARSE_RECOVER;
931+
xmlOptions |= XML_PARSE_NSCLEAN;
932+
880933
return xmlReadMemory((const char*)CFDataGetBytePtr(data), CFDataGetLength(data), NULL, NULL, xmlOptions);
881934
}
882935

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+
886943
return CFStringCreateWithCString(NULL, (const char*)result, kCFStringEncodingUTF8);
887944
}
888945

889-
CF_RETURNS_RETAINED CFStringRef _CFXMLNodePrefix(_CFXMLNodePtr node) {
946+
CFStringRef _CFXMLNodeCopyPrefix(_CFXMLNodePtr node) {
890947
xmlChar* result = NULL;
891-
xmlChar* unused = xmlSplitQName2(((xmlNodePtr)node)->name, &result);
948+
xmlChar* unused = xmlSplitQName2(_getQName((xmlNodePtr)node), &result);
892949

893950
CFStringRef resultString = CFStringCreateWithCString(NULL, (const char*)result, kCFStringEncodingUTF8);
894951
xmlFree(result);
@@ -983,7 +1040,7 @@ _CFXMLDTDPtr _Nullable _CFXMLParseDTDFromData(CFDataRef data, CFErrorRef _Nullab
9831040
return dtd;
9841041
}
9851042

986-
CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDExternalID(_CFXMLDTDPtr dtd) {
1043+
CFStringRef _Nullable _CFXMLDTDCopyExternalID(_CFXMLDTDPtr dtd) {
9871044
const unsigned char* externalID = ((xmlDtdPtr)dtd)->ExternalID;
9881045
if (externalID) {
9891046
return CFStringCreateWithCString(NULL, (const char*)externalID, kCFStringEncodingUTF8);
@@ -1008,7 +1065,7 @@ void _CFXMLDTDSetExternalID(_CFXMLDTDPtr dtd, const unsigned char* externalID) {
10081065
dtdPtr->ExternalID = xmlStrdup(externalID);
10091066
}
10101067

1011-
CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDSystemID(_CFXMLDTDPtr dtd) {
1068+
CFStringRef _Nullable _CFXMLDTDCopySystemID(_CFXMLDTDPtr dtd) {
10121069
const unsigned char* systemID = ((xmlDtdPtr)dtd)->SystemID;
10131070
if (systemID) {
10141071
return CFStringCreateWithCString(NULL, (const char*)systemID, kCFStringEncodingUTF8);
@@ -1095,7 +1152,7 @@ CFIndex _CFXMLDTDAttributeNodeGetType(_CFXMLDTDNodePtr node) {
10951152
return ((xmlAttributePtr)node)->atype;
10961153
}
10971154

1098-
CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDNodeGetSystemID(_CFXMLDTDNodePtr node) {
1155+
CFStringRef _Nullable _CFXMLDTDNodeCopySystemID(_CFXMLDTDNodePtr node) {
10991156
switch (((xmlNodePtr)node)->type) {
11001157
case XML_ENTITY_DECL:
11011158
return CFStringCreateWithCString(NULL, (const char*)((xmlEntityPtr)node)->SystemID, kCFStringEncodingUTF8);
@@ -1137,7 +1194,7 @@ void _CFXMLDTDNodeSetSystemID(_CFXMLDTDNodePtr node, const unsigned char* system
11371194
}
11381195
}
11391196

1140-
CF_RETURNS_RETAINED CFStringRef _Nullable _CFXMLDTDNodeGetPublicID(_CFXMLDTDNodePtr node) {
1197+
CFStringRef _Nullable _CFXMLDTDNodeCopyPublicID(_CFXMLDTDNodePtr node) {
11411198
switch (((xmlNodePtr)node)->type) {
11421199
case XML_ENTITY_DECL:
11431200
return CFStringCreateWithCString(NULL, (const char*)((xmlEntityPtr)node)->ExternalID, kCFStringEncodingUTF8);
@@ -1179,6 +1236,131 @@ void _CFXMLDTDNodeSetPublicID(_CFXMLDTDNodePtr node, const unsigned char* public
11791236
}
11801237
}
11811238

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+
11821364
void _CFXMLFreeNode(_CFXMLNodePtr node) {
11831365
if (!node) {
11841366
return;
@@ -1231,6 +1413,13 @@ void _CFXMLFreeNode(_CFXMLNodePtr node) {
12311413
}
12321414

12331415
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+
}
12341423
xmlFreeNode(node);
12351424
}
12361425
}

0 commit comments

Comments
 (0)