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

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

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

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

byte_array_new:
   27|    295|{
   28|    295|	bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t));
   29|    295|	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|    295|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|      0|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|      0|#define PAGE_SIZE 4096
  ------------------
              	a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
  ------------------
  |  |   24|    590|#define PAGE_SIZE 4096
  ------------------
  |  Branch (29:16): [True: 0, False: 295]
  ------------------
   30|    295|	a->data = malloc(a->capacity);
   31|    295|	a->len = 0;
   32|       |	a->stream = NULL;
   33|    295|	return a;
   34|    295|}
byte_array_free:
   47|    295|{
   48|    295|	if (!ba) return;
  ------------------
  |  Branch (48:6): [True: 0, False: 295]
  ------------------
   49|    295|	if (ba->data) {
  ------------------
  |  Branch (49:6): [True: 57, False: 238]
  ------------------
   50|     57|		free(ba->data);
   51|     57|	}
   52|    295|	free(ba);
   53|    295|}
byte_array_append:
   76|  1.80k|{
   77|  1.80k|	if (!ba || (!ba->stream && !ba->data) || (len <= 0)) return;
  ------------------
  |  Branch (77:6): [True: 0, False: 1.80k]
  |  Branch (77:14): [True: 1.80k, False: 0]
  |  Branch (77:29): [True: 0, False: 1.80k]
  |  Branch (77:43): [True: 0, False: 1.80k]
  ------------------
   78|  1.80k|	if (ba->stream) {
  ------------------
  |  Branch (78:6): [True: 0, False: 1.80k]
  ------------------
   79|      0|		if (fwrite(buf, 1, len, ba->stream) < len) {
  ------------------
  |  Branch (79:7): [True: 0, False: 0]
  ------------------
   80|       |#if DEBUG
   81|       |			fprintf(stderr, "ERROR: Failed to write to stream.\n");
   82|       |#endif
   83|      0|		}
   84|  1.80k|	} else {
   85|  1.80k|		size_t remaining = ba->capacity-ba->len;
   86|  1.80k|		if (len > remaining) {
  ------------------
  |  Branch (86:7): [True: 0, False: 1.80k]
  ------------------
   87|      0|			size_t needed = len - remaining;
   88|      0|			byte_array_grow(ba, needed);
   89|      0|			if (!ba->data) {
  ------------------
  |  Branch (89:8): [True: 0, False: 0]
  ------------------
   90|      0|				return;
   91|      0|			}
   92|      0|		}
   93|  1.80k|		memcpy(((char*)ba->data) + ba->len, buf, len);
   94|  1.80k|	}
   95|  1.80k|	ba->len += len;
   96|  1.80k|}

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

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:
  967|  1.53k|{
  968|  1.53k|    if (!plist) {
  ------------------
  |  Branch (968:9): [True: 0, False: 1.53k]
  ------------------
  969|      0|        return PLIST_ERR_INVALID_ARG;
  970|      0|    }
  971|  1.53k|    *plist = NULL;
  972|  1.53k|    if (!plist_ostep || (length == 0)) {
  ------------------
  |  Branch (972:9): [True: 0, False: 1.53k]
  |  Branch (972:25): [True: 0, False: 1.53k]
  ------------------
  973|      0|        return PLIST_ERR_INVALID_ARG;
  974|      0|    }
  975|       |
  976|  1.53k|    struct _parse_ctx ctx = { plist_ostep, plist_ostep, plist_ostep + length, 0 , 0 };
  977|       |
  978|  1.53k|    plist_err_t err = node_from_openstep(&ctx, plist);
  979|  1.53k|    if (err == 0) {
  ------------------
  |  Branch (979:9): [True: 1.06k, False: 462]
  ------------------
  980|  1.06k|        if (!*plist) {
  ------------------
  |  Branch (980:13): [True: 54, False: 1.01k]
  ------------------
  981|       |            /* whitespace only file is considered an empty dictionary */
  982|     54|            *plist = plist_new_dict();
  983|  1.01k|        } else if (ctx.pos < ctx.end && *ctx.pos == '=') {
  ------------------
  |  Branch (983:20): [True: 843, False: 172]
  |  Branch (983:41): [True: 833, False: 10]
  ------------------
  984|       |            /* attempt to parse this as 'strings' data */
  985|    833|            plist_free(*plist);
  986|    833|            *plist = NULL;
  987|    833|            plist_t pl = plist_new_dict();
  988|    833|            ctx.pos = plist_ostep;
  989|    833|            parse_dict_data(&ctx, pl);
  990|    833|            if (ctx.err > 0) {
  ------------------
  |  Branch (990:17): [True: 0, False: 833]
  ------------------
  991|      0|                plist_free(pl);
  992|      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]
  |  |  ------------------
  ------------------
  993|      0|                err = PLIST_ERR_PARSE;
  994|    833|            } else {
  995|    833|                *plist = pl;
  996|    833|            }
  997|    833|        }
  998|  1.06k|    }
  999|       |
 1000|  1.53k|    return err;
 1001|  1.53k|}
