LLVMFuzzerTestOneInput:
   26|  1.58k|{
   27|  1.58k|	plist_t root_node = NULL;
   28|  1.58k|	plist_from_openstep(reinterpret_cast<const char*>(data), size, &root_node);
   29|  1.58k|	plist_free(root_node);
   30|       |
   31|  1.58k|	return 0;
   32|  1.58k|}

node_destroy:
   31|   329k|{
   32|   329k|	if(!node) return;
  ------------------
  |  Branch (32:5): [True: 0, False: 329k]
  ------------------
   33|       |
   34|   329k|	if (node->children && node->children->count > 0) {
  ------------------
  |  Branch (34:6): [True: 18.6k, False: 311k]
  |  Branch (34:24): [True: 0, False: 18.6k]
  ------------------
   35|      0|		node_t ch;
   36|      0|		while ((ch = node->children->begin)) {
  ------------------
  |  Branch (36:10): [True: 0, False: 0]
  ------------------
   37|      0|			node_list_remove(node->children, ch);
   38|      0|			node_destroy(ch);
   39|      0|		}
   40|      0|	}
   41|   329k|	node_list_destroy(node->children);
   42|   329k|	node->children = NULL;
   43|       |
   44|   329k|	free(node);
   45|   329k|}
node_create:
   48|   329k|{
   49|   329k|	int error = 0;
   50|       |
   51|   329k|	node_t node = (node_t)calloc(1, sizeof(struct node));
   52|   329k|	if (node == NULL) {
  ------------------
  |  Branch (52:6): [True: 0, False: 329k]
  ------------------
   53|      0|		return NULL;
   54|      0|	}
   55|       |
   56|   329k|	node->data = data;
   57|   329k|	node->next = NULL;
   58|   329k|	node->prev = NULL;
   59|   329k|	node->count = 0;
   60|   329k|	node->parent = NULL;
   61|   329k|	node->children = NULL;
   62|       |
   63|       |	// Pass NULL to create a root node
   64|   329k|	if (parent != NULL) {
  ------------------
  |  Branch (64:6): [True: 0, False: 329k]
  ------------------
   65|       |		// This is a child node so attach it to it's parent
   66|      0|		error = node_attach(parent, node);
   67|      0|		if (error < 0) {
  ------------------
  |  Branch (67:7): [True: 0, False: 0]
  ------------------
   68|       |			// Unable to attach nodes
   69|      0|			node_destroy(node);
   70|      0|			return NULL;
   71|      0|		}
   72|      0|	}
   73|       |
   74|   329k|	return node;
   75|   329k|}
node_attach:
  133|   223k|{
  134|   223k|	if (!parent || !child) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (134:6): [True: 0, False: 223k]
  |  Branch (134:17): [True: 0, False: 223k]
  ------------------
  135|       |
  136|       |	// already parented?
  137|   223k|	if (child->parent) return NODE_ERR_PARENT;
  ------------------
  |  |   39|      0|#define NODE_ERR_PARENT       -3
  ------------------
  |  Branch (137:6): [True: 0, False: 223k]
  ------------------
  138|       |
  139|       |	// self/cycle guard
  140|   223k|	if (parent == child) return NODE_ERR_CIRCULAR_REF;
  ------------------
  |  |   40|      0|#define NODE_ERR_CIRCULAR_REF -4
  ------------------
  |  Branch (140:6): [True: 0, False: 223k]
  ------------------
  141|   223k|	if (would_create_cycle(parent, child)) return NODE_ERR_CIRCULAR_REF;
  ------------------
  |  |   40|      0|#define NODE_ERR_CIRCULAR_REF -4
  ------------------
  |  Branch (141:6): [True: 0, False: 223k]
  ------------------
  142|       |
  143|       |	// depth guard: depth(parent)+1+max_depth(child_subtree) <= NODE_MAX_DEPTH
  144|   223k|	int pd = node_depth_from_root(parent);
  145|   223k|	int cd = node_subtree_max_depth(child);
  146|   223k|	if (pd + 1 + cd > NODE_MAX_DEPTH) {
  ------------------
  |  |   33|   223k|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (146:6): [True: 0, False: 223k]
  ------------------
  147|      0|		return NODE_ERR_MAX_DEPTH;
  ------------------
  |  |   41|      0|#define NODE_ERR_MAX_DEPTH    -5
  ------------------
  148|      0|	}
  149|       |
  150|   223k|	if (!parent->children) {
  ------------------
  |  Branch (150:6): [True: 18.6k, False: 204k]
  ------------------
  151|  18.6k|		parent->children = node_list_create();
  152|  18.6k|		if (!parent->children) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (152:7): [True: 0, False: 18.6k]
  ------------------
  153|  18.6k|	}
  154|   223k|	int res = node_list_add(parent->children, child);
  155|   223k|	if (res == 0) {
  ------------------
  |  Branch (155:6): [True: 223k, False: 0]
  ------------------
  156|   223k|		child->parent = parent;
  157|   223k|		parent->count++;
  158|   223k|	}
  159|   223k|	return res;
  160|   223k|}
node_detach:
  163|   225k|{
  164|   225k|	if (!parent || !child) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (164:6): [True: 0, False: 225k]
  |  Branch (164:17): [True: 0, False: 225k]
  ------------------
  165|   225k|	if (!parent->children) return NODE_ERR_NOT_FOUND;
  ------------------
  |  |   42|      0|#define NODE_ERR_NOT_FOUND    -6
  ------------------
  |  Branch (165:6): [True: 0, False: 225k]
  ------------------
  166|   225k|	if (child->parent && child->parent != parent) return NODE_ERR_PARENT;
  ------------------
  |  |   39|      0|#define NODE_ERR_PARENT       -3
  ------------------
  |  Branch (166:6): [True: 225k, False: 0]
  |  Branch (166:23): [True: 0, False: 225k]
  ------------------
  167|       |
  168|   225k|	int node_index = node_list_remove(parent->children, child);
  169|   225k|	if (node_index >= 0) {
  ------------------
  |  Branch (169:6): [True: 225k, False: 0]
  ------------------
  170|   225k|		if (parent->count > 0) parent->count--;
  ------------------
  |  Branch (170:7): [True: 225k, False: 0]
  ------------------
  171|   225k|		child->parent = NULL;
  172|   225k|		child->prev = NULL;
  173|       |		child->next = NULL;
  174|   225k|	}
  175|   225k|	return node_index;
  176|   225k|}
node_insert:
  179|  1.63k|{
  180|  1.63k|	if (!parent || !child) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (180:6): [True: 0, False: 1.63k]
  |  Branch (180:17): [True: 0, False: 1.63k]
  ------------------
  181|       |
  182|       |	// already parented?
  183|  1.63k|	if (child->parent) return NODE_ERR_PARENT;
  ------------------
  |  |   39|      0|#define NODE_ERR_PARENT       -3
  ------------------
  |  Branch (183:6): [True: 0, False: 1.63k]
  ------------------
  184|       |
  185|       |	// self/cycle guard
  186|  1.63k|	if (parent == child) return NODE_ERR_CIRCULAR_REF;
  ------------------
  |  |   40|      0|#define NODE_ERR_CIRCULAR_REF -4
  ------------------
  |  Branch (186:6): [True: 0, False: 1.63k]
  ------------------
  187|  1.63k|	if (would_create_cycle(parent, child)) return NODE_ERR_CIRCULAR_REF;
  ------------------
  |  |   40|      0|#define NODE_ERR_CIRCULAR_REF -4
  ------------------
  |  Branch (187:6): [True: 0, False: 1.63k]
  ------------------
  188|       |
  189|       |	// depth guard: depth(parent)+1+max_depth(child_subtree) <= NODE_MAX_DEPTH
  190|  1.63k|	int pd = node_depth_from_root(parent);
  191|  1.63k|	int cd = node_subtree_max_depth(child);
  192|  1.63k|	if (pd + 1 + cd > NODE_MAX_DEPTH) {
  ------------------
  |  |   33|  1.63k|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (192:6): [True: 0, False: 1.63k]
  ------------------
  193|      0|		return NODE_ERR_MAX_DEPTH;
  ------------------
  |  |   41|      0|#define NODE_ERR_MAX_DEPTH    -5
  ------------------
  194|      0|	}
  195|       |
  196|  1.63k|	if (!parent->children) {
  ------------------
  |  Branch (196:6): [True: 0, False: 1.63k]
  ------------------
  197|      0|		parent->children = node_list_create();
  198|      0|		if (!parent->children) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (198:7): [True: 0, False: 0]
  ------------------
  199|      0|	}
  200|  1.63k|	int res = node_list_insert(parent->children, node_index, child);
  201|  1.63k|	if (res == 0) {
  ------------------
  |  Branch (201:6): [True: 1.63k, False: 0]
  ------------------
  202|  1.63k|		child->parent = parent;
  203|  1.63k|		parent->count++;
  204|  1.63k|	}
  205|  1.63k|	return res;
  206|  1.63k|}
node_first_child:
  262|  3.87M|{
  263|  3.87M|	if (!node || !node->children) return NULL;
  ------------------
  |  Branch (263:6): [True: 0, False: 3.87M]
  |  Branch (263:15): [True: 311k, False: 3.56M]
  ------------------
  264|  3.56M|	return node->children->begin;
  265|  3.87M|}
node_prev_sibling:
  268|  1.63k|{
  269|  1.63k|	if (!node) return NULL;
  ------------------
  |  Branch (269:6): [True: 0, False: 1.63k]
  ------------------
  270|  1.63k|	return node->prev;
  271|  1.63k|}
node_next_sibling:
  274|  24.5M|{
  275|  24.5M|	if (!node) return NULL;
  ------------------
  |  Branch (275:6): [True: 0, False: 24.5M]
  ------------------
  276|  24.5M|	return node->next;
  277|  24.5M|}
node.c:would_create_cycle:
  124|   225k|{
  125|       |	// if parent is anywhere in child's ancestor chain => cycle
  126|   450k|	for (node_t p = parent; p; p = p->parent) {
  ------------------
  |  Branch (126:26): [True: 225k, False: 225k]
  ------------------
  127|   225k|		if (p == child) return 1;
  ------------------
  |  Branch (127:7): [True: 0, False: 225k]
  ------------------
  128|   225k|	}
  129|   225k|	return 0;
  130|   225k|}
node.c:node_depth_from_root:
   78|   225k|{
   79|   225k|	int d = 0;
   80|   225k|	while (n && n->parent) {
  ------------------
  |  Branch (80:9): [True: 225k, False: 0]
  |  Branch (80:14): [True: 0, False: 225k]
  ------------------
   81|      0|		d++;
   82|      0|		n = n->parent;
   83|      0|		if (d > NODE_MAX_DEPTH) return d; // early out
  ------------------
  |  |   33|      0|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (83:7): [True: 0, False: 0]
  ------------------
   84|      0|	}
   85|   225k|	return d;
   86|   225k|}
