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

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

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

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|    301|{
   28|    301|	bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t));
   29|    301|	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|    301|#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|    602|#define PAGE_SIZE 4096
  ------------------
  |  Branch (29:16): [True: 0, False: 301]
  ------------------
   30|    301|	a->data = malloc(a->capacity);
   31|    301|	a->len = 0;
   32|       |	a->stream = NULL;
   33|    301|	return a;
   34|    301|}
byte_array_free:
   47|    301|{
   48|    301|	if (!ba) return;
  ------------------
  |  Branch (48:6): [True: 0, False: 301]
  ------------------
   49|    301|	if (ba->data) {
  ------------------
  |  Branch (49:6): [True: 57, False: 244]
  ------------------
   50|     57|		free(ba->data);
   51|     57|	}
   52|    301|	free(ba);
   53|    301|}
byte_array_append:
   66|  1.82k|{
   67|  1.82k|	if (!ba || (!ba->stream && !ba->data) || (len <= 0)) return;
  ------------------
  |  Branch (67:6): [True: 0, False: 1.82k]
  |  Branch (67:14): [True: 1.82k, False: 0]
  |  Branch (67:29): [True: 0, False: 1.82k]
  |  Branch (67:43): [True: 0, False: 1.82k]
  ------------------
   68|  1.82k|	if (ba->stream) {
  ------------------
  |  Branch (68:6): [True: 0, False: 1.82k]
  ------------------
   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.82k|	} else {
   75|  1.82k|		size_t remaining = ba->capacity-ba->len;
   76|  1.82k|		if (len > remaining) {
  ------------------
  |  Branch (76:7): [True: 0, False: 1.82k]
  ------------------
   77|      0|			size_t needed = len - remaining;
   78|      0|			byte_array_grow(ba, needed);
   79|      0|		}
   80|  1.82k|		memcpy(((char*)ba->data) + ba->len, buf, len);
   81|  1.82k|	}
   82|  1.82k|	ba->len += len;
   83|  1.82k|}

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

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.60k|{
  956|  1.60k|    if (!plist) {
  ------------------
  |  Branch (956:9): [True: 0, False: 1.60k]
  ------------------
  957|      0|        return PLIST_ERR_INVALID_ARG;
  958|      0|    }
  959|  1.60k|    *plist = NULL;
  960|  1.60k|    if (!plist_ostep || (length == 0)) {
  ------------------
  |  Branch (960:9): [True: 0, False: 1.60k]
  |  Branch (960:25): [True: 0, False: 1.60k]
  ------------------
  961|      0|        return PLIST_ERR_INVALID_ARG;
  962|      0|    }
  963|       |
  964|  1.60k|    struct _parse_ctx ctx = { plist_ostep, plist_ostep, plist_ostep + length, 0 , 0 };
  965|       |
  966|  1.60k|    plist_err_t err = node_from_openstep(&ctx, plist);
  967|  1.60k|    if (err == 0) {
  ------------------
  |  Branch (967:9): [True: 1.08k, False: 519]
  ------------------
  968|  1.08k|        if (!*plist) {
  ------------------
  |  Branch (968:13): [True: 65, False: 1.01k]
  ------------------
  969|       |            /* whitespace only file is considered an empty dictionary */
  970|     65|            *plist = plist_new_dict();
  971|  1.01k|        } else if (ctx.pos < ctx.end && *ctx.pos == '=') {
  ------------------
  |  Branch (971:20): [True: 852, False: 167]
  |  Branch (971:41): [True: 836, False: 16]
  ------------------
  972|       |            /* attempt to parse this as 'strings' data */
  973|    836|            plist_free(*plist);
  974|    836|            *plist = NULL;
  975|    836|            plist_t pl = plist_new_dict();
  976|    836|            ctx.pos = plist_ostep;
  977|    836|            parse_dict_data(&ctx, pl);
  978|    836|            if (ctx.err > 0) {
  ------------------
  |  Branch (978:17): [True: 0, False: 836]
  ------------------
  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|    836|            } else {
  983|    836|                *plist = pl;
  984|    836|            }
  985|    836|        }
  986|  1.08k|    }
  987|       |
  988|  1.60k|    return err;
  989|  1.60k|}