oplist.c:node_from_openstep:
  670|   228k|{
  671|   228k|    plist_t subnode = NULL;
  672|   228k|    const char *p = NULL;
  673|   228k|    ctx->depth++;
  674|   228k|    if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
  ------------------
  |  |   56|   228k|#define PLIST_MAX_NESTING_DEPTH NODE_MAX_DEPTH
  |  |  ------------------
  |  |  |  |   33|   228k|#define NODE_MAX_DEPTH 512
  |  |  ------------------
  ------------------
  |  Branch (674:9): [True: 5, False: 228k]
  ------------------
  675|      5|        PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      5|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 5]
  |  |  ------------------
  ------------------
  676|      5|        ctx->err = PLIST_ERR_MAX_NESTING;
  677|      5|        return ctx->err;
  678|      5|    }
  679|   228k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (679:12): [True: 228k, False: 0]
  |  Branch (679:35): [True: 228k, False: 0]
  ------------------
  680|   228k|        parse_skip_ws(ctx);
  681|   228k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (681:13): [True: 61, False: 228k]
  ------------------
  682|     61|            break;
  683|     61|        }
  684|   228k|        plist_data_t data = plist_new_plist_data();
  685|   228k|        if (*ctx->pos == '{') {
  ------------------
  |  Branch (685:13): [True: 18.5k, False: 209k]
  ------------------
  686|  18.5k|            data->type = PLIST_DICT;
  687|  18.5k|            subnode = plist_new_node(data);
  688|  18.5k|            ctx->pos++;
  689|  18.5k|            parse_dict_data(ctx, subnode);
  690|  18.5k|            if (ctx->err) {
  ------------------
  |  Branch (690:17): [True: 12.9k, False: 5.60k]
  ------------------
  691|  12.9k|                goto err_out;
  692|  12.9k|            }
  693|  5.60k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (693:17): [True: 94, False: 5.50k]
  ------------------
  694|     94|                PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     94|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 94]
  |  |  ------------------
  ------------------
  695|     94|                ctx->err = PLIST_ERR_PARSE;
  696|     94|                break;
  697|     94|            }
  698|  5.50k|            if (*ctx->pos != '}') {
  ------------------
  |  Branch (698:17): [True: 0, False: 5.50k]
  ------------------
  699|      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]
  |  |  ------------------
  ------------------
  700|      0|                ctx->err = PLIST_ERR_PARSE;
  701|      0|                goto err_out;
  702|      0|            }
  703|  5.50k|            ctx->pos++;
  704|  5.50k|            *plist = subnode;
  705|  5.50k|            parse_skip_ws(ctx);
  706|  5.50k|            break;
  707|   209k|        } else if (*ctx->pos == '(') {
  ------------------
  |  Branch (707:20): [True: 17.7k, False: 192k]
  ------------------
  708|  17.7k|            data->type = PLIST_ARRAY;
  709|  17.7k|            subnode = plist_new_node(data);
  710|  17.7k|            ctx->pos++;
  711|  17.7k|            plist_t tmp = NULL;
  712|  53.8k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (712:20): [True: 53.8k, False: 22]
  |  Branch (712:43): [True: 53.8k, False: 0]
  ------------------
  713|  53.8k|                parse_skip_ws(ctx);
  714|  53.8k|                if (ctx->pos >= ctx->end || *ctx->pos == ')') {
  ------------------
  |  Branch (714:21): [True: 2, False: 53.8k]
  |  Branch (714:45): [True: 359, False: 53.5k]
  ------------------
  715|    361|                    break;
  716|    361|                }
  717|  53.5k|                ctx->err = node_from_openstep(ctx, &tmp);
  718|  53.5k|                if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (718:21): [True: 1.77k, False: 51.7k]
  ------------------
  719|  1.77k|                    break;
  720|  1.77k|                }
  721|  51.7k|                if (!tmp) {
  ------------------
  |  Branch (721:21): [True: 1, False: 51.7k]
  ------------------
  722|      1|                    ctx->err = PLIST_ERR_PARSE;
  723|      1|                    break;
  724|      1|                }
  725|  51.7k|                plist_array_append_item(subnode, tmp);
  726|  51.7k|                tmp = NULL;
  727|  51.7k|                parse_skip_ws(ctx);
  728|  51.7k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (728:21): [True: 99, False: 51.6k]
  ------------------
  729|     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]
  |  |  ------------------
  ------------------
  730|     99|                    ctx->err = PLIST_ERR_PARSE;
  731|     99|                    break;
  732|     99|                }
  733|  51.6k|                if (*ctx->pos != ',') {
  ------------------
  |  Branch (733:21): [True: 15.4k, False: 36.1k]
  ------------------
  734|  15.4k|                    break;
  735|  15.4k|                }
  736|  36.1k|                ctx->pos++;
  737|  36.1k|            }
  738|  17.7k|	    plist_free(tmp);
  739|  17.7k|	    tmp = NULL;
  740|  17.7k|            if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (740:17): [True: 1.87k, False: 15.8k]
  ------------------
  741|  1.87k|                goto err_out;
  742|  1.87k|            }
  743|  15.8k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (743:17): [True: 24, False: 15.8k]
  ------------------
  744|     24|                PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     24|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 24]
  |  |  ------------------
  ------------------
  745|     24|                ctx->err = PLIST_ERR_PARSE;
  746|     24|                break;
  747|     24|            }
  748|  15.8k|            if (*ctx->pos != ')') {
  ------------------
  |  Branch (748:17): [True: 13, False: 15.7k]
  ------------------
  749|     13|                PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     13|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 13]
  |  |  ------------------
  ------------------
  750|     13|                ctx->err = PLIST_ERR_PARSE;
  751|     13|                goto err_out;
  752|     13|            }
  753|  15.7k|            ctx->pos++;
  754|  15.7k|            *plist = subnode;
  755|  15.7k|            parse_skip_ws(ctx);
  756|  15.7k|            break;
  757|   192k|        } else if (*ctx->pos == '<') {
  ------------------
  |  Branch (757:20): [True: 295, False: 191k]
  ------------------
  758|    295|            data->type = PLIST_DATA;
  759|    295|            ctx->pos++;
  760|    295|            bytearray_t *bytes = byte_array_new(256);
  761|  2.09k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (761:20): [True: 2.06k, False: 29]
  |  Branch (761:43): [True: 2.06k, False: 0]
  ------------------
  762|  2.06k|                parse_skip_ws(ctx);
  763|  2.06k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (763:21): [True: 1, False: 2.06k]
  ------------------
  764|      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]
  |  |  ------------------
  ------------------
  765|      1|                    ctx->err = PLIST_ERR_PARSE;
  766|      1|                    break;
  767|      1|                }
  768|  2.06k|                if (*ctx->pos == '>') {
  ------------------
  |  Branch (768:21): [True: 238, False: 1.82k]
  ------------------
  769|    238|                    break;
  770|    238|                }
  771|  1.82k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (771:21): [True: 7, False: 1.82k]
  ------------------
  772|      7|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      7|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 7]
  |  |  ------------------
  ------------------
  773|      7|                    ctx->err = PLIST_ERR_PARSE;
  774|      7|                    break;
  775|      7|                }
  776|  1.82k|                uint8_t b = HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  596|  1.82k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (596:23): [True: 260, False: 1.56k]
  |  |  |  Branch (596:49): [True: 439, False: 1.12k]
  |  |  ------------------
  ------------------
  777|  1.82k|                ctx->pos++;
  778|  1.82k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (778:21): [True: 19, False: 1.80k]
  ------------------
  779|     19|                    PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     19|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 19]
  |  |  ------------------
  ------------------
  780|     19|                    ctx->err = PLIST_ERR_PARSE;
  781|     19|                    break;
  782|     19|                }
  783|  1.80k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (783:21): [True: 1, False: 1.80k]
  ------------------
  784|      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]
  |  |  ------------------
  ------------------
  785|      1|                    ctx->err = PLIST_ERR_PARSE;
  786|      1|                    break;
  787|      1|                }
  788|  1.80k|                b = (b << 4) + HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  596|  1.80k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (596:23): [True: 251, False: 1.54k]
  |  |  |  Branch (596:49): [True: 430, False: 1.11k]
  |  |  ------------------
  ------------------
  789|  1.80k|                byte_array_append(bytes, &b, 1);
  790|  1.80k|                if (!bytes->data) {
  ------------------
  |  Branch (790:21): [True: 0, False: 1.80k]
  ------------------
  791|      0|                    PLIST_OSTEP_ERR("Out of memory while parsing data 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]
  |  |  ------------------
  ------------------
  792|      0|                    ctx->err = PLIST_ERR_NO_MEM;
  793|      0|                    break;
  794|      0|                }
  795|  1.80k|                ctx->pos++;
  796|  1.80k|            }
  797|    295|            if (ctx->err) {
  ------------------
  |  Branch (797:17): [True: 28, False: 267]
  ------------------
  798|     28|                byte_array_free(bytes);
  799|     28|                plist_free_data(data);
  800|     28|                goto err_out;
  801|     28|            }
  802|    267|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (802:17): [True: 29, False: 238]
  ------------------
  803|     29|                byte_array_free(bytes);
  804|     29|                plist_free_data(data);
  805|     29|                PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     29|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 29]
  |  |  ------------------
  ------------------
  806|     29|                ctx->err = PLIST_ERR_PARSE;
  807|     29|                goto err_out;
  808|     29|            }
  809|    238|            if (*ctx->pos != '>') {
  ------------------
  |  Branch (809:17): [True: 0, False: 238]
  ------------------
  810|      0|                byte_array_free(bytes);
  811|      0|                plist_free_data(data);
  812|      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]
  |  |  ------------------
  ------------------
  813|      0|                ctx->err = PLIST_ERR_PARSE;
  814|      0|                goto err_out;
  815|      0|            }
  816|    238|            ctx->pos++;
  817|    238|            data->buff = (uint8_t*)bytes->data;
  818|    238|            data->length = bytes->len;
  819|    238|            bytes->data = NULL;
  820|    238|            byte_array_free(bytes);
  821|    238|            *plist = plist_new_node(data);
  822|    238|            parse_skip_ws(ctx);
  823|    238|            break;
  824|   191k|        } else if (*ctx->pos == '"' || *ctx->pos == '\'') {
  ------------------
  |  Branch (824:20): [True: 23.8k, False: 167k]
  |  Branch (824:40): [True: 4.90k, False: 162k]
  ------------------
  825|  28.7k|            char c = *ctx->pos;
  826|  28.7k|            ctx->pos++;
  827|  28.7k|            p = ctx->pos;
  828|  28.7k|            size_t num_escapes = 0;
  829|   102k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (829:20): [True: 102k, False: 61]
  ------------------
  830|   102k|                if (*ctx->pos == '\\') {
  ------------------
  |  Branch (830:21): [True: 15.1k, False: 87.4k]
  ------------------
  831|  15.1k|                    num_escapes++;
  832|  15.1k|                }
  833|   102k|                if ((*ctx->pos == c) && (*(ctx->pos-1) != '\\')) {
  ------------------
  |  Branch (833:21): [True: 29.1k, False: 73.4k]
  |  Branch (833:41): [True: 28.7k, False: 434]
  ------------------
  834|  28.7k|                    break;
  835|  28.7k|                }
  836|  73.8k|                ctx->pos++;
  837|  73.8k|            }
  838|  28.7k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (838:17): [True: 61, False: 28.7k]
  ------------------
  839|     61|                plist_free_data(data);
  840|     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]
  |  |  ------------------
  ------------------
  841|     61|                ctx->err = PLIST_ERR_PARSE;
  842|     61|                goto err_out;
  843|     61|            }
  844|  28.7k|            if (*ctx->pos != c) {
  ------------------
  |  Branch (844:17): [True: 0, False: 28.7k]
  ------------------
  845|      0|                plist_free_data(data);
  846|      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]
  |  |  ------------------
  ------------------
  847|      0|                ctx->err = PLIST_ERR_PARSE;
  848|      0|                goto err_out;
  849|      0|            }
  850|  28.7k|            size_t slen = ctx->pos - p;
  851|  28.7k|            ctx->pos++; // skip the closing quote
  852|  28.7k|            char* strbuf = (char*)malloc(slen+1);
  853|  28.7k|            if (num_escapes > 0) {
  ------------------
  |  Branch (853:17): [True: 993, False: 27.7k]
  ------------------
  854|    993|                size_t i = 0;
  855|    993|                size_t o = 0;
  856|  27.8k|                while (i < slen) {
  ------------------
  |  Branch (856:24): [True: 26.8k, False: 993]
  ------------------
  857|  26.8k|                    if (p[i] == '\\') {
  ------------------
  |  Branch (857:25): [True: 6.95k, False: 19.9k]
  ------------------
  858|       |                        /* handle escape sequence */
  859|  6.95k|                        i++;
  860|  6.95k|                        switch (p[i]) {
  861|    434|                            case '0':
  ------------------
  |  Branch (861:29): [True: 434, False: 6.52k]
  ------------------
  862|    835|                            case '1':
  ------------------
  |  Branch (862:29): [True: 401, False: 6.55k]
  ------------------
  863|  1.19k|                            case '2':
  ------------------
  |  Branch (863:29): [True: 361, False: 6.59k]
  ------------------
  864|  1.50k|                            case '3':
  ------------------
  |  Branch (864:29): [True: 312, False: 6.64k]
  ------------------
  865|  1.89k|                            case '4':
  ------------------
  |  Branch (865:29): [True: 383, False: 6.57k]
  ------------------
  866|  2.26k|                            case '5':
  ------------------
  |  Branch (866:29): [True: 375, False: 6.58k]
  ------------------
  867|  2.63k|                            case '6':
  ------------------
  |  Branch (867:29): [True: 366, False: 6.59k]
  ------------------
  868|  3.18k|                            case '7': {
  ------------------
  |  Branch (868:29): [True: 553, False: 6.40k]
  ------------------
  869|       |                                // max 3 digits octal
  870|  3.18k|                                unsigned char chr = 0;
  871|  3.18k|                                int maxd = 3;
  872|  6.89k|                                while ((i < slen) && (p[i] >= '0' && p[i] <= '7') && --maxd) {
  ------------------
  |  Branch (872:40): [True: 6.51k, False: 379]
  |  Branch (872:55): [True: 6.16k, False: 351]
  |  Branch (872:70): [True: 3.98k, False: 2.17k]
  |  Branch (872:86): [True: 3.70k, False: 279]
  ------------------
  873|  3.70k|                                    chr = (chr << 3) + p[i] - '0';
  874|  3.70k|                                    i++;
  875|  3.70k|                                }
  876|  3.18k|                                strbuf[o++] = (char)chr;
  877|  3.18k|                            }   break;
  878|  1.25k|                            case 'U': {
  ------------------
  |  Branch (878:29): [True: 1.25k, False: 5.69k]
  ------------------
  879|  1.25k|                                i++;
  880|       |                                // max 4 digits hex
  881|  1.25k|                                uint16_t wchr = 0;
  882|  1.25k|                                int maxd = 4;
  883|  3.11k|                                while ((i < slen) && isxdigit(p[i]) && maxd--) {
  ------------------
  |  Branch (883:40): [True: 2.80k, False: 314]
  |  Branch (883:54): [True: 1.89k, False: 912]
  |  Branch (883:72): [True: 1.86k, False: 32]
  ------------------
  884|  1.86k|                                    wchr = (wchr << 4) + ((p[i] <= '9') ? (p[i] - '0') : ((p[i] <= 'F') ? (p[i] - 'A' + 10) : (p[i] - 'a' + 10)));
  ------------------
  |  Branch (884:59): [True: 438, False: 1.42k]
  |  Branch (884:91): [True: 681, False: 741]
  ------------------
  885|  1.86k|                                    i++;
  886|  1.86k|                                }
  887|  1.25k|                                if (wchr >= 0x800) {
  ------------------
  |  Branch (887:37): [True: 375, False: 883]
  ------------------
  888|    375|                                    strbuf[o++] = (char)(0xE0 + ((wchr >> 12) & 0xF));
  889|    375|                                    strbuf[o++] = (char)(0x80 + ((wchr >> 6) & 0x3F));
  890|    375|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  891|    883|                                } else if (wchr >= 0x80) {
  ------------------
  |  Branch (891:44): [True: 231, False: 652]
  ------------------
  892|    231|                                    strbuf[o++] = (char)(0xC0 + ((wchr >> 6) & 0x1F));
  893|    231|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  894|    652|                                } else {
  895|    652|                                    strbuf[o++] = (char)(wchr & 0x7F);
  896|    652|                                }
  897|  1.25k|                            }   break;
  898|    200|                            case 'a': strbuf[o++] = '\a'; i++; break;
  ------------------
  |  Branch (898:29): [True: 200, False: 6.75k]
  ------------------
  899|    206|                            case 'b': strbuf[o++] = '\b'; i++; break;
  ------------------
  |  Branch (899:29): [True: 206, False: 6.75k]
  ------------------
  900|    197|                            case 'f': strbuf[o++] = '\f'; i++; break;
  ------------------
  |  Branch (900:29): [True: 197, False: 6.75k]
  ------------------
  901|    208|                            case 'n': strbuf[o++] = '\n'; i++; break;
  ------------------
  |  Branch (901:29): [True: 208, False: 6.74k]
  ------------------
  902|    216|                            case 'r': strbuf[o++] = '\r'; i++; break;
  ------------------
  |  Branch (902:29): [True: 216, False: 6.74k]
  ------------------
  903|    203|                            case 't': strbuf[o++] = '\t'; i++; break;
  ------------------
  |  Branch (903:29): [True: 203, False: 6.75k]
  ------------------
  904|    195|                            case 'v': strbuf[o++] = '\v'; i++; break;
  ------------------
  |  Branch (904:29): [True: 195, False: 6.76k]
  ------------------
  905|    220|                            case '"': strbuf[o++] = '"';  i++; break;
  ------------------
  |  Branch (905:29): [True: 220, False: 6.73k]
  ------------------
  906|    232|                            case '\'': strbuf[o++] = '\''; i++; break;
  ------------------
  |  Branch (906:29): [True: 232, False: 6.72k]
  ------------------
  907|    636|                            default:
  ------------------
  |  Branch (907:29): [True: 636, False: 6.32k]
  ------------------
  908|    636|                                break;
  909|  6.95k|                        }
  910|  19.9k|                    } else {
  911|  19.9k|                        strbuf[o++] = p[i++];
  912|  19.9k|                    }
  913|  26.8k|                }
  914|    993|                strbuf[o] = '\0';
  915|    993|                slen = o;
  916|  27.7k|            } else {
  917|  27.7k|                strncpy(strbuf, p, slen);
  918|  27.7k|                strbuf[slen] = '\0';
  919|  27.7k|            }
  920|  28.7k|            data->type = PLIST_STRING;
  921|  28.7k|            data->strval = strbuf;
  922|  28.7k|            data->length = slen;
  923|  28.7k|            *plist = plist_new_node(data);
  924|  28.7k|            parse_skip_ws(ctx);
  925|  28.7k|            break;
  926|   162k|        } else {
  927|       |            // unquoted string
  928|   162k|            size_t slen = 0;
  929|   162k|            parse_skip_ws(ctx);
  930|   162k|            p = ctx->pos;
  931|   395k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (931:20): [True: 395k, False: 104]
  ------------------
  932|   395k|                if (!allowed_unquoted_chars[(uint8_t)*ctx->pos]) {
  ------------------
  |  Branch (932:21): [True: 162k, False: 232k]
  ------------------
  933|   162k|                    break;
  934|   162k|                }
  935|   232k|                ctx->pos++;
  936|   232k|            }
  937|   162k|            slen = ctx->pos-p;
  938|   162k|            if (slen > 0) {
  ------------------
  |  Branch (938:17): [True: 162k, False: 112]
  ------------------
  939|   162k|                data->type = PLIST_STRING;
  940|   162k|                data->strval = strndup(p, slen);
  941|   162k|                data->length = slen;
  942|   162k|                *plist = plist_new_node(data);
  943|   162k|                parse_skip_ws(ctx);
  944|   162k|                break;
  945|   162k|            } else {
  946|    112|                plist_free_data(data);
  947|    112|                PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    112|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 112]
  |  |  ------------------
  ------------------
  948|    112|                ctx->err = PLIST_ERR_PARSE;
  949|    112|                break;
  950|    112|            }
  951|   162k|        }
  952|      0|        ctx->pos++;
  953|      0|    }
  954|   213k|    ctx->depth--;
  955|       |
  956|   228k|err_out:
  957|   228k|    if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (957:9): [True: 15.2k, False: 213k]
  ------------------
  958|  15.2k|        plist_free(subnode);
  959|  15.2k|        plist_free(*plist);
  960|  15.2k|        *plist = NULL;
  961|  15.2k|        return ctx->err;
  962|  15.2k|    }
  963|   213k|    return PLIST_ERR_SUCCESS;
  964|   228k|}