node.c:node_subtree_max_depth:
   89|   225k|{
   90|   225k|	if (!root) return 0;
  ------------------
  |  Branch (90:6): [True: 0, False: 225k]
  ------------------
   91|       |
   92|   225k|	typedef struct { node_t n; int depth; } frame_t;
   93|   225k|	size_t cap = 64, sp = 0;
   94|   225k|	frame_t *st = (frame_t*)malloc(cap * sizeof(*st));
   95|   225k|	if (!st) return NODE_MAX_DEPTH + 1;
  ------------------
  |  |   33|      0|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (95:6): [True: 0, False: 225k]
  ------------------
   96|       |
   97|   225k|	st[sp++] = (frame_t){ root, 0 };
   98|   225k|	int maxd = 0;
   99|       |
  100|  3.75M|	while (sp) {
  ------------------
  |  Branch (100:9): [True: 3.52M, False: 225k]
  ------------------
  101|  3.52M|		frame_t f = st[--sp];
  102|  3.52M|		if (f.depth > maxd) maxd = f.depth;
  ------------------
  |  Branch (102:7): [True: 3.23M, False: 290k]
  ------------------
  103|  3.52M|		if (maxd > NODE_MAX_DEPTH) break;
  ------------------
  |  |   33|  3.52M|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (103:7): [True: 0, False: 3.52M]
  ------------------
  104|       |
  105|  3.52M|		if (!f.n->children) continue;
  ------------------
  |  Branch (105:7): [True: 290k, False: 3.23M]
  ------------------
  106|       |
  107|  6.53M|		for (node_t ch = node_first_child(f.n); ch; ch = node_next_sibling(ch)) {
  ------------------
  |  Branch (107:43): [True: 3.30M, False: 3.23M]
  ------------------
  108|  3.30M|			if (sp == cap) {
  ------------------
  |  Branch (108:8): [True: 356, False: 3.29M]
  ------------------
  109|    356|				cap *= 2;
  110|    356|				frame_t *tmp = (frame_t*)realloc(st, cap * sizeof(*st));
  111|    356|				if (!tmp) { maxd = NODE_MAX_DEPTH + 1; goto out; }
  ------------------
  |  |   33|      0|#define NODE_MAX_DEPTH 512
  ------------------
  |  Branch (111:9): [True: 0, False: 356]
  ------------------
  112|    356|				st = tmp;
  113|    356|			}
  114|  3.30M|			st[sp++] = (frame_t){ ch, f.depth + 1 };
  115|  3.30M|		}
  116|  3.23M|	}
  117|       |
  118|   225k|out:
  119|   225k|	free(st);
  120|   225k|	return maxd;
  121|   225k|}

node_list_destroy:
   32|   329k|{
   33|   329k|	free(list);
   34|   329k|}
node_list_create:
   37|  18.6k|{
   38|  18.6k|	node_list_t list = (node_list_t)calloc(1, sizeof(struct node_list));
   39|  18.6k|	if (list == NULL) {
  ------------------
  |  Branch (39:6): [True: 0, False: 18.6k]
  ------------------
   40|      0|		return NULL;
   41|      0|	}
   42|       |
   43|       |	// Initialize structure
   44|  18.6k|	list->begin = NULL;
   45|       |	list->end = NULL;
   46|  18.6k|	list->count = 0;
   47|  18.6k|	return list;
   48|  18.6k|}
node_list_add:
   51|   223k|{
   52|   223k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (52:6): [True: 0, False: 223k]
  |  Branch (52:15): [True: 0, False: 223k]
  ------------------
   53|       |
   54|       |	// Find the last element in the list
   55|   223k|	node_t last = list->end;
   56|       |
   57|       |	// Setup our new node as the new last element
   58|   223k|	node->next = NULL;
   59|   223k|	node->prev = last;
   60|       |
   61|       |	// Set the next element of our old "last" element
   62|   223k|	if (last) {
  ------------------
  |  Branch (62:6): [True: 205k, False: 18.6k]
  ------------------
   63|       |		// but only if the node list is not empty
   64|   205k|		last->next = node;
   65|   205k|	} else {
   66|       |		// otherwise this is the start of the list
   67|  18.6k|		list->begin = node;
   68|  18.6k|	}
   69|       |
   70|       |	// Set the lists prev to the new last element
   71|   223k|	list->end = node;
   72|       |
   73|       |	// Increment our node count for this list
   74|   223k|	list->count++;
   75|   223k|	return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|   223k|#define NODE_ERR_SUCCESS       0
  ------------------
   76|   223k|}
node_list_insert:
   79|  1.63k|{
   80|  1.63k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (80:6): [True: 0, False: 1.63k]
  |  Branch (80:15): [True: 0, False: 1.63k]
  ------------------
   81|  1.63k|	if (node_index > list->count) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (81:6): [True: 0, False: 1.63k]
  ------------------
   82|  1.63k|	if (node_index == list->count) {
  ------------------
  |  Branch (82:6): [True: 398, False: 1.24k]
  ------------------
   83|    398|		return node_list_add(list, node);
   84|    398|	}
   85|       |
   86|       |	// Get the first element in the list
   87|  1.24k|	node_t cur = list->begin;
   88|  1.24k|	node_t prev = NULL;
   89|       |
   90|   193k|	for (unsigned int pos = 0; pos < node_index; pos++) {
  ------------------
  |  Branch (90:29): [True: 192k, False: 1.24k]
  ------------------
   91|   192k|		if (!cur) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (91:7): [True: 0, False: 192k]
  ------------------
   92|   192k|		prev = cur;
   93|   192k|		cur = cur->next;
   94|   192k|	}
   95|       |
   96|       |	// insert node before cur
   97|  1.24k|	node->prev = prev;
   98|  1.24k|	node->next = cur;
   99|       |
  100|  1.24k|	if (prev) {
  ------------------
  |  Branch (100:6): [True: 1.24k, False: 0]
  ------------------
  101|  1.24k|		prev->next = node;
  102|  1.24k|	} else {
  103|      0|		list->begin = node;
  104|      0|	}
  105|       |
  106|  1.24k|	if (cur) {
  ------------------
  |  Branch (106:6): [True: 1.24k, False: 0]
  ------------------
  107|  1.24k|		cur->prev = node;
  108|  1.24k|	} else {
  109|       |		// should not happen with bounds above, but keeps things consistent
  110|      0|		list->end = node;
  111|      0|	}
  112|       |
  113|       |	// Increment our node count for this list
  114|  1.24k|	list->count++;
  115|  1.24k|	return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.24k|#define NODE_ERR_SUCCESS       0
  ------------------
  116|  1.24k|}
node_list_remove:
  120|   225k|{
  121|   225k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (121:6): [True: 0, False: 225k]
  |  Branch (121:15): [True: 0, False: 225k]
  ------------------
  122|   225k|	if (list->count == 0) return NODE_ERR_NOT_FOUND;
  ------------------
  |  |   42|      0|#define NODE_ERR_NOT_FOUND    -6
  ------------------
  |  Branch (122:6): [True: 0, False: 225k]
  ------------------
  123|       |
  124|   225k|	int node_index = 0;
  125|   422k|	for (node_t n = list->begin; n; n = n->next, node_index++) {
  ------------------
  |  Branch (125:31): [True: 422k, False: 0]
  ------------------
  126|   422k|		if (node != n) continue;
  ------------------
  |  Branch (126:7): [True: 197k, False: 225k]
  ------------------
  127|       |
  128|   225k|		node_t newnode = node->next;
  129|   225k|		if (node->prev) {
  ------------------
  |  Branch (129:7): [True: 1.63k, False: 223k]
  ------------------
  130|  1.63k|			node->prev->next = newnode;
  131|   223k|		} else {
  132|       |			// we just removed the first element
  133|   223k|			list->begin = newnode;
  134|   223k|		}
  135|       |
  136|   225k|		if (newnode) {
  ------------------
  |  Branch (136:7): [True: 206k, False: 19.0k]
  ------------------
  137|   206k|			newnode->prev = node->prev;
  138|   206k|		} else {
  139|       |			// we removed the last element, set new end
  140|  19.0k|			list->end = node->prev;
  141|  19.0k|		}
  142|       |
  143|       |		// fully detach node from list
  144|   225k|		node->prev = NULL;
  145|   225k|		node->next = NULL;
  146|       |
  147|   225k|		list->count--;
  148|   225k|		return node_index;
  149|   422k|	}
  150|      0|	return NODE_ERR_NOT_FOUND;
  ------------------
  |  |   42|      0|#define NODE_ERR_NOT_FOUND    -6
  ------------------
  151|   225k|}

plist_bin_init:
  254|      2|{
  255|       |    /* init binary plist stuff */
  256|      2|#ifdef DEBUG
  257|      2|    char *env_debug = getenv("PLIST_BIN_DEBUG");
  258|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (258:9): [True: 0, False: 2]
  |  Branch (258:22): [True: 0, False: 0]
  ------------------
  259|      0|        plist_bin_debug = 1;
  260|      0|    }
  261|      2|#endif
  262|      2|}

byte_array_new:
   27|    295|{
   28|    295|	bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t));
   29|    295|	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|    295|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|      0|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|      0|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|    590|#define PAGE_SIZE 4096
  ------------------
  |  Branch (29:16): [True: 0, False: 295]
  ------------------
   30|    295|	a->data = malloc(a->capacity);
   31|    295|	a->len = 0;
   32|       |	a->stream = NULL;
   33|    295|	return a;
   34|    295|}
byte_array_free:
   47|    295|{
   48|    295|	if (!ba) return;
  ------------------
  |  Branch (48:6): [True: 0, False: 295]
  ------------------
   49|    295|	if (ba->data) {
  ------------------
  |  Branch (49:6): [True: 56, False: 239]
  ------------------
   50|     56|		free(ba->data);
   51|     56|	}
   52|    295|	free(ba);
   53|    295|}
byte_array_append:
   66|  1.79k|{
   67|  1.79k|	if (!ba || (!ba->stream && !ba->data) || (len <= 0)) return;
  ------------------
  |  Branch (67:6): [True: 0, False: 1.79k]
  |  Branch (67:14): [True: 1.79k, False: 0]
  |  Branch (67:29): [True: 0, False: 1.79k]
  |  Branch (67:43): [True: 0, False: 1.79k]
  ------------------
   68|  1.79k|	if (ba->stream) {
  ------------------
  |  Branch (68:6): [True: 0, False: 1.79k]
  ------------------
   69|      0|		if (fwrite(buf, 1, len, ba->stream) < len) {
  ------------------
  |  Branch (69:7): [True: 0, False: 0]
  ------------------
   70|       |#if DEBUG
   71|       |			fprintf(stderr, "ERROR: Failed to write to stream.\n");
   72|       |#endif
   73|      0|		}
   74|  1.79k|	} else {
   75|  1.79k|		size_t remaining = ba->capacity-ba->len;
   76|  1.79k|		if (len > remaining) {
  ------------------
  |  Branch (76:7): [True: 0, False: 1.79k]
  ------------------
   77|      0|			size_t needed = len - remaining;
   78|      0|			byte_array_grow(ba, needed);
   79|      0|		}
   80|  1.79k|		memcpy(((char*)ba->data) + ba->len, buf, len);
   81|  1.79k|	}
   82|  1.79k|	ba->len += len;
   83|  1.79k|}

