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

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

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

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

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

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

plist_ostep_init:
   54|      2|{
   55|       |    /* init OpenStep stuff */
   56|      2|#ifdef DEBUG
   57|      2|    char *env_debug = getenv("PLIST_OSTEP_DEBUG");
   58|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (58:9): [True: 0, False: 2]
  |  Branch (58:22): [True: 0, False: 0]
  ------------------
   59|      0|        plist_ostep_debug = 1;
   60|      0|    }
   61|      2|#endif
   62|      2|}
plist_from_openstep:
  955|  1.58k|{
  956|  1.58k|    if (!plist) {
  ------------------
  |  Branch (956:9): [True: 0, False: 1.58k]
  ------------------
  957|      0|        return PLIST_ERR_INVALID_ARG;
  958|      0|    }
  959|  1.58k|    *plist = NULL;
  960|  1.58k|    if (!plist_ostep || (length == 0)) {
  ------------------
  |  Branch (960:9): [True: 0, False: 1.58k]
  |  Branch (960:25): [True: 0, False: 1.58k]
  ------------------
  961|      0|        return PLIST_ERR_INVALID_ARG;
  962|      0|    }
  963|       |
  964|  1.58k|    struct _parse_ctx ctx = { plist_ostep, plist_ostep, plist_ostep + length, 0 , 0 };
  965|       |
  966|  1.58k|    plist_err_t err = node_from_openstep(&ctx, plist);
  967|  1.58k|    if (err == 0) {
  ------------------
  |  Branch (967:9): [True: 1.06k, False: 515]
  ------------------
  968|  1.06k|        if (!*plist) {
  ------------------
  |  Branch (968:13): [True: 59, False: 1.00k]
  ------------------
  969|       |            /* whitespace only file is considered an empty dictionary */
  970|     59|            *plist = plist_new_dict();
  971|  1.00k|        } else if (ctx.pos < ctx.end && *ctx.pos == '=') {
  ------------------
  |  Branch (971:20): [True: 842, False: 166]
  |  Branch (971:41): [True: 826, False: 16]
  ------------------
  972|       |            /* attempt to parse this as 'strings' data */
  973|    826|            plist_free(*plist);
  974|    826|            *plist = NULL;
  975|    826|            plist_t pl = plist_new_dict();
  976|    826|            ctx.pos = plist_ostep;
  977|    826|            parse_dict_data(&ctx, pl);
  978|    826|            if (ctx.err > 0) {
  ------------------
  |  Branch (978:17): [True: 0, False: 826]
  ------------------
  979|      0|                plist_free(pl);
  980|      0|                PLIST_OSTEP_ERR("Failed to parse strings data\n");
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  981|      0|                err = PLIST_ERR_PARSE;
  982|    826|            } else {
  983|    826|                *plist = pl;
  984|    826|            }
  985|    826|        }
  986|  1.06k|    }
  987|       |
  988|  1.58k|    return err;
  989|  1.58k|}