oplist.c:parse_skip_ws:
  560|   970k|{
  561|   972k|    while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (561:12): [True: 971k, False: 467]
  ------------------
  562|       |        // skip comments
  563|   971k|        if (*ctx->pos == '/' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (563:13): [True: 792, False: 970k]
  |  Branch (563:33): [True: 775, False: 17]
  ------------------
  564|    775|            if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (564:17): [True: 367, False: 408]
  ------------------
  565|    367|                ctx->pos++;
  566|  2.14k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (566:24): [True: 2.12k, False: 18]
  ------------------
  567|  2.12k|                    if ((*ctx->pos == '\n') || (*ctx->pos == '\r')) {
  ------------------
  |  Branch (567:25): [True: 123, False: 2.00k]
  |  Branch (567:48): [True: 226, False: 1.77k]
  ------------------
  568|    349|                        break;
  569|    349|                    }
  570|  1.77k|                    ctx->pos++;
  571|  1.77k|                }
  572|    408|            } else if (*(ctx->pos+1) == '*') {
  ------------------
  |  Branch (572:24): [True: 371, False: 37]
  ------------------
  573|    371|                ctx->pos++;
  574|  14.4k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (574:24): [True: 14.4k, False: 29]
  ------------------
  575|  14.4k|                    if (*ctx->pos == '*' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (575:25): [True: 1.04k, False: 13.4k]
  |  Branch (575:45): [True: 1.04k, False: 5]
  ------------------
  576|  1.04k|                        if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (576:29): [True: 342, False: 700]
  ------------------
  577|    342|                            ctx->pos+=2;
  578|    342|                            break;
  579|    342|                        }
  580|  1.04k|                    }
  581|  14.1k|                    ctx->pos++;
  582|  14.1k|                }
  583|    371|            }
  584|    775|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (584:17): [True: 53, False: 722]
  ------------------
  585|     53|                break;
  586|     53|            }
  587|    775|        }
  588|       |        // break on any char that's not white space
  589|   971k|        if (!(((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n')))) {
  ------------------
  |  Branch (589:16): [True: 299, False: 971k]
  |  Branch (589:40): [True: 233, False: 971k]
  |  Branch (589:65): [True: 398, False: 970k]
  |  Branch (589:90): [True: 199, False: 970k]
  ------------------
  590|   970k|            break;
  591|   970k|        }
  592|  1.12k|        ctx->pos++;
  593|  1.12k|    }
  594|   970k|}
oplist.c:parse_dict_data:
  601|  19.4k|{
  602|  19.4k|    plist_t key = NULL;
  603|  19.4k|    plist_t val = NULL;
  604|  99.1k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (604:12): [True: 98.7k, False: 389]
  |  Branch (604:35): [True: 98.7k, False: 0]
  ------------------
  605|  98.7k|        parse_skip_ws(ctx);
  606|  98.7k|        if (ctx->pos >= ctx->end || *ctx->pos == '}') {
  ------------------
  |  Branch (606:13): [True: 3, False: 98.7k]
  |  Branch (606:37): [True: 5.51k, False: 93.2k]
  ------------------
  607|  5.51k|            break;
  608|  5.51k|        }
  609|  93.2k|        key = NULL;
  610|  93.2k|        ctx->err = node_from_openstep(ctx, &key);
  611|  93.2k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (611:13): [True: 12.7k, False: 80.5k]
  ------------------
  612|  12.7k|            break;
  613|  12.7k|        }
  614|  80.5k|        if (!PLIST_IS_STRING(key)) {
  ------------------
  |  | 1250|  80.5k|    #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
  |  |  ------------------
  |  |  |  | 1240|  80.5k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 80.5k, False: 2]
  |  |  |  |  |  Branch (1240:63): [True: 80.3k, False: 233]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  615|    235|            PLIST_OSTEP_ERR("Invalid type for dictionary key 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]
  |  |  ------------------
  ------------------
  616|    235|            ctx->err = PLIST_ERR_PARSE;
  617|    235|            break;
  618|    235|        }
  619|  80.3k|        parse_skip_ws(ctx);
  620|  80.3k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (620:13): [True: 33, False: 80.2k]
  ------------------
  621|     33|            PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     33|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 33]
  |  |  ------------------
  ------------------
  622|     33|            ctx->err = PLIST_ERR_PARSE;
  623|     33|            break;
  624|     33|        }
  625|  80.2k|        if (*ctx->pos != '=') {
  ------------------
  |  Branch (625:13): [True: 16, False: 80.2k]
  ------------------
  626|     16|            PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     16|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 16]
  |  |  ------------------
  ------------------
  627|     16|            ctx->err = PLIST_ERR_PARSE;
  628|     16|            break;
  629|     16|        }
  630|  80.2k|        ctx->pos++;
  631|  80.2k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (631:13): [True: 229, False: 80.0k]
  ------------------
  632|    229|            PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    229|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 229]
  |  |  ------------------
  ------------------
  633|    229|            ctx->err = PLIST_ERR_PARSE;
  634|    229|            break;
  635|    229|        }
  636|  80.0k|        val = NULL;
  637|  80.0k|        ctx->err = node_from_openstep(ctx, &val);
  638|  80.0k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (638:13): [True: 233, False: 79.7k]
  ------------------
  639|    233|            break;
  640|    233|        }
  641|  79.7k|        if (!val) {
  ------------------
  |  Branch (641:13): [True: 4, False: 79.7k]
  ------------------
  642|      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]
  |  |  ------------------
  ------------------
  643|      4|            ctx->err = PLIST_ERR_PARSE;
  644|      4|            break;
  645|      4|        }
  646|  79.7k|        parse_skip_ws(ctx);
  647|  79.7k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (647:13): [True: 9, False: 79.7k]
  ------------------
  648|      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]
  |  |  ------------------
  ------------------
  649|      9|            ctx->err = PLIST_ERR_PARSE;
  650|      9|            break;
  651|      9|        }
  652|  79.7k|        if (*ctx->pos != ';') {
  ------------------
  |  Branch (652:13): [True: 2, False: 79.7k]
  ------------------
  653|      2|            PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      2|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 2]
  |  |  ------------------
  ------------------
  654|      2|            ctx->err = PLIST_ERR_PARSE;
  655|      2|            break;
  656|      2|        }
  657|       |
  658|  79.7k|        plist_dict_set_item(dict, plist_get_string_ptr(key, NULL), val);
  659|  79.7k|        plist_free(key);
  660|  79.7k|        key = NULL;
  661|  79.7k|        val = NULL;
  662|       |
  663|  79.7k|        ctx->pos++;
  664|  79.7k|    }
  665|  19.4k|    plist_free(key);
  666|  19.4k|    plist_free(val);
  667|  19.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|   307k|{
  349|       |    return (plist_t) node_create(NULL, data);
  350|   307k|}