oplist.c:node_from_openstep:
  663|   239k|{
  664|   239k|    plist_t subnode = NULL;
  665|   239k|    const char *p = NULL;
  666|   239k|    ctx->depth++;
  667|   239k|    if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
  ------------------
  |  |   56|   239k|#define PLIST_MAX_NESTING_DEPTH NODE_MAX_DEPTH
  |  |  ------------------
  |  |  |  |   33|   239k|#define NODE_MAX_DEPTH 512
  |  |  ------------------
  ------------------
  |  Branch (667:9): [True: 4, False: 239k]
  ------------------
  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|   239k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (672:12): [True: 239k, False: 0]
  |  Branch (672:35): [True: 239k, False: 0]
  ------------------
  673|   239k|        parse_skip_ws(ctx);
  674|   239k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (674:13): [True: 73, False: 239k]
  ------------------
  675|     73|            break;
  676|     73|        }
  677|   239k|        plist_data_t data = plist_new_plist_data();
  678|   239k|        if (*ctx->pos == '{') {
  ------------------
  |  Branch (678:13): [True: 19.5k, False: 219k]
  ------------------
  679|  19.5k|            data->type = PLIST_DICT;
  680|  19.5k|            subnode = plist_new_node(data);
  681|  19.5k|            ctx->pos++;
  682|  19.5k|            parse_dict_data(ctx, subnode);
  683|  19.5k|            if (ctx->err) {
  ------------------
  |  Branch (683:17): [True: 12.0k, False: 7.58k]
  ------------------
  684|  12.0k|                goto err_out;
  685|  12.0k|            }
  686|  7.58k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (686:17): [True: 78, False: 7.51k]
  ------------------
  687|     78|                PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     78|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 78]
  |  |  ------------------
  ------------------
  688|     78|                ctx->err = PLIST_ERR_PARSE;
  689|     78|                break;
  690|     78|            }
  691|  7.51k|            if (*ctx->pos != '}') {
  ------------------
  |  Branch (691:17): [True: 0, False: 7.51k]
  ------------------
  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.51k|            ctx->pos++;
  697|  7.51k|            *plist = subnode;
  698|  7.51k|            parse_skip_ws(ctx);
  699|  7.51k|            break;
  700|   219k|        } else if (*ctx->pos == '(') {
  ------------------
  |  Branch (700:20): [True: 19.3k, False: 200k]
  ------------------
  701|  19.3k|            data->type = PLIST_ARRAY;
  702|  19.3k|            subnode = plist_new_node(data);
  703|  19.3k|            ctx->pos++;
  704|  19.3k|            plist_t tmp = NULL;
  705|  53.1k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (705:20): [True: 53.1k, False: 26]
  |  Branch (705:43): [True: 53.1k, False: 0]
  ------------------
  706|  53.1k|                parse_skip_ws(ctx);
  707|  53.1k|                if (ctx->pos >= ctx->end || *ctx->pos == ')') {
  ------------------
  |  Branch (707:21): [True: 2, False: 53.1k]
  |  Branch (707:45): [True: 352, False: 52.8k]
  ------------------
  708|    354|                    break;
  709|    354|                }
  710|  52.8k|                ctx->err = node_from_openstep(ctx, &tmp);
  711|  52.8k|                if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (711:21): [True: 2.43k, False: 50.3k]
  ------------------
  712|  2.43k|                    break;
  713|  2.43k|                }
  714|  50.3k|                if (!tmp) {
  ------------------
  |  Branch (714:21): [True: 2, False: 50.3k]
  ------------------
  715|      2|                    ctx->err = PLIST_ERR_PARSE;
  716|      2|                    break;
  717|      2|                }
  718|  50.3k|                plist_array_append_item(subnode, tmp);
  719|  50.3k|                tmp = NULL;
  720|  50.3k|                parse_skip_ws(ctx);
  721|  50.3k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (721:21): [True: 99, False: 50.2k]
  ------------------
  722|     99|                    PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     99|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 99]
  |  |  ------------------
  ------------------
  723|     99|                    ctx->err = PLIST_ERR_PARSE;
  724|     99|                    break;
  725|     99|                }
  726|  50.2k|                if (*ctx->pos != ',') {
  ------------------
  |  Branch (726:21): [True: 16.3k, False: 33.8k]
  ------------------
  727|  16.3k|                    break;
  728|  16.3k|                }
  729|  33.8k|                ctx->pos++;
  730|  33.8k|            }
  731|  19.3k|	    plist_free(tmp);
  732|  19.3k|	    tmp = NULL;
  733|  19.3k|            if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (733:17): [True: 2.53k, False: 16.7k]
  ------------------
  734|  2.53k|                goto err_out;
  735|  2.53k|            }
  736|  16.7k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (736:17): [True: 28, False: 16.7k]
  ------------------
  737|     28|                PLIST_OSTEP_ERR("EOF while parsing array 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]
  |  |  ------------------
  ------------------
  738|     28|                ctx->err = PLIST_ERR_PARSE;
  739|     28|                break;
  740|     28|            }
  741|  16.7k|            if (*ctx->pos != ')') {
  ------------------
  |  Branch (741:17): [True: 18, False: 16.7k]
  ------------------
  742|     18|                PLIST_OSTEP_ERR("Missing terminating ')' 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]
  |  |  ------------------
  ------------------
  743|     18|                ctx->err = PLIST_ERR_PARSE;
  744|     18|                goto err_out;
  745|     18|            }
  746|  16.7k|            ctx->pos++;
  747|  16.7k|            *plist = subnode;
  748|  16.7k|            parse_skip_ws(ctx);
  749|  16.7k|            break;
  750|   200k|        } else if (*ctx->pos == '<') {
  ------------------
  |  Branch (750:20): [True: 301, False: 200k]
  ------------------
  751|    301|            data->type = PLIST_DATA;
  752|    301|            ctx->pos++;
  753|    301|            bytearray_t *bytes = byte_array_new(256);
  754|  2.12k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (754:20): [True: 2.09k, False: 27]
  |  Branch (754:43): [True: 2.09k, False: 0]
  ------------------
  755|  2.09k|                parse_skip_ws(ctx);
  756|  2.09k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (756:21): [True: 1, False: 2.09k]
  ------------------
  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.09k|                if (*ctx->pos == '>') {
  ------------------
  |  Branch (761:21): [True: 244, False: 1.85k]
  ------------------
  762|    244|                    break;
  763|    244|                }
  764|  1.85k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (764:21): [True: 11, False: 1.84k]
  ------------------
  765|     11|                    PLIST_OSTEP_ERR("Invalid byte group in data 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]
  |  |  ------------------
  ------------------
  766|     11|                    ctx->err = PLIST_ERR_PARSE;
  767|     11|                    break;
  768|     11|                }
  769|  1.84k|                uint8_t b = HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.84k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 388, False: 1.45k]
  |  |  |  Branch (589:49): [True: 510, False: 944]
  |  |  ------------------
  ------------------
  770|  1.84k|                ctx->pos++;
  771|  1.84k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (771:21): [True: 17, False: 1.82k]
  ------------------
  772|     17|                    PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     17|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 17]
  |  |  ------------------
  ------------------
  773|     17|                    ctx->err = PLIST_ERR_PARSE;
  774|     17|                    break;
  775|     17|                }
  776|  1.82k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (776:21): [True: 1, False: 1.82k]
  ------------------
  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.82k|                b = (b << 4) + HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.82k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 390, False: 1.43k]
  |  |  |  Branch (589:49): [True: 500, False: 934]
  |  |  ------------------
  ------------------
  782|  1.82k|                byte_array_append(bytes, &b, 1);
  783|  1.82k|                ctx->pos++;
  784|  1.82k|            }
  785|    301|            if (ctx->err) {
  ------------------
  |  Branch (785:17): [True: 30, False: 271]
  ------------------
  786|     30|                byte_array_free(bytes);
  787|     30|                plist_free_data(data);
  788|     30|                goto err_out;
  789|     30|            }
  790|    271|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (790:17): [True: 27, False: 244]
  ------------------
  791|     27|                byte_array_free(bytes);
  792|     27|                plist_free_data(data);
  793|     27|                PLIST_OSTEP_ERR("EOF while parsing data 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]
  |  |  ------------------
  ------------------
  794|     27|                ctx->err = PLIST_ERR_PARSE;
  795|     27|                goto err_out;
  796|     27|            }
  797|    244|            if (*ctx->pos != '>') {
  ------------------
  |  Branch (797:17): [True: 0, False: 244]
  ------------------
  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|    244|            ctx->pos++;
  805|    244|            data->buff = (uint8_t*)bytes->data;
  806|    244|            data->length = bytes->len;
  807|    244|            bytes->data = NULL;
  808|    244|            byte_array_free(bytes);
  809|    244|            *plist = plist_new_node(data);
  810|    244|            parse_skip_ws(ctx);
  811|    244|            break;
  812|   200k|        } else if (*ctx->pos == '"' || *ctx->pos == '\'') {
  ------------------
  |  Branch (812:20): [True: 30.7k, False: 169k]
  |  Branch (812:40): [True: 6.44k, False: 163k]
  ------------------
  813|  37.1k|            char c = *ctx->pos;
  814|  37.1k|            ctx->pos++;
  815|  37.1k|            p = ctx->pos;
  816|  37.1k|            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.7k, False: 81.3k]
  |  Branch (821:41): [True: 37.1k, False: 631]
  ------------------
  822|  37.1k|                    break;
  823|  37.1k|                }
  824|  81.9k|                ctx->pos++;
  825|  81.9k|            }
  826|  37.1k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (826:17): [True: 61, False: 37.1k]
  ------------------
  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|  37.1k|            if (*ctx->pos != c) {
  ------------------
  |  Branch (832:17): [True: 0, False: 37.1k]
  ------------------
  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|  37.1k|            size_t slen = ctx->pos - p;
  839|  37.1k|            ctx->pos++; // skip the closing quote
  840|  37.1k|            char* strbuf = (char*)malloc(slen+1);
  841|  37.1k|            if (num_escapes > 0) {
  ------------------
  |  Branch (841:17): [True: 1.19k, False: 35.9k]
  ------------------
  842|  1.19k|                size_t i = 0;
  843|  1.19k|                size_t o = 0;
  844|  28.2k|                while (i < slen) {
  ------------------
  |  Branch (844:24): [True: 27.0k, False: 1.19k]
  ------------------
  845|  27.0k|                    if (p[i] == '\\') {
  ------------------
  |  Branch (845:25): [True: 8.02k, False: 19.0k]
  ------------------
  846|       |                        /* handle escape sequence */
  847|  8.02k|                        i++;
  848|  8.02k|                        switch (p[i]) {
  849|    667|                            case '0':
  ------------------
  |  Branch (849:29): [True: 667, False: 7.35k]
  ------------------
  850|  1.18k|                            case '1':
  ------------------
  |  Branch (850:29): [True: 518, False: 7.50k]
  ------------------
  851|  1.58k|                            case '2':
  ------------------
  |  Branch (851:29): [True: 399, False: 7.62k]
  ------------------
  852|  1.86k|                            case '3':
  ------------------
  |  Branch (852:29): [True: 280, False: 7.74k]
  ------------------
  853|  2.38k|                            case '4':
  ------------------
  |  Branch (853:29): [True: 523, False: 7.50k]
  ------------------
  854|  2.75k|                            case '5':
  ------------------
  |  Branch (854:29): [True: 367, False: 7.65k]
  ------------------
  855|  3.09k|                            case '6':
  ------------------
  |  Branch (855:29): [True: 339, False: 7.68k]
  ------------------
  856|  3.64k|                            case '7': {
  ------------------
  |  Branch (856:29): [True: 548, False: 7.47k]
  ------------------
  857|       |                                // max 3 digits octal
  858|  3.64k|                                unsigned char chr = 0;
  859|  3.64k|                                int maxd = 3;
  860|  8.00k|                                while ((i < slen) && (p[i] >= '0' && p[i] <= '7') && --maxd) {
  ------------------
  |  Branch (860:40): [True: 7.58k, False: 415]
  |  Branch (860:55): [True: 7.09k, False: 493]
  |  Branch (860:70): [True: 4.67k, False: 2.41k]
  |  Branch (860:86): [True: 4.36k, False: 315]
  ------------------
  861|  4.36k|                                    chr = (chr << 3) + p[i] - '0';
  862|  4.36k|                                    i++;
  863|  4.36k|                                }
  864|  3.64k|                                strbuf[o++] = (char)chr;
  865|  3.64k|                            }   break;
  866|  1.35k|                            case 'U': {
  ------------------
  |  Branch (866:29): [True: 1.35k, False: 6.67k]
  ------------------
  867|  1.35k|                                i++;
  868|       |                                // max 4 digits hex
  869|  1.35k|                                uint16_t wchr = 0;
  870|  1.35k|                                int maxd = 4;
  871|  3.18k|                                while ((i < slen) && isxdigit(p[i]) && maxd--) {
  ------------------
  |  Branch (871:40): [True: 2.74k, False: 439]
  |  Branch (871:54): [True: 1.86k, False: 880]
  |  Branch (871:72): [True: 1.83k, False: 33]
  ------------------
  872|  1.83k|                                    wchr = (wchr << 4) + ((p[i] <= '9') ? (p[i] - '0') : ((p[i] <= 'F') ? (p[i] - 'A' + 10) : (p[i] - 'a' + 10)));
  ------------------
  |  Branch (872:59): [True: 487, False: 1.34k]
  |  Branch (872:91): [True: 1.01k, False: 334]
  ------------------
  873|  1.83k|                                    i++;
  874|  1.83k|                                }
  875|  1.35k|                                if (wchr >= 0x800) {
  ------------------
  |  Branch (875:37): [True: 376, False: 976]
  ------------------
  876|    376|                                    strbuf[o++] = (char)(0xE0 + ((wchr >> 12) & 0xF));
  877|    376|                                    strbuf[o++] = (char)(0x80 + ((wchr >> 6) & 0x3F));
  878|    376|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  879|    976|                                } else if (wchr >= 0x80) {
  ------------------
  |  Branch (879:44): [True: 223, False: 753]
  ------------------
  880|    223|                                    strbuf[o++] = (char)(0xC0 + ((wchr >> 6) & 0x1F));
  881|    223|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  882|    753|                                } else {
  883|    753|                                    strbuf[o++] = (char)(wchr & 0x7F);
  884|    753|                                }
  885|  1.35k|                            }   break;
  886|    217|                            case 'a': strbuf[o++] = '\a'; i++; break;
  ------------------
  |  Branch (886:29): [True: 217, False: 7.80k]
  ------------------
  887|    268|                            case 'b': strbuf[o++] = '\b'; i++; break;
  ------------------
  |  Branch (887:29): [True: 268, False: 7.75k]
  ------------------
  888|    233|                            case 'f': strbuf[o++] = '\f'; i++; break;
  ------------------
  |  Branch (888:29): [True: 233, False: 7.79k]
  ------------------
  889|    257|                            case 'n': strbuf[o++] = '\n'; i++; break;
  ------------------
  |  Branch (889:29): [True: 257, False: 7.76k]
  ------------------
  890|    209|                            case 'r': strbuf[o++] = '\r'; i++; break;
  ------------------
  |  Branch (890:29): [True: 209, False: 7.81k]
  ------------------
  891|    213|                            case 't': strbuf[o++] = '\t'; i++; break;
  ------------------
  |  Branch (891:29): [True: 213, False: 7.81k]
  ------------------
  892|    227|                            case 'v': strbuf[o++] = '\v'; i++; break;
  ------------------
  |  Branch (892:29): [True: 227, False: 7.79k]
  ------------------
  893|    312|                            case '"': strbuf[o++] = '"';  i++; break;
  ------------------
  |  Branch (893:29): [True: 312, False: 7.71k]
  ------------------
  894|    360|                            case '\'': strbuf[o++] = '\''; i++; break;
  ------------------
  |  Branch (894:29): [True: 360, False: 7.66k]
  ------------------
  895|    736|                            default:
  ------------------
  |  Branch (895:29): [True: 736, False: 7.28k]
  ------------------
  896|    736|                                break;
  897|  8.02k|                        }
  898|  19.0k|                    } else {
  899|  19.0k|                        strbuf[o++] = p[i++];
  900|  19.0k|                    }
  901|  27.0k|                }
  902|  1.19k|                strbuf[o] = '\0';
  903|  1.19k|                slen = o;
  904|  35.9k|            } else {
  905|  35.9k|                strncpy(strbuf, p, slen);
  906|  35.9k|                strbuf[slen] = '\0';
  907|  35.9k|            }
  908|  37.1k|            data->type = PLIST_STRING;
  909|  37.1k|            data->strval = strbuf;
  910|  37.1k|            data->length = slen;
  911|  37.1k|            *plist = plist_new_node(data);
  912|  37.1k|            parse_skip_ws(ctx);
  913|  37.1k|            break;
  914|   163k|        } else {
  915|       |            // unquoted string
  916|   163k|            size_t slen = 0;
  917|   163k|            parse_skip_ws(ctx);
  918|   163k|            p = ctx->pos;
  919|   397k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (919:20): [True: 397k, False: 118]
  ------------------
  920|   397k|                if (!allowed_unquoted_chars[(uint8_t)*ctx->pos]) {
  ------------------
  |  Branch (920:21): [True: 162k, False: 234k]
  ------------------
  921|   162k|                    break;
  922|   162k|                }
  923|   234k|                ctx->pos++;
  924|   234k|            }
  925|   163k|            slen = ctx->pos-p;
  926|   163k|            if (slen > 0) {
  ------------------
  |  Branch (926:17): [True: 162k, False: 156]
  ------------------
  927|   162k|                data->type = PLIST_STRING;
  928|   162k|                data->strval = strndup(p, slen);
  929|   162k|                data->length = slen;
  930|   162k|                *plist = plist_new_node(data);
  931|   162k|                parse_skip_ws(ctx);
  932|   162k|                break;
  933|   162k|            } else {
  934|    156|                plist_free_data(data);
  935|    156|                PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    156|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 156]
  |  |  ------------------
  ------------------
  936|    156|                ctx->err = PLIST_ERR_PARSE;
  937|    156|                break;
  938|    156|            }
  939|   163k|        }
  940|      0|        ctx->pos++;
  941|      0|    }
  942|   224k|    ctx->depth--;
  943|       |
  944|   239k|err_out:
  945|   239k|    if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (945:9): [True: 14.9k, False: 224k]
  ------------------
  946|  14.9k|        plist_free(subnode);
  947|  14.9k|        plist_free(*plist);
  948|  14.9k|        *plist = NULL;
  949|  14.9k|        return ctx->err;
  950|  14.9k|    }
  951|   224k|    return PLIST_ERR_SUCCESS;
  952|   239k|}