hash_table_new:
   24|    327|{
   25|    327|	hashtable_t* ht = (hashtable_t*)malloc(sizeof(hashtable_t));
   26|    327|	int i;
   27|  1.33M|	for (i = 0; i < 4096; i++) {
  ------------------
  |  Branch (27:14): [True: 1.33M, False: 327]
  ------------------
   28|       |		ht->entries[i] = NULL;
   29|  1.33M|	}
   30|    327|	ht->count = 0;
   31|    327|	ht->hash_func = hash_func;
   32|    327|	ht->compare_func = compare_func;
   33|    327|	ht->free_func = free_func;
   34|    327|	return ht;
   35|    327|}
hash_table_destroy:
   38|  20.7k|{
   39|  20.7k|	if (!ht) return;
  ------------------
  |  Branch (39:6): [True: 20.3k, False: 327]
  ------------------
   40|       |
   41|    327|	int i = 0;
   42|  1.33M|	for (i = 0; i < 4096; i++) {
  ------------------
  |  Branch (42:14): [True: 1.33M, False: 327]
  ------------------
   43|  1.33M|		if (ht->entries[i]) {
  ------------------
  |  Branch (43:7): [True: 80.8k, False: 1.25M]
  ------------------
   44|  80.8k|			hashentry_t* e = ht->entries[i];
   45|   163k|			while (e) {
  ------------------
  |  Branch (45:11): [True: 82.7k, False: 80.8k]
  ------------------
   46|  82.7k|				if (ht->free_func) {
  ------------------
  |  Branch (46:9): [True: 0, False: 82.7k]
  ------------------
   47|      0|					ht->free_func(e->value);
   48|      0|				}
   49|  82.7k|				hashentry_t* old = e;
   50|  82.7k|				e = e->next;
   51|  82.7k|				free(old);
   52|  82.7k|			}
   53|  80.8k|		}
   54|  1.33M|	}
   55|    327|	free(ht);
   56|    327|}
hash_table_insert:
   59|  83.4k|{
   60|  83.4k|	if (!ht || !key) return;
  ------------------
  |  Branch (60:6): [True: 0, False: 83.4k]
  |  Branch (60:13): [True: 0, False: 83.4k]
  ------------------
   61|       |
   62|  83.4k|	unsigned int hash = ht->hash_func(key);
   63|       |
   64|  83.4k|	int idx0 = hash & 0xFFF;
   65|       |
   66|       |	// get the idx0 list
   67|  83.4k|	hashentry_t* e = ht->entries[idx0];
   68|  85.9k|	while (e) {
  ------------------
  |  Branch (68:9): [True: 3.24k, False: 82.7k]
  ------------------
   69|  3.24k|		if (ht->compare_func(e->key, key)) {
  ------------------
  |  Branch (69:7): [True: 690, False: 2.55k]
  ------------------
   70|       |			// element already present. replace value.
   71|    690|			e->value = value;
   72|    690|			return;
   73|    690|		}
   74|  2.55k|		e = e->next;
   75|  2.55k|	}
   76|       |
   77|       |	// if we get here, the element is not yet in the list.
   78|       |
   79|       |	// make a new entry.
   80|  82.7k|	hashentry_t* entry = (hashentry_t*)malloc(sizeof(hashentry_t));
   81|  82.7k|	entry->key = key;
   82|  82.7k|	entry->value = value;
   83|  82.7k|	if (!ht->entries[idx0]) {
  ------------------
  |  Branch (83:6): [True: 80.8k, False: 1.89k]
  ------------------
   84|       |		// first entry
   85|  80.8k|		entry->next = NULL;
   86|  80.8k|	} else {
   87|       |		// add to list
   88|  1.89k|		entry->next = ht->entries[idx0];
   89|  1.89k|	}
   90|  82.7k|	ht->entries[idx0] = entry;
   91|  82.7k|	ht->count++;
   92|  82.7k|}
hash_table_lookup:
   95|  1.32k|{
   96|  1.32k|	if (!ht || !key) return NULL;
  ------------------
  |  Branch (96:6): [True: 0, False: 1.32k]
  |  Branch (96:13): [True: 0, False: 1.32k]
  ------------------
   97|  1.32k|	unsigned int hash = ht->hash_func(key);
   98|       |
   99|  1.32k|	int idx0 = hash & 0xFFF;
  100|       |
  101|  1.32k|	hashentry_t* e = ht->entries[idx0];
  102|  1.86k|	while (e) {
  ------------------
  |  Branch (102:9): [True: 1.22k, False: 638]
  ------------------
  103|  1.22k|		if (ht->compare_func(e->key, key)) {
  ------------------
  |  Branch (103:7): [True: 690, False: 536]
  ------------------
  104|    690|			return e->value;
  105|    690|		}
  106|    536|		e = e->next;
  107|    536|	}
  108|    638|	return NULL;
  109|  1.32k|}

plist_json_init:
   56|      2|{
   57|       |    /* init JSON stuff */
   58|      2|#ifdef DEBUG
   59|      2|    char *env_debug = getenv("PLIST_JSON_DEBUG");
   60|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (60:9): [True: 0, False: 2]
  |  Branch (60:22): [True: 0, False: 0]
  ------------------
   61|      0|        plist_json_debug = 1;
   62|      0|    }
   63|      2|#endif
   64|      2|}

plist_ostep_init:
   54|      2|{
   55|       |    /* init OpenStep stuff */
   56|      2|#ifdef DEBUG
   57|      2|    char *env_debug = getenv("PLIST_OSTEP_DEBUG");
   58|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (58:9): [True: 0, False: 2]
  |  Branch (58:22): [True: 0, False: 0]
  ------------------
   59|      0|        plist_ostep_debug = 1;
   60|      0|    }
   61|      2|#endif
   62|      2|}
plist_from_openstep:
  955|  1.58k|{
  956|  1.58k|    if (!plist) {
  ------------------
  |  Branch (956:9): [True: 0, False: 1.58k]
  ------------------
  957|      0|        return PLIST_ERR_INVALID_ARG;
  958|      0|    }
  959|  1.58k|    *plist = NULL;
  960|  1.58k|    if (!plist_ostep || (length == 0)) {
  ------------------
  |  Branch (960:9): [True: 0, False: 1.58k]
  |  Branch (960:25): [True: 0, False: 1.58k]
  ------------------
  961|      0|        return PLIST_ERR_INVALID_ARG;
  962|      0|    }
  963|       |
  964|  1.58k|    struct _parse_ctx ctx = { plist_ostep, plist_ostep, plist_ostep + length, 0 , 0 };
  965|       |
  966|  1.58k|    plist_err_t err = node_from_openstep(&ctx, plist);
  967|  1.58k|    if (err == 0) {
  ------------------
  |  Branch (967:9): [True: 1.08k, False: 506]
  ------------------
  968|  1.08k|        if (!*plist) {
  ------------------
  |  Branch (968:13): [True: 59, False: 1.02k]
  ------------------
  969|       |            /* whitespace only file is considered an empty dictionary */
  970|     59|            *plist = plist_new_dict();
  971|  1.02k|        } else if (ctx.pos < ctx.end && *ctx.pos == '=') {
  ------------------
  |  Branch (971:20): [True: 856, False: 167]
  |  Branch (971:41): [True: 843, False: 13]
  ------------------
  972|       |            /* attempt to parse this as 'strings' data */
  973|    843|            plist_free(*plist);
  974|    843|            *plist = NULL;
  975|    843|            plist_t pl = plist_new_dict();
  976|    843|            ctx.pos = plist_ostep;
  977|    843|            parse_dict_data(&ctx, pl);
  978|    843|            if (ctx.err > 0) {
  ------------------
  |  Branch (978:17): [True: 0, False: 843]
  ------------------
  979|      0|                plist_free(pl);
  980|      0|                PLIST_OSTEP_ERR("Failed to parse strings data\n");
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  981|      0|                err = PLIST_ERR_PARSE;
  982|    843|            } else {
  983|    843|                *plist = pl;
  984|    843|            }
  985|    843|        }
  986|  1.08k|    }
  987|       |
  988|  1.58k|    return err;
  989|  1.58k|}
