Esempio n. 1
0
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, "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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
value_ptr bplist_read_pref(char *filename, OSType folder_type)
{
	char cstr[MAXPATHLEN];
	char *foundstr;

	memset(cstr, 0, MAXPATHLEN);

	// for later OS X, the user preferences folder (~/Library/Preferences) is not available directly from Cocoa,
	// Apple documentation suggests just using POSIX APIs like so.
	if (folder_type == kPreferencesFolderType)
	{
		strlcpy(cstr, getenv("HOME"), MAXPATHLEN);
		strlcat(cstr, "/Library/Preferences", MAXPATHLEN);
	}
	else // the system preferences folder (~/Library/PreferencePanes) is accessible from Cocoa however
	{
		foundstr = FindPrefsDir();

		if (!foundstr) {
			bplist_log("Error finding preferences folder\n");
			return NULL;
		}

		strlcat(cstr, foundstr, MAXPATHLEN);
		free(foundstr);
		foundstr = NULL;
	}

	strlcat(cstr, "/", MAXPATHLEN);
	strlcat(cstr, filename, MAXPATHLEN);

	return bplist_read_file(cstr);
}
Esempio n. 6
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;
}
Esempio n. 7
0
value_ptr bplist_read_pref(char *filename, OSType folder_type)
{
    FSRef prefdir;
    char cstr[MAXPATHLEN];

    OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
                             FALSE, &prefdir);
    if (err) {
        bplist_log("Error finding preferences folder: %d\n", err);
        return NULL;
    }
    err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
    if (err) {
        bplist_log("Error making path name for preferences folder: %d\n", err);
        return NULL;
    }
    strlcat(cstr, "/", MAXPATHLEN);
    strlcat(cstr, filename, MAXPATHLEN);
    return bplist_read_file(cstr);
}
Esempio n. 8
0
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;
    }
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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, "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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}