oplist.c:parse_skip_ws:
  553|  1.01M|{
  554|  1.01M|    while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (554:12): [True: 1.01M, False: 490]
  ------------------
  555|       |        // skip comments
  556|  1.01M|        if (*ctx->pos == '/' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (556:13): [True: 830, False: 1.01M]
  |  Branch (556:33): [True: 812, False: 18]
  ------------------
  557|    812|            if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (557:17): [True: 395, False: 417]
  ------------------
  558|    395|                ctx->pos++;
  559|  2.95k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (559:24): [True: 2.93k, False: 24]
  ------------------
  560|  2.93k|                    if ((*ctx->pos == '\n') || (*ctx->pos == '\r')) {
  ------------------
  |  Branch (560:25): [True: 137, False: 2.79k]
  |  Branch (560:48): [True: 234, False: 2.56k]
  ------------------
  561|    371|                        break;
  562|    371|                    }
  563|  2.56k|                    ctx->pos++;
  564|  2.56k|                }
  565|    417|            } else if (*(ctx->pos+1) == '*') {
  ------------------
  |  Branch (565:24): [True: 360, False: 57]
  ------------------
  566|    360|                ctx->pos++;
  567|  9.32k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (567:24): [True: 9.29k, False: 34]
  ------------------
  568|  9.29k|                    if (*ctx->pos == '*' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (568:25): [True: 1.00k, False: 8.28k]
  |  Branch (568:45): [True: 1.00k, False: 2]
  ------------------
  569|  1.00k|                        if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (569:29): [True: 326, False: 681]
  ------------------
  570|    326|                            ctx->pos+=2;
  571|    326|                            break;
  572|    326|                        }
  573|  1.00k|                    }
  574|  8.96k|                    ctx->pos++;
  575|  8.96k|                }
  576|    360|            }
  577|    812|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (577:17): [True: 61, False: 751]
  ------------------
  578|     61|                break;
  579|     61|            }
  580|    812|        }
  581|       |        // break on any char that's not white space
  582|  1.01M|        if (!(((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n')))) {
  ------------------
  |  Branch (582:16): [True: 382, False: 1.01M]
  |  Branch (582:40): [True: 247, False: 1.01M]
  |  Branch (582:65): [True: 286, False: 1.01M]
  |  Branch (582:90): [True: 323, False: 1.01M]
  ------------------
  583|  1.01M|            break;
  584|  1.01M|        }
  585|  1.23k|        ctx->pos++;
  586|  1.23k|    }
  587|  1.01M|}
oplist.c:parse_dict_data:
  594|  20.4k|{
  595|  20.4k|    plist_t key = NULL;
  596|  20.4k|    plist_t val = NULL;
  597|   106k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (597:12): [True: 106k, False: 340]
  |  Branch (597:35): [True: 106k, False: 0]
  ------------------
  598|   106k|        parse_skip_ws(ctx);
  599|   106k|        if (ctx->pos >= ctx->end || *ctx->pos == '}') {
  ------------------
  |  Branch (599:13): [True: 2, False: 106k]
  |  Branch (599:37): [True: 7.51k, False: 98.7k]
  ------------------
  600|  7.51k|            break;
  601|  7.51k|        }
  602|  98.7k|        key = NULL;
  603|  98.7k|        ctx->err = node_from_openstep(ctx, &key);
  604|  98.7k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (604:13): [True: 11.7k, False: 86.9k]
  ------------------
  605|  11.7k|            break;
  606|  11.7k|        }
  607|  86.9k|        if (!PLIST_IS_STRING(key)) {
  ------------------
  |  | 1250|  86.9k|    #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
  |  |  ------------------
  |  |  |  | 1240|  86.9k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 86.9k, False: 2]
  |  |  |  |  |  Branch (1240:63): [True: 86.7k, False: 259]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  608|    261|            PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    261|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 261]
  |  |  ------------------
  ------------------
  609|    261|            ctx->err = PLIST_ERR_PARSE;
  610|    261|            break;
  611|    261|        }
  612|  86.7k|        parse_skip_ws(ctx);
  613|  86.7k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (613:13): [True: 44, False: 86.6k]
  ------------------
  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|  86.6k|        if (*ctx->pos != '=') {
  ------------------
  |  Branch (618:13): [True: 26, False: 86.6k]
  ------------------
  619|     26|            PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     26|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 26]
  |  |  ------------------
  ------------------
  620|     26|            ctx->err = PLIST_ERR_PARSE;
  621|     26|            break;
  622|     26|        }
  623|  86.6k|        ctx->pos++;
  624|  86.6k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (624:13): [True: 235, False: 86.4k]
  ------------------
  625|    235|            PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    235|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 235]
  |  |  ------------------
  ------------------
  626|    235|            ctx->err = PLIST_ERR_PARSE;
  627|    235|            break;
  628|    235|        }
  629|  86.4k|        val = NULL;
  630|  86.4k|        ctx->err = node_from_openstep(ctx, &val);
  631|  86.4k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (631:13): [True: 257, False: 86.1k]
  ------------------
  632|    257|            break;
  633|    257|        }
  634|  86.1k|        if (!val) {
  ------------------
  |  Branch (634:13): [True: 4, False: 86.1k]
  ------------------
  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|  86.1k|        parse_skip_ws(ctx);
  640|  86.1k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (640:13): [True: 9, False: 86.1k]
  ------------------
  641|      9|            PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      9|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 9]
  |  |  ------------------
  ------------------
  642|      9|            ctx->err = PLIST_ERR_PARSE;
  643|      9|            break;
  644|      9|        }
  645|  86.1k|        if (*ctx->pos != ';') {
  ------------------
  |  Branch (645:13): [True: 3, False: 86.1k]
  ------------------
  646|      3|            PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      3|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 3]
  |  |  ------------------
  ------------------
  647|      3|            ctx->err = PLIST_ERR_PARSE;
  648|      3|            break;
  649|      3|        }
  650|       |
  651|  86.1k|        plist_dict_set_item(dict, plist_get_string_ptr(key, NULL), val);
  652|  86.1k|        plist_free(key);
  653|  86.1k|        key = NULL;
  654|  86.1k|        val = NULL;
  655|       |
  656|  86.1k|        ctx->pos++;
  657|  86.1k|    }
  658|  20.4k|    plist_free(key);
  659|  20.4k|    plist_free(val);
  660|  20.4k|}

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|   324k|{
  349|       |    return (plist_t) node_create(NULL, data);
  350|   324k|}