oplist.c:node_from_openstep:
  663|   243k|{
  664|   243k|    plist_t subnode = NULL;
  665|   243k|    const char *p = NULL;
  666|   243k|    ctx->depth++;
  667|   243k|    if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
  ------------------
  |  |   56|   243k|#define PLIST_MAX_NESTING_DEPTH NODE_MAX_DEPTH
  |  |  ------------------
  |  |  |  |   33|   243k|#define NODE_MAX_DEPTH 512
  |  |  ------------------
  ------------------
  |  Branch (667:9): [True: 4, False: 243k]
  ------------------
  668|      4|        PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      4|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 4]
  |  |  ------------------
  ------------------
  669|      4|        ctx->err = PLIST_ERR_MAX_NESTING;
  670|      4|        return ctx->err;
  671|      4|    }
  672|   243k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (672:12): [True: 243k, False: 0]
  |  Branch (672:35): [True: 243k, False: 0]
  ------------------
  673|   243k|        parse_skip_ws(ctx);
  674|   243k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (674:13): [True: 67, False: 243k]
  ------------------
  675|     67|            break;
  676|     67|        }
  677|   243k|        plist_data_t data = plist_new_plist_data();
  678|   243k|        if (*ctx->pos == '{') {
  ------------------
  |  Branch (678:13): [True: 19.8k, False: 223k]
  ------------------
  679|  19.8k|            data->type = PLIST_DICT;
  680|  19.8k|            subnode = plist_new_node(data);
  681|  19.8k|            ctx->pos++;
  682|  19.8k|            parse_dict_data(ctx, subnode);
  683|  19.8k|            if (ctx->err) {
  ------------------
  |  Branch (683:17): [True: 12.3k, False: 7.47k]
  ------------------
  684|  12.3k|                goto err_out;
  685|  12.3k|            }
  686|  7.47k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (686:17): [True: 71, False: 7.40k]
  ------------------
  687|     71|                PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     71|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 71]
  |  |  ------------------
  ------------------
  688|     71|                ctx->err = PLIST_ERR_PARSE;
  689|     71|                break;
  690|     71|            }
  691|  7.40k|            if (*ctx->pos != '}') {
  ------------------
  |  Branch (691:17): [True: 0, False: 7.40k]
  ------------------
  692|      0|                PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  693|      0|                ctx->err = PLIST_ERR_PARSE;
  694|      0|                goto err_out;
  695|      0|            }
  696|  7.40k|            ctx->pos++;
  697|  7.40k|            *plist = subnode;
  698|  7.40k|            parse_skip_ws(ctx);
  699|  7.40k|            break;
  700|   223k|        } else if (*ctx->pos == '(') {
  ------------------
  |  Branch (700:20): [True: 19.6k, False: 203k]
  ------------------
  701|  19.6k|            data->type = PLIST_ARRAY;
  702|  19.6k|            subnode = plist_new_node(data);
  703|  19.6k|            ctx->pos++;
  704|  19.6k|            plist_t tmp = NULL;
  705|  53.4k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (705:20): [True: 53.3k, False: 26]
  |  Branch (705:43): [True: 53.3k, False: 0]
  ------------------
  706|  53.3k|                parse_skip_ws(ctx);
  707|  53.3k|                if (ctx->pos >= ctx->end || *ctx->pos == ')') {
  ------------------
  |  Branch (707:21): [True: 1, False: 53.3k]
  |  Branch (707:45): [True: 351, False: 53.0k]
  ------------------
  708|    352|                    break;
  709|    352|                }
  710|  53.0k|                ctx->err = node_from_openstep(ctx, &tmp);
  711|  53.0k|                if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (711:21): [True: 1.72k, False: 51.2k]
  ------------------
  712|  1.72k|                    break;
  713|  1.72k|                }
  714|  51.2k|                if (!tmp) {
  ------------------
  |  Branch (714:21): [True: 1, False: 51.2k]
  ------------------
  715|      1|                    ctx->err = PLIST_ERR_PARSE;
  716|      1|                    break;
  717|      1|                }
  718|  51.2k|                plist_array_append_item(subnode, tmp);
  719|  51.2k|                tmp = NULL;
  720|  51.2k|                parse_skip_ws(ctx);
  721|  51.2k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (721:21): [True: 103, False: 51.1k]
  ------------------
  722|    103|                    PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    103|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 103]
  |  |  ------------------
  ------------------
  723|    103|                    ctx->err = PLIST_ERR_PARSE;
  724|    103|                    break;
  725|    103|                }
  726|  51.1k|                if (*ctx->pos != ',') {
  ------------------
  |  Branch (726:21): [True: 17.4k, False: 33.7k]
  ------------------
  727|  17.4k|                    break;
  728|  17.4k|                }
  729|  33.7k|                ctx->pos++;
  730|  33.7k|            }
  731|  19.6k|	    plist_free(tmp);
  732|  19.6k|	    tmp = NULL;
  733|  19.6k|            if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (733:17): [True: 1.83k, False: 17.8k]
  ------------------
  734|  1.83k|                goto err_out;
  735|  1.83k|            }
  736|  17.8k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (736:17): [True: 27, False: 17.8k]
  ------------------
  737|     27|                PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     27|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 27]
  |  |  ------------------
  ------------------
  738|     27|                ctx->err = PLIST_ERR_PARSE;
  739|     27|                break;
  740|     27|            }
  741|  17.8k|            if (*ctx->pos != ')') {
  ------------------
  |  Branch (741:17): [True: 20, False: 17.7k]
  ------------------
  742|     20|                PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     20|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 20]
  |  |  ------------------
  ------------------
  743|     20|                ctx->err = PLIST_ERR_PARSE;
  744|     20|                goto err_out;
  745|     20|            }
  746|  17.7k|            ctx->pos++;
  747|  17.7k|            *plist = subnode;
  748|  17.7k|            parse_skip_ws(ctx);
  749|  17.7k|            break;
  750|   203k|        } else if (*ctx->pos == '<') {
  ------------------
  |  Branch (750:20): [True: 295, False: 203k]
  ------------------
  751|    295|            data->type = PLIST_DATA;
  752|    295|            ctx->pos++;
  753|    295|            bytearray_t *bytes = byte_array_new(256);
  754|  2.09k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (754:20): [True: 2.06k, False: 28]
  |  Branch (754:43): [True: 2.06k, False: 0]
  ------------------
  755|  2.06k|                parse_skip_ws(ctx);
  756|  2.06k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (756:21): [True: 1, False: 2.06k]
  ------------------
  757|      1|                    PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  758|      1|                    ctx->err = PLIST_ERR_PARSE;
  759|      1|                    break;
  760|      1|                }
  761|  2.06k|                if (*ctx->pos == '>') {
  ------------------
  |  Branch (761:21): [True: 239, False: 1.82k]
  ------------------
  762|    239|                    break;
  763|    239|                }
  764|  1.82k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (764:21): [True: 8, False: 1.81k]
  ------------------
  765|      8|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      8|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 8]
  |  |  ------------------
  ------------------
  766|      8|                    ctx->err = PLIST_ERR_PARSE;
  767|      8|                    break;
  768|      8|                }
  769|  1.81k|                uint8_t b = HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.81k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 1.04k, False: 772]
  |  |  |  Branch (589:49): [True: 399, False: 373]
  |  |  ------------------
  ------------------
  770|  1.81k|                ctx->pos++;
  771|  1.81k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (771:21): [True: 18, False: 1.79k]
  ------------------
  772|     18|                    PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     18|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 18]
  |  |  ------------------
  ------------------
  773|     18|                    ctx->err = PLIST_ERR_PARSE;
  774|     18|                    break;
  775|     18|                }
  776|  1.79k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (776:21): [True: 1, False: 1.79k]
  ------------------
  777|      1|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  778|      1|                    ctx->err = PLIST_ERR_PARSE;
  779|      1|                    break;
  780|      1|                }
  781|  1.79k|                b = (b << 4) + HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.79k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 1.04k, False: 758]
  |  |  |  Branch (589:49): [True: 394, False: 364]
  |  |  ------------------
  ------------------
  782|  1.79k|                byte_array_append(bytes, &b, 1);
  783|  1.79k|                ctx->pos++;
  784|  1.79k|            }
  785|    295|            if (ctx->err) {
  ------------------
  |  Branch (785:17): [True: 28, False: 267]
  ------------------
  786|     28|                byte_array_free(bytes);
  787|     28|                plist_free_data(data);
  788|     28|                goto err_out;
  789|     28|            }
  790|    267|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (790:17): [True: 28, False: 239]
  ------------------
  791|     28|                byte_array_free(bytes);
  792|     28|                plist_free_data(data);
  793|     28|                PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     28|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 28]
  |  |  ------------------
  ------------------
  794|     28|                ctx->err = PLIST_ERR_PARSE;
  795|     28|                goto err_out;
  796|     28|            }
  797|    239|            if (*ctx->pos != '>') {
  ------------------
  |  Branch (797:17): [True: 0, False: 239]
  ------------------
  798|      0|                byte_array_free(bytes);
  799|      0|                plist_free_data(data);
  800|      0|                PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  801|      0|                ctx->err = PLIST_ERR_PARSE;
  802|      0|                goto err_out;
  803|      0|            }
  804|    239|            ctx->pos++;
  805|    239|            data->buff = (uint8_t*)bytes->data;
  806|    239|            data->length = bytes->len;
  807|    239|            bytes->data = NULL;
  808|    239|            byte_array_free(bytes);
  809|    239|            *plist = plist_new_node(data);
  810|    239|            parse_skip_ws(ctx);
  811|    239|            break;
  812|   203k|        } else if (*ctx->pos == '"' || *ctx->pos == '\'') {
  ------------------
  |  Branch (812:20): [True: 30.2k, False: 173k]
  |  Branch (812:40): [True: 6.45k, False: 166k]
  ------------------
  813|  36.7k|            char c = *ctx->pos;
  814|  36.7k|            ctx->pos++;
  815|  36.7k|            p = ctx->pos;
  816|  36.7k|            size_t num_escapes = 0;
  817|   119k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (817:20): [True: 119k, False: 61]
  ------------------
  818|   119k|                if (*ctx->pos == '\\') {
  ------------------
  |  Branch (818:21): [True: 15.7k, False: 103k]
  ------------------
  819|  15.7k|                    num_escapes++;
  820|  15.7k|                }
  821|   119k|                if ((*ctx->pos == c) && (*(ctx->pos-1) != '\\')) {
  ------------------
  |  Branch (821:21): [True: 37.2k, False: 82.3k]
  |  Branch (821:41): [True: 36.6k, False: 583]
  ------------------
  822|  36.6k|                    break;
  823|  36.6k|                }
  824|  82.9k|                ctx->pos++;
  825|  82.9k|            }
  826|  36.7k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (826:17): [True: 61, False: 36.6k]
  ------------------
  827|     61|                plist_free_data(data);
  828|     61|                PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     61|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 61]
  |  |  ------------------
  ------------------
  829|     61|                ctx->err = PLIST_ERR_PARSE;
  830|     61|                goto err_out;
  831|     61|            }
  832|  36.6k|            if (*ctx->pos != c) {
  ------------------
  |  Branch (832:17): [True: 0, False: 36.6k]
  ------------------
  833|      0|                plist_free_data(data);
  834|      0|                PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  835|      0|                ctx->err = PLIST_ERR_PARSE;
  836|      0|                goto err_out;
  837|      0|            }
  838|  36.6k|            size_t slen = ctx->pos - p;
  839|  36.6k|            ctx->pos++; // skip the closing quote
  840|  36.6k|            char* strbuf = (char*)malloc(slen+1);
  841|  36.6k|            if (num_escapes > 0) {
  ------------------
  |  Branch (841:17): [True: 1.02k, False: 35.6k]
  ------------------
  842|  1.02k|                size_t i = 0;
  843|  1.02k|                size_t o = 0;
  844|  30.1k|                while (i < slen) {
  ------------------
  |  Branch (844:24): [True: 29.0k, False: 1.02k]
  ------------------
  845|  29.0k|                    if (p[i] == '\\') {
  ------------------
  |  Branch (845:25): [True: 8.08k, False: 21.0k]
  ------------------
  846|       |                        /* handle escape sequence */
  847|  8.08k|                        i++;
  848|  8.08k|                        switch (p[i]) {
  849|    651|                            case '0':
  ------------------
  |  Branch (849:29): [True: 651, False: 7.43k]
  ------------------
  850|  1.18k|                            case '1':
  ------------------
  |  Branch (850:29): [True: 538, False: 7.54k]
  ------------------
  851|  1.62k|                            case '2':
  ------------------
  |  Branch (851:29): [True: 433, False: 7.65k]
  ------------------
  852|  1.89k|                            case '3':
  ------------------
  |  Branch (852:29): [True: 275, False: 7.81k]
  ------------------
  853|  2.37k|                            case '4':
  ------------------
  |  Branch (853:29): [True: 474, False: 7.61k]
  ------------------
  854|  2.66k|                            case '5':
  ------------------
  |  Branch (854:29): [True: 289, False: 7.79k]
  ------------------
  855|  3.04k|                            case '6':
  ------------------
  |  Branch (855:29): [True: 380, False: 7.70k]
  ------------------
  856|  3.62k|                            case '7': {
  ------------------
  |  Branch (856:29): [True: 588, False: 7.49k]
  ------------------
  857|       |                                // max 3 digits octal
  858|  3.62k|                                unsigned char chr = 0;
  859|  3.62k|                                int maxd = 3;
  860|  7.98k|                                while ((i < slen) && (p[i] >= '0' && p[i] <= '7') && --maxd) {
  ------------------
  |  Branch (860:40): [True: 7.59k, False: 386]
  |  Branch (860:55): [True: 7.18k, False: 412]
  |  Branch (860:70): [True: 4.68k, False: 2.49k]
  |  Branch (860:86): [True: 4.35k, False: 331]
  ------------------
  861|  4.35k|                                    chr = (chr << 3) + p[i] - '0';
  862|  4.35k|                                    i++;
  863|  4.35k|                                }
  864|  3.62k|                                strbuf[o++] = (char)chr;
  865|  3.62k|                            }   break;
  866|  1.34k|                            case 'U': {
  ------------------
  |  Branch (866:29): [True: 1.34k, False: 6.74k]
  ------------------
  867|  1.34k|                                i++;
  868|       |                                // max 4 digits hex
  869|  1.34k|                                uint16_t wchr = 0;
  870|  1.34k|                                int maxd = 4;
  871|  3.47k|                                while ((i < slen) && isxdigit(p[i]) && maxd--) {
  ------------------
  |  Branch (871:40): [True: 3.16k, False: 309]
  |  Branch (871:54): [True: 2.17k, False: 992]
  |  Branch (871:72): [True: 2.12k, False: 44]
  ------------------
  872|  2.12k|                                    wchr = (wchr << 4) + ((p[i] <= '9') ? (p[i] - '0') : ((p[i] <= 'F') ? (p[i] - 'A' + 10) : (p[i] - 'a' + 10)));
  ------------------
  |  Branch (872:59): [True: 598, False: 1.53k]
  |  Branch (872:91): [True: 672, False: 859]
  ------------------
  873|  2.12k|                                    i++;
  874|  2.12k|                                }
  875|  1.34k|                                if (wchr >= 0x800) {
  ------------------
  |  Branch (875:37): [True: 389, False: 956]
  ------------------
  876|    389|                                    strbuf[o++] = (char)(0xE0 + ((wchr >> 12) & 0xF));
  877|    389|                                    strbuf[o++] = (char)(0x80 + ((wchr >> 6) & 0x3F));
  878|    389|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  879|    956|                                } else if (wchr >= 0x80) {
  ------------------
  |  Branch (879:44): [True: 284, False: 672]
  ------------------
  880|    284|                                    strbuf[o++] = (char)(0xC0 + ((wchr >> 6) & 0x1F));
  881|    284|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  882|    672|                                } else {
  883|    672|                                    strbuf[o++] = (char)(wchr & 0x7F);
  884|    672|                                }
  885|  1.34k|                            }   break;
  886|    203|                            case 'a': strbuf[o++] = '\a'; i++; break;
  ------------------
  |  Branch (886:29): [True: 203, False: 7.88k]
  ------------------
  887|    290|                            case 'b': strbuf[o++] = '\b'; i++; break;
  ------------------
  |  Branch (887:29): [True: 290, False: 7.79k]
  ------------------
  888|    220|                            case 'f': strbuf[o++] = '\f'; i++; break;
  ------------------
  |  Branch (888:29): [True: 220, False: 7.86k]
  ------------------
  889|    207|                            case 'n': strbuf[o++] = '\n'; i++; break;
  ------------------
  |  Branch (889:29): [True: 207, False: 7.88k]
  ------------------
  890|    204|                            case 'r': strbuf[o++] = '\r'; i++; break;
  ------------------
  |  Branch (890:29): [True: 204, False: 7.88k]
  ------------------
  891|    225|                            case 't': strbuf[o++] = '\t'; i++; break;
  ------------------
  |  Branch (891:29): [True: 225, False: 7.86k]
  ------------------
  892|    234|                            case 'v': strbuf[o++] = '\v'; i++; break;
  ------------------
  |  Branch (892:29): [True: 234, False: 7.85k]
  ------------------
  893|    241|                            case '"': strbuf[o++] = '"';  i++; break;
  ------------------
  |  Branch (893:29): [True: 241, False: 7.84k]
  ------------------
  894|    377|                            case '\'': strbuf[o++] = '\''; i++; break;
  ------------------
  |  Branch (894:29): [True: 377, False: 7.71k]
  ------------------
  895|    913|                            default:
  ------------------
  |  Branch (895:29): [True: 913, False: 7.17k]
  ------------------
  896|    913|                                break;
  897|  8.08k|                        }
  898|  21.0k|                    } else {
  899|  21.0k|                        strbuf[o++] = p[i++];
  900|  21.0k|                    }
  901|  29.0k|                }
  902|  1.02k|                strbuf[o] = '\0';
  903|  1.02k|                slen = o;
  904|  35.6k|            } else {
  905|  35.6k|                strncpy(strbuf, p, slen);
  906|  35.6k|                strbuf[slen] = '\0';
  907|  35.6k|            }
  908|  36.6k|            data->type = PLIST_STRING;
  909|  36.6k|            data->strval = strbuf;
  910|  36.6k|            data->length = slen;
  911|  36.6k|            *plist = plist_new_node(data);
  912|  36.6k|            parse_skip_ws(ctx);
  913|  36.6k|            break;
  914|   166k|        } else {
  915|       |            // unquoted string
  916|   166k|            size_t slen = 0;
  917|   166k|            parse_skip_ws(ctx);
  918|   166k|            p = ctx->pos;
  919|   406k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (919:20): [True: 406k, False: 119]
  ------------------
  920|   406k|                if (!allowed_unquoted_chars[(uint8_t)*ctx->pos]) {
  ------------------
  |  Branch (920:21): [True: 166k, False: 240k]
  ------------------
  921|   166k|                    break;
  922|   166k|                }
  923|   240k|                ctx->pos++;
  924|   240k|            }
  925|   166k|            slen = ctx->pos-p;
  926|   166k|            if (slen > 0) {
  ------------------
  |  Branch (926:17): [True: 166k, False: 151]
  ------------------
  927|   166k|                data->type = PLIST_STRING;
  928|   166k|                data->strval = strndup(p, slen);
  929|   166k|                data->length = slen;
  930|   166k|                *plist = plist_new_node(data);
  931|   166k|                parse_skip_ws(ctx);
  932|   166k|                break;
  933|   166k|            } else {
  934|    151|                plist_free_data(data);
  935|    151|                PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    151|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 151]
  |  |  ------------------
  ------------------
  936|    151|                ctx->err = PLIST_ERR_PARSE;
  937|    151|                break;
  938|    151|            }
  939|   166k|        }
  940|      0|        ctx->pos++;
  941|      0|    }
  942|   228k|    ctx->depth--;
  943|       |
  944|   243k|err_out:
  945|   243k|    if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (945:9): [True: 14.5k, False: 228k]
  ------------------
  946|  14.5k|        plist_free(subnode);
  947|  14.5k|        plist_free(*plist);
  948|  14.5k|        *plist = NULL;
  949|  14.5k|        return ctx->err;
  950|  14.5k|    }
  951|   228k|    return PLIST_ERR_SUCCESS;
  952|   243k|}
