in CoreFoundation/Parsing.subproj/CFPropertyList.c [2007:2214]
static Boolean parseXMLElement(_CFXMLPlistParseInfo * _Nonnull pInfo, Boolean * _Nullable isKey, CFTypeRef * _Nullable out, size_t curDepth) {
const char *marker = pInfo->curr;
int markerLength = -1;
Boolean isEmpty;
int markerIx = -1;
if (isKey) *isKey = false;
while (pInfo->curr < pInfo->end) {
char ch = *(pInfo->curr);
if (ch == ' ' || ch == '\t' || ch == '\n' || ch =='\r') {
if (markerLength == -1) markerLength = pInfo->curr - marker;
} else if (ch == '>') {
break;
}
pInfo->curr ++;
}
if (pInfo->curr >= pInfo->end) {
return false;
}
isEmpty = (*(pInfo->curr-1) == '/');
if (markerLength == -1)
markerLength = pInfo->curr - (isEmpty ? 1 : 0) - marker;
pInfo->curr ++; // Advance past '>'
if (markerLength == 0) {
// Back up to the beginning of the marker
pInfo->curr = marker;
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed tag on line %d"), lineNumber(pInfo));
return false;
}
switch (*marker) {
case 'a': // Array
if (markerLength == ARRAY_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH))
markerIx = ARRAY_IX;
break;
case 'd': // Dictionary, data, or date; Fortunately, they all have the same marker length....
if (markerLength != DICT_TAG_LENGTH)
break;
if (!memcmp(marker, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH))
markerIx = DICT_IX;
else if (!memcmp(marker, CFXMLPlistTags[DATA_IX], DATA_TAG_LENGTH))
markerIx = DATA_IX;
else if (!memcmp(marker, CFXMLPlistTags[DATE_IX], DATE_TAG_LENGTH))
markerIx = DATE_IX;
break;
case 'f': // false (boolean)
if (markerLength == FALSE_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[FALSE_IX], FALSE_TAG_LENGTH)) {
markerIx = FALSE_IX;
}
break;
case 'i': // integer
if (markerLength == INTEGER_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[INTEGER_IX], INTEGER_TAG_LENGTH))
markerIx = INTEGER_IX;
break;
case 'k': // Key of a dictionary
if (markerLength == KEY_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[KEY_IX], KEY_TAG_LENGTH)) {
markerIx = KEY_IX;
if (isKey) *isKey = true;
}
break;
case 'p': // Plist
if (markerLength == PLIST_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[PLIST_IX], PLIST_TAG_LENGTH))
markerIx = PLIST_IX;
break;
case 'r': // real
if (markerLength == REAL_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH))
markerIx = REAL_IX;
break;
case 's': // String
if (markerLength == STRING_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[STRING_IX], STRING_TAG_LENGTH))
markerIx = STRING_IX;
break;
case 't': // true (boolean)
if (markerLength == TRUE_TAG_LENGTH && !memcmp(marker, CFXMLPlistTags[TRUE_IX], TRUE_TAG_LENGTH))
markerIx = TRUE_IX;
break;
}
if (!pInfo->allowNewTypes && markerIx != PLIST_IX && markerIx != ARRAY_IX && markerIx != DICT_IX && markerIx != STRING_IX && markerIx != KEY_IX && markerIx != DATA_IX) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered new tag when expecting only old-style property list objects"));
return false;
}
switch (markerIx) {
case PLIST_IX:
if (isEmpty) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty plist tag"));
return false;
}
return parsePListTag(pInfo, out, curDepth);
case ARRAY_IX:
if (isEmpty) {
if (pInfo->skip) {
*out = NULL;
} else {
if (pInfo->mutabilityOption == kCFPropertyListImmutable) {
*out = CFArrayCreate(pInfo->allocator, NULL, 0, &kCFTypeArrayCallBacks);
} else {
*out = CFArrayCreateMutable(pInfo->allocator, 0, &kCFTypeArrayCallBacks);
}
}
return true;
} else {
return parseArrayTag(pInfo, out, curDepth + 1);
}
case DICT_IX:
if (isEmpty) {
if (pInfo->skip) {
*out = NULL;
} else {
if (pInfo->mutabilityOption == kCFPropertyListImmutable) {
*out = CFDictionaryCreate(pInfo->allocator, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
} else {
*out = CFDictionaryCreateMutable(pInfo->allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
}
return true;
} else {
return parseDictTag(pInfo, out, curDepth + 1);
}
case KEY_IX:
case STRING_IX:
{
int tagLen = (markerIx == KEY_IX) ? KEY_TAG_LENGTH : STRING_TAG_LENGTH;
if (isEmpty) {
if (pInfo->skip) {
*out = NULL;
} else {
if (pInfo->mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
*out = CFStringCreateMutable(pInfo->allocator, 0);
} else {
*out = CFStringCreateWithCharacters(pInfo->allocator, NULL, 0);
}
}
return true;
}
if (!parseStringTag(pInfo, (CFStringRef *)out)) {
return false; // parseStringTag will already have set the error string
}
if (!checkForCloseTag(pInfo, CFXMLPlistTags[markerIx], tagLen)) {
__CFPListRelease(*out, pInfo->allocator);
return false;
} else {
return true;
}
}
case DATA_IX:
if (isEmpty) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty <data> on line %d"), lineNumber(pInfo));
return false;
} else {
return parseDataTag(pInfo, out);
}
case DATE_IX:
if (isEmpty) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty <date> on line %d"), lineNumber(pInfo));
return false;
} else {
return parseDateTag(pInfo, out);
}
case TRUE_IX:
if (!isEmpty) {
if (!checkForCloseTag(pInfo, CFXMLPlistTags[TRUE_IX], TRUE_TAG_LENGTH)) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered non-empty <true> on line %d"), lineNumber(pInfo));
return false;
}
}
if (pInfo->skip) {
*out = NULL;
} else {
*out = CFRetain(kCFBooleanTrue);
}
return true;
case FALSE_IX:
if (!isEmpty) {
if (!checkForCloseTag(pInfo, CFXMLPlistTags[FALSE_IX], FALSE_TAG_LENGTH)) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered non-empty <false> on line %d"), lineNumber(pInfo));
return false;
}
}
if (pInfo->skip) {
*out = NULL;
} else {
*out = CFRetain(kCFBooleanFalse);
}
return true;
case REAL_IX:
if (isEmpty) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty <real> on line %d"), lineNumber(pInfo));
return false;
} else {
return parseRealTag(pInfo, out);
}
case INTEGER_IX:
if (isEmpty) {
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty <integer> on line %d"), lineNumber(pInfo));
return false;
} else {
return parseIntegerTag(pInfo, out);
}
default: {
CFStringRef markerStr = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)marker, markerLength, kCFStringEncodingUTF8, NO);
pInfo->curr = marker;
pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown tag %@ on line %d"), markerStr ? markerStr : CFSTR("<unknown>"), lineNumber(pInfo));
if (markerStr) CFRelease(markerStr);
return false;
}
}
}