plist_get_data:
  353|  31.8M|{
  354|  31.8M|    if (!node)
  ------------------
  |  Branch (354:9): [True: 0, False: 31.8M]
  ------------------
  355|      0|        return NULL;
  356|  31.8M|    return (plist_data_t)((node_t)node)->data;
  357|  31.8M|}
plist_new_plist_data:
  360|   324k|{
  361|   324k|    return (plist_data_t) calloc(1, sizeof(struct plist_data_s));
  362|   324k|}
plist_free_data:
  421|   324k|{
  422|   324k|    if (!data) return;
  ------------------
  |  Branch (422:9): [True: 0, False: 324k]
  ------------------
  423|   324k|    _plist_free_data(data);
  424|   324k|    free(data);
  425|   324k|}
plist_new_dict:
  528|    901|{
  529|    901|    plist_data_t data = plist_new_plist_data();
  530|    901|    if (!data) {
  ------------------
  |  Branch (530:9): [True: 0, False: 901]
  ------------------
  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|    901|    data->type = PLIST_DICT;
  535|    901|    return plist_new_node(data);
  536|    901|}
plist_free:
  713|   178k|{
  714|   178k|    if (plist)
  ------------------
  |  Branch (714:9): [True: 103k, False: 75.0k]
  ------------------
  715|   103k|    {
  716|   103k|        plist_free_node((node_t)plist);
  717|   103k|    }
  718|   178k|}
plist_array_append_item:
 1080|  50.3k|{
 1081|  50.3k|    if (!PLIST_IS_ARRAY(node) || !item) {
  ------------------
  |  | 1252|  50.3k|    #define PLIST_IS_ARRAY(__plist)   _PLIST_IS_TYPE(__plist, ARRAY)
  |  |  ------------------
  |  |  |  | 1240|   100k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 50.3k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 50.3k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1081:34): [True: 0, False: 50.3k]
  ------------------
 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|  50.3k|    node_t it = (node_t)item;
 1086|  50.3k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1086:9): [True: 0, False: 50.3k]
  ------------------
 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|  50.3k|    int r = node_attach((node_t)node, (node_t)item);
 1093|  50.3k|    if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  50.3k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1093:9): [True: 0, False: 50.3k]
  ------------------
 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|  50.3k|    _plist_array_post_insert(node, item, -1);
 1098|       |
 1099|  50.3k|    return PLIST_ERR_SUCCESS;
 1100|  50.3k|}