oplist.c:parse_skip_ws:
  553|  1.02M|{
  554|  1.03M|    while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (554:12): [True: 1.03M, False: 498]
  ------------------
  555|       |        // skip comments
  556|  1.03M|        if (*ctx->pos == '/' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (556:13): [True: 908, False: 1.02M]
  |  Branch (556:33): [True: 885, False: 23]
  ------------------
  557|    885|            if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (557:17): [True: 384, False: 501]
  ------------------
  558|    384|                ctx->pos++;
  559|  2.29k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (559:24): [True: 2.26k, False: 22]
  ------------------
  560|  2.26k|                    if ((*ctx->pos == '\n') || (*ctx->pos == '\r')) {
  ------------------
  |  Branch (560:25): [True: 180, False: 2.08k]
  |  Branch (560:48): [True: 182, False: 1.90k]
  ------------------
  561|    362|                        break;
  562|    362|                    }
  563|  1.90k|                    ctx->pos++;
  564|  1.90k|                }
  565|    501|            } else if (*(ctx->pos+1) == '*') {
  ------------------
  |  Branch (565:24): [True: 451, False: 50]
  ------------------
  566|    451|                ctx->pos++;
  567|  11.0k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (567:24): [True: 11.0k, False: 32]
  ------------------
  568|  11.0k|                    if (*ctx->pos == '*' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (568:25): [True: 1.19k, False: 9.82k]
  |  Branch (568:45): [True: 1.19k, False: 2]
  ------------------
  569|  1.19k|                        if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (569:29): [True: 419, False: 771]
  ------------------
  570|    419|                            ctx->pos+=2;
  571|    419|                            break;
  572|    419|                        }
  573|  1.19k|                    }
  574|  10.5k|                    ctx->pos++;
  575|  10.5k|                }
  576|    451|            }
  577|    885|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (577:17): [True: 58, False: 827]
  ------------------
  578|     58|                break;
  579|     58|            }
  580|    885|        }
  581|       |        // break on any char that's not white space
  582|  1.03M|        if (!(((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n')))) {
  ------------------
  |  Branch (582:16): [True: 424, False: 1.02M]
  |  Branch (582:40): [True: 258, False: 1.02M]
  |  Branch (582:65): [True: 388, False: 1.02M]
  |  Branch (582:90): [True: 282, False: 1.02M]
  ------------------
  583|  1.02M|            break;
  584|  1.02M|        }
  585|  1.35k|        ctx->pos++;
  586|  1.35k|    }
  587|  1.02M|}
oplist.c:parse_dict_data:
  594|  20.6k|{
  595|  20.6k|    plist_t key = NULL;
  596|  20.6k|    plist_t val = NULL;
  597|   108k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (597:12): [True: 108k, False: 332]
  |  Branch (597:35): [True: 108k, False: 0]
  ------------------
  598|   108k|        parse_skip_ws(ctx);
  599|   108k|        if (ctx->pos >= ctx->end || *ctx->pos == '}') {
  ------------------
  |  Branch (599:13): [True: 1, False: 108k]
  |  Branch (599:37): [True: 7.41k, False: 100k]
  ------------------
  600|  7.41k|            break;
  601|  7.41k|        }
  602|   100k|        key = NULL;
  603|   100k|        ctx->err = node_from_openstep(ctx, &key);
  604|   100k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (604:13): [True: 12.0k, False: 88.5k]
  ------------------
  605|  12.0k|            break;
  606|  12.0k|        }
  607|  88.5k|        if (!PLIST_IS_STRING(key)) {
  ------------------
  |  | 1250|  88.5k|    #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
  |  |  ------------------
  |  |  |  | 1240|  88.5k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 88.5k, False: 3]
  |  |  |  |  |  Branch (1240:63): [True: 88.3k, False: 264]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  608|    267|            PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    267|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 267]
  |  |  ------------------
  ------------------
  609|    267|            ctx->err = PLIST_ERR_PARSE;
  610|    267|            break;
  611|    267|        }
  612|  88.3k|        parse_skip_ws(ctx);
  613|  88.3k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (613:13): [True: 44, False: 88.2k]
  ------------------
  614|     44|            PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     44|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 44]
  |  |  ------------------
  ------------------
  615|     44|            ctx->err = PLIST_ERR_PARSE;
  616|     44|            break;
  617|     44|        }
  618|  88.2k|        if (*ctx->pos != '=') {
  ------------------
  |  Branch (618:13): [True: 19, False: 88.2k]
  ------------------
  619|     19|            PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     19|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 19]
  |  |  ------------------
  ------------------
  620|     19|            ctx->err = PLIST_ERR_PARSE;
  621|     19|            break;
  622|     19|        }
  623|  88.2k|        ctx->pos++;
  624|  88.2k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (624:13): [True: 238, False: 88.0k]
  ------------------
  625|    238|            PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    238|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 238]
  |  |  ------------------
  ------------------
  626|    238|            ctx->err = PLIST_ERR_PARSE;
  627|    238|            break;
  628|    238|        }
  629|  88.0k|        val = NULL;
  630|  88.0k|        ctx->err = node_from_openstep(ctx, &val);
  631|  88.0k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (631:13): [True: 275, False: 87.7k]
  ------------------
  632|    275|            break;
  633|    275|        }
  634|  87.7k|        if (!val) {
  ------------------
  |  Branch (634:13): [True: 4, False: 87.7k]
  ------------------
  635|      4|            PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      4|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 4]
  |  |  ------------------
  ------------------
  636|      4|            ctx->err = PLIST_ERR_PARSE;
  637|      4|            break;
  638|      4|        }
  639|  87.7k|        parse_skip_ws(ctx);
  640|  87.7k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (640:13): [True: 11, False: 87.7k]
  ------------------
  641|     11|            PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     11|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 11]
  |  |  ------------------
  ------------------
  642|     11|            ctx->err = PLIST_ERR_PARSE;
  643|     11|            break;
  644|     11|        }
  645|  87.7k|        if (*ctx->pos != ';') {
  ------------------
  |  Branch (645:13): [True: 5, False: 87.7k]
  ------------------
  646|      5|            PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      5|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 5]
  |  |  ------------------
  ------------------
  647|      5|            ctx->err = PLIST_ERR_PARSE;
  648|      5|            break;
  649|      5|        }
  650|       |
  651|  87.7k|        plist_dict_set_item(dict, plist_get_string_ptr(key, NULL), val);
  652|  87.7k|        plist_free(key);
  653|  87.7k|        key = NULL;
  654|  87.7k|        val = NULL;
  655|       |
  656|  87.7k|        ctx->pos++;
  657|  87.7k|    }
  658|  20.6k|    plist_free(key);
  659|  20.6k|    plist_free(val);
  660|  20.6k|}