plist_get_data:
  353|  29.4M|{
  354|  29.4M|    if (!node)
  ------------------
  |  Branch (354:9): [True: 0, False: 29.4M]
  ------------------
  355|      0|        return NULL;
  356|  29.4M|    return (plist_data_t)((node_t)node)->data;
  357|  29.4M|}
plist_new_plist_data:
  360|   307k|{
  361|   307k|    return (plist_data_t) calloc(1, sizeof(struct plist_data_s));
  362|   307k|}
plist_free_data:
  421|   307k|{
  422|   307k|    if (!data) return;
  ------------------
  |  Branch (422:9): [True: 0, False: 307k]
  ------------------
  423|   307k|    _plist_free_data(data);
  424|   307k|    free(data);
  425|   307k|}
plist_new_dict:
  528|    887|{
  529|    887|    plist_data_t data = plist_new_plist_data();
  530|    887|    if (!data) {
  ------------------
  |  Branch (530:9): [True: 0, False: 887]
  ------------------
  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|    887|    data->type = PLIST_DICT;
  535|    887|    return plist_new_node(data);
  536|    887|}
plist_free:
  713|   169k|{
  714|   169k|    if (plist)
  ------------------
  |  Branch (714:9): [True: 97.4k, False: 71.6k]
  ------------------
  715|  97.4k|    {
  716|  97.4k|        plist_free_node((node_t)plist);
  717|  97.4k|    }
  718|   169k|}
plist_array_append_item:
 1090|  51.7k|{
 1091|  51.7k|    if (!PLIST_IS_ARRAY(node) || !item) {
  ------------------
  |  | 1252|  51.7k|    #define PLIST_IS_ARRAY(__plist)   _PLIST_IS_TYPE(__plist, ARRAY)
  |  |  ------------------
  |  |  |  | 1240|   103k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 51.7k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 51.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1091:34): [True: 0, False: 51.7k]
  ------------------
 1092|      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]
  |  |  ------------------
  ------------------
 1093|      0|        return PLIST_ERR_INVALID_ARG;
 1094|      0|    }
 1095|  51.7k|    node_t it = (node_t)item;
 1096|  51.7k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1096:9): [True: 0, False: 51.7k]
  ------------------
 1097|      0|        assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first");
  ------------------
  |  Branch (1097:9): [True: 0, False: 0]
  |  Branch (1097:9): [True: 0, False: 0]
  |  Branch (1097:9): [True: 0, False: 0]
  |  Branch (1097:9): [True: 0, False: 0]
  ------------------
 1098|      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]
  |  |  ------------------
  ------------------
 1099|      0|        return PLIST_ERR_INVALID_ARG;
 1100|      0|    }
 1101|       |
 1102|  51.7k|    int r = node_attach((node_t)node, (node_t)item);
 1103|  51.7k|    if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  51.7k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1103:9): [True: 0, False: 51.7k]
  ------------------
 1104|      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]
  |  |  ------------------
  ------------------
 1105|      0|        return PLIST_ERR_UNKNOWN;
 1106|      0|    }
 1107|  51.7k|    _plist_array_post_insert(node, item, -1);
 1108|       |
 1109|  51.7k|    return PLIST_ERR_SUCCESS;
 1110|  51.7k|}
