X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_utilities/lib/cfmunge.cpp diff --git a/libsecurity_utilities/lib/cfmunge.cpp b/libsecurity_utilities/lib/cfmunge.cpp deleted file mode 100644 index 478835fe..00000000 --- a/libsecurity_utilities/lib/cfmunge.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -// -// CoreFoundation building and parsing functions. -// -// These classes provide a printf/scanf-like interface to nested data structures -// of the Property List Subset of CoreFoundation. -// -#include "cfmunge.h" -#include -#include - -namespace Security { - - -// -// Format codes for consistency -// -#define F_ARRAY 'A' -#define F_BOOLEAN 'B' -#define F_DATA 'X' -#define F_DICTIONARY 'D' -#define F_OBJECT 'O' -#define F_STRING 'S' -#define F_NUMBER 'N' - - -// -// Initialize a CFMunge. We start out with the default CFAllocator, and -// we do not throw errors. -// -CFMunge::CFMunge(const char *fmt, va_list arg) - : format(fmt), allocator(NULL), error(errSecSuccess) -{ - va_copy(args, arg); -} - -CFMunge::~CFMunge() -{ - va_end(args); -} - - -// -// Skip whitespace and other fluff and deliver the next significant character. -// -char CFMunge::next() -{ - while (*format && (isspace(*format) || *format == ',')) ++format; - return *format; -} - - -// -// Locate and consume an optional character -// -bool CFMunge::next(char c) -{ - if (next() == c) { - ++format; - return true; - } else - return false; -} - - -// -// Process @? parameter specifications. -// The @ operator is used for side effects, and does not return a value. -// -bool CFMunge::parameter() -{ - switch (*++format) { - case 'A': - ++format; - allocator = va_arg(args, CFAllocatorRef); - return true; - case 'E': - ++format; - error = va_arg(args, OSStatus); - return true; - default: - return false; - } -} - - -// -// The top constructor. -// -CFTypeRef CFMake::make() -{ - while (next() == '@') - parameter(); - switch (next()) { - case '\0': - return NULL; - case '{': - return makedictionary(); - case '[': - return makearray(); - case '\'': - return makestring(); - case '%': - return makeformat(); - case '#': - return makespecial(); - case ']': - case '}': - return NULL; // error - default: - if (isdigit(*format) || *format == '-') - return makenumber(); - else if (isalpha(*format)) - return makestring(); - else { - assert(false); - return NULL; - } - } -} - - -CFTypeRef CFMake::makeformat() -{ - ++format; - switch (*format++) { - case 'b': // blob (pointer, length) - { - const void *data = va_arg(args, const void *); - size_t length = va_arg(args, size_t); - return CFDataCreate(allocator, (const UInt8 *)data, length); - } - case F_BOOLEAN: // boolean (with int promotion) - return va_arg(args, int) ? kCFBooleanTrue : kCFBooleanFalse; - case 'd': - return makeCFNumber(va_arg(args, int)); - case 's': - return CFStringCreateWithCString(allocator, va_arg(args, const char *), - kCFStringEncodingUTF8); - case F_OBJECT: - return CFRetain(va_arg(args, CFTypeRef)); - case 'u': - return makeCFNumber(va_arg(args, unsigned int)); - default: - assert(false); - return NULL; - } -} - - -CFTypeRef CFMake::makespecial() -{ - ++format; - switch (*format++) { - case 'N': - return kCFNull; - case 't': - case 'T': - return kCFBooleanTrue; - case 'f': - case 'F': - return kCFBooleanFalse; - default: - assert(false); - return NULL; - } -} - - -CFTypeRef CFMake::makenumber() -{ - double value = strtod(format, (char **)&format); - return CFNumberCreate(allocator, kCFNumberDoubleType, &value); -} - - -// -// Embedded strings can either be alphanumeric (only), or delimited with single quotes ''. -// No escapes are processed within such quotes. If you want arbitrary string values, use %s. -// -CFTypeRef CFMake::makestring() -{ - const char *start, *end; - if (*format == '\'') { - start = ++format; // next quote - if (!(end = strchr(format, '\''))) { - assert(false); - return NULL; - } - format = end + 1; - } else { - start = format; - for (end = start + 1; isalnum(*end); ++end) ; - format = end; - } - return CFStringCreateWithBytes(allocator, - (const UInt8 *)start, end - start, - kCFStringEncodingUTF8, false); -} - - -// -// Construct a CFDictionary -// -CFTypeRef CFMake::makedictionary() -{ - ++format; // next '{' - next('!'); // indicates mutable (currently always true) - CFMutableDictionaryRef dict; - if (next('+')) { // {+%O, => copy dictionary argument, then proceed - if (next('%') && next('O')) { - CFDictionaryRef source = va_arg(args, CFDictionaryRef); - dict = CFDictionaryCreateMutableCopy(allocator, NULL, source); - if (next('}')) - return dict; - } else - return NULL; // bad syntax - } else - dict = CFDictionaryCreateMutable(allocator, 0, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (add(dict)) - return dict; - else { - CFRelease(dict); - return NULL; - } -} - -CFDictionaryRef CFMake::add(CFMutableDictionaryRef dict) -{ - while (next() != '}') { - CFTypeRef key = make(); - if (key == NULL) - return NULL; - if (!next('=')) { - CFRelease(key); - return NULL; - } - if (CFTypeRef value = make()) { - CFDictionaryAddValue(dict, key, value); - CFRelease(key); - CFRelease(value); - } else { - CFRelease(key); - return NULL; - } - } - ++format; - return dict; -} - - -CFDictionaryRef CFMake::addto(CFMutableDictionaryRef dict) -{ - if (next('{')) - return add(dict); - else { - assert(false); - return NULL; - } -} - - -// -// Construct a CFArray -// -CFTypeRef CFMake::makearray() -{ - ++format; // next '[' - next('!'); // indicates mutable (currently always) - CFMutableArrayRef array = makeCFMutableArray(0); - while (next() != ']') { - CFTypeRef value = make(); - if (value == NULL) { - CFRelease(array); - return NULL; - } - CFArrayAppendValue(array, value); - CFRelease(value); - } - ++format; - return array; -} - - -// -// A CFScan processes its format by parsing through an existing CF object -// structure, matching and extracting values as directed. Note that CFScan -// is a structure (tree) scanner rather than a linear parser, and will happily -// parse out a subset of the input object graph. -// -class CFScan : public CFMake { -public: - CFScan(const char *format, va_list args) - : CFMake(format, args), suppress(false) { } - - bool scan(CFTypeRef obj); - CFTypeRef dictpath(CFTypeRef obj); - -protected: - bool scandictionary(CFDictionaryRef obj); - bool scanarray(CFArrayRef obj); - bool scanformat(CFTypeRef obj); - - enum Typescan { fail = -1, more = 0, done = 1 }; - Typescan typescan(CFTypeRef obj, CFTypeID type); - - template - bool scannumber(CFTypeRef obj); - - template - void store(Type value); - - bool suppress; // output suppression -}; - - -// -// Master scan function -// -bool CFScan::scan(CFTypeRef obj) -{ - while (next() == '@') - parameter(); - switch (next()) { - case '\0': - return true; // done, okay - case '{': - if (obj && CFGetTypeID(obj) != CFDictionaryGetTypeID()) - return false; - return scandictionary(CFDictionaryRef(obj)); - case '[': - if (obj && CFGetTypeID(obj) != CFArrayGetTypeID()) - return false; - return scanarray(CFArrayRef(obj)); - case '%': // return this value in some form - return scanformat(obj); - case '=': // match value - { - ++format; - CFTypeRef match = make(); - bool rc = CFEqual(obj, match); - CFRelease(match); - return rc; - } - case ']': - case '}': - assert(false); // unexpected - return false; - default: - assert(false); - return false; - } -} - - -// -// Primitive type-match helper. -// Ensures the object has the CF runtime type required, and processes -// the %?o format (return CFTypeRef) and %?n format (ignore value). -// -CFScan::Typescan CFScan::typescan(CFTypeRef obj, CFTypeID type) -{ - if (obj && CFGetTypeID(obj) != type) - return fail; - switch (*++format) { - case F_OBJECT: // return CFTypeRef - ++format; - store(obj); - return done; - case 'n': // suppress assignment - ++format; - return done; - default: - return more; - } -} - - -// -// Store a value into the next varargs slot, unless output suppression is on. -// -template -void CFScan::store(Type value) -{ - if (!suppress) - *va_arg(args, Type *) = value; -} - - -// -// Convert a CFNumber to an external numeric form -// -template -bool CFScan::scannumber(CFTypeRef obj) -{ - ++format; // consume format code - if (!obj) - return true; // suppressed, okay - if (CFGetTypeID(obj) != CFNumberGetTypeID()) - return false; - store(cfNumber(CFNumberRef(obj))); - return true; -} - - -// -// Process % scan forms. -// This delivers the object value, scanf-style, somehow. -// -bool CFScan::scanformat(CFTypeRef obj) -{ - switch (*++format) { - case F_OBJECT: - store(obj); - return true; - case F_ARRAY: // %a* - return typescan(obj, CFArrayGetTypeID()) == done; - case F_BOOLEAN: - if (Typescan rc = typescan(obj, CFBooleanGetTypeID())) - return rc == done; - switch (*format) { - case 'f': // %Bf - two arguments (value, &variable) - { - unsigned flag = va_arg(args, unsigned); - unsigned *value = va_arg(args, unsigned *); - if (obj == kCFBooleanTrue && !suppress) - *value |= flag; - return true; - } - default: // %b - CFBoolean as int boolean - store(obj == kCFBooleanTrue); - return true; - } - case F_DICTIONARY: - return typescan(obj, CFDictionaryGetTypeID()) == done; - case 'd': // %d - int - return scannumber(obj); - case F_NUMBER: - return typescan(obj, CFNumberGetTypeID()) == done; - case F_STRING: - case 's': - if (Typescan rc = typescan(obj, CFStringGetTypeID())) - return rc == done; - // %s - store(cfString(CFStringRef(obj))); - return true; - case 'u': - return scannumber(obj); - case F_DATA: - return typescan(obj, CFDataGetTypeID()) == done; - default: - assert(false); - return false; - } -} - - -bool CFScan::scandictionary(CFDictionaryRef obj) -{ - ++format; // skip '{' - while (next() != '}') { - bool optional = next('?'); - if (CFTypeRef key = make()) { - bool oldSuppress = suppress; - CFTypeRef elem = obj ? CFDictionaryGetValue(obj, key) : NULL; - if (elem || optional) { - suppress |= (elem == NULL); - if (next('=')) { - if (scan(elem)) { - suppress = oldSuppress; // restore - CFRelease(key); - continue; - } - } - } - CFRelease(key); - return false; - } else { - assert(false); // bad format - return false; - } - } - return true; -} - - -bool CFScan::scanarray(CFArrayRef obj) -{ - ++format; // skip '[' - CFIndex length = CFArrayGetCount(obj); - for (int pos = 0; pos < length; ++pos) { - if (next() == ']') - return true; - if (!scan(CFArrayGetValueAtIndex(obj, pos))) - return false; - } - return false; // array length exceeded -} - - -// -// Run down a "dictionary path", validating heavily. -// -CFTypeRef CFScan::dictpath(CFTypeRef obj) -{ - while (next()) { // while we've got more text - next('.'); // optional - if (obj == NULL || CFGetTypeID(obj) != CFDictionaryGetTypeID()) - return NULL; - CFTypeRef key = make(); - obj = CFDictionaryGetValue(CFDictionaryRef(obj), key); - CFRelease(key); - } - return obj; -} - - -// -// The public functions -// -CFTypeRef cfmake(const char *format, ...) -{ - va_list args; - va_start(args, format); - CFTypeRef result = CFMake(format, args).make(); - va_end(args); - return result; -} - -CFTypeRef vcfmake(const char *format, va_list args) -{ - return CFMake(format, args).make(); -} - -CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...) -{ - va_list args; - va_start(args, format); - CFDictionaryRef result = CFMake(format, args).addto(dict); - va_end(args); - return result; -} - - -bool cfscan(CFTypeRef obj, const char *format, ...) -{ - va_list args; - va_start(args, format); - bool result = vcfscan(obj, format, args); - va_end(args); - return result; -} - -bool vcfscan(CFTypeRef obj, const char *format, va_list args) -{ - return CFScan(format, args).scan(obj); -} - - -CFTypeRef cfget(CFTypeRef obj, const char *format, ...) -{ - va_list args; - va_start(args, format); - CFTypeRef result = vcfget(obj, format, args); - va_end(args); - return result; -} - -CFTypeRef vcfget(CFTypeRef obj, const char *format, va_list args) -{ - return CFScan(format, args).dictpath(obj); -} - -} // end namespace Security