plist.c:internal_plist_init:
  153|      2|{
  154|      2|    plist_bin_init();
  155|      2|    plist_xml_init();
  156|      2|    plist_json_init();
  157|      2|    plist_ostep_init();
  158|      2|    atexit(internal_plist_deinit);
  159|      2|}
plist_new_node:
  348|   329k|{
  349|       |    return (plist_t) node_create(NULL, data);
  350|   329k|}
plist_get_data:
  353|  32.4M|{
  354|  32.4M|    if (!node)
  ------------------
  |  Branch (354:9): [True: 0, False: 32.4M]
  ------------------
  355|      0|        return NULL;
  356|  32.4M|    return (plist_data_t)((node_t)node)->data;
  357|  32.4M|}
plist_new_plist_data:
  360|   330k|{
  361|   330k|    return (plist_data_t) calloc(1, sizeof(struct plist_data_s));
  362|   330k|}
plist_free_data:
  421|   330k|{
  422|   330k|    if (!data) return;
  ------------------
  |  Branch (422:9): [True: 0, False: 330k]
  ------------------
  423|   330k|    _plist_free_data(data);
  424|   330k|    free(data);
  425|   330k|}
plist_new_dict:
  528|    902|{
  529|    902|    plist_data_t data = plist_new_plist_data();
  530|    902|    if (!data) {
  ------------------
  |  Branch (530:9): [True: 0, False: 902]
  ------------------
  531|      0|        PLIST_ERR("%s: failed to allocate plist data\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  532|      0|        return NULL;
  533|      0|    }
  534|    902|    data->type = PLIST_DICT;
  535|    902|    return plist_new_node(data);
  536|    902|}
plist_free:
  713|   180k|{
  714|   180k|    if (plist)
  ------------------
  |  Branch (714:9): [True: 104k, False: 75.4k]
  ------------------
  715|   104k|    {
  716|   104k|        plist_free_node((node_t)plist);
  717|   104k|    }
  718|   180k|}
plist_array_append_item:
 1080|  51.2k|{
 1081|  51.2k|    if (!PLIST_IS_ARRAY(node) || !item) {
  ------------------
  |  | 1252|  51.2k|    #define PLIST_IS_ARRAY(__plist)   _PLIST_IS_TYPE(__plist, ARRAY)
  |  |  ------------------
  |  |  |  | 1240|   102k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 51.2k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 51.2k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1081:34): [True: 0, False: 51.2k]
  ------------------
 1082|      0|        PLIST_ERR("invalid argument passed to %s (node=%p, item=%p)\n", __func__, node, item);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1083|      0|        return PLIST_ERR_INVALID_ARG;
 1084|      0|    }
 1085|  51.2k|    node_t it = (node_t)item;
 1086|  51.2k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1086:9): [True: 0, False: 51.2k]
  ------------------
 1087|      0|        assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first");
  ------------------
  |  Branch (1087:9): [True: 0, False: 0]
  |  Branch (1087:9): [True: 0, False: 0]
  |  Branch (1087:9): [True: 0, False: 0]
  |  Branch (1087:9): [True: 0, False: 0]
  ------------------
 1088|      0|        PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1089|      0|        return PLIST_ERR_INVALID_ARG;
 1090|      0|    }
 1091|       |
 1092|  51.2k|    int r = node_attach((node_t)node, (node_t)item);
 1093|  51.2k|    if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  51.2k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1093:9): [True: 0, False: 51.2k]
  ------------------
 1094|      0|        PLIST_ERR("%s: failed to append item (err=%d)\n", __func__, r);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1095|      0|        return PLIST_ERR_UNKNOWN;
 1096|      0|    }
 1097|  51.2k|    _plist_array_post_insert(node, item, -1);
 1098|       |
 1099|  51.2k|    return PLIST_ERR_SUCCESS;
 1100|  51.2k|}
plist_dict_get_item:
 1281|  87.7k|{
 1282|  87.7k|    plist_t ret = NULL;
 1283|  87.7k|    if (!PLIST_IS_DICT(node) || !key) {
  ------------------
  |  | 1254|  87.7k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   175k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 87.7k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 87.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1283:33): [True: 0, False: 87.7k]
  ------------------
 1284|      0|        PLIST_ERR("invalid argument passed to %s (node=%p, key=%p)\n", __func__, node, key);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1285|      0|        return NULL;
 1286|      0|    }
 1287|  87.7k|    plist_data_t data = plist_get_data(node);
 1288|  87.7k|    if (!data) {
  ------------------
  |  Branch (1288:9): [True: 0, False: 87.7k]
  ------------------
 1289|      0|        PLIST_ERR("%s: invalid node\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1290|      0|        return NULL;
 1291|      0|    }
 1292|  87.7k|    size_t keylen = strlen(key);
 1293|  87.7k|    hashtable_t *ht = (hashtable_t*)data->hashtable;
 1294|  87.7k|    if (ht) {
  ------------------
  |  Branch (1294:9): [True: 1.32k, False: 86.3k]
  ------------------
 1295|  1.32k|        struct plist_data_s sdata = { 0 };
 1296|  1.32k|        sdata.strval = (char*)key;
 1297|  1.32k|        sdata.length = keylen;
 1298|  1.32k|        return (plist_t)hash_table_lookup(ht, &sdata);
 1299|  86.3k|    } else {
 1300|  86.3k|        plist_t k = NULL;
 1301|  10.6M|        for (k = (plist_t)node_first_child((node_t)node); k; ) {
  ------------------
  |  Branch (1301:59): [True: 10.5M, False: 85.4k]
  ------------------
 1302|  10.5M|            plist_t v = (plist_t)node_next_sibling(k);
 1303|  10.5M|            if (!v) break;
  ------------------
  |  Branch (1303:17): [True: 0, False: 10.5M]
  ------------------
 1304|  10.5M|            data = plist_get_data(k);
 1305|  10.5M|            assert(PLIST_IS_KEY(k));
  ------------------
  |  Branch (1305:13): [True: 0, False: 10.5M]
  |  Branch (1305:13): [True: 0, False: 0]
  |  Branch (1305:13): [True: 10.5M, False: 0]
  |  Branch (1305:13): [True: 10.5M, False: 0]
  ------------------
 1306|  10.5M|            if (!PLIST_IS_KEY(k) || !data || !data->strval) {
  ------------------
  |  | 1260|  10.5M|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  21.0M|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 10.5M, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 10.5M, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1306:37): [True: 0, False: 10.5M]
  |  Branch (1306:46): [True: 0, False: 10.5M]
  ------------------
 1307|      0|                PLIST_ERR("invalid key node at %p\n", k);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1308|      0|                break;
 1309|      0|            }
 1310|  10.5M|            if (data->length == keylen && !memcmp(key, data->strval, keylen+1)) {
  ------------------
  |  Branch (1310:17): [True: 5.09M, False: 5.41M]
  |  Branch (1310:43): [True: 948, False: 5.09M]
  ------------------
 1311|    948|                ret = v;
 1312|    948|                break;
 1313|    948|            }
 1314|  10.5M|            k = node_next_sibling(v);
 1315|  10.5M|        }
 1316|  86.3k|    }
 1317|  86.3k|    return ret;
 1318|  87.7k|}