plist_dict_get_item:
 1281|  86.1k|{
 1282|  86.1k|    plist_t ret = NULL;
 1283|  86.1k|    if (!PLIST_IS_DICT(node) || !key) {
  ------------------
  |  | 1254|  86.1k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   172k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 86.1k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 86.1k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1283:33): [True: 0, False: 86.1k]
  ------------------
 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|  86.1k|    plist_data_t data = plist_get_data(node);
 1288|  86.1k|    if (!data) {
  ------------------
  |  Branch (1288:9): [True: 0, False: 86.1k]
  ------------------
 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|  86.1k|    size_t keylen = strlen(key);
 1293|  86.1k|    hashtable_t *ht = (hashtable_t*)data->hashtable;
 1294|  86.1k|    if (ht) {
  ------------------
  |  Branch (1294:9): [True: 1.19k, False: 84.9k]
  ------------------
 1295|  1.19k|        struct plist_data_s sdata = { 0 };
 1296|  1.19k|        sdata.strval = (char*)key;
 1297|  1.19k|        sdata.length = keylen;
 1298|  1.19k|        return (plist_t)hash_table_lookup(ht, &sdata);
 1299|  84.9k|    } else {
 1300|  84.9k|        plist_t k = NULL;
 1301|  10.4M|        for (k = (plist_t)node_first_child((node_t)node); k; ) {
  ------------------
  |  Branch (1301:59): [True: 10.3M, False: 84.0k]
  ------------------
 1302|  10.3M|            plist_t v = (plist_t)node_next_sibling(k);
 1303|  10.3M|            if (!v) break;
  ------------------
  |  Branch (1303:17): [True: 0, False: 10.3M]
  ------------------
 1304|  10.3M|            data = plist_get_data(k);
 1305|  10.3M|            assert(PLIST_IS_KEY(k));
  ------------------
  |  Branch (1305:13): [True: 0, False: 10.3M]
  |  Branch (1305:13): [True: 0, False: 0]
  |  Branch (1305:13): [True: 10.3M, False: 0]
  |  Branch (1305:13): [True: 10.3M, False: 0]
  ------------------
 1306|  10.3M|            if (!PLIST_IS_KEY(k) || !data || !data->strval) {
  ------------------
  |  | 1260|  10.3M|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  20.6M|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 10.3M, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 10.3M, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1306:37): [True: 0, False: 10.3M]
  |  Branch (1306:46): [True: 0, False: 10.3M]
  ------------------
 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.3M|            if (data->length == keylen && !memcmp(key, data->strval, keylen+1)) {
  ------------------
  |  Branch (1310:17): [True: 4.98M, False: 5.34M]
  |  Branch (1310:43): [True: 922, False: 4.98M]
  ------------------
 1311|    922|                ret = v;
 1312|    922|                break;
 1313|    922|            }
 1314|  10.3M|            k = node_next_sibling(v);
 1315|  10.3M|        }
 1316|  84.9k|    }
 1317|  84.9k|    return ret;
 1318|  86.1k|}
plist_dict_set_item:
 1321|  86.1k|{
 1322|  86.1k|    if (!PLIST_IS_DICT(node) || !key || !item) {
  ------------------
  |  | 1254|  86.1k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   172k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 86.1k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 86.1k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1322:33): [True: 0, False: 86.1k]
  |  Branch (1322:41): [True: 0, False: 86.1k]
  ------------------
 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|  86.1k|    node_t it = (node_t)item;
 1327|  86.1k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1327:9): [True: 0, False: 86.1k]
  ------------------
 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|  86.1k|    hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
 1334|       |
 1335|  86.1k|    plist_t old_item = plist_dict_get_item(node, key);
 1336|  86.1k|    plist_t key_node = NULL;
 1337|       |
 1338|  86.1k|    if (old_item) {
  ------------------
  |  Branch (1338:9): [True: 1.55k, False: 84.5k]
  ------------------
 1339|       |        // --- REPLACE EXISTING VALUE ---
 1340|  1.55k|        node_t old_val = (node_t)old_item;
 1341|  1.55k|        node_t old_key = node_prev_sibling(old_val);
 1342|  1.55k|        if (!old_key) {
  ------------------
  |  Branch (1342:13): [True: 0, False: 1.55k]
  ------------------
 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.55k|        if (!PLIST_IS_KEY((plist_t)old_key)) {
  ------------------
  |  | 1260|  1.55k|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  1.55k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 1.55k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 1.55k, 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.55k|        int idx = node_detach((node_t)node, old_val);
 1353|  1.55k|        if (idx < 0) {
  ------------------
  |  Branch (1353:13): [True: 0, False: 1.55k]
  ------------------
 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.55k|        int r = node_insert((node_t)node, (unsigned)idx, (node_t)item);
 1360|  1.55k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  1.55k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1360:13): [True: 0, False: 1.55k]
  ------------------
 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.55k|        key_node = old_key;
 1370|       |
 1371|       |        // update hash table
 1372|  1.55k|        if (ht) {
  ------------------
  |  Branch (1372:13): [True: 637, False: 922]
  ------------------
 1373|    637|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1374|    637|        }
 1375|       |
 1376|       |        // now it’s safe to free old value
 1377|  1.55k|        plist_free_node(old_val);
 1378|  84.5k|    } else {
 1379|       |        // --- INSERT NEW KEY/VALUE PAIR ---
 1380|  84.5k|        key_node = plist_new_key(key);
 1381|  84.5k|        if (!key_node) return PLIST_ERR_NO_MEM;
  ------------------
  |  Branch (1381:13): [True: 0, False: 84.5k]
  ------------------
 1382|       |
 1383|  84.5k|        int r = node_attach((node_t)node, (node_t)key_node);
 1384|  84.5k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  84.5k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1384:13): [True: 0, False: 84.5k]
  ------------------
 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|  84.5k|        r = node_attach((node_t)node, (node_t)item);
 1390|  84.5k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  84.5k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1390:13): [True: 0, False: 84.5k]
  ------------------
 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|  84.5k|        if (ht) {
  ------------------
  |  Branch (1398:13): [True: 561, False: 84.0k]
  ------------------
 1399|       |            // store pointer to item in hash table
 1400|    561|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1401|  84.0k|        } else if (((node_t)node)->count > 500) {
  ------------------
  |  Branch (1401:20): [True: 321, False: 83.7k]
  ------------------
 1402|       |            // make new hash table
 1403|    321|            ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
 1404|       |            // calculate the hashes for all entries we have so far
 1405|    321|            plist_t current = NULL;
 1406|    321|            for (current = (plist_t)node_first_child((node_t)node);
 1407|  80.8k|                 ht && current;
  ------------------
  |  Branch (1407:18): [True: 80.8k, False: 0]
  |  Branch (1407:24): [True: 80.5k, False: 321]
  ------------------
 1408|  80.5k|                 current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
 1409|  80.5k|            {
 1410|  80.5k|                hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
 1411|  80.5k|            }
 1412|    321|            ((plist_data_t)((node_t)node)->data)->hashtable = ht;
 1413|    321|        }
 1414|  84.5k|    }
 1415|  86.1k|    return PLIST_ERR_SUCCESS;
 1416|  86.1k|}
plist_get_node_type:
 1746|  21.0M|{
 1747|  21.0M|    if (node)
  ------------------
  |  Branch (1747:9): [True: 21.0M, False: 0]
  ------------------
 1748|  21.0M|    {
 1749|  21.0M|        plist_data_t data = plist_get_data(node);
 1750|  21.0M|        if (data)
  ------------------
  |  Branch (1750:13): [True: 21.0M, False: 0]
  ------------------
 1751|  21.0M|            return data->type;
 1752|  21.0M|    }
 1753|      0|    return PLIST_NONE;
 1754|  21.0M|}
plist_get_string_ptr:
 1785|  86.1k|{
 1786|  86.1k|    if (!node)
  ------------------
  |  Branch (1786:9): [True: 0, False: 86.1k]
  ------------------
 1787|      0|        return NULL;
 1788|  86.1k|    plist_type type = plist_get_node_type(node);
 1789|  86.1k|    if (PLIST_STRING != type)
  ------------------
  |  Branch (1789:9): [True: 0, False: 86.1k]
  ------------------
 1790|      0|        return NULL;
 1791|  86.1k|    plist_data_t data = plist_get_data(node);
 1792|  86.1k|    if (length)
  ------------------
  |  Branch (1792:9): [True: 0, False: 86.1k]
  ------------------
 1793|      0|        *length = data->length;
 1794|  86.1k|    return (const char*)data->strval;
 1795|  86.1k|}
plist.c:_plist_free_data:
  390|   324k|{
  391|   324k|    if (!data) return;
  ------------------
  |  Branch (391:9): [True: 0, False: 324k]
  ------------------
  392|   324k|    switch (data->type) {
  393|  84.5k|        case PLIST_KEY:
  ------------------
  |  Branch (393:9): [True: 84.5k, False: 240k]
  ------------------
  394|   284k|        case PLIST_STRING:
  ------------------
  |  Branch (394:9): [True: 200k, False: 124k]
  ------------------
  395|   284k|            free(data->strval);
  396|   284k|            data->strval = NULL;
  397|   284k|            break;
  398|    301|        case PLIST_DATA:
  ------------------
  |  Branch (398:9): [True: 301, False: 324k]
  ------------------
  399|    301|            free(data->buff);
  400|    301|            data->buff = NULL;
  401|    301|            break;
  402|  19.3k|        case PLIST_ARRAY:
  ------------------
  |  Branch (402:9): [True: 19.3k, False: 305k]
  ------------------
  403|  19.3k|            ptr_array_free((ptrarray_t*)data->hashtable);
  404|  19.3k|            data->hashtable = NULL;
  405|  19.3k|            break;
  406|  20.4k|        case PLIST_DICT: {
  ------------------
  |  Branch (406:9): [True: 20.4k, False: 304k]
  ------------------
  407|  20.4k|            hashtable_t *ht = (hashtable_t*)data->hashtable;
  408|       |            // PLIST_DICT hashtables must not own/free values; values are freed via node tree.
  409|  20.4k|            assert(!ht || ht->free_func == NULL);
  ------------------
  |  Branch (409:13): [True: 20.4k, False: 0]
  |  Branch (409:13): [True: 0, False: 0]
  |  Branch (409:13): [True: 20.1k, False: 321]
  |  Branch (409:13): [True: 321, False: 0]
  ------------------
  410|  20.4k|            if (ht) ht->free_func = NULL;
  ------------------
  |  Branch (410:17): [True: 321, False: 20.1k]
  ------------------
  411|  20.4k|            hash_table_destroy(ht);
  412|  20.4k|            data->hashtable = NULL;
  413|  20.4k|            break;
  414|  20.4k|        }
  415|    217|        default:
  ------------------
  |  Branch (415:9): [True: 217, False: 324k]
  ------------------
  416|    217|            break;
  417|   324k|    }
  418|   324k|}
plist.c:plist_free_node:
  500|   105k|{
  501|   105k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (501:9): [True: 0, False: 105k]
  ------------------
  502|       |
  503|   105k|    int root_index = -1;
  504|       |
  505|   105k|    if (root->parent) {
  ------------------
  |  Branch (505:9): [True: 0, False: 105k]
  ------------------
  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|   105k|    int r = plist_free_children(root);
  513|   105k|    if (r < 0) {
  ------------------
  |  Branch (513:9): [True: 0, False: 105k]
  ------------------
  514|       |        // root is already detached; caller should treat as error.
  515|      0|        return r;
  516|      0|    }
  517|       |
  518|   105k|    plist_data_t data = plist_get_data(root);
  519|   105k|    plist_free_data(data);
  520|   105k|    root->data = NULL;
  521|       |
  522|   105k|    node_destroy(root);
  523|       |
  524|   105k|    return root_index;
  525|   105k|}
plist.c:plist_free_children:
  428|   105k|{
  429|   105k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (429:9): [True: 0, False: 105k]
  ------------------
  430|       |
  431|   105k|    if (!node_first_child(root)) {
  ------------------
  |  Branch (431:9): [True: 103k, False: 1.18k]
  ------------------
  432|   103k|        return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|   103k|#define NODE_ERR_SUCCESS       0
  ------------------
  433|   103k|    }
  434|       |
  435|  1.18k|    size_t cap = 64, sp = 0;
  436|  1.18k|    node_t *stack = (node_t*)malloc(cap * sizeof(*stack));
  437|  1.18k|    if (!stack) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (437:9): [True: 0, False: 1.18k]
  ------------------
  438|       |
  439|       |    // Push *direct* children onto the stack, detached from root.
  440|   189k|    for (;;) {
  441|   189k|        node_t ch = node_first_child(root);
  442|   189k|        if (!ch) break;
  ------------------
  |  Branch (442:13): [True: 1.18k, False: 187k]
  ------------------
  443|       |
  444|   187k|        int di = node_detach(root, ch);
  445|   187k|        if (di < 0) {
  ------------------
  |  Branch (445:13): [True: 0, False: 187k]
  ------------------
  446|      0|            free(stack);
  447|      0|            return di;
  448|      0|        }
  449|       |
  450|   187k|        if (sp == cap) {
  ------------------
  |  Branch (450:13): [True: 2.57k, False: 185k]
  ------------------
  451|  2.57k|            cap += 64;
  452|  2.57k|            node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  453|  2.57k|            if (!tmp) {
  ------------------
  |  Branch (453:17): [True: 0, False: 2.57k]
  ------------------
  454|      0|                free(stack);
  455|      0|                return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  456|      0|            }
  457|  2.57k|            stack = tmp;
  458|  2.57k|        }
  459|   187k|        stack[sp++] = ch;
  460|   187k|    }
  461|       |
  462|       |    // Now free the detached subtree nodes (and their descendants).
  463|   252k|    while (sp) {
  ------------------
  |  Branch (463:12): [True: 251k, False: 1.18k]
  ------------------
  464|   251k|        node_t node = stack[sp - 1];
  465|   251k|        node_t ch = node_first_child(node);
  466|   251k|        if (ch) {
  ------------------
  |  Branch (466:13): [True: 31.5k, False: 219k]
  ------------------
  467|  31.5k|            int di = node_detach(node, ch);
  468|  31.5k|            if (di < 0) {
  ------------------
  |  Branch (468:17): [True: 0, False: 31.5k]
  ------------------
  469|      0|                free(stack);
  470|      0|                return di;
  471|      0|            }
  472|       |
  473|  31.5k|            if (sp == cap) {
  ------------------
  |  Branch (473:17): [True: 225, False: 31.3k]
  ------------------
  474|    225|                cap += 64;
  475|    225|                node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  476|    225|                if (!tmp) {
  ------------------
  |  Branch (476:21): [True: 0, False: 225]
  ------------------
  477|      0|                    free(stack);
  478|      0|                    return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  479|      0|                }
  480|    225|                stack = tmp;
  481|    225|            }
  482|  31.5k|            stack[sp++] = ch;
  483|  31.5k|            continue;
  484|  31.5k|        }
  485|       |
  486|   219k|        plist_data_t data = plist_get_data(node);
  487|   219k|        plist_free_data(data);
  488|   219k|        node->data = NULL;
  489|       |
  490|   219k|        node_destroy(node);
  491|       |
  492|   219k|        sp--;
  493|   219k|    }
  494|       |
  495|  1.18k|    free(stack);
  496|  1.18k|    return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.18k|#define NODE_ERR_SUCCESS       0
  ------------------
  497|  1.18k|}
plist.c:_plist_array_post_insert:
  986|  50.3k|{
  987|  50.3k|    ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
  988|  50.3k|    if (pa) {
  ------------------
  |  Branch (988:9): [True: 13.4k, False: 36.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|  36.8k|    if (((node_t)node)->count > 100) {
  ------------------
  |  Branch (994:9): [True: 162, False: 36.7k]
  ------------------
  995|       |       /* make new lookup array */
  996|    162|       pa = ptr_array_new(128);
  997|    162|       plist_t current = NULL;
  998|    162|       for (current = (plist_t)node_first_child((node_t)node);
  999|  16.5k|            pa && current;
  ------------------
  |  Branch (999:13): [True: 16.5k, False: 0]
  |  Branch (999:19): [True: 16.3k, False: 162]
  ------------------
 1000|  16.3k|            current = (plist_t)node_next_sibling((node_t)current))
 1001|  16.3k|       {
 1002|  16.3k|           ptr_array_add(pa, current);
 1003|  16.3k|       }
 1004|    162|       ((plist_data_t)((node_t)node)->data)->hashtable = pa;
 1005|    162|    }
 1006|  36.8k|}
plist.c:plist_new_key:
  551|  84.5k|{
  552|  84.5k|    plist_data_t data = plist_new_plist_data();
  553|  84.5k|    if (!data) {
  ------------------
  |  Branch (553:9): [True: 0, False: 84.5k]
  ------------------
  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|  84.5k|    data->type = PLIST_KEY;
  558|  84.5k|    data->strval = strdup(val);
  559|  84.5k|    if (!data->strval) {
  ------------------
  |  Branch (559:9): [True: 0, False: 84.5k]
  ------------------
  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|  84.5k|    } else {
  564|  84.5k|        data->length = strlen(val);
  565|  84.5k|    }
  566|  84.5k|    return plist_new_node(data);
  567|  84.5k|}
plist.c:dict_key_hash:
  365|  82.9k|{
  366|  82.9k|    plist_data_t keydata = (plist_data_t)data;
  367|  82.9k|    unsigned int hash = 5381;
  368|  82.9k|    size_t i;
  369|  82.9k|    char *str = keydata->strval;
  370|   240k|    for (i = 0; i < keydata->length; str++, i++) {
  ------------------
  |  Branch (370:17): [True: 157k, False: 82.9k]
  ------------------
  371|   157k|        hash = ((hash << 5) + hash) + *str;
  372|   157k|    }
  373|  82.9k|    return hash;
  374|  82.9k|}
plist.c:dict_key_compare:
  377|  4.16k|{
  378|  4.16k|    plist_data_t data_a = (plist_data_t)a;
  379|  4.16k|    plist_data_t data_b = (plist_data_t)b;
  380|  4.16k|    if (data_a->strval == NULL || data_b->strval == NULL) {
  ------------------
  |  Branch (380:9): [True: 0, False: 4.16k]
  |  Branch (380:35): [True: 0, False: 4.16k]
  ------------------
  381|      0|        return FALSE;
  ------------------
  |  |   32|      0|#define FALSE 0
  ------------------
  382|      0|    }
  383|  4.16k|    if (data_a->length != data_b->length) {
  ------------------
  |  Branch (383:9): [True: 1.22k, False: 2.93k]
  ------------------
  384|  1.22k|        return FALSE;
  ------------------
  |  |   32|  1.22k|#define FALSE 0
  ------------------
  385|  1.22k|    }
  386|  2.93k|    return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   28|  1.27k|#define TRUE 1
  ------------------
                  return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   32|  1.66k|#define FALSE 0
  ------------------
  |  Branch (386:12): [True: 1.27k, False: 1.66k]
  ------------------
  387|  4.16k|}

ptr_array_new:
   25|    162|{
   26|    162|	ptrarray_t *pa = (ptrarray_t*)malloc(sizeof(ptrarray_t));
   27|    162|	pa->pdata = (void**)malloc(sizeof(void*) * capacity);
   28|    162|	pa->capacity = capacity;
   29|    162|	pa->capacity_step = (capacity > 4096) ? 4096 : capacity;
  ------------------
  |  Branch (29:22): [True: 0, False: 162]
  ------------------
   30|    162|	pa->len = 0;
   31|    162|	return pa;
   32|    162|}
ptr_array_free:
   35|  19.3k|{
   36|  19.3k|	if (!pa) return;
  ------------------
  |  Branch (36:6): [True: 19.1k, False: 162]
  ------------------
   37|    162|	if (pa->pdata) {
  ------------------
  |  Branch (37:6): [True: 162, False: 0]
  ------------------
   38|    162|		free(pa->pdata);
   39|    162|	}
   40|    162|	free(pa);
   41|    162|}
ptr_array_insert:
   44|  29.8k|{
   45|  29.8k|	if (!pa || !pa->pdata) return;
  ------------------
  |  Branch (45:6): [True: 0, False: 29.8k]
  |  Branch (45:13): [True: 0, False: 29.8k]
  ------------------
   46|  29.8k|	long remaining = pa->capacity-pa->len;
   47|  29.8k|	if (remaining == 0) {
  ------------------
  |  Branch (47:6): [True: 115, False: 29.7k]
  ------------------
   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.8k|	if (array_index < 0 || array_index >= pa->len) {
  ------------------
  |  Branch (51:6): [True: 29.8k, False: 0]
  |  Branch (51:25): [True: 0, False: 0]
  ------------------
   52|  29.8k|		pa->pdata[pa->len] = data;
   53|  29.8k|	} 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.8k|	pa->len++;
   58|  29.8k|}
ptr_array_add:
   61|  16.3k|{
   62|  16.3k|	ptr_array_insert(pa, data, -1);
   63|  16.3k|}

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|}