plist_dict_get_item:
 1291|  79.7k|{
 1292|  79.7k|    plist_t ret = NULL;
 1293|  79.7k|    if (!PLIST_IS_DICT(node) || !key) {
  ------------------
  |  | 1254|  79.7k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   159k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 79.7k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 79.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1293:33): [True: 0, False: 79.7k]
  ------------------
 1294|      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]
  |  |  ------------------
  ------------------
 1295|      0|        return NULL;
 1296|      0|    }
 1297|  79.7k|    plist_data_t data = plist_get_data(node);
 1298|  79.7k|    if (!data) {
  ------------------
  |  Branch (1298:9): [True: 0, False: 79.7k]
  ------------------
 1299|      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]
  |  |  ------------------
  ------------------
 1300|      0|        return NULL;
 1301|      0|    }
 1302|  79.7k|    size_t keylen = strlen(key);
 1303|  79.7k|    hashtable_t *ht = (hashtable_t*)data->hashtable;
 1304|  79.7k|    if (ht) {
  ------------------
  |  Branch (1304:9): [True: 1.16k, False: 78.6k]
  ------------------
 1305|  1.16k|        struct plist_data_s sdata = { 0 };
 1306|  1.16k|        sdata.strval = (char*)key;
 1307|  1.16k|        sdata.length = keylen;
 1308|  1.16k|        return (plist_t)hash_table_lookup(ht, &sdata);
 1309|  78.6k|    } else {
 1310|  78.6k|        plist_t k = NULL;
 1311|  9.60M|        for (k = (plist_t)node_first_child((node_t)node); k; ) {
  ------------------
  |  Branch (1311:59): [True: 9.53M, False: 77.9k]
  ------------------
 1312|  9.53M|            plist_t v = (plist_t)node_next_sibling(k);
 1313|  9.53M|            if (!v) break;
  ------------------
  |  Branch (1313:17): [True: 0, False: 9.53M]
  ------------------
 1314|  9.53M|            data = plist_get_data(k);
 1315|  9.53M|            assert(PLIST_IS_KEY(k));
  ------------------
  |  Branch (1315:13): [True: 0, False: 9.53M]
  |  Branch (1315:13): [True: 0, False: 0]
  |  Branch (1315:13): [True: 9.53M, False: 0]
  |  Branch (1315:13): [True: 9.53M, False: 0]
  ------------------
 1316|  9.53M|            if (!PLIST_IS_KEY(k) || !data || !data->strval) {
  ------------------
  |  | 1260|  9.53M|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  19.0M|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 9.53M, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 9.53M, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1316:37): [True: 0, False: 9.53M]
  |  Branch (1316:46): [True: 0, False: 9.53M]
  ------------------
 1317|      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]
  |  |  ------------------
  ------------------
 1318|      0|                break;
 1319|      0|            }
 1320|  9.53M|            if (data->length == keylen && !memcmp(key, data->strval, keylen+1)) {
  ------------------
  |  Branch (1320:17): [True: 4.76M, False: 4.76M]
  |  Branch (1320:43): [True: 702, False: 4.76M]
  ------------------
 1321|    702|                ret = v;
 1322|    702|                break;
 1323|    702|            }
 1324|  9.53M|            k = node_next_sibling(v);
 1325|  9.53M|        }
 1326|  78.6k|    }
 1327|  78.6k|    return ret;
 1328|  79.7k|}