plist_dict_set_item:
 1321|  87.7k|{
 1322|  87.7k|    if (!PLIST_IS_DICT(node) || !key || !item) {
  ------------------
  |  | 1254|  87.7k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   175k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 87.7k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 87.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1322:33): [True: 0, False: 87.7k]
  |  Branch (1322:41): [True: 0, False: 87.7k]
  ------------------
 1323|      0|        PLIST_ERR("invalid argument passed to %s (node=%p, key=%p, item=%p)\n", __func__, node, key, item);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1324|      0|        return PLIST_ERR_INVALID_ARG;
 1325|      0|    }
 1326|  87.7k|    node_t it = (node_t)item;
 1327|  87.7k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1327:9): [True: 0, False: 87.7k]
  ------------------
 1328|      0|        assert(it->parent == NULL && "item already has a parent");
  ------------------
  |  Branch (1328:9): [True: 0, False: 0]
  |  Branch (1328:9): [True: 0, False: 0]
  |  Branch (1328:9): [True: 0, False: 0]
  |  Branch (1328:9): [True: 0, False: 0]
  ------------------
 1329|      0|        PLIST_ERR("%s: item already has a parent\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1330|      0|        return PLIST_ERR_INVALID_ARG;
 1331|      0|    }
 1332|       |
 1333|  87.7k|    hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
 1334|       |
 1335|  87.7k|    plist_t old_item = plist_dict_get_item(node, key);
 1336|  87.7k|    plist_t key_node = NULL;
 1337|       |
 1338|  87.7k|    if (old_item) {
  ------------------
  |  Branch (1338:9): [True: 1.63k, False: 86.0k]
  ------------------
 1339|       |        // --- REPLACE EXISTING VALUE ---
 1340|  1.63k|        node_t old_val = (node_t)old_item;
 1341|  1.63k|        node_t old_key = node_prev_sibling(old_val);
 1342|  1.63k|        if (!old_key) {
  ------------------
  |  Branch (1342:13): [True: 0, False: 1.63k]
  ------------------
 1343|      0|            PLIST_ERR("%s: corrupt dict (value without key)\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1344|      0|            return PLIST_ERR_UNKNOWN;
 1345|      0|        }
 1346|  1.63k|        if (!PLIST_IS_KEY((plist_t)old_key)) {
  ------------------
  |  | 1260|  1.63k|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  1.63k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 1.63k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 1.63k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 1347|      0|            PLIST_ERR("%s: corrupt dict ('key' node is not PLIST_KEY\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1348|      0|            return PLIST_ERR_UNKNOWN;
 1349|      0|        }
 1350|       |
 1351|       |        // detach old value (do NOT free yet)
 1352|  1.63k|        int idx = node_detach((node_t)node, old_val);
 1353|  1.63k|        if (idx < 0) {
  ------------------
  |  Branch (1353:13): [True: 0, False: 1.63k]
  ------------------
 1354|      0|            PLIST_ERR("%s: failed to detach old value (err=%d)\n", __func__, idx);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1355|      0|            return PLIST_ERR_UNKNOWN;
 1356|      0|        }
 1357|       |
 1358|       |        // insert new value at same position
 1359|  1.63k|        int r = node_insert((node_t)node, (unsigned)idx, (node_t)item);
 1360|  1.63k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  1.63k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1360:13): [True: 0, False: 1.63k]
  ------------------
 1361|       |            // rollback: reinsert old value
 1362|      0|            int rb = node_insert((node_t)node, (unsigned)idx, old_val);
 1363|      0|            if (rb == NODE_ERR_SUCCESS && ht) {
  ------------------
  |  |   36|      0|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1363:17): [True: 0, False: 0]
  |  Branch (1363:43): [True: 0, False: 0]
  ------------------
 1364|      0|                hash_table_insert(ht, ((node_t)old_key)->data, old_item);
 1365|      0|            }
 1366|      0|            PLIST_ERR("%s: failed to replace dict value (err=%d)\n", __func__, r);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1367|      0|            return PLIST_ERR_UNKNOWN;
 1368|      0|        }
 1369|  1.63k|        key_node = old_key;
 1370|       |
 1371|       |        // update hash table
 1372|  1.63k|        if (ht) {
  ------------------
  |  Branch (1372:13): [True: 690, False: 948]
  ------------------
 1373|    690|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1374|    690|        }
 1375|       |
 1376|       |        // now it’s safe to free old value
 1377|  1.63k|        plist_free_node(old_val);
 1378|  86.0k|    } else {
 1379|       |        // --- INSERT NEW KEY/VALUE PAIR ---
 1380|  86.0k|        key_node = plist_new_key(key);
 1381|  86.0k|        if (!key_node) return PLIST_ERR_NO_MEM;
  ------------------
  |  Branch (1381:13): [True: 0, False: 86.0k]
  ------------------
 1382|       |
 1383|  86.0k|        int r = node_attach((node_t)node, (node_t)key_node);
 1384|  86.0k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  86.0k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1384:13): [True: 0, False: 86.0k]
  ------------------
 1385|      0|            plist_free_node((node_t)key_node);
 1386|      0|            PLIST_ERR("%s: failed to attach dict key (err=%d)\n", __func__, r);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1387|      0|            return PLIST_ERR_UNKNOWN;
 1388|      0|        }
 1389|  86.0k|        r = node_attach((node_t)node, (node_t)item);
 1390|  86.0k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  86.0k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1390:13): [True: 0, False: 86.0k]
  ------------------
 1391|       |            // rollback key insertion
 1392|      0|            node_detach((node_t)node, (node_t)key_node);
 1393|      0|            plist_free_node((node_t)key_node);
 1394|      0|            PLIST_ERR("%s: failed to attach dict value (err=%d)\n", __func__, r);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1395|      0|            return PLIST_ERR_UNKNOWN;
 1396|      0|        }
 1397|       |
 1398|  86.0k|        if (ht) {
  ------------------
  |  Branch (1398:13): [True: 638, False: 85.4k]
  ------------------
 1399|       |            // store pointer to item in hash table
 1400|    638|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1401|  85.4k|        } else if (((node_t)node)->count > 500) {
  ------------------
  |  Branch (1401:20): [True: 327, False: 85.1k]
  ------------------
 1402|       |            // make new hash table
 1403|    327|            ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
 1404|       |            // calculate the hashes for all entries we have so far
 1405|    327|            plist_t current = NULL;
 1406|    327|            for (current = (plist_t)node_first_child((node_t)node);
 1407|  82.4k|                 ht && current;
  ------------------
  |  Branch (1407:18): [True: 82.4k, False: 0]
  |  Branch (1407:24): [True: 82.0k, False: 327]
  ------------------
 1408|  82.0k|                 current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
 1409|  82.0k|            {
 1410|  82.0k|                hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
 1411|  82.0k|            }
 1412|    327|            ((plist_data_t)((node_t)node)->data)->hashtable = ht;
 1413|    327|        }
 1414|  86.0k|    }
 1415|  87.7k|    return PLIST_ERR_SUCCESS;
 1416|  87.7k|}
plist_get_node_type:
 1746|  21.4M|{
 1747|  21.4M|    if (node)
  ------------------
  |  Branch (1747:9): [True: 21.4M, False: 0]
  ------------------
 1748|  21.4M|    {
 1749|  21.4M|        plist_data_t data = plist_get_data(node);
 1750|  21.4M|        if (data)
  ------------------
  |  Branch (1750:13): [True: 21.4M, False: 0]
  ------------------
 1751|  21.4M|            return data->type;
 1752|  21.4M|    }
 1753|      0|    return PLIST_NONE;
 1754|  21.4M|}
plist_get_string_ptr:
 1785|  87.7k|{
 1786|  87.7k|    if (!node)
  ------------------
  |  Branch (1786:9): [True: 0, False: 87.7k]
  ------------------
 1787|      0|        return NULL;
 1788|  87.7k|    plist_type type = plist_get_node_type(node);
 1789|  87.7k|    if (PLIST_STRING != type)
  ------------------
  |  Branch (1789:9): [True: 0, False: 87.7k]
  ------------------
 1790|      0|        return NULL;
 1791|  87.7k|    plist_data_t data = plist_get_data(node);
 1792|  87.7k|    if (length)
  ------------------
  |  Branch (1792:9): [True: 0, False: 87.7k]
  ------------------
 1793|      0|        *length = data->length;
 1794|  87.7k|    return (const char*)data->strval;
 1795|  87.7k|}
plist.c:_plist_free_data:
  390|   330k|{
  391|   330k|    if (!data) return;
  ------------------
  |  Branch (391:9): [True: 0, False: 330k]
  ------------------
  392|   330k|    switch (data->type) {
  393|  86.0k|        case PLIST_KEY:
  ------------------
  |  Branch (393:9): [True: 86.0k, False: 244k]
  ------------------
  394|   289k|        case PLIST_STRING:
  ------------------
  |  Branch (394:9): [True: 203k, False: 126k]
  ------------------
  395|   289k|            free(data->strval);
  396|   289k|            data->strval = NULL;
  397|   289k|            break;
  398|    295|        case PLIST_DATA:
  ------------------
  |  Branch (398:9): [True: 295, False: 329k]
  ------------------
  399|    295|            free(data->buff);
  400|    295|            data->buff = NULL;
  401|    295|            break;
  402|  19.6k|        case PLIST_ARRAY:
  ------------------
  |  Branch (402:9): [True: 19.6k, False: 310k]
  ------------------
  403|  19.6k|            ptr_array_free((ptrarray_t*)data->hashtable);
  404|  19.6k|            data->hashtable = NULL;
  405|  19.6k|            break;
  406|  20.7k|        case PLIST_DICT: {
  ------------------
  |  Branch (406:9): [True: 20.7k, False: 309k]
  ------------------
  407|  20.7k|            hashtable_t *ht = (hashtable_t*)data->hashtable;
  408|       |            // PLIST_DICT hashtables must not own/free values; values are freed via node tree.
  409|  20.7k|            assert(!ht || ht->free_func == NULL);
  ------------------
  |  Branch (409:13): [True: 20.7k, False: 0]
  |  Branch (409:13): [True: 0, False: 0]
  |  Branch (409:13): [True: 20.3k, False: 327]
  |  Branch (409:13): [True: 327, False: 0]
  ------------------
  410|  20.7k|            if (ht) ht->free_func = NULL;
  ------------------
  |  Branch (410:17): [True: 327, False: 20.3k]
  ------------------
  411|  20.7k|            hash_table_destroy(ht);
  412|  20.7k|            data->hashtable = NULL;
  413|  20.7k|            break;
  414|  20.7k|        }
  415|    212|        default:
  ------------------
  |  Branch (415:9): [True: 212, False: 329k]
  ------------------
  416|    212|            break;
  417|   330k|    }
  418|   330k|}
plist.c:plist_free_node:
  500|   106k|{
  501|   106k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (501:9): [True: 0, False: 106k]
  ------------------
  502|       |
  503|   106k|    int root_index = -1;
  504|       |
  505|   106k|    if (root->parent) {
  ------------------
  |  Branch (505:9): [True: 0, False: 106k]
  ------------------
  506|      0|        root_index = node_detach(root->parent, root);
  507|      0|        if (root_index < 0) {
  ------------------
  |  Branch (507:13): [True: 0, False: 0]
  ------------------
  508|      0|            return root_index;
  509|      0|        }
  510|      0|    }
  511|       |
  512|   106k|    int r = plist_free_children(root);
  513|   106k|    if (r < 0) {
  ------------------
  |  Branch (513:9): [True: 0, False: 106k]
  ------------------
  514|       |        // root is already detached; caller should treat as error.
  515|      0|        return r;
  516|      0|    }
  517|       |
  518|   106k|    plist_data_t data = plist_get_data(root);
  519|   106k|    plist_free_data(data);
  520|   106k|    root->data = NULL;
  521|       |
  522|   106k|    node_destroy(root);
  523|       |
  524|   106k|    return root_index;
  525|   106k|}
