diff options
author | 2013-01-11 07:32:46 +0000 | |
---|---|---|
committer | 2013-01-11 07:32:46 +0000 | |
commit | 0e19f641d3186cdbf51f8ca857e2b07ab95779c2 (patch) | |
tree | 234109de1123b13f217494af4b3f8efad346d5cc /src/lib/portmidi/readbinaryplist.c | |
parent | 111157ca09a9ff60fe4a9ba49173c315e94314fa (diff) |
Cleanups and version bumpmame0148
Diffstat (limited to 'src/lib/portmidi/readbinaryplist.c')
-rw-r--r-- | src/lib/portmidi/readbinaryplist.c | 1498 |
1 files changed, 748 insertions, 750 deletions
diff --git a/src/lib/portmidi/readbinaryplist.c b/src/lib/portmidi/readbinaryplist.c index dad2ba75762..7adf031b95d 100644 --- a/src/lib/portmidi/readbinaryplist.c +++ b/src/lib/portmidi/readbinaryplist.c @@ -54,7 +54,7 @@ depth-first search to free nodes, you will free nodes twice. I decided to allocate memory from blocks of 1024 bytes and keep the blocks in a list associated with but private to this module. So the user should access this module by calling: - bplist_read_file() or bplist_read_user_pref() or + bplist_read_file() or bplist_read_user_pref() or bplist_read_system_pref() which returns a value. When you are done with the value, call bplist_free_data() @@ -91,33 +91,33 @@ memory requested or calls longjmp, so callers don't have to check. /* there are 2 levels of error logging/printing: * BPLIST_LOG and BPLIST_LOG_VERBOSE * either or both can be set to non-zero to turn on - * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG + * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG * is also true. - * + * * In the code, logging is done by calling either * bplist_log() or bplist_log_verbose(), which take * parameters like printf but might be a no-op. */ - + #define BPLIST_LOG_VERBOSE 0 #define BPLIST_LOG 0 #if BPLIST_LOG_VERBOSE - #ifndef BPLIST_LOG - #define BPLIST_LOG 1 - #endif + #ifndef BPLIST_LOG + #define BPLIST_LOG 1 + #endif #endif #if BPLIST_LOG - #define bplist_log printf + #define bplist_log printf #else - #define bplist_log(...) + #define bplist_log(...) #endif #if BPLIST_LOG_VERBOSE - #define bplist_log_verbose bplist_log + #define bplist_log_verbose bplist_log #else - #define bplist_log_verbose(...) + #define bplist_log_verbose(...) #endif @@ -133,54 +133,54 @@ static jmp_buf abort_parsing; static void *allocate(size_t size) { - void *result; - if (free_ptr + size > end_ptr) { - size_t how_much = BLOCK_SIZE; - // align everything to 8 bytes - if (size > BLOCK_SIZE - ALIGNMENT) { - how_much = size + ALIGNMENT; - } - result = malloc(how_much); - if (result == NULL) { - /* serious problem */ - longjmp(abort_parsing, 1); - } - *((void **)result) = block_list; - block_list = result; - free_ptr = ((char *) result) + ALIGNMENT; - end_ptr = ((char *) result) + how_much; - } - // now, there is enough rooom at free_ptr - result = free_ptr; - free_ptr += size; - return result; + void *result; + if (free_ptr + size > end_ptr) { + size_t how_much = BLOCK_SIZE; + // align everything to 8 bytes + if (size > BLOCK_SIZE - ALIGNMENT) { + how_much = size + ALIGNMENT; + } + result = malloc(how_much); + if (result == NULL) { + /* serious problem */ + longjmp(abort_parsing, 1); + } + *((void **)result) = block_list; + block_list = result; + free_ptr = ((char *) result) + ALIGNMENT; + end_ptr = ((char *) result) + how_much; + } + // now, there is enough rooom at free_ptr + result = free_ptr; + free_ptr += size; + return result; } void bplist_free_data() { - while (block_list) { - void *next = *(void **)block_list; - free(block_list); - block_list = next; - } - free_ptr = NULL; - end_ptr = NULL; + while (block_list) { + void *next = *(void **)block_list; + free(block_list); + block_list = next; + } + free_ptr = NULL; + end_ptr = NULL; } // layout of trailer -- last 32 bytes in plist data - uint8_t unused[6]; - uint8_t offset_int_size; - uint8_t object_ref_size; - uint64_t object_count; - uint64_t top_level_object; - uint64_t offset_table_offset; + uint8_t unused[6]; + uint8_t offset_int_size; + uint8_t object_ref_size; + uint64_t object_count; + uint64_t top_level_object; + uint64_t offset_table_offset; enum { - kHEADER_SIZE = 8, - kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node), - kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE + kHEADER_SIZE = 8, + kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node), + kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE }; @@ -188,21 +188,21 @@ static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00"; // map from UID key to previously parsed value typedef struct cache_struct { - uint64_t key; - value_ptr value; - struct cache_struct *next; + uint64_t key; + value_ptr value; + struct cache_struct *next; } cache_node, *cache_ptr; typedef struct bplist_info { - uint64_t object_count; - const uint8_t *data_bytes; - uint64_t length; - uint64_t offset_table_offset; - uint8_t offset_int_size; - uint8_t object_ref_size; - cache_ptr cache; + uint64_t object_count; + const uint8_t *data_bytes; + uint64_t length; + uint64_t offset_table_offset; + uint8_t offset_int_size; + uint8_t object_ref_size; + cache_ptr cache; } bplist_info_node, *bplist_info_ptr; @@ -227,163 +227,163 @@ static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset); value_ptr value_create(void) { - value_ptr value = (value_ptr) allocate(sizeof(value_node)); - return value; + value_ptr value = (value_ptr) allocate(sizeof(value_node)); + return value; } void value_set_integer(value_ptr v, int64_t i) { - v->tag = kTAG_INT; v->integer = i; + v->tag = kTAG_INT; v->integer = i; } void value_set_real(value_ptr v, double d) { - v->tag = kTAG_REAL; v->real = d; + v->tag = kTAG_REAL; v->real = d; } // d is seconds since 1 January 2001 void value_set_date(value_ptr v, double d) { - v->tag = kTAG_DATE; v->real = d; + v->tag = kTAG_DATE; v->real = d; } void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) { - v->tag = kTAG_ASCIISTRING; - v->string = (char *) allocate(len + 1); - memcpy(v->string, s, len); - v->string[len] = 0; + v->tag = kTAG_ASCIISTRING; + v->string = (char *) allocate(len + 1); + memcpy(v->string, s, len); + v->string[len] = 0; } void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) { - v->tag = kTAG_UNICODESTRING; - v->string = (char *) allocate(len + 1); - memcpy(v->string, s, len); - v->string[len] = 0; + v->tag = kTAG_UNICODESTRING; + v->string = (char *) allocate(len + 1); + memcpy(v->string, s, len); + v->string[len] = 0; } void value_set_uid(value_ptr v, uint64_t uid) { - v->tag = kTAG_UID; v->uinteger = uid; + v->tag = kTAG_UID; v->uinteger = uid; } // v->data points to a pldata that points to the actual bytes // the bytes are copied, so caller must free byte source (*data) void value_set_data(value_ptr v, const uint8_t *data, size_t len) { - v->tag = kTAG_DATA; - pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node)); - pldata->data = (uint8_t *) allocate(len); - memcpy(pldata->data, data, len); - pldata->len = len; - v->data = pldata; - printf("value at %p gets data at %p\n", v, pldata); + v->tag = kTAG_DATA; + pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node)); + pldata->data = (uint8_t *) allocate(len); + memcpy(pldata->data, data, len); + pldata->len = len; + v->data = pldata; + printf("value at %p gets data at %p\n", v, pldata); } // caller releases ownership of array to value_ptr v void value_set_array(value_ptr v, value_ptr *array, size_t length) { - array_ptr a = (array_ptr) allocate(sizeof(array_node)); - a->array = array; - a->length = length; - v->tag = kTAG_ARRAY; - v->array = a; + array_ptr a = (array_ptr) allocate(sizeof(array_node)); + a->array = array; + a->length = length; + v->tag = kTAG_ARRAY; + v->array = a; } // caller releases ownership of dict to value_ptr v void value_set_dict(value_ptr v, dict_ptr dict) { - v->tag = kTAG_DICTIONARY; - v->dict = dict; + v->tag = kTAG_DICTIONARY; + v->dict = dict; } // look up an objectref in the cache, a ref->value_ptr mapping value_ptr cache_lookup(cache_ptr cache, uint64_t ref) { - while (cache) { - if (cache->key == ref) { - return cache->value; - } - cache = cache->next; - } - return NULL; + while (cache) { + if (cache->key == ref) { + return cache->value; + } + cache = cache->next; + } + return NULL; } // insert an objectref and value in the cache void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value) { - cache_ptr c = (cache_ptr) allocate(sizeof(cache_node)); - c->key = ref; - c->value = value; - c->next = *cache; - *cache = c; + cache_ptr c = (cache_ptr) allocate(sizeof(cache_node)); + c->key = ref; + c->value = value; + c->next = *cache; + *cache = c; } // insert an objectref and value in a dictionary void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value) { - dict_ptr d = (dict_ptr) allocate(sizeof(dict_node)); - d->key = key; - d->value = value; - d->next = *dict; - *dict = d; + dict_ptr d = (dict_ptr) allocate(sizeof(dict_node)); + d->key = key; + d->value = value; + d->next = *dict; + *dict = d; } BOOL is_binary_plist(pldata_ptr data) { - if (data->len < kMINIMUM_SANE_SIZE) return NO; - return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0; + if (data->len < kMINIMUM_SANE_SIZE) return NO; + return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0; } value_ptr bplist_read_file(char *filename) { - struct stat stbuf; - pldata_node pldata; - FILE *file; - size_t n; - value_ptr value; - int rslt = stat(filename, &stbuf); - if (rslt) { - #if BPLIST_LOG - perror("in stat"); - #endif - bplist_log("Could not stat %s, error %d\n", filename, rslt); - return NULL; - } - // if file is >100MB, assume it is not a preferences file and give up - if (stbuf.st_size > 100000000) { - bplist_log("Large file %s encountered (%llu bytes) -- not read\n", - filename, stbuf.st_size); - return NULL; - } - pldata.len = (size_t) stbuf.st_size; - // note: this is supposed to be malloc, not allocate. It is separate - // from the graph structure, large, and easy to free right after - // parsing. - pldata.data = (uint8_t *) malloc(pldata.len); - if (!pldata.data) { - bplist_log("Could not allocate %lu bytes for %s\n", - (unsigned long) pldata.len, filename); - return NULL; - } - file = fopen(filename, "rb"); - if (!file) { - bplist_log("Could not open %s\n", filename); - return NULL; - } - n = fread(pldata.data, 1, pldata.len, file); - if (n != pldata.len) { - bplist_log("Error reading from %s\n", filename); - return NULL; - } - value = bplist_read_pldata(&pldata); - free(pldata.data); - return value; + struct stat stbuf; + pldata_node pldata; + FILE *file; + size_t n; + value_ptr value; + int rslt = stat(filename, &stbuf); + if (rslt) { + #if BPLIST_LOG + perror("in stat"); + #endif + bplist_log("Could not stat %s, error %d\n", filename, rslt); + return NULL; + } + // if file is >100MB, assume it is not a preferences file and give up + if (stbuf.st_size > 100000000) { + bplist_log("Large file %s encountered (%llu bytes) -- not read\n", + filename, stbuf.st_size); + return NULL; + } + pldata.len = (size_t) stbuf.st_size; + // note: this is supposed to be malloc, not allocate. It is separate + // from the graph structure, large, and easy to free right after + // parsing. + pldata.data = (uint8_t *) malloc(pldata.len); + if (!pldata.data) { + bplist_log("Could not allocate %lu bytes for %s\n", + (unsigned long) pldata.len, filename); + return NULL; + } + file = fopen(filename, "rb"); + if (!file) { + bplist_log("Could not open %s\n", filename); + return NULL; + } + n = fread(pldata.data, 1, pldata.len, file); + if (n != pldata.len) { + bplist_log("Error reading from %s\n", filename); + return NULL; + } + value = bplist_read_pldata(&pldata); + free(pldata.data); + return value; } value_ptr bplist_read_pref(char *filename, OSType folder_type) { - char cstr[MAXPATHLEN]; + char cstr[MAXPATHLEN]; char *foundstr; memset(cstr, 0, MAXPATHLEN); @@ -409,20 +409,20 @@ value_ptr bplist_read_pref(char *filename, OSType folder_type) foundstr = NULL; } - strlcat(cstr, "/", MAXPATHLEN); - strlcat(cstr, filename, MAXPATHLEN); + strlcat(cstr, "/", MAXPATHLEN); + strlcat(cstr, filename, MAXPATHLEN); return bplist_read_file(cstr); } value_ptr bplist_read_system_pref(char *filename) { - return bplist_read_pref(filename, kSystemPreferencesFolderType); + return bplist_read_pref(filename, kSystemPreferencesFolderType); } value_ptr bplist_read_user_pref(char *filename) { - return bplist_read_pref(filename, kPreferencesFolderType); + return bplist_read_pref(filename, kPreferencesFolderType); } @@ -431,578 +431,578 @@ value_ptr bplist_read_user_pref(char *filename) { // uint64_t convert_uint64(uint8_t *ptr) { - uint64_t rslt = 0; - int i; - // shift in bytes, high-order first - for (i = 0; i < sizeof(uint64_t); i++) { - rslt <<= 8; - rslt += ptr[i]; - } - return rslt; + uint64_t rslt = 0; + int i; + // shift in bytes, high-order first + for (i = 0; i < sizeof(uint64_t); i++) { + rslt <<= 8; + rslt += ptr[i]; + } + return rslt; } value_ptr bplist_read_pldata(pldata_ptr data) { - value_ptr result = NULL; - bplist_info_node bplist; - uint8_t *ptr; - uint64_t top_level_object; - int i; - - if (data == NULL) return NULL; - if (!is_binary_plist(data)) { - bplist_log("Bad binary plist: too short or invalid header.\n"); - return NULL; - } - - // read trailer - ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE); - bplist.offset_int_size = ptr[6]; - bplist.object_ref_size = ptr[7]; - bplist.object_count = convert_uint64(ptr + 8); - top_level_object = convert_uint64(ptr + 16); - bplist.offset_table_offset = convert_uint64(ptr + 24); - - // Basic sanity checks - if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 || - bplist.object_ref_size < 1 || bplist.object_ref_size > 8 || - bplist.offset_table_offset < kHEADER_SIZE) { - bplist_log("Bad binary plist: trailer declared insane.\n"); - return NULL; - } - - // Ensure offset table is inside file - uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count; - if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > - data->len) { - bplist_log("Bad binary plist: offset table overlaps end of container.\n"); - return NULL; - } - - bplist.data_bytes = data->data; - bplist.length = data->len; - bplist.cache = NULL; /* dictionary is empty */ - - bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", - bplist.object_count, bplist.offset_int_size, - bplist.object_ref_size); - /* at this point, we are ready to do some parsing which allocates - memory for the result data structure. If memory allocation (using - allocate fails, a longjmp will return to here and we simply give up - */ - i = setjmp(abort_parsing); - if (i == 0) { - result = extract_object(&bplist, top_level_object); - } else { - bplist_log("allocate() failed to allocate memory. Giving up.\n"); - result = NULL; - } - if (!result) { - bplist_free_data(); - } - return result; + value_ptr result = NULL; + bplist_info_node bplist; + uint8_t *ptr; + uint64_t top_level_object; + int i; + + if (data == NULL) return NULL; + if (!is_binary_plist(data)) { + bplist_log("Bad binary plist: too short or invalid header.\n"); + return NULL; + } + + // read trailer + ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE); + bplist.offset_int_size = ptr[6]; + bplist.object_ref_size = ptr[7]; + bplist.object_count = convert_uint64(ptr + 8); + top_level_object = convert_uint64(ptr + 16); + bplist.offset_table_offset = convert_uint64(ptr + 24); + + // Basic sanity checks + if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 || + bplist.object_ref_size < 1 || bplist.object_ref_size > 8 || + bplist.offset_table_offset < kHEADER_SIZE) { + bplist_log("Bad binary plist: trailer declared insane.\n"); + return NULL; + } + + // Ensure offset table is inside file + uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count; + if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > + data->len) { + bplist_log("Bad binary plist: offset table overlaps end of container.\n"); + return NULL; + } + + bplist.data_bytes = data->data; + bplist.length = data->len; + bplist.cache = NULL; /* dictionary is empty */ + + bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", + bplist.object_count, bplist.offset_int_size, + bplist.object_ref_size); + /* at this point, we are ready to do some parsing which allocates + memory for the result data structure. If memory allocation (using + allocate fails, a longjmp will return to here and we simply give up + */ + i = setjmp(abort_parsing); + if (i == 0) { + result = extract_object(&bplist, top_level_object); + } else { + bplist_log("allocate() failed to allocate memory. Giving up.\n"); + result = NULL; + } + if (!result) { + bplist_free_data(); + } + return result; } static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef) { - uint64_t offset; - value_ptr result = NULL; - uint8_t objectTag; - - if (objectRef >= bplist->object_count) { - // Out-of-range object reference. - bplist_log("Bad binary plist: object index is out of range.\n"); - return NULL; - } - - // Use cached object if it exists - result = cache_lookup(bplist->cache, objectRef); - if (result != NULL) return result; - - // Otherwise, find object in file. - offset = read_offset(bplist, objectRef); - if (offset > bplist->length) { - // Out-of-range offset. - bplist_log("Bad binary plist: object outside container.\n"); - return NULL; - } - objectTag = *(bplist->data_bytes + offset); - switch (objectTag & 0xF0) { - case kTAG_SIMPLE: - result = extract_simple(bplist, offset); - break; - - case kTAG_INT: - result = extract_int(bplist, offset); - break; - - case kTAG_REAL: - result = extract_real(bplist, offset); - break; - - case kTAG_DATE: - result = extract_date(bplist, offset); - break; - - case kTAG_DATA: - result = extract_data(bplist, offset); - break; - - case kTAG_ASCIISTRING: - result = extract_ascii_string(bplist, offset); - break; - - case kTAG_UNICODESTRING: - result = extract_unicode_string(bplist, offset); - break; - - case kTAG_UID: - result = extract_uid(bplist, offset); - break; - - case kTAG_ARRAY: - result = extract_array(bplist, offset); - break; - - case kTAG_DICTIONARY: - result = extract_dictionary(bplist, offset); - break; - - default: - // Unknown tag. - bplist_log("Bad binary plist: unknown tag 0x%X.\n", - (objectTag & 0x0F) >> 4); - result = NULL; - } - - // Cache and return result. - if (result != NULL) - cache_insert(&bplist->cache, objectRef, result); - return result; + uint64_t offset; + value_ptr result = NULL; + uint8_t objectTag; + + if (objectRef >= bplist->object_count) { + // Out-of-range object reference. + bplist_log("Bad binary plist: object index is out of range.\n"); + return NULL; + } + + // Use cached object if it exists + result = cache_lookup(bplist->cache, objectRef); + if (result != NULL) return result; + + // Otherwise, find object in file. + offset = read_offset(bplist, objectRef); + if (offset > bplist->length) { + // Out-of-range offset. + bplist_log("Bad binary plist: object outside container.\n"); + return NULL; + } + objectTag = *(bplist->data_bytes + offset); + switch (objectTag & 0xF0) { + case kTAG_SIMPLE: + result = extract_simple(bplist, offset); + break; + + case kTAG_INT: + result = extract_int(bplist, offset); + break; + + case kTAG_REAL: + result = extract_real(bplist, offset); + break; + + case kTAG_DATE: + result = extract_date(bplist, offset); + break; + + case kTAG_DATA: + result = extract_data(bplist, offset); + break; + + case kTAG_ASCIISTRING: + result = extract_ascii_string(bplist, offset); + break; + + case kTAG_UNICODESTRING: + result = extract_unicode_string(bplist, offset); + break; + + case kTAG_UID: + result = extract_uid(bplist, offset); + break; + + case kTAG_ARRAY: + result = extract_array(bplist, offset); + break; + + case kTAG_DICTIONARY: + result = extract_dictionary(bplist, offset); + break; + + default: + // Unknown tag. + bplist_log("Bad binary plist: unknown tag 0x%X.\n", + (objectTag & 0x0F) >> 4); + result = NULL; + } + + // Cache and return result. + if (result != NULL) + cache_insert(&bplist->cache, objectRef, result); + return result; } -static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, - uint8_t size) +static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, + uint8_t size) { - assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && - offset + size <= bplist->length); - - uint64_t result = 0; - const uint8_t *byte = bplist->data_bytes + offset; - - do { - // note that ints seem to be high-order first - result = (result << 8) | *byte++; - } while (--size); - - return result; + assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && + offset + size <= bplist->length); + + uint64_t result = 0; + const uint8_t *byte = bplist->data_bytes + offset; + + do { + // note that ints seem to be high-order first + result = (result << 8) | *byte++; + } while (--size); + + return result; } static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index) { - assert(index < bplist->object_count); - - return read_sized_int(bplist, - bplist->offset_table_offset + bplist->offset_int_size * index, - bplist->offset_int_size); + assert(index < bplist->object_count); + + return read_sized_int(bplist, + bplist->offset_table_offset + bplist->offset_int_size * index, + bplist->offset_int_size); } -static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, - uint64_t *outValue, size_t *outSize) +static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, + uint64_t *outValue, size_t *outSize) { - uint32_t size; - int64_t value; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - size = 1 << (bplist->data_bytes[offset] & 0x0F); - if (size > 8) { - // Maximum allowable size in this implementation is 1<<3 = 8 bytes. - // This also happens to be the biggest we can handle. - return NO; - } - - if (offset + 1 + size > bplist->length) { - // Out of range. - return NO; - } - - value = read_sized_int(bplist, offset + 1, size); - - if (outValue != NULL) *outValue = value; - if (outSize != NULL) *outSize = size + 1; // +1 for tag byte. - return YES; + uint32_t size; + int64_t value; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + size = 1 << (bplist->data_bytes[offset] & 0x0F); + if (size > 8) { + // Maximum allowable size in this implementation is 1<<3 = 8 bytes. + // This also happens to be the biggest we can handle. + return NO; + } + + if (offset + 1 + size > bplist->length) { + // Out of range. + return NO; + } + + value = read_sized_int(bplist, offset + 1, size); + + if (outValue != NULL) *outValue = value; + if (outSize != NULL) *outSize = size + 1; // +1 for tag byte. + return YES; } static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset) { - assert(bplist->data_bytes != NULL && offset < bplist->length); - value_ptr value = value_create(); - - switch (bplist->data_bytes[offset]) { - case kVALUE_NULL: - value->tag = kVALUE_NULL; - return value; - - case kVALUE_TRUE: - value->tag = kVALUE_TRUE; - return value; - - case kVALUE_FALSE: - value->tag = kVALUE_FALSE; - return value; - } - - // Note: kVALUE_FILLER is treated as invalid, because it, er, is. - bplist_log("Bad binary plist: invalid atom.\n"); - free(value); - return NULL; + assert(bplist->data_bytes != NULL && offset < bplist->length); + value_ptr value = value_create(); + + switch (bplist->data_bytes[offset]) { + case kVALUE_NULL: + value->tag = kVALUE_NULL; + return value; + + case kVALUE_TRUE: + value->tag = kVALUE_TRUE; + return value; + + case kVALUE_FALSE: + value->tag = kVALUE_FALSE; + return value; + } + + // Note: kVALUE_FILLER is treated as invalid, because it, er, is. + bplist_log("Bad binary plist: invalid atom.\n"); + free(value); + return NULL; } static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset) { - value_ptr value = value_create(); - value->tag = kTAG_INT; - - if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) { - bplist_log("Bad binary plist: invalid integer object.\n"); - } - - /* NOTE: originally, I sign-extended here. This was the wrong thing; it - turns out that negative ints are always stored as 64-bit, and smaller - ints are unsigned. - */ - return value; + value_ptr value = value_create(); + value->tag = kTAG_INT; + + if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) { + bplist_log("Bad binary plist: invalid integer object.\n"); + } + + /* NOTE: originally, I sign-extended here. This was the wrong thing; it + turns out that negative ints are always stored as 64-bit, and smaller + ints are unsigned. + */ + return value; } static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset) { - value_ptr value = value_create(); - uint32_t size; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - size = 1 << (bplist->data_bytes[offset] & 0x0F); - - // FIXME: what to do if faced with other sizes for float/double? - assert (sizeof (float) == sizeof (uint32_t) && - sizeof (double) == sizeof (uint64_t)); - - if (offset + 1 + size > bplist->length) { - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "floating-point number"); - free(value); - return NULL; - } - - if (size == sizeof (float)) { - // cast is ok because we know size is 4 bytes - uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); - // Note that this handles byte swapping. - value_set_real(value, *(float *)&i); - return value; - } else if (size == sizeof (double)) { - uint64_t i = read_sized_int(bplist, offset + 1, size); - // Note that this handles byte swapping. - value_set_real(value, *(double *)&i); - return value; - } else { - // Can't handle floats of other sizes. - bplist_log("Bad binary plist: can't handle %u-byte float.\n", size); - free(value); - return NULL; - } + value_ptr value = value_create(); + uint32_t size; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + size = 1 << (bplist->data_bytes[offset] & 0x0F); + + // FIXME: what to do if faced with other sizes for float/double? + assert (sizeof (float) == sizeof (uint32_t) && + sizeof (double) == sizeof (uint64_t)); + + if (offset + 1 + size > bplist->length) { + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "floating-point number"); + free(value); + return NULL; + } + + if (size == sizeof (float)) { + // cast is ok because we know size is 4 bytes + uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); + // Note that this handles byte swapping. + value_set_real(value, *(float *)&i); + return value; + } else if (size == sizeof (double)) { + uint64_t i = read_sized_int(bplist, offset + 1, size); + // Note that this handles byte swapping. + value_set_real(value, *(double *)&i); + return value; + } else { + // Can't handle floats of other sizes. + bplist_log("Bad binary plist: can't handle %u-byte float.\n", size); + free(value); + return NULL; + } } static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset) { - value_ptr value; - assert(bplist->data_bytes != NULL && offset < bplist->length); - - // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid. - if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) { - bplist_log("Bad binary plist: invalid size for date object.\n"); - return NULL; - } - - if (offset + 1 + sizeof (double) > bplist->length) { - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "date"); - return NULL; - } - - // FIXME: what to do if faced with other sizes for double? - assert (sizeof (double) == sizeof (uint64_t)); - - uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double)); - // Note that this handles byte swapping. - value = value_create(); - value_set_date(value, *(double *)&date); - return value; + value_ptr value; + assert(bplist->data_bytes != NULL && offset < bplist->length); + + // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid. + if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) { + bplist_log("Bad binary plist: invalid size for date object.\n"); + return NULL; + } + + if (offset + 1 + sizeof (double) > bplist->length) { + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "date"); + return NULL; + } + + // FIXME: what to do if faced with other sizes for double? + assert (sizeof (double) == sizeof (uint64_t)); + + uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double)); + // Note that this handles byte swapping. + value = value_create(); + value_set_date(value, *(double *)&date); + return value; } -uint64_t bplist_get_a_size(bplist_info_ptr bplist, - uint64_t *offset_ptr, char *msg) +uint64_t bplist_get_a_size(bplist_info_ptr bplist, + uint64_t *offset_ptr, char *msg) { - uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F; - (*offset_ptr)++; - if (size == 0x0F) { - // 0x0F means separate int size follows. - // Smaller values are used for short data. - size_t extra; // the length of the data size we are about to read - if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) { - // Bad data, mistagged size int - bplist_log("Bad binary plist: %s object size is not tagged as int.\n", - msg); - return UINT64_MAX; // error - } - - // read integer data as size, extra tells how many bytes to skip - if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) { - bplist_log("Bad binary plist: invalid %s object size tag.\n", - "data"); - return UINT64_MAX; // error - } - (*offset_ptr) += extra; - } - - if (*offset_ptr + size > bplist->length) { - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "data"); - return UINT64_MAX; // error - } - return size; + uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F; + (*offset_ptr)++; + if (size == 0x0F) { + // 0x0F means separate int size follows. + // Smaller values are used for short data. + size_t extra; // the length of the data size we are about to read + if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) { + // Bad data, mistagged size int + bplist_log("Bad binary plist: %s object size is not tagged as int.\n", + msg); + return UINT64_MAX; // error + } + + // read integer data as size, extra tells how many bytes to skip + if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) { + bplist_log("Bad binary plist: invalid %s object size tag.\n", + "data"); + return UINT64_MAX; // error + } + (*offset_ptr) += extra; + } + + if (*offset_ptr + size > bplist->length) { + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "data"); + return UINT64_MAX; // error + } + return size; } static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset) { - uint64_t size; - value_ptr value; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - if ((size = bplist_get_a_size(bplist, &offset, (char *)"data")) == UINT64_MAX) - return NULL; - - value = value_create(); - // cast is ok because we only allow files up to 100MB: - value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size); - return value; + uint64_t size; + value_ptr value; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + if ((size = bplist_get_a_size(bplist, &offset, (char *)"data")) == UINT64_MAX) + return NULL; + + value = value_create(); + // cast is ok because we only allow files up to 100MB: + value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size); + return value; } static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset) { - uint64_t size; - value_ptr value; // return value - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - if ((size = bplist_get_a_size(bplist, &offset, (char *)"ascii string")) == - UINT64_MAX) - return NULL; - - value = value_create(); - // cast is ok because we only allow 100MB files - value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, - (size_t) size); - return value; + uint64_t size; + value_ptr value; // return value + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + if ((size = bplist_get_a_size(bplist, &offset, (char *)"ascii string")) == + UINT64_MAX) + return NULL; + + value = value_create(); + // cast is ok because we only allow 100MB files + value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, + (size_t) size); + return value; } static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset) { - uint64_t size; - value_ptr value; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - if ((size = bplist_get_a_size(bplist, &offset, (char *)"unicode string")) == - UINT64_MAX) - return NULL; - - value = value_create(); - // cast is ok because we only allow 100MB files - value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, - (size_t) size); - return value; + uint64_t size; + value_ptr value; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + if ((size = bplist_get_a_size(bplist, &offset, (char *)"unicode string")) == + UINT64_MAX) + return NULL; + + value = value_create(); + // cast is ok because we only allow 100MB files + value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, + (size_t) size); + return value; } static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset) { - /* UIDs are used by Cocoa's key-value coder. - When writing other plist formats, they are expanded to dictionaries of - the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we - do the same here on reading. This results in plists identical to what - running plutil -convert xml1 gives us. However, this is not the same - result as [Core]Foundation's plist parser, which extracts them as un- - introspectable CF objects. In fact, it even seems to convert the CF$UID - dictionaries from XML plists on the fly. - */ - - value_ptr value; - uint64_t uid; - - if (!read_self_sized_int(bplist, offset, &uid, NULL)) { - bplist_log("Bad binary plist: invalid UID object.\n"); - return NULL; - } - - // assert(NO); // original code suggests using a string for a key - // but our dictionaries all use big ints for keys, so I don't know - // what to do here - - // In practice, I believe this code is never executed by PortMidi. - // I changed it to do something and not raise compiler warnings, but - // not sure what the code should do. - - value = value_create(); - value_set_uid(value, uid); - // return [NSDictionary dictionaryWithObject: - // [NSNumber numberWithUnsignedLongLong:value] - // forKey:"CF$UID"]; - return value; + /* UIDs are used by Cocoa's key-value coder. + When writing other plist formats, they are expanded to dictionaries of + the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we + do the same here on reading. This results in plists identical to what + running plutil -convert xml1 gives us. However, this is not the same + result as [Core]Foundation's plist parser, which extracts them as un- + introspectable CF objects. In fact, it even seems to convert the CF$UID + dictionaries from XML plists on the fly. + */ + + value_ptr value; + uint64_t uid; + + if (!read_self_sized_int(bplist, offset, &uid, NULL)) { + bplist_log("Bad binary plist: invalid UID object.\n"); + return NULL; + } + + // assert(NO); // original code suggests using a string for a key + // but our dictionaries all use big ints for keys, so I don't know + // what to do here + + // In practice, I believe this code is never executed by PortMidi. + // I changed it to do something and not raise compiler warnings, but + // not sure what the code should do. + + value = value_create(); + value_set_uid(value, uid); + // return [NSDictionary dictionaryWithObject: + // [NSNumber numberWithUnsignedLongLong:value] + // forKey:"CF$UID"]; + return value; } static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset) { - uint64_t i, count; - uint64_t size; - uint64_t elementID; - value_ptr element = NULL; - value_ptr *array = NULL; - value_ptr value = NULL; - BOOL ok = YES; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX) - return NULL; - - if (count > UINT64_MAX / bplist->object_ref_size - offset) { - // Offset overflow. - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "array"); - return NULL; - } - - size = bplist->object_ref_size * count; - if (size + offset > bplist->length) { - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "array"); - return NULL; - } - - // got count, the number of array elements - - value = value_create(); - assert(value); - - if (count == 0) { - // count must be size_t or smaller because max file size is 100MB - value_set_array(value, array, (size_t) count); - return value; - } - - array = allocate(sizeof(value_ptr) * (size_t) count); - - for (i = 0; i != count; ++i) { - bplist_log_verbose("[%u]\n", i); - elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, - bplist->object_ref_size); - element = extract_object(bplist, elementID); - if (element != NULL) { - array[i] = element; - } else { - ok = NO; - break; - } - } - if (ok) { // count is smaller than size_t max because of 100MB file limit - value_set_array(value, array, (size_t) count); - } - - return value; + uint64_t i, count; + uint64_t size; + uint64_t elementID; + value_ptr element = NULL; + value_ptr *array = NULL; + value_ptr value = NULL; + BOOL ok = YES; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX) + return NULL; + + if (count > UINT64_MAX / bplist->object_ref_size - offset) { + // Offset overflow. + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "array"); + return NULL; + } + + size = bplist->object_ref_size * count; + if (size + offset > bplist->length) { + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "array"); + return NULL; + } + + // got count, the number of array elements + + value = value_create(); + assert(value); + + if (count == 0) { + // count must be size_t or smaller because max file size is 100MB + value_set_array(value, array, (size_t) count); + return value; + } + + array = allocate(sizeof(value_ptr) * (size_t) count); + + for (i = 0; i != count; ++i) { + bplist_log_verbose("[%u]\n", i); + elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, + bplist->object_ref_size); + element = extract_object(bplist, elementID); + if (element != NULL) { + array[i] = element; + } else { + ok = NO; + break; + } + } + if (ok) { // count is smaller than size_t max because of 100MB file limit + value_set_array(value, array, (size_t) count); + } + + return value; } static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset) { - uint64_t i, count; - uint64_t size; - uint64_t elementID; - value_ptr value = NULL; - dict_ptr dict = NULL; - BOOL ok = YES; - - assert(bplist->data_bytes != NULL && offset < bplist->length); - - - if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX) - return NULL; - - if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) { - // Offset overflow. - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "dictionary"); - return NULL; - } - - size = bplist->object_ref_size * count * 2; - if (size + offset > bplist->length) { - bplist_log("Bad binary plist: %s object overlaps end of container.\n", - "dictionary"); - return NULL; - } - - value = value_create(); - if (count == 0) { - value_set_dict(value, NULL); - return value; - } - - for (i = 0; i != count; ++i) { - value_ptr key; - value_ptr val; - elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, - bplist->object_ref_size); - key = extract_object(bplist, elementID); - if (key != NULL) { - bplist_log_verbose("key: %p\n", key); - } else { - ok = NO; - break; - } - - elementID = read_sized_int(bplist, - offset + (i + count) * bplist->object_ref_size, - bplist->object_ref_size); - val = extract_object(bplist, elementID); - if (val != NULL) { - dict_insert(&dict, key, val); - } else { - ok = NO; - break; - } - } - if (ok) { - value_set_dict(value, dict); - } - - return value; + uint64_t i, count; + uint64_t size; + uint64_t elementID; + value_ptr value = NULL; + dict_ptr dict = NULL; + BOOL ok = YES; + + assert(bplist->data_bytes != NULL && offset < bplist->length); + + + if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX) + return NULL; + + if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) { + // Offset overflow. + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "dictionary"); + return NULL; + } + + size = bplist->object_ref_size * count * 2; + if (size + offset > bplist->length) { + bplist_log("Bad binary plist: %s object overlaps end of container.\n", + "dictionary"); + return NULL; + } + + value = value_create(); + if (count == 0) { + value_set_dict(value, NULL); + return value; + } + + for (i = 0; i != count; ++i) { + value_ptr key; + value_ptr val; + elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, + bplist->object_ref_size); + key = extract_object(bplist, elementID); + if (key != NULL) { + bplist_log_verbose("key: %p\n", key); + } else { + ok = NO; + break; + } + + elementID = read_sized_int(bplist, + offset + (i + count) * bplist->object_ref_size, + bplist->object_ref_size); + val = extract_object(bplist, elementID); + if (val != NULL) { + dict_insert(&dict, key, val); + } else { + ok = NO; + break; + } + } + if (ok) { + value_set_dict(value, dict); + } + + return value; } /*************** functions for accessing values ****************/ @@ -1010,122 +1010,120 @@ static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset) char *value_get_asciistring(value_ptr v) { - if (v->tag != kTAG_ASCIISTRING) return NULL; - return v->string; + if (v->tag != kTAG_ASCIISTRING) return NULL; + return v->string; } value_ptr value_dict_lookup_using_string(value_ptr v, char *key) { - dict_ptr dict; - if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary - dict = v->dict; - /* search for key */ - while (dict) { - if (dict->key && dict->key->tag == kTAG_ASCIISTRING && - strcmp(key, dict->key->string) == 0) { // found it - return dict->value; - } - dict = dict->next; - } - return NULL; /* not found */ + dict_ptr dict; + if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary + dict = v->dict; + /* search for key */ + while (dict) { + if (dict->key && dict->key->tag == kTAG_ASCIISTRING && + strcmp(key, dict->key->string) == 0) { // found it + return dict->value; + } + dict = dict->next; + } + return NULL; /* not found */ } value_ptr value_dict_lookup_using_path(value_ptr v, char *path) { - char key[MAX_KEY_SIZE]; - while (*path) { /* more to the path */ - int i = 0; - while (i < MAX_KEY_SIZE - 1) { - key[i] = *path++; - if (key[i] == '/') { /* end of entry in path */ - key[i + 1] = 0; - break; - } - if (!key[i]) { - path--; /* back up to end of string char */ - break; /* this will cause outer loop to exit */ - } - i++; - } - if (!v || v->tag != kTAG_DICTIONARY) return NULL; - /* now, look up the key to get next value */ - v = value_dict_lookup_using_string(v, key); - if (v == NULL) return NULL; - } - return v; + char key[MAX_KEY_SIZE]; + while (*path) { /* more to the path */ + int i = 0; + while (i < MAX_KEY_SIZE - 1) { + key[i] = *path++; + if (key[i] == '/') { /* end of entry in path */ + key[i + 1] = 0; + break; + } + if (!key[i]) { + path--; /* back up to end of string char */ + break; /* this will cause outer loop to exit */ + } + i++; + } + if (!v || v->tag != kTAG_DICTIONARY) return NULL; + /* now, look up the key to get next value */ + v = value_dict_lookup_using_string(v, key); + if (v == NULL) return NULL; + } + return v; } - + /*************** functions for debugging ***************/ void plist_print(value_ptr v) { - size_t i; - int comma_needed; - dict_ptr dict; - if (!v) { - printf("NULL"); - return; - } - switch (v->tag & 0xF0) { - case kTAG_SIMPLE: - switch (v->tag) { - case kVALUE_NULL: - printf("NULL@%p", v); break; - case kVALUE_FALSE: - printf("FALSE@%p", v); break; - case kVALUE_TRUE: - printf("TRUE@%p", v); break; - default: - printf("UNKNOWN tag=%x@%p", v->tag, v); break; - } - break; - case kTAG_INT: - printf("%lld@%p", v->integer, v); break; - case kTAG_REAL: - printf("%g@%p", v->real, v); break; - case kTAG_DATE: - printf("date:%g@%p", v->real, v); break; - case kTAG_DATA: - printf("data@%p->%p:[%p:", v, v->data, v->data->data); - for (i = 0; i < v->data->len; i++) { - printf(" %2x", v->data->data[i]); - } - printf("]"); break; - case kTAG_ASCIISTRING: - printf("%p:\"%s\"@%p", v->string, v->string, v); break; - case kTAG_UNICODESTRING: - printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break; - case kTAG_UID: - printf("UID:%llu@%p", v->uinteger, v); break; - case kTAG_ARRAY: - comma_needed = FALSE; - printf("%p->%p:[%p:", v, v->array, v->array->array); - for (i = 0; i < v->array->length; i++) { - if (comma_needed) printf(", "); - plist_print(v->array->array[i]); - comma_needed = TRUE; - } - printf("]"); break; - case kTAG_DICTIONARY: - comma_needed = FALSE; - printf("%p:[", v); - dict = v->dict; - while (dict) { - if (comma_needed) printf(", "); - printf("%p:", dict); - plist_print(dict->key); - printf("->"); - plist_print(dict->value); - comma_needed = TRUE; - dict = dict->next; - } - printf("]"); break; - default: - printf("UNKNOWN tag=%x", v->tag); - break; - } + size_t i; + int comma_needed; + dict_ptr dict; + if (!v) { + printf("NULL"); + return; + } + switch (v->tag & 0xF0) { + case kTAG_SIMPLE: + switch (v->tag) { + case kVALUE_NULL: + printf("NULL@%p", v); break; + case kVALUE_FALSE: + printf("FALSE@%p", v); break; + case kVALUE_TRUE: + printf("TRUE@%p", v); break; + default: + printf("UNKNOWN tag=%x@%p", v->tag, v); break; + } + break; + case kTAG_INT: + printf("%lld@%p", v->integer, v); break; + case kTAG_REAL: + printf("%g@%p", v->real, v); break; + case kTAG_DATE: + printf("date:%g@%p", v->real, v); break; + case kTAG_DATA: + printf("data@%p->%p:[%p:", v, v->data, v->data->data); + for (i = 0; i < v->data->len; i++) { + printf(" %2x", v->data->data[i]); + } + printf("]"); break; + case kTAG_ASCIISTRING: + printf("%p:\"%s\"@%p", v->string, v->string, v); break; + case kTAG_UNICODESTRING: + printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break; + case kTAG_UID: + printf("UID:%llu@%p", v->uinteger, v); break; + case kTAG_ARRAY: + comma_needed = FALSE; + printf("%p->%p:[%p:", v, v->array, v->array->array); + for (i = 0; i < v->array->length; i++) { + if (comma_needed) printf(", "); + plist_print(v->array->array[i]); + comma_needed = TRUE; + } + printf("]"); break; + case kTAG_DICTIONARY: + comma_needed = FALSE; + printf("%p:[", v); + dict = v->dict; + while (dict) { + if (comma_needed) printf(", "); + printf("%p:", dict); + plist_print(dict->key); + printf("->"); + plist_print(dict->value); + comma_needed = TRUE; + dict = dict->next; + } + printf("]"); break; + default: + printf("UNKNOWN tag=%x", v->tag); + break; + } } - - |