plist_dict_set_item:
 1331|  79.7k|{
 1332|  79.7k|    if (!PLIST_IS_DICT(node) || !key || !item) {
  ------------------
  |  | 1254|  79.7k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1240|   159k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 79.7k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 79.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1332:33): [True: 0, False: 79.7k]
  |  Branch (1332:41): [True: 0, False: 79.7k]
  ------------------
 1333|      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]
  |  |  ------------------
  ------------------
 1334|      0|        return PLIST_ERR_INVALID_ARG;
 1335|      0|    }
 1336|  79.7k|    node_t it = (node_t)item;
 1337|  79.7k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1337:9): [True: 0, False: 79.7k]
  ------------------
 1338|      0|        assert(it->parent == NULL && "item already has a parent");
  ------------------
  |  Branch (1338:9): [True: 0, False: 0]
  |  Branch (1338:9): [True: 0, False: 0]
  |  Branch (1338:9): [True: 0, False: 0]
  |  Branch (1338:9): [True: 0, False: 0]
  ------------------
 1339|      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]
  |  |  ------------------
  ------------------
 1340|      0|        return PLIST_ERR_INVALID_ARG;
 1341|      0|    }
 1342|       |
 1343|  79.7k|    hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
 1344|       |
 1345|  79.7k|    plist_t old_item = plist_dict_get_item(node, key);
 1346|  79.7k|    plist_t key_node = NULL;
 1347|       |
 1348|  79.7k|    if (old_item) {
  ------------------
  |  Branch (1348:9): [True: 1.34k, False: 78.4k]
  ------------------
 1349|       |        // --- REPLACE EXISTING VALUE ---
 1350|  1.34k|        node_t old_val = (node_t)old_item;
 1351|  1.34k|        node_t old_key = node_prev_sibling(old_val);
 1352|  1.34k|        if (!old_key) {
  ------------------
  |  Branch (1352:13): [True: 0, False: 1.34k]
  ------------------
 1353|      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]
  |  |  ------------------
  ------------------
 1354|      0|            return PLIST_ERR_UNKNOWN;
 1355|      0|        }
 1356|  1.34k|        if (!PLIST_IS_KEY((plist_t)old_key)) {
  ------------------
  |  | 1260|  1.34k|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1240|  1.34k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 1.34k, False: 0]
  |  |  |  |  |  Branch (1240:63): [True: 1.34k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 1357|      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]
  |  |  ------------------
  ------------------
 1358|      0|            return PLIST_ERR_UNKNOWN;
 1359|      0|        }
 1360|       |
 1361|       |        // detach old value (do NOT free yet)
 1362|  1.34k|        int idx = node_detach((node_t)node, old_val);
 1363|  1.34k|        if (idx < 0) {
  ------------------
  |  Branch (1363:13): [True: 0, False: 1.34k]
  ------------------
 1364|      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]
  |  |  ------------------
  ------------------
 1365|      0|            return PLIST_ERR_UNKNOWN;
 1366|      0|        }
 1367|       |
 1368|       |        // insert new value at same position
 1369|  1.34k|        int r = node_insert((node_t)node, (unsigned)idx, (node_t)item);
 1370|  1.34k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  1.34k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1370:13): [True: 0, False: 1.34k]
  ------------------
 1371|       |            // rollback: reinsert old value
 1372|      0|            int rb = node_insert((node_t)node, (unsigned)idx, old_val);
 1373|      0|            if (rb == NODE_ERR_SUCCESS && ht) {
  ------------------
  |  |   36|      0|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1373:17): [True: 0, False: 0]
  |  Branch (1373:43): [True: 0, False: 0]
  ------------------
 1374|      0|                hash_table_insert(ht, ((node_t)old_key)->data, old_item);
 1375|      0|            }
 1376|      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]
  |  |  ------------------
  ------------------
 1377|      0|            return PLIST_ERR_UNKNOWN;
 1378|      0|        }
 1379|  1.34k|        key_node = old_key;
 1380|       |
 1381|       |        // update hash table
 1382|  1.34k|        if (ht) {
  ------------------
  |  Branch (1382:13): [True: 639, False: 702]
  ------------------
 1383|    639|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1384|    639|        }
 1385|       |
 1386|       |        // now it’s safe to free old value
 1387|  1.34k|        plist_free_node(old_val);
 1388|  78.4k|    } else {
 1389|       |        // --- INSERT NEW KEY/VALUE PAIR ---
 1390|  78.4k|        key_node = plist_new_key(key);
 1391|  78.4k|        if (!key_node) return PLIST_ERR_NO_MEM;
  ------------------
  |  Branch (1391:13): [True: 0, False: 78.4k]
  ------------------
 1392|       |
 1393|  78.4k|        int r = node_attach((node_t)node, (node_t)key_node);
 1394|  78.4k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  78.4k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1394:13): [True: 0, False: 78.4k]
  ------------------
 1395|      0|            plist_free_node((node_t)key_node);
 1396|      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]
  |  |  ------------------
  ------------------
 1397|      0|            return PLIST_ERR_UNKNOWN;
 1398|      0|        }
 1399|  78.4k|        r = node_attach((node_t)node, (node_t)item);
 1400|  78.4k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  78.4k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1400:13): [True: 0, False: 78.4k]
  ------------------
 1401|       |            // rollback key insertion
 1402|      0|            node_detach((node_t)node, (node_t)key_node);
 1403|      0|            plist_free_node((node_t)key_node);
 1404|      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]
  |  |  ------------------
  ------------------
 1405|      0|            return PLIST_ERR_UNKNOWN;
 1406|      0|        }
 1407|       |
 1408|  78.4k|        if (ht) {
  ------------------
  |  Branch (1408:13): [True: 525, False: 77.9k]
  ------------------
 1409|       |            // store pointer to item in hash table
 1410|    525|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1411|  77.9k|        } else if (((node_t)node)->count > 500) {
  ------------------
  |  Branch (1411:20): [True: 296, False: 77.6k]
  ------------------
 1412|       |            // make new hash table
 1413|    296|            ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
 1414|       |            // calculate the hashes for all entries we have so far
 1415|    296|            plist_t current = NULL;
 1416|    296|            for (current = (plist_t)node_first_child((node_t)node);
 1417|  74.5k|                 ht && current;
  ------------------
  |  Branch (1417:18): [True: 74.5k, False: 0]
  |  Branch (1417:24): [True: 74.2k, False: 296]
  ------------------
 1418|  74.2k|                 current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
 1419|  74.2k|            {
 1420|  74.2k|                hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
 1421|  74.2k|            }
 1422|    296|            ((plist_data_t)((node_t)node)->data)->hashtable = ht;
 1423|    296|        }
 1424|  78.4k|    }
 1425|  79.7k|    return PLIST_ERR_SUCCESS;
 1426|  79.7k|}