plist.c:plist_free_children:
  428|   106k|{
  429|   106k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (429:9): [True: 0, False: 106k]
  ------------------
  430|       |
  431|   106k|    if (!node_first_child(root)) {
  ------------------
  |  Branch (431:9): [True: 105k, False: 1.20k]
  ------------------
  432|   105k|        return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|   105k|#define NODE_ERR_SUCCESS       0
  ------------------
  433|   105k|    }
  434|       |
  435|  1.20k|    size_t cap = 64, sp = 0;
  436|  1.20k|    node_t *stack = (node_t*)malloc(cap * sizeof(*stack));
  437|  1.20k|    if (!stack) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (437:9): [True: 0, False: 1.20k]
  ------------------
  438|       |
  439|       |    // Push *direct* children onto the stack, detached from root.
  440|   192k|    for (;;) {
  441|   192k|        node_t ch = node_first_child(root);
  442|   192k|        if (!ch) break;
  ------------------
  |  Branch (442:13): [True: 1.20k, False: 191k]
  ------------------
  443|       |
  444|   191k|        int di = node_detach(root, ch);
  445|   191k|        if (di < 0) {
  ------------------
  |  Branch (445:13): [True: 0, False: 191k]
  ------------------
  446|      0|            free(stack);
  447|      0|            return di;
  448|      0|        }
  449|       |
  450|   191k|        if (sp == cap) {
  ------------------
  |  Branch (450:13): [True: 2.62k, False: 188k]
  ------------------
  451|  2.62k|            cap += 64;
  452|  2.62k|            node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  453|  2.62k|            if (!tmp) {
  ------------------
  |  Branch (453:17): [True: 0, False: 2.62k]
  ------------------
  454|      0|                free(stack);
  455|      0|                return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  456|      0|            }
  457|  2.62k|            stack = tmp;
  458|  2.62k|        }
  459|   191k|        stack[sp++] = ch;
  460|   191k|    }
  461|       |
  462|       |    // Now free the detached subtree nodes (and their descendants).
  463|   256k|    while (sp) {
  ------------------
  |  Branch (463:12): [True: 255k, False: 1.20k]
  ------------------
  464|   255k|        node_t node = stack[sp - 1];
  465|   255k|        node_t ch = node_first_child(node);
  466|   255k|        if (ch) {
  ------------------
  |  Branch (466:13): [True: 32.0k, False: 223k]
  ------------------
  467|  32.0k|            int di = node_detach(node, ch);
  468|  32.0k|            if (di < 0) {
  ------------------
  |  Branch (468:17): [True: 0, False: 32.0k]
  ------------------
  469|      0|                free(stack);
  470|      0|                return di;
  471|      0|            }
  472|       |
  473|  32.0k|            if (sp == cap) {
  ------------------
  |  Branch (473:17): [True: 236, False: 31.8k]
  ------------------
  474|    236|                cap += 64;
  475|    236|                node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  476|    236|                if (!tmp) {
  ------------------
  |  Branch (476:21): [True: 0, False: 236]
  ------------------
  477|      0|                    free(stack);
  478|      0|                    return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  479|      0|                }
  480|    236|                stack = tmp;
  481|    236|            }
  482|  32.0k|            stack[sp++] = ch;
  483|  32.0k|            continue;
  484|  32.0k|        }
  485|       |
  486|   223k|        plist_data_t data = plist_get_data(node);
  487|   223k|        plist_free_data(data);
  488|   223k|        node->data = NULL;
  489|       |
  490|   223k|        node_destroy(node);
  491|       |
  492|   223k|        sp--;
  493|   223k|    }
  494|       |
  495|  1.20k|    free(stack);
  496|  1.20k|    return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.20k|#define NODE_ERR_SUCCESS       0
  ------------------
  497|  1.20k|}
plist.c:_plist_array_post_insert:
  986|  51.2k|{
  987|  51.2k|    ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
  988|  51.2k|    if (pa) {
  ------------------
  |  Branch (988:9): [True: 13.4k, False: 37.8k]
  ------------------
  989|       |        /* store pointer to item in array */
  990|  13.4k|        ptr_array_insert(pa, item, n);
  991|  13.4k|        return;
  992|  13.4k|    }
  993|       |
  994|  37.8k|    if (((node_t)node)->count > 100) {
  ------------------
  |  Branch (994:9): [True: 160, False: 37.6k]
  ------------------
  995|       |       /* make new lookup array */
  996|    160|       pa = ptr_array_new(128);
  997|    160|       plist_t current = NULL;
  998|    160|       for (current = (plist_t)node_first_child((node_t)node);
  999|  16.3k|            pa && current;
  ------------------
  |  Branch (999:13): [True: 16.3k, False: 0]
  |  Branch (999:19): [True: 16.1k, False: 160]
  ------------------
 1000|  16.1k|            current = (plist_t)node_next_sibling((node_t)current))
 1001|  16.1k|       {
 1002|  16.1k|           ptr_array_add(pa, current);
 1003|  16.1k|       }
 1004|    160|       ((plist_data_t)((node_t)node)->data)->hashtable = pa;
 1005|    160|    }
 1006|  37.8k|}
plist.c:plist_new_key:
  551|  86.0k|{
  552|  86.0k|    plist_data_t data = plist_new_plist_data();
  553|  86.0k|    if (!data) {
  ------------------
  |  Branch (553:9): [True: 0, False: 86.0k]
  ------------------
  554|      0|        PLIST_ERR("%s: failed to allocate plist data\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  555|      0|        return NULL;
  556|      0|    }
  557|  86.0k|    data->type = PLIST_KEY;
  558|  86.0k|    data->strval = strdup(val);
  559|  86.0k|    if (!data->strval) {
  ------------------
  |  Branch (559:9): [True: 0, False: 86.0k]
  ------------------
  560|      0|        plist_free_data(data);
  561|      0|        PLIST_ERR("%s: strdup failed\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  562|      0|        return NULL;
  563|  86.0k|    } else {
  564|  86.0k|        data->length = strlen(val);
  565|  86.0k|    }
  566|  86.0k|    return plist_new_node(data);
  567|  86.0k|}
plist.c:dict_key_hash:
  365|  84.7k|{
  366|  84.7k|    plist_data_t keydata = (plist_data_t)data;
  367|  84.7k|    unsigned int hash = 5381;
  368|  84.7k|    size_t i;
  369|  84.7k|    char *str = keydata->strval;
  370|   247k|    for (i = 0; i < keydata->length; str++, i++) {
  ------------------
  |  Branch (370:17): [True: 162k, False: 84.7k]
  ------------------
  371|   162k|        hash = ((hash << 5) + hash) + *str;
  372|   162k|    }
  373|  84.7k|    return hash;
  374|  84.7k|}
plist.c:dict_key_compare:
  377|  4.46k|{
  378|  4.46k|    plist_data_t data_a = (plist_data_t)a;
  379|  4.46k|    plist_data_t data_b = (plist_data_t)b;
  380|  4.46k|    if (data_a->strval == NULL || data_b->strval == NULL) {
  ------------------
  |  Branch (380:9): [True: 0, False: 4.46k]
  |  Branch (380:35): [True: 0, False: 4.46k]
  ------------------
  381|      0|        return FALSE;
  ------------------
  |  |   32|      0|#define FALSE 0
  ------------------
  382|      0|    }
  383|  4.46k|    if (data_a->length != data_b->length) {
  ------------------
  |  Branch (383:9): [True: 1.26k, False: 3.19k]
  ------------------
  384|  1.26k|        return FALSE;
  ------------------
  |  |   32|  1.26k|#define FALSE 0
  ------------------
  385|  1.26k|    }
  386|  3.19k|    return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   28|  1.38k|#define TRUE 1
  ------------------
                  return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   32|  1.81k|#define FALSE 0
  ------------------
  |  Branch (386:12): [True: 1.38k, False: 1.81k]
  ------------------
  387|  4.46k|}

ptr_array_new:
   25|    160|{
   26|    160|	ptrarray_t *pa = (ptrarray_t*)malloc(sizeof(ptrarray_t));
   27|    160|	pa->pdata = (void**)malloc(sizeof(void*) * capacity);
   28|    160|	pa->capacity = capacity;
   29|    160|	pa->capacity_step = (capacity > 4096) ? 4096 : capacity;
  ------------------
  |  Branch (29:22): [True: 0, False: 160]
  ------------------
   30|    160|	pa->len = 0;
   31|    160|	return pa;
   32|    160|}
ptr_array_free:
   35|  19.6k|{
   36|  19.6k|	if (!pa) return;
  ------------------
  |  Branch (36:6): [True: 19.5k, False: 160]
  ------------------
   37|    160|	if (pa->pdata) {
  ------------------
  |  Branch (37:6): [True: 160, False: 0]
  ------------------
   38|    160|		free(pa->pdata);
   39|    160|	}
   40|    160|	free(pa);
   41|    160|}
ptr_array_insert:
   44|  29.6k|{
   45|  29.6k|	if (!pa || !pa->pdata) return;
  ------------------
  |  Branch (45:6): [True: 0, False: 29.6k]
  |  Branch (45:13): [True: 0, False: 29.6k]
  ------------------
   46|  29.6k|	long remaining = pa->capacity-pa->len;
   47|  29.6k|	if (remaining == 0) {
  ------------------
  |  Branch (47:6): [True: 115, False: 29.5k]
  ------------------
   48|    115|		pa->pdata = (void**)realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step));
   49|    115|		pa->capacity += pa->capacity_step;
   50|    115|	}
   51|  29.6k|	if (array_index < 0 || array_index >= pa->len) {
  ------------------
  |  Branch (51:6): [True: 29.6k, False: 0]
  |  Branch (51:25): [True: 0, False: 0]
  ------------------
   52|  29.6k|		pa->pdata[pa->len] = data;
   53|  29.6k|	} else {
   54|      0|		memmove(&pa->pdata[array_index+1], &pa->pdata[array_index], (pa->len-array_index) * sizeof(void*));
   55|      0|		pa->pdata[array_index] = data;
   56|      0|	}
   57|  29.6k|	pa->len++;
   58|  29.6k|}
ptr_array_add:
   61|  16.1k|{
   62|  16.1k|	ptr_array_insert(pa, data, -1);
   63|  16.1k|}

plist_xml_init:
   91|      2|{
   92|       |    /* init XML stuff */
   93|      2|#ifdef DEBUG
   94|      2|    char *env_debug = getenv("PLIST_XML_DEBUG");
   95|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (95:9): [True: 0, False: 2]
  |  Branch (95:22): [True: 0, False: 0]
  ------------------
   96|      0|        plist_xml_debug = 1;
   97|      0|    }
   98|      2|#endif
   99|      2|}