oplist.c:node_from_openstep:
  663|   237k|{
  664|   237k|    plist_t subnode = NULL;
  665|   237k|    const char *p = NULL;
  666|   237k|    ctx->depth++;
  667|   237k|    if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
  ------------------
  |  |   56|   237k|#define PLIST_MAX_NESTING_DEPTH NODE_MAX_DEPTH
  |  |  ------------------
  |  |  |  |   33|   237k|#define NODE_MAX_DEPTH 512
  |  |  ------------------
  ------------------
  |  Branch (667:9): [True: 3, False: 237k]
  ------------------
  668|      3|        PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      3|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 3]
  |  |  ------------------
  ------------------
  669|      3|        ctx->err = PLIST_ERR_MAX_NESTING;
  670|      3|        return ctx->err;
  671|      3|    }
  672|   237k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (672:12): [True: 237k, False: 0]
  |  Branch (672:35): [True: 237k, False: 0]
  ------------------
  673|   237k|        parse_skip_ws(ctx);
  674|   237k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (674:13): [True: 69, False: 237k]
  ------------------
  675|     69|            break;
  676|     69|        }
  677|   237k|        plist_data_t data = plist_new_plist_data();
  678|   237k|        if (*ctx->pos == '{') {
  ------------------
  |  Branch (678:13): [True: 18.9k, False: 218k]
  ------------------
  679|  18.9k|            data->type = PLIST_DICT;
  680|  18.9k|            subnode = plist_new_node(data);
  681|  18.9k|            ctx->pos++;
  682|  18.9k|            parse_dict_data(ctx, subnode);
  683|  18.9k|            if (ctx->err) {
  ------------------
  |  Branch (683:17): [True: 11.4k, False: 7.50k]
  ------------------
  684|  11.4k|                goto err_out;
  685|  11.4k|            }
  686|  7.50k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (686:17): [True: 75, False: 7.42k]
  ------------------
  687|     75|                PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     75|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 75]
  |  |  ------------------
  ------------------
  688|     75|                ctx->err = PLIST_ERR_PARSE;
  689|     75|                break;
  690|     75|            }
  691|  7.42k|            if (*ctx->pos != '}') {
  ------------------
  |  Branch (691:17): [True: 0, False: 7.42k]
  ------------------
  692|      0|                PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  693|      0|                ctx->err = PLIST_ERR_PARSE;
  694|      0|                goto err_out;
  695|      0|            }
  696|  7.42k|            ctx->pos++;
  697|  7.42k|            *plist = subnode;
  698|  7.42k|            parse_skip_ws(ctx);
  699|  7.42k|            break;
  700|   218k|        } else if (*ctx->pos == '(') {
  ------------------
  |  Branch (700:20): [True: 18.1k, False: 200k]
  ------------------
  701|  18.1k|            data->type = PLIST_ARRAY;
  702|  18.1k|            subnode = plist_new_node(data);
  703|  18.1k|            ctx->pos++;
  704|  18.1k|            plist_t tmp = NULL;
  705|  53.0k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (705:20): [True: 53.0k, False: 31]
  |  Branch (705:43): [True: 53.0k, False: 0]
  ------------------
  706|  53.0k|                parse_skip_ws(ctx);
  707|  53.0k|                if (ctx->pos >= ctx->end || *ctx->pos == ')') {
  ------------------
  |  Branch (707:21): [True: 1, False: 53.0k]
  |  Branch (707:45): [True: 353, False: 52.6k]
  ------------------
  708|    354|                    break;
  709|    354|                }
  710|  52.6k|                ctx->err = node_from_openstep(ctx, &tmp);
  711|  52.6k|                if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (711:21): [True: 1.83k, False: 50.8k]
  ------------------
  712|  1.83k|                    break;
  713|  1.83k|                }
  714|  50.8k|                if (!tmp) {
  ------------------
  |  Branch (714:21): [True: 2, False: 50.8k]
  ------------------
  715|      2|                    ctx->err = PLIST_ERR_PARSE;
  716|      2|                    break;
  717|      2|                }
  718|  50.8k|                plist_array_append_item(subnode, tmp);
  719|  50.8k|                tmp = NULL;
  720|  50.8k|                parse_skip_ws(ctx);
  721|  50.8k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (721:21): [True: 103, False: 50.7k]
  ------------------
  722|    103|                    PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    103|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 103]
  |  |  ------------------
  ------------------
  723|    103|                    ctx->err = PLIST_ERR_PARSE;
  724|    103|                    break;
  725|    103|                }
  726|  50.7k|                if (*ctx->pos != ',') {
  ------------------
  |  Branch (726:21): [True: 15.8k, False: 34.8k]
  ------------------
  727|  15.8k|                    break;
  728|  15.8k|                }
  729|  34.8k|                ctx->pos++;
  730|  34.8k|            }
  731|  18.1k|	    plist_free(tmp);
  732|  18.1k|	    tmp = NULL;
  733|  18.1k|            if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (733:17): [True: 1.94k, False: 16.2k]
  ------------------
  734|  1.94k|                goto err_out;
  735|  1.94k|            }
  736|  16.2k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (736:17): [True: 32, False: 16.2k]
  ------------------
  737|     32|                PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     32|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 32]
  |  |  ------------------
  ------------------
  738|     32|                ctx->err = PLIST_ERR_PARSE;
  739|     32|                break;
  740|     32|            }
  741|  16.2k|            if (*ctx->pos != ')') {
  ------------------
  |  Branch (741:17): [True: 18, False: 16.2k]
  ------------------
  742|     18|                PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     18|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 18]
  |  |  ------------------
  ------------------
  743|     18|                ctx->err = PLIST_ERR_PARSE;
  744|     18|                goto err_out;
  745|     18|            }
  746|  16.2k|            ctx->pos++;
  747|  16.2k|            *plist = subnode;
  748|  16.2k|            parse_skip_ws(ctx);
  749|  16.2k|            break;
  750|   200k|        } else if (*ctx->pos == '<') {
  ------------------
  |  Branch (750:20): [True: 294, False: 199k]
  ------------------
  751|    294|            data->type = PLIST_DATA;
  752|    294|            ctx->pos++;
  753|    294|            bytearray_t *bytes = byte_array_new(256);
  754|  2.11k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (754:20): [True: 2.08k, False: 26]
  |  Branch (754:43): [True: 2.08k, False: 0]
  ------------------
  755|  2.08k|                parse_skip_ws(ctx);
  756|  2.08k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (756:21): [True: 1, False: 2.08k]
  ------------------
  757|      1|                    PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  758|      1|                    ctx->err = PLIST_ERR_PARSE;
  759|      1|                    break;
  760|      1|                }
  761|  2.08k|                if (*ctx->pos == '>') {
  ------------------
  |  Branch (761:21): [True: 240, False: 1.84k]
  ------------------
  762|    240|                    break;
  763|    240|                }
  764|  1.84k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (764:21): [True: 7, False: 1.84k]
  ------------------
  765|      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]
  |  |  ------------------
  ------------------
  766|      7|                    ctx->err = PLIST_ERR_PARSE;
  767|      7|                    break;
  768|      7|                }
  769|  1.84k|                uint8_t b = HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.84k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 535, False: 1.30k]
  |  |  |  Branch (589:49): [True: 380, False: 926]
  |  |  ------------------
  ------------------
  770|  1.84k|                ctx->pos++;
  771|  1.84k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (771:21): [True: 19, False: 1.82k]
  ------------------
  772|     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]
  |  |  ------------------
  ------------------
  773|     19|                    ctx->err = PLIST_ERR_PARSE;
  774|     19|                    break;
  775|     19|                }
  776|  1.82k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (776:21): [True: 1, False: 1.82k]
  ------------------
  777|      1|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  778|      1|                    ctx->err = PLIST_ERR_PARSE;
  779|      1|                    break;
  780|      1|                }
  781|  1.82k|                b = (b << 4) + HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  589|  1.82k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (589:23): [True: 526, False: 1.29k]
  |  |  |  Branch (589:49): [True: 375, False: 920]
  |  |  ------------------
  ------------------
  782|  1.82k|                byte_array_append(bytes, &b, 1);
  783|  1.82k|                ctx->pos++;
  784|  1.82k|            }
  785|    294|            if (ctx->err) {
  ------------------
  |  Branch (785:17): [True: 28, False: 266]
  ------------------
  786|     28|                byte_array_free(bytes);
  787|     28|                plist_free_data(data);
  788|     28|                goto err_out;
  789|     28|            }
  790|    266|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (790:17): [True: 26, False: 240]
  ------------------
  791|     26|                byte_array_free(bytes);
  792|     26|                plist_free_data(data);
  793|     26|                PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     26|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 26]
  |  |  ------------------
  ------------------
  794|     26|                ctx->err = PLIST_ERR_PARSE;
  795|     26|                goto err_out;
  796|     26|            }
  797|    240|            if (*ctx->pos != '>') {
  ------------------
  |  Branch (797:17): [True: 0, False: 240]
  ------------------
  798|      0|                byte_array_free(bytes);
  799|      0|                plist_free_data(data);
  800|      0|                PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  801|      0|                ctx->err = PLIST_ERR_PARSE;
  802|      0|                goto err_out;
  803|      0|            }
  804|    240|            ctx->pos++;
  805|    240|            data->buff = (uint8_t*)bytes->data;
  806|    240|            data->length = bytes->len;
  807|    240|            bytes->data = NULL;
  808|    240|            byte_array_free(bytes);
  809|    240|            *plist = plist_new_node(data);
  810|    240|            parse_skip_ws(ctx);
  811|    240|            break;
  812|   199k|        } else if (*ctx->pos == '"' || *ctx->pos == '\'') {
  ------------------
  |  Branch (812:20): [True: 30.1k, False: 169k]
  |  Branch (812:40): [True: 6.41k, False: 163k]
  ------------------
  813|  36.5k|            char c = *ctx->pos;
  814|  36.5k|            ctx->pos++;
  815|  36.5k|            p = ctx->pos;
  816|  36.5k|            size_t num_escapes = 0;
  817|   126k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (817:20): [True: 126k, False: 63]
  ------------------
  818|   126k|                if (*ctx->pos == '\\') {
  ------------------
  |  Branch (818:21): [True: 16.7k, False: 110k]
  ------------------
  819|  16.7k|                    num_escapes++;
  820|  16.7k|                }
  821|   126k|                if ((*ctx->pos == c) && (*(ctx->pos-1) != '\\')) {
  ------------------
  |  Branch (821:21): [True: 37.2k, False: 89.6k]
  |  Branch (821:41): [True: 36.5k, False: 744]
  ------------------
  822|  36.5k|                    break;
  823|  36.5k|                }
  824|  90.3k|                ctx->pos++;
  825|  90.3k|            }
  826|  36.5k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (826:17): [True: 63, False: 36.5k]
  ------------------
  827|     63|                plist_free_data(data);
  828|     63|                PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     63|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 63]
  |  |  ------------------
  ------------------
  829|     63|                ctx->err = PLIST_ERR_PARSE;
  830|     63|                goto err_out;
  831|     63|            }
  832|  36.5k|            if (*ctx->pos != c) {
  ------------------
  |  Branch (832:17): [True: 0, False: 36.5k]
  ------------------
  833|      0|                plist_free_data(data);
  834|      0|                PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  835|      0|                ctx->err = PLIST_ERR_PARSE;
  836|      0|                goto err_out;
  837|      0|            }
  838|  36.5k|            size_t slen = ctx->pos - p;
  839|  36.5k|            ctx->pos++; // skip the closing quote
  840|  36.5k|            char* strbuf = (char*)malloc(slen+1);
  841|  36.5k|            if (num_escapes > 0) {
  ------------------
  |  Branch (841:17): [True: 1.17k, False: 35.3k]
  ------------------
  842|  1.17k|                size_t i = 0;
  843|  1.17k|                size_t o = 0;
  844|  36.0k|                while (i < slen) {
  ------------------
  |  Branch (844:24): [True: 34.8k, False: 1.17k]
  ------------------
  845|  34.8k|                    if (p[i] == '\\') {
  ------------------
  |  Branch (845:25): [True: 9.09k, False: 25.7k]
  ------------------
  846|       |                        /* handle escape sequence */
  847|  9.09k|                        i++;
  848|  9.09k|                        switch (p[i]) {
  849|    665|                            case '0':
  ------------------
  |  Branch (849:29): [True: 665, False: 8.43k]
  ------------------
  850|  1.44k|                            case '1':
  ------------------
  |  Branch (850:29): [True: 775, False: 8.32k]
  ------------------
  851|  1.87k|                            case '2':
  ------------------
  |  Branch (851:29): [True: 433, False: 8.66k]
  ------------------
  852|  2.17k|                            case '3':
  ------------------
  |  Branch (852:29): [True: 298, False: 8.79k]
  ------------------
  853|  2.54k|                            case '4':
  ------------------
  |  Branch (853:29): [True: 374, False: 8.72k]
  ------------------
  854|  2.97k|                            case '5':
  ------------------
  |  Branch (854:29): [True: 430, False: 8.66k]
  ------------------
  855|  3.32k|                            case '6':
  ------------------
  |  Branch (855:29): [True: 349, False: 8.74k]
  ------------------
  856|  3.71k|                            case '7': {
  ------------------
  |  Branch (856:29): [True: 394, False: 8.70k]
  ------------------
  857|       |                                // max 3 digits octal
  858|  3.71k|                                unsigned char chr = 0;
  859|  3.71k|                                int maxd = 3;
  860|  7.99k|                                while ((i < slen) && (p[i] >= '0' && p[i] <= '7') && --maxd) {
  ------------------
  |  Branch (860:40): [True: 7.59k, False: 407]
  |  Branch (860:55): [True: 7.09k, False: 498]
  |  Branch (860:70): [True: 4.51k, False: 2.58k]
  |  Branch (860:86): [True: 4.28k, False: 233]
  ------------------
  861|  4.28k|                                    chr = (chr << 3) + p[i] - '0';
  862|  4.28k|                                    i++;
  863|  4.28k|                                }
  864|  3.71k|                                strbuf[o++] = (char)chr;
  865|  3.71k|                            }   break;
  866|  1.64k|                            case 'U': {
  ------------------
  |  Branch (866:29): [True: 1.64k, False: 7.44k]
  ------------------
  867|  1.64k|                                i++;
  868|       |                                // max 4 digits hex
  869|  1.64k|                                uint16_t wchr = 0;
  870|  1.64k|                                int maxd = 4;
  871|  4.35k|                                while ((i < slen) && isxdigit(p[i]) && maxd--) {
  ------------------
  |  Branch (871:40): [True: 3.92k, False: 432]
  |  Branch (871:54): [True: 2.73k, False: 1.18k]
  |  Branch (871:72): [True: 2.70k, False: 31]
  ------------------
  872|  2.70k|                                    wchr = (wchr << 4) + ((p[i] <= '9') ? (p[i] - '0') : ((p[i] <= 'F') ? (p[i] - 'A' + 10) : (p[i] - 'a' + 10)));
  ------------------
  |  Branch (872:59): [True: 1.33k, False: 1.37k]
  |  Branch (872:91): [True: 998, False: 378]
  ------------------
  873|  2.70k|                                    i++;
  874|  2.70k|                                }
  875|  1.64k|                                if (wchr >= 0x800) {
  ------------------
  |  Branch (875:37): [True: 374, False: 1.27k]
  ------------------
  876|    374|                                    strbuf[o++] = (char)(0xE0 + ((wchr >> 12) & 0xF));
  877|    374|                                    strbuf[o++] = (char)(0x80 + ((wchr >> 6) & 0x3F));
  878|    374|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  879|  1.27k|                                } else if (wchr >= 0x80) {
  ------------------
  |  Branch (879:44): [True: 524, False: 750]
  ------------------
  880|    524|                                    strbuf[o++] = (char)(0xC0 + ((wchr >> 6) & 0x1F));
  881|    524|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  882|    750|                                } else {
  883|    750|                                    strbuf[o++] = (char)(wchr & 0x7F);
  884|    750|                                }
  885|  1.64k|                            }   break;
  886|    208|                            case 'a': strbuf[o++] = '\a'; i++; break;
  ------------------
  |  Branch (886:29): [True: 208, False: 8.88k]
  ------------------
  887|    380|                            case 'b': strbuf[o++] = '\b'; i++; break;
  ------------------
  |  Branch (887:29): [True: 380, False: 8.71k]
  ------------------
  888|    211|                            case 'f': strbuf[o++] = '\f'; i++; break;
  ------------------
  |  Branch (888:29): [True: 211, False: 8.88k]
  ------------------
  889|    217|                            case 'n': strbuf[o++] = '\n'; i++; break;
  ------------------
  |  Branch (889:29): [True: 217, False: 8.87k]
  ------------------
  890|    197|                            case 'r': strbuf[o++] = '\r'; i++; break;
  ------------------
  |  Branch (890:29): [True: 197, False: 8.89k]
  ------------------
  891|    348|                            case 't': strbuf[o++] = '\t'; i++; break;
  ------------------
  |  Branch (891:29): [True: 348, False: 8.74k]
  ------------------
  892|    346|                            case 'v': strbuf[o++] = '\v'; i++; break;
  ------------------
  |  Branch (892:29): [True: 346, False: 8.75k]
  ------------------
  893|    259|                            case '"': strbuf[o++] = '"';  i++; break;
  ------------------
  |  Branch (893:29): [True: 259, False: 8.83k]
  ------------------
  894|    534|                            case '\'': strbuf[o++] = '\''; i++; break;
  ------------------
  |  Branch (894:29): [True: 534, False: 8.56k]
  ------------------
  895|  1.03k|                            default:
  ------------------
  |  Branch (895:29): [True: 1.03k, False: 8.06k]
  ------------------
  896|  1.03k|                                break;
  897|  9.09k|                        }
  898|  25.7k|                    } else {
  899|  25.7k|                        strbuf[o++] = p[i++];
  900|  25.7k|                    }
  901|  34.8k|                }
  902|  1.17k|                strbuf[o] = '\0';
  903|  1.17k|                slen = o;
  904|  35.3k|            } else {
  905|  35.3k|                strncpy(strbuf, p, slen);
  906|  35.3k|                strbuf[slen] = '\0';
  907|  35.3k|            }
  908|  36.5k|            data->type = PLIST_STRING;
  909|  36.5k|            data->strval = strbuf;
  910|  36.5k|            data->length = slen;
  911|  36.5k|            *plist = plist_new_node(data);
  912|  36.5k|            parse_skip_ws(ctx);
  913|  36.5k|            break;
  914|   163k|        } else {
  915|       |            // unquoted string
  916|   163k|            size_t slen = 0;
  917|   163k|            parse_skip_ws(ctx);
  918|   163k|            p = ctx->pos;
  919|   397k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (919:20): [True: 397k, False: 120]
  ------------------
  920|   397k|                if (!allowed_unquoted_chars[(uint8_t)*ctx->pos]) {
  ------------------
  |  Branch (920:21): [True: 163k, False: 234k]
  ------------------
  921|   163k|                    break;
  922|   163k|                }
  923|   234k|                ctx->pos++;
  924|   234k|            }
  925|   163k|            slen = ctx->pos-p;
  926|   163k|            if (slen > 0) {
  ------------------
  |  Branch (926:17): [True: 163k, False: 152]
  ------------------
  927|   163k|                data->type = PLIST_STRING;
  928|   163k|                data->strval = strndup(p, slen);
  929|   163k|                data->length = slen;
  930|   163k|                *plist = plist_new_node(data);
  931|   163k|                parse_skip_ws(ctx);
  932|   163k|                break;
  933|   163k|            } else {
  934|    152|                plist_free_data(data);
  935|    152|                PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    152|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 152]
  |  |  ------------------
  ------------------
  936|    152|                ctx->err = PLIST_ERR_PARSE;
  937|    152|                break;
  938|    152|            }
  939|   163k|        }
  940|      0|        ctx->pos++;
  941|      0|    }
  942|   223k|    ctx->depth--;
  943|       |
  944|   237k|err_out:
  945|   237k|    if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (945:9): [True: 13.7k, False: 223k]
  ------------------
  946|  13.7k|        plist_free(subnode);
  947|  13.7k|        plist_free(*plist);
  948|  13.7k|        *plist = NULL;
  949|  13.7k|        return ctx->err;
  950|  13.7k|    }
  951|   223k|    return PLIST_ERR_SUCCESS;
  952|   237k|}