plist_get_node_type:
 1756|  19.4M|{
 1757|  19.4M|    if (node)
  ------------------
  |  Branch (1757:9): [True: 19.4M, False: 0]
  ------------------
 1758|  19.4M|    {
 1759|  19.4M|        plist_data_t data = plist_get_data(node);
 1760|  19.4M|        if (data)
  ------------------
  |  Branch (1760:13): [True: 19.4M, False: 0]
  ------------------
 1761|  19.4M|            return data->type;
 1762|  19.4M|    }
 1763|      0|    return PLIST_NONE;
 1764|  19.4M|}
plist_get_string_ptr:
 1795|  79.7k|{
 1796|  79.7k|    if (!node)
  ------------------
  |  Branch (1796:9): [True: 0, False: 79.7k]
  ------------------
 1797|      0|        return NULL;
 1798|  79.7k|    plist_type type = plist_get_node_type(node);
 1799|  79.7k|    if (PLIST_STRING != type)
  ------------------
  |  Branch (1799:9): [True: 0, False: 79.7k]
  ------------------
 1800|      0|        return NULL;
 1801|  79.7k|    plist_data_t data = plist_get_data(node);
 1802|  79.7k|    if (length)
  ------------------
  |  Branch (1802:9): [True: 0, False: 79.7k]
  ------------------
 1803|      0|        *length = data->length;
 1804|  79.7k|    return (const char*)data->strval;
 1805|  79.7k|}
plist.c:_plist_free_data:
  390|   307k|{
  391|   307k|    if (!data) return;
  ------------------
  |  Branch (391:9): [True: 0, False: 307k]
  ------------------
  392|   307k|    switch (data->type) {
  393|  78.4k|        case PLIST_KEY:
  ------------------
  |  Branch (393:9): [True: 78.4k, False: 229k]
  ------------------
  394|   269k|        case PLIST_STRING:
  ------------------
  |  Branch (394:9): [True: 191k, False: 116k]
  ------------------
  395|   269k|            free(data->strval);
  396|   269k|            data->strval = NULL;
  397|   269k|            break;
  398|    295|        case PLIST_DATA:
  ------------------
  |  Branch (398:9): [True: 295, False: 307k]
  ------------------
  399|    295|            free(data->buff);
  400|    295|            data->buff = NULL;
  401|    295|            break;
  402|  17.7k|        case PLIST_ARRAY:
  ------------------
  |  Branch (402:9): [True: 17.7k, False: 289k]
  ------------------
  403|  17.7k|            ptr_array_free((ptrarray_t*)data->hashtable);
  404|  17.7k|            data->hashtable = NULL;
  405|  17.7k|            break;
  406|  19.4k|        case PLIST_DICT: {
  ------------------
  |  Branch (406:9): [True: 19.4k, False: 288k]
  ------------------
  407|  19.4k|            hashtable_t *ht = (hashtable_t*)data->hashtable;
  408|       |            // PLIST_DICT hashtables must not own/free values; values are freed via node tree.
  409|  19.4k|            assert(!ht || ht->free_func == NULL);
  ------------------
  |  Branch (409:13): [True: 19.4k, False: 0]
  |  Branch (409:13): [True: 0, False: 0]
  |  Branch (409:13): [True: 19.1k, False: 296]
  |  Branch (409:13): [True: 296, False: 0]
  ------------------
  410|  19.4k|            if (ht) ht->free_func = NULL;
  ------------------
  |  Branch (410:17): [True: 296, False: 19.1k]
  ------------------
  411|  19.4k|            hash_table_destroy(ht);
  412|  19.4k|            data->hashtable = NULL;
  413|  19.4k|            break;
  414|  19.4k|        }
  415|    173|        default:
  ------------------
  |  Branch (415:9): [True: 173, False: 307k]
  ------------------
  416|    173|            break;
  417|   307k|    }
  418|   307k|}
plist.c:plist_free_node:
  500|  98.7k|{
  501|  98.7k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (501:9): [True: 0, False: 98.7k]
  ------------------
  502|       |
  503|  98.7k|    int root_index = -1;
  504|       |
  505|  98.7k|    if (root->parent) {
  ------------------
  |  Branch (505:9): [True: 0, False: 98.7k]
  ------------------
  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|  98.7k|    int r = plist_free_children(root);
  513|  98.7k|    if (r < 0) {
  ------------------
  |  Branch (513:9): [True: 0, False: 98.7k]
  ------------------
  514|       |        // root is already detached; caller should treat as error.
  515|      0|        return r;
  516|      0|    }
  517|       |
  518|  98.7k|    plist_data_t data = plist_get_data(root);
  519|  98.7k|    plist_free_data(data);
  520|  98.7k|    root->data = NULL;
  521|       |
  522|  98.7k|    node_destroy(root);
  523|       |
  524|  98.7k|    return root_index;
  525|  98.7k|}
plist.c:plist_free_children:
  428|  98.7k|{
  429|  98.7k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (429:9): [True: 0, False: 98.7k]
  ------------------
  430|       |
  431|  98.7k|    if (!node_first_child(root)) {
  ------------------
  |  Branch (431:9): [True: 97.6k, False: 1.14k]
  ------------------
  432|  97.6k|        return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  97.6k|#define NODE_ERR_SUCCESS       0
  ------------------
  433|  97.6k|    }
  434|       |
  435|  1.14k|    size_t cap = 64, sp = 0;
  436|  1.14k|    node_t *stack = (node_t*)malloc(cap * sizeof(*stack));
  437|  1.14k|    if (!stack) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (437:9): [True: 0, False: 1.14k]
  ------------------
  438|       |
  439|       |    // Push *direct* children onto the stack, detached from root.
  440|   180k|    for (;;) {
  441|   180k|        node_t ch = node_first_child(root);
  442|   180k|        if (!ch) break;
  ------------------
  |  Branch (442:13): [True: 1.14k, False: 179k]
  ------------------
  443|       |
  444|   179k|        int di = node_detach(root, ch);
  445|   179k|        if (di < 0) {
  ------------------
  |  Branch (445:13): [True: 0, False: 179k]
  ------------------
  446|      0|            free(stack);
  447|      0|            return di;
  448|      0|        }
  449|       |
  450|   179k|        if (sp == cap) {
  ------------------
  |  Branch (450:13): [True: 2.45k, False: 177k]
  ------------------
  451|  2.45k|            cap += 64;
  452|  2.45k|            node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  453|  2.45k|            if (!tmp) {
  ------------------
  |  Branch (453:17): [True: 0, False: 2.45k]
  ------------------
  454|      0|                free(stack);
  455|      0|                return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  456|      0|            }
  457|  2.45k|            stack = tmp;
  458|  2.45k|        }
  459|   179k|        stack[sp++] = ch;
  460|   179k|    }
  461|       |
  462|       |    // Now free the detached subtree nodes (and their descendants).
  463|   238k|    while (sp) {
  ------------------
  |  Branch (463:12): [True: 237k, False: 1.14k]
  ------------------
  464|   237k|        node_t node = stack[sp - 1];
  465|   237k|        node_t ch = node_first_child(node);
  466|   237k|        if (ch) {
  ------------------
  |  Branch (466:13): [True: 28.9k, False: 208k]
  ------------------
  467|  28.9k|            int di = node_detach(node, ch);
  468|  28.9k|            if (di < 0) {
  ------------------
  |  Branch (468:17): [True: 0, False: 28.9k]
  ------------------
  469|      0|                free(stack);
  470|      0|                return di;
  471|      0|            }
  472|       |
  473|  28.9k|            if (sp == cap) {
  ------------------
  |  Branch (473:17): [True: 211, False: 28.7k]
  ------------------
  474|    211|                cap += 64;
  475|    211|                node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  476|    211|                if (!tmp) {
  ------------------
  |  Branch (476:21): [True: 0, False: 211]
  ------------------
  477|      0|                    free(stack);
  478|      0|                    return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  479|      0|                }
  480|    211|                stack = tmp;
  481|    211|            }
  482|  28.9k|            stack[sp++] = ch;
  483|  28.9k|            continue;
  484|  28.9k|        }
  485|       |
  486|   208k|        plist_data_t data = plist_get_data(node);
  487|   208k|        plist_free_data(data);
  488|   208k|        node->data = NULL;
  489|       |
  490|   208k|        node_destroy(node);
  491|       |
  492|   208k|        sp--;
  493|   208k|    }
  494|       |
  495|  1.14k|    free(stack);
  496|  1.14k|    return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.14k|#define NODE_ERR_SUCCESS       0
  ------------------
  497|  1.14k|}
plist.c:_plist_array_post_insert:
  989|  51.7k|{
  990|  51.7k|    ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
  991|  51.7k|    if (pa) {
  ------------------
  |  Branch (991:9): [True: 15.8k, False: 35.9k]
  ------------------
  992|       |        /* store pointer to item in array */
  993|  15.8k|        if (ptr_array_insert(pa, item, n) < 0) {
  ------------------
  |  Branch (993:13): [True: 0, False: 15.8k]
  ------------------
  994|       |            /* lookup array would be out of sync, drop it */
  995|      0|            ptr_array_free(pa);
  996|      0|            ((plist_data_t)((node_t)node)->data)->hashtable = NULL;
  997|      0|        }
  998|  15.8k|        return;
  999|  15.8k|    }
 1000|       |
 1001|  35.9k|    if (((node_t)node)->count > 100) {
  ------------------
  |  Branch (1001:9): [True: 162, False: 35.7k]
  ------------------
 1002|       |       /* make new lookup array */
 1003|    162|       pa = ptr_array_new(128);
 1004|    162|       plist_t current = NULL;
 1005|    162|       for (current = (plist_t)node_first_child((node_t)node);
 1006|  16.5k|            pa && current;
  ------------------
  |  Branch (1006:13): [True: 16.5k, False: 0]
  |  Branch (1006:19): [True: 16.3k, False: 162]
  ------------------
 1007|  16.3k|            current = (plist_t)node_next_sibling((node_t)current))
 1008|  16.3k|       {
 1009|  16.3k|           if (ptr_array_add(pa, current) < 0) {
  ------------------
  |  Branch (1009:16): [True: 0, False: 16.3k]
  ------------------
 1010|      0|               ptr_array_free(pa);
 1011|       |               pa = NULL;
 1012|      0|           }
 1013|  16.3k|       }
 1014|    162|       ((plist_data_t)((node_t)node)->data)->hashtable = pa;
 1015|    162|    }
 1016|  35.9k|}
plist.c:plist_new_key:
  551|  78.4k|{
  552|  78.4k|    plist_data_t data = plist_new_plist_data();
  553|  78.4k|    if (!data) {
  ------------------
  |  Branch (553:9): [True: 0, False: 78.4k]
  ------------------
  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|  78.4k|    data->type = PLIST_KEY;
  558|  78.4k|    data->strval = strdup(val);
  559|  78.4k|    if (!data->strval) {
  ------------------
  |  Branch (559:9): [True: 0, False: 78.4k]
  ------------------
  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|  78.4k|    } else {
  564|  78.4k|        data->length = strlen(val);
  565|  78.4k|    }
  566|  78.4k|    return plist_new_node(data);
  567|  78.4k|}
plist.c:dict_key_hash:
  365|  76.6k|{
  366|  76.6k|    plist_data_t keydata = (plist_data_t)data;
  367|  76.6k|    unsigned int hash = 5381;
  368|  76.6k|    size_t i;
  369|  76.6k|    char *str = keydata->strval;
  370|   221k|    for (i = 0; i < keydata->length; str++, i++) {
  ------------------
  |  Branch (370:17): [True: 144k, False: 76.6k]
  ------------------
  371|   144k|        hash = ((hash << 5) + hash) + *str;
  372|   144k|    }
  373|  76.6k|    return hash;
  374|  76.6k|}
plist.c:dict_key_compare:
  377|  4.12k|{
  378|  4.12k|    plist_data_t data_a = (plist_data_t)a;
  379|  4.12k|    plist_data_t data_b = (plist_data_t)b;
  380|  4.12k|    if (data_a->strval == NULL || data_b->strval == NULL) {
  ------------------
  |  Branch (380:9): [True: 0, False: 4.12k]
  |  Branch (380:35): [True: 0, False: 4.12k]
  ------------------
  381|      0|        return FALSE;
  ------------------
  |  |   32|      0|#define FALSE 0
  ------------------
  382|      0|    }
  383|  4.12k|    if (data_a->length != data_b->length) {
  ------------------
  |  Branch (383:9): [True: 1.35k, False: 2.76k]
  ------------------
  384|  1.35k|        return FALSE;
  ------------------
  |  |   32|  1.35k|#define FALSE 0
  ------------------
  385|  1.35k|    }
  386|  2.76k|    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.48k|#define FALSE 0
  ------------------
  |  Branch (386:12): [True: 1.27k, False: 1.48k]
  ------------------
  387|  4.12k|}

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|  17.7k|{
   36|  17.7k|	if (!pa) return;
  ------------------
  |  Branch (36:6): [True: 17.5k, 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|  32.1k|{
   45|  32.1k|	if (!pa || !pa->pdata) return -1;
  ------------------
  |  Branch (45:6): [True: 0, False: 32.1k]
  |  Branch (45:13): [True: 0, False: 32.1k]
  ------------------
   46|  32.1k|	long remaining = pa->capacity-pa->len;
   47|  32.1k|	if (remaining == 0) {
  ------------------
  |  Branch (47:6): [True: 131, False: 32.0k]
  ------------------
   48|    131|		void **newdata = (void**)realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step));
   49|    131|		if (!newdata) {
  ------------------
  |  Branch (49:7): [True: 0, False: 131]
  ------------------
   50|      0|			return -1;
   51|      0|		}
   52|    131|		pa->pdata = newdata;
   53|    131|		pa->capacity += pa->capacity_step;
   54|    131|	}
   55|  32.1k|	if (array_index < 0 || array_index >= pa->len) {
  ------------------
  |  Branch (55:6): [True: 32.1k, False: 0]
  |  Branch (55:25): [True: 0, False: 0]
  ------------------
   56|  32.1k|		pa->pdata[pa->len] = data;
   57|  32.1k|	} else {
   58|      0|		memmove(&pa->pdata[array_index+1], &pa->pdata[array_index], (pa->len-array_index) * sizeof(void*));
   59|      0|		pa->pdata[array_index] = data;
   60|      0|	}
   61|  32.1k|	pa->len++;
   62|  32.1k|	return 0;
   63|  32.1k|}
ptr_array_add:
   66|  16.3k|{
   67|  16.3k|	return ptr_array_insert(pa, data, -1);
   68|  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|}