oplist.c:parse_skip_ws:
  553|  1.00M|{
  554|  1.00M|    while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (554:12): [True: 1.00M, False: 490]
  ------------------
  555|       |        // skip comments
  556|  1.00M|        if (*ctx->pos == '/' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (556:13): [True: 760, False: 1.00M]
  |  Branch (556:33): [True: 738, False: 22]
  ------------------
  557|    738|            if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (557:17): [True: 342, False: 396]
  ------------------
  558|    342|                ctx->pos++;
  559|  1.64k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (559:24): [True: 1.62k, False: 23]
  ------------------
  560|  1.62k|                    if ((*ctx->pos == '\n') || (*ctx->pos == '\r')) {
  ------------------
  |  Branch (560:25): [True: 106, False: 1.51k]
  |  Branch (560:48): [True: 213, False: 1.30k]
  ------------------
  561|    319|                        break;
  562|    319|                    }
  563|  1.30k|                    ctx->pos++;
  564|  1.30k|                }
  565|    396|            } else if (*(ctx->pos+1) == '*') {
  ------------------
  |  Branch (565:24): [True: 351, False: 45]
  ------------------
  566|    351|                ctx->pos++;
  567|  9.90k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (567:24): [True: 9.87k, False: 32]
  ------------------
  568|  9.87k|                    if (*ctx->pos == '*' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (568:25): [True: 820, False: 9.05k]
  |  Branch (568:45): [True: 816, False: 4]
  ------------------
  569|    816|                        if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (569:29): [True: 319, False: 497]
  ------------------
  570|    319|                            ctx->pos+=2;
  571|    319|                            break;
  572|    319|                        }
  573|    816|                    }
  574|  9.55k|                    ctx->pos++;
  575|  9.55k|                }
  576|    351|            }
  577|    738|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (577:17): [True: 57, False: 681]
  ------------------
  578|     57|                break;
  579|     57|            }
  580|    738|        }
  581|       |        // break on any char that's not white space
  582|  1.00M|        if (!(((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n')))) {
  ------------------
  |  Branch (582:16): [True: 327, False: 1.00M]
  |  Branch (582:40): [True: 251, False: 1.00M]
  |  Branch (582:65): [True: 404, False: 1.00M]
  |  Branch (582:90): [True: 161, False: 1.00M]
  ------------------
  583|  1.00M|            break;
  584|  1.00M|        }
  585|  1.14k|        ctx->pos++;
  586|  1.14k|    }
  587|  1.00M|}
oplist.c:parse_dict_data:
  594|  19.7k|{
  595|  19.7k|    plist_t key = NULL;
  596|  19.7k|    plist_t val = NULL;
  597|   105k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (597:12): [True: 104k, False: 322]
  |  Branch (597:35): [True: 104k, False: 0]
  ------------------
  598|   104k|        parse_skip_ws(ctx);
  599|   104k|        if (ctx->pos >= ctx->end || *ctx->pos == '}') {
  ------------------
  |  Branch (599:13): [True: 2, False: 104k]
  |  Branch (599:37): [True: 7.43k, False: 97.4k]
  ------------------
  600|  7.44k|            break;
  601|  7.44k|        }
  602|  97.4k|        key = NULL;
  603|  97.4k|        ctx->err = node_from_openstep(ctx, &key);
  604|  97.4k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (604:13): [True: 11.1k, False: 86.2k]
  ------------------
  605|  11.1k|            break;
  606|  11.1k|        }
  607|  86.2k|        if (!PLIST_IS_STRING(key)) {
  ------------------
  |  | 1250|  86.2k|    #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
  |  |  ------------------
  |  |  |  | 1240|  86.2k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1240:52): [True: 86.2k, False: 3]
  |  |  |  |  |  Branch (1240:63): [True: 85.9k, False: 260]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  608|    263|            PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    263|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 263]
  |  |  ------------------
  ------------------
  609|    263|            ctx->err = PLIST_ERR_PARSE;
  610|    263|            break;
  611|    263|        }
  612|  85.9k|        parse_skip_ws(ctx);
  613|  85.9k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (613:13): [True: 42, False: 85.9k]
  ------------------
  614|     42|            PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     42|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 42]
  |  |  ------------------
  ------------------
  615|     42|            ctx->err = PLIST_ERR_PARSE;
  616|     42|            break;
  617|     42|        }
  618|  85.9k|        if (*ctx->pos != '=') {
  ------------------
  |  Branch (618:13): [True: 23, False: 85.9k]
  ------------------
  619|     23|            PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|     23|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 23]
  |  |  ------------------
  ------------------
  620|     23|            ctx->err = PLIST_ERR_PARSE;
  621|     23|            break;
  622|     23|        }
  623|  85.9k|        ctx->pos++;
  624|  85.9k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (624:13): [True: 235, False: 85.6k]
  ------------------
  625|    235|            PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|    235|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 235]
  |  |  ------------------
  ------------------
  626|    235|            ctx->err = PLIST_ERR_PARSE;
  627|    235|            break;
  628|    235|        }
  629|  85.6k|        val = NULL;
  630|  85.6k|        ctx->err = node_from_openstep(ctx, &val);
  631|  85.6k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (631:13): [True: 242, False: 85.4k]
  ------------------
  632|    242|            break;
  633|    242|        }
  634|  85.4k|        if (!val) {
  ------------------
  |  Branch (634:13): [True: 5, False: 85.4k]
  ------------------
  635|      5|            PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      5|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 5]
  |  |  ------------------
  ------------------
  636|      5|            ctx->err = PLIST_ERR_PARSE;
  637|      5|            break;
  638|      5|        }
  639|  85.4k|        parse_skip_ws(ctx);
  640|  85.4k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (640:13): [True: 8, False: 85.4k]
  ------------------
  641|      8|            PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      8|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 8]
  |  |  ------------------
  ------------------
  642|      8|            ctx->err = PLIST_ERR_PARSE;
  643|      8|            break;
  644|      8|        }
  645|  85.4k|        if (*ctx->pos != ';') {
  ------------------
  |  Branch (645:13): [True: 5, False: 85.4k]
  ------------------
  646|      5|            PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   46|      5|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (46:34): [True: 0, False: 5]
  |  |  ------------------
  ------------------
  647|      5|            ctx->err = PLIST_ERR_PARSE;
  648|      5|            break;
  649|      5|        }
  650|       |
  651|  85.4k|        plist_dict_set_item(dict, plist_get_string_ptr(key, NULL), val);
  652|  85.4k|        plist_free(key);
  653|  85.4k|        key = NULL;
  654|  85.4k|        val = NULL;
  655|       |
  656|  85.4k|        ctx->pos++;
  657|  85.4k|    }
  658|  19.7k|    plist_free(key);
  659|  19.7k|    plist_free(val);
  660|  19.7k|}

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

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

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

