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

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

node_list_destroy:
   32|   322k|{
   33|   322k|	free(list);
   34|   322k|}
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|   217k|{
   52|   217k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (52:6): [True: 0, False: 217k]
  |  Branch (52:15): [True: 0, False: 217k]
  ------------------
   53|       |
   54|       |	// Find the last element in the list
   55|   217k|	node_t last = list->end;
   56|       |
   57|       |	// Setup our new node as the new last element
   58|   217k|	node->next = NULL;
   59|   217k|	node->prev = last;
   60|       |
   61|       |	// Set the next element of our old "last" element
   62|   217k|	if (last) {
  ------------------
  |  Branch (62:6): [True: 200k, False: 17.1k]
  ------------------
   63|       |		// but only if the node list is not empty
   64|   200k|		last->next = node;
   65|   200k|	} 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|   217k|	list->end = node;
   72|       |
   73|       |	// Increment our node count for this list
   74|   217k|	list->count++;
   75|   217k|	return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|   217k|#define NODE_ERR_SUCCESS       0
  ------------------
   76|   217k|}
node_list_insert:
   79|  1.63k|{
   80|  1.63k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (80:6): [True: 0, False: 1.63k]
  |  Branch (80:15): [True: 0, False: 1.63k]
  ------------------
   81|  1.63k|	if (node_index > list->count) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (81:6): [True: 0, False: 1.63k]
  ------------------
   82|  1.63k|	if (node_index == list->count) {
  ------------------
  |  Branch (82:6): [True: 318, False: 1.31k]
  ------------------
   83|    318|		return node_list_add(list, node);
   84|    318|	}
   85|       |
   86|       |	// Get the first element in the list
   87|  1.31k|	node_t cur = list->begin;
   88|  1.31k|	node_t prev = NULL;
   89|       |
   90|   188k|	for (unsigned int pos = 0; pos < node_index; pos++) {
  ------------------
  |  Branch (90:29): [True: 186k, False: 1.31k]
  ------------------
   91|   186k|		if (!cur) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (91:7): [True: 0, False: 186k]
  ------------------
   92|   186k|		prev = cur;
   93|   186k|		cur = cur->next;
   94|   186k|	}
   95|       |
   96|       |	// insert node before cur
   97|  1.31k|	node->prev = prev;
   98|  1.31k|	node->next = cur;
   99|       |
  100|  1.31k|	if (prev) {
  ------------------
  |  Branch (100:6): [True: 1.31k, False: 0]
  ------------------
  101|  1.31k|		prev->next = node;
  102|  1.31k|	} else {
  103|      0|		list->begin = node;
  104|      0|	}
  105|       |
  106|  1.31k|	if (cur) {
  ------------------
  |  Branch (106:6): [True: 1.31k, False: 0]
  ------------------
  107|  1.31k|		cur->prev = node;
  108|  1.31k|	} 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.31k|	list->count++;
  115|  1.31k|	return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.31k|#define NODE_ERR_SUCCESS       0
  ------------------
  116|  1.31k|}
node_list_remove:
  120|   219k|{
  121|   219k|	if (!list || !node) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (121:6): [True: 0, False: 219k]
  |  Branch (121:15): [True: 0, False: 219k]
  ------------------
  122|   219k|	if (list->count == 0) return NODE_ERR_NOT_FOUND;
  ------------------
  |  |   42|      0|#define NODE_ERR_NOT_FOUND    -6
  ------------------
  |  Branch (122:6): [True: 0, False: 219k]
  ------------------
  123|       |
  124|   219k|	int node_index = 0;
  125|   419k|	for (node_t n = list->begin; n; n = n->next, node_index++) {
  ------------------
  |  Branch (125:31): [True: 419k, False: 0]
  ------------------
  126|   419k|		if (node != n) continue;
  ------------------
  |  Branch (126:7): [True: 199k, False: 219k]
  ------------------
  127|       |
  128|   219k|		node_t newnode = node->next;
  129|   219k|		if (node->prev) {
  ------------------
  |  Branch (129:7): [True: 1.63k, False: 217k]
  ------------------
  130|  1.63k|			node->prev->next = newnode;
  131|   217k|		} else {
  132|       |			// we just removed the first element
  133|   217k|			list->begin = newnode;
  134|   217k|		}
  135|       |
  136|   219k|		if (newnode) {
  ------------------
  |  Branch (136:7): [True: 201k, False: 17.4k]
  ------------------
  137|   201k|			newnode->prev = node->prev;
  138|   201k|		} else {
  139|       |			// we removed the last element, set new end
  140|  17.4k|			list->end = node->prev;
  141|  17.4k|		}
  142|       |
  143|       |		// fully detach node from list
  144|   219k|		node->prev = NULL;
  145|   219k|		node->next = NULL;
  146|       |
  147|   219k|		list->count--;
  148|   219k|		return node_index;
  149|   419k|	}
  150|      0|	return NODE_ERR_NOT_FOUND;
  ------------------
  |  |   42|      0|#define NODE_ERR_NOT_FOUND    -6
  ------------------
  151|   219k|}

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

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

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

plist_ostep_init:
   55|      2|{
   56|       |    /* init OpenStep stuff */
   57|      2|#ifdef DEBUG
   58|      2|    char *env_debug = getenv("PLIST_OSTEP_DEBUG");
   59|      2|    if (env_debug && !strcmp(env_debug, "1")) {
  ------------------
  |  Branch (59:9): [True: 0, False: 2]
  |  Branch (59:22): [True: 0, False: 0]
  ------------------
   60|      0|        plist_ostep_debug = 1;
   61|      0|    }
   62|      2|#endif
   63|      2|}
plist_from_openstep:
 1014|  1.59k|{
 1015|  1.59k|    if (!plist) {
  ------------------
  |  Branch (1015:9): [True: 0, False: 1.59k]
  ------------------
 1016|      0|        return PLIST_ERR_INVALID_ARG;
 1017|      0|    }
 1018|  1.59k|    *plist = NULL;
 1019|  1.59k|    if (!plist_ostep || (length == 0)) {
  ------------------
  |  Branch (1019:9): [True: 0, False: 1.59k]
  |  Branch (1019:25): [True: 0, False: 1.59k]
  ------------------
 1020|      0|        return PLIST_ERR_INVALID_ARG;
 1021|      0|    }
 1022|       |
 1023|  1.59k|    struct _parse_ctx ctx = { plist_ostep, plist_ostep, plist_ostep + length, 0 , 0 };
 1024|       |
 1025|  1.59k|    plist_err_t err = node_from_openstep(&ctx, plist);
 1026|  1.59k|    if (err == 0) {
  ------------------
  |  Branch (1026:9): [True: 1.08k, False: 510]
  ------------------
 1027|  1.08k|        if (!*plist) {
  ------------------
  |  Branch (1027:13): [True: 60, False: 1.02k]
  ------------------
 1028|       |            /* whitespace only file is considered an empty dictionary */
 1029|     60|            *plist = plist_new_dict();
 1030|  1.02k|        } else if (ctx.pos < ctx.end && *ctx.pos == '=') {
  ------------------
  |  Branch (1030:20): [True: 847, False: 173]
  |  Branch (1030:41): [True: 832, False: 15]
  ------------------
 1031|       |            /* attempt to parse this as 'strings' data */
 1032|    832|            plist_free(*plist);
 1033|    832|            *plist = NULL;
 1034|    832|            plist_t pl = plist_new_dict();
 1035|    832|            ctx.pos = plist_ostep;
 1036|    832|            parse_dict_data(&ctx, pl);
 1037|    832|            if (ctx.err > 0) {
  ------------------
  |  Branch (1037:17): [True: 0, False: 832]
  ------------------
 1038|      0|                plist_free(pl);
 1039|      0|                PLIST_OSTEP_ERR("Failed to parse strings data\n");
  ------------------
  |  |   47|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1040|      0|                err = PLIST_ERR_PARSE;
 1041|    832|            } else {
 1042|    832|                *plist = pl;
 1043|    832|            }
 1044|    832|        }
 1045|  1.08k|    }
 1046|       |
 1047|  1.59k|    return err;
 1048|  1.59k|}
oplist.c:node_from_openstep:
  722|   237k|{
  723|   237k|    plist_t subnode = NULL;
  724|   237k|    const char *p = NULL;
  725|   237k|    ctx->depth++;
  726|   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 (726:9): [True: 4, False: 237k]
  ------------------
  727|      4|        PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      4|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 4]
  |  |  ------------------
  ------------------
  728|      4|        ctx->err = PLIST_ERR_MAX_NESTING;
  729|      4|        return ctx->err;
  730|      4|    }
  731|   237k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (731:12): [True: 237k, False: 0]
  |  Branch (731:35): [True: 237k, False: 0]
  ------------------
  732|   237k|        parse_skip_ws(ctx);
  733|   237k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (733:13): [True: 66, False: 237k]
  ------------------
  734|     66|            break;
  735|     66|        }
  736|   237k|        plist_data_t data = plist_new_plist_data();
  737|   237k|        if (*ctx->pos == '{') {
  ------------------
  |  Branch (737:13): [True: 19.6k, False: 217k]
  ------------------
  738|  19.6k|            data->type = PLIST_DICT;
  739|  19.6k|            subnode = plist_new_node(data);
  740|  19.6k|            ctx->pos++;
  741|  19.6k|            parse_dict_data(ctx, subnode);
  742|  19.6k|            if (ctx->err) {
  ------------------
  |  Branch (742:17): [True: 12.0k, False: 7.55k]
  ------------------
  743|  12.0k|                goto err_out;
  744|  12.0k|            }
  745|  7.55k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (745:17): [True: 71, False: 7.48k]
  ------------------
  746|     71|                PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     71|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 71]
  |  |  ------------------
  ------------------
  747|     71|                ctx->err = PLIST_ERR_PARSE;
  748|     71|                break;
  749|     71|            }
  750|  7.48k|            if (*ctx->pos != '}') {
  ------------------
  |  Branch (750:17): [True: 0, False: 7.48k]
  ------------------
  751|      0|                PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  752|      0|                ctx->err = PLIST_ERR_PARSE;
  753|      0|                goto err_out;
  754|      0|            }
  755|  7.48k|            ctx->pos++;
  756|  7.48k|            *plist = subnode;
  757|  7.48k|            parse_skip_ws(ctx);
  758|  7.48k|            break;
  759|   217k|        } else if (*ctx->pos == '(') {
  ------------------
  |  Branch (759:20): [True: 18.3k, False: 199k]
  ------------------
  760|  18.3k|            data->type = PLIST_ARRAY;
  761|  18.3k|            subnode = plist_new_node(data);
  762|  18.3k|            ctx->pos++;
  763|  18.3k|            plist_t tmp = NULL;
  764|  50.0k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (764:20): [True: 50.0k, False: 32]
  |  Branch (764:43): [True: 50.0k, False: 0]
  ------------------
  765|  50.0k|                parse_skip_ws(ctx);
  766|  50.0k|                if (ctx->pos >= ctx->end || *ctx->pos == ')') {
  ------------------
  |  Branch (766:21): [True: 1, False: 50.0k]
  |  Branch (766:45): [True: 354, False: 49.6k]
  ------------------
  767|    355|                    break;
  768|    355|                }
  769|  49.6k|                ctx->err = node_from_openstep(ctx, &tmp);
  770|  49.6k|                if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (770:21): [True: 1.87k, False: 47.7k]
  ------------------
  771|  1.87k|                    break;
  772|  1.87k|                }
  773|  47.7k|                if (!tmp) {
  ------------------
  |  Branch (773:21): [True: 1, False: 47.7k]
  ------------------
  774|      1|                    ctx->err = PLIST_ERR_PARSE;
  775|      1|                    break;
  776|      1|                }
  777|  47.7k|                plist_array_append_item(subnode, tmp);
  778|  47.7k|                tmp = NULL;
  779|  47.7k|                parse_skip_ws(ctx);
  780|  47.7k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (780:21): [True: 102, False: 47.6k]
  ------------------
  781|    102|                    PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|    102|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 102]
  |  |  ------------------
  ------------------
  782|    102|                    ctx->err = PLIST_ERR_PARSE;
  783|    102|                    break;
  784|    102|                }
  785|  47.6k|                if (*ctx->pos != ',') {
  ------------------
  |  Branch (785:21): [True: 16.0k, False: 31.6k]
  ------------------
  786|  16.0k|                    break;
  787|  16.0k|                }
  788|  31.6k|                ctx->pos++;
  789|  31.6k|            }
  790|  18.3k|	    plist_free(tmp);
  791|  18.3k|	    tmp = NULL;
  792|  18.3k|            if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (792:17): [True: 1.98k, False: 16.3k]
  ------------------
  793|  1.98k|                goto err_out;
  794|  1.98k|            }
  795|  16.3k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (795:17): [True: 33, False: 16.3k]
  ------------------
  796|     33|                PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     33|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 33]
  |  |  ------------------
  ------------------
  797|     33|                ctx->err = PLIST_ERR_PARSE;
  798|     33|                break;
  799|     33|            }
  800|  16.3k|            if (*ctx->pos != ')') {
  ------------------
  |  Branch (800:17): [True: 16, False: 16.3k]
  ------------------
  801|     16|                PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     16|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 16]
  |  |  ------------------
  ------------------
  802|     16|                ctx->err = PLIST_ERR_PARSE;
  803|     16|                goto err_out;
  804|     16|            }
  805|  16.3k|            ctx->pos++;
  806|  16.3k|            *plist = subnode;
  807|  16.3k|            parse_skip_ws(ctx);
  808|  16.3k|            break;
  809|   199k|        } else if (*ctx->pos == '<') {
  ------------------
  |  Branch (809:20): [True: 293, False: 198k]
  ------------------
  810|    293|            data->type = PLIST_DATA;
  811|    293|            ctx->pos++;
  812|    293|            bytearray_t *bytes = byte_array_new(256);
  813|  2.09k|            while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (813:20): [True: 2.06k, False: 26]
  |  Branch (813:43): [True: 2.06k, False: 0]
  ------------------
  814|  2.06k|                parse_skip_ws(ctx);
  815|  2.06k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (815:21): [True: 1, False: 2.06k]
  ------------------
  816|      1|                    PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  817|      1|                    ctx->err = PLIST_ERR_PARSE;
  818|      1|                    break;
  819|      1|                }
  820|  2.06k|                if (*ctx->pos == '>') {
  ------------------
  |  Branch (820:21): [True: 238, False: 1.82k]
  ------------------
  821|    238|                    break;
  822|    238|                }
  823|  1.82k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (823:21): [True: 9, False: 1.81k]
  ------------------
  824|      9|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      9|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 9]
  |  |  ------------------
  ------------------
  825|      9|                    ctx->err = PLIST_ERR_PARSE;
  826|      9|                    break;
  827|      9|                }
  828|  1.81k|                uint8_t b = HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  648|  1.81k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (648:23): [True: 449, False: 1.36k]
  |  |  |  Branch (648:49): [True: 375, False: 993]
  |  |  ------------------
  ------------------
  829|  1.81k|                ctx->pos++;
  830|  1.81k|                if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (830:21): [True: 18, False: 1.79k]
  ------------------
  831|     18|                    PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     18|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 18]
  |  |  ------------------
  ------------------
  832|     18|                    ctx->err = PLIST_ERR_PARSE;
  833|     18|                    break;
  834|     18|                }
  835|  1.79k|                if (!isxdigit(*ctx->pos)) {
  ------------------
  |  Branch (835:21): [True: 1, False: 1.79k]
  ------------------
  836|      1|                    PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      1|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  837|      1|                    ctx->err = PLIST_ERR_PARSE;
  838|      1|                    break;
  839|      1|                }
  840|  1.79k|                b = (b << 4) + HEX_DIGIT(*ctx->pos);
  ------------------
  |  |  648|  1.79k|#define HEX_DIGIT(x) ((x <= '9') ? (x - '0') : ((x <= 'F') ? (x - 'A' + 10) : (x - 'a' + 10)))
  |  |  ------------------
  |  |  |  Branch (648:23): [True: 445, False: 1.35k]
  |  |  |  Branch (648:49): [True: 366, False: 987]
  |  |  ------------------
  ------------------
  841|  1.79k|                byte_array_append(bytes, &b, 1);
  842|  1.79k|                ctx->pos++;
  843|  1.79k|            }
  844|    293|            if (ctx->err) {
  ------------------
  |  Branch (844:17): [True: 29, False: 264]
  ------------------
  845|     29|                byte_array_free(bytes);
  846|     29|                plist_free_data(data);
  847|     29|                goto err_out;
  848|     29|            }
  849|    264|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (849:17): [True: 26, False: 238]
  ------------------
  850|     26|                byte_array_free(bytes);
  851|     26|                plist_free_data(data);
  852|     26|                PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     26|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 26]
  |  |  ------------------
  ------------------
  853|     26|                ctx->err = PLIST_ERR_PARSE;
  854|     26|                goto err_out;
  855|     26|            }
  856|    238|            if (*ctx->pos != '>') {
  ------------------
  |  Branch (856:17): [True: 0, False: 238]
  ------------------
  857|      0|                byte_array_free(bytes);
  858|      0|                plist_free_data(data);
  859|      0|                PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  860|      0|                ctx->err = PLIST_ERR_PARSE;
  861|      0|                goto err_out;
  862|      0|            }
  863|    238|            ctx->pos++;
  864|    238|            data->buff = (uint8_t*)bytes->data;
  865|    238|            data->length = bytes->len;
  866|    238|            bytes->data = NULL;
  867|    238|            byte_array_free(bytes);
  868|    238|            *plist = plist_new_node(data);
  869|    238|            parse_skip_ws(ctx);
  870|    238|            break;
  871|   198k|        } else if (*ctx->pos == '"' || *ctx->pos == '\'') {
  ------------------
  |  Branch (871:20): [True: 30.6k, False: 168k]
  |  Branch (871:40): [True: 6.54k, False: 161k]
  ------------------
  872|  37.2k|            char c = *ctx->pos;
  873|  37.2k|            ctx->pos++;
  874|  37.2k|            p = ctx->pos;
  875|  37.2k|            size_t num_escapes = 0;
  876|   125k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (876:20): [True: 125k, False: 60]
  ------------------
  877|   125k|                if (*ctx->pos == '\\') {
  ------------------
  |  Branch (877:21): [True: 15.8k, False: 109k]
  ------------------
  878|  15.8k|                    num_escapes++;
  879|  15.8k|                }
  880|   125k|                if ((*ctx->pos == c) && (*(ctx->pos-1) != '\\')) {
  ------------------
  |  Branch (880:21): [True: 37.7k, False: 88.1k]
  |  Branch (880:41): [True: 37.1k, False: 574]
  ------------------
  881|  37.1k|                    break;
  882|  37.1k|                }
  883|  88.7k|                ctx->pos++;
  884|  88.7k|            }
  885|  37.2k|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (885:17): [True: 60, False: 37.1k]
  ------------------
  886|     60|                plist_free_data(data);
  887|     60|                PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     60|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 60]
  |  |  ------------------
  ------------------
  888|     60|                ctx->err = PLIST_ERR_PARSE;
  889|     60|                goto err_out;
  890|     60|            }
  891|  37.1k|            if (*ctx->pos != c) {
  ------------------
  |  Branch (891:17): [True: 0, False: 37.1k]
  ------------------
  892|      0|                plist_free_data(data);
  893|      0|                PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      0|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  894|      0|                ctx->err = PLIST_ERR_PARSE;
  895|      0|                goto err_out;
  896|      0|            }
  897|  37.1k|            size_t slen = ctx->pos - p;
  898|  37.1k|            ctx->pos++; // skip the closing quote
  899|  37.1k|            char* strbuf = (char*)malloc(slen+1);
  900|  37.1k|            if (num_escapes > 0) {
  ------------------
  |  Branch (900:17): [True: 1.04k, False: 36.1k]
  ------------------
  901|  1.04k|                size_t i = 0;
  902|  1.04k|                size_t o = 0;
  903|  32.2k|                while (i < slen) {
  ------------------
  |  Branch (903:24): [True: 31.2k, False: 1.04k]
  ------------------
  904|  31.2k|                    if (p[i] == '\\') {
  ------------------
  |  Branch (904:25): [True: 8.19k, False: 23.0k]
  ------------------
  905|       |                        /* handle escape sequence */
  906|  8.19k|                        i++;
  907|  8.19k|                        switch (p[i]) {
  908|    561|                            case '0':
  ------------------
  |  Branch (908:29): [True: 561, False: 7.63k]
  ------------------
  909|  1.12k|                            case '1':
  ------------------
  |  Branch (909:29): [True: 565, False: 7.63k]
  ------------------
  910|  1.57k|                            case '2':
  ------------------
  |  Branch (910:29): [True: 447, False: 7.74k]
  ------------------
  911|  1.88k|                            case '3':
  ------------------
  |  Branch (911:29): [True: 314, False: 7.88k]
  ------------------
  912|  2.97k|                            case '4':
  ------------------
  |  Branch (912:29): [True: 1.09k, False: 7.10k]
  ------------------
  913|  3.26k|                            case '5':
  ------------------
  |  Branch (913:29): [True: 289, False: 7.90k]
  ------------------
  914|  3.50k|                            case '6':
  ------------------
  |  Branch (914:29): [True: 236, False: 7.95k]
  ------------------
  915|  3.87k|                            case '7': {
  ------------------
  |  Branch (915:29): [True: 372, False: 7.82k]
  ------------------
  916|       |                                // max 3 digits octal
  917|  3.87k|                                unsigned char chr = 0;
  918|  3.87k|                                int maxd = 3;
  919|  8.68k|                                while ((i < slen) && (p[i] >= '0' && p[i] <= '7') && --maxd) {
  ------------------
  |  Branch (919:40): [True: 8.27k, False: 412]
  |  Branch (919:55): [True: 7.81k, False: 460]
  |  Branch (919:70): [True: 5.03k, False: 2.77k]
  |  Branch (919:86): [True: 4.81k, False: 226]
  ------------------
  920|  4.81k|                                    chr = (chr << 3) + p[i] - '0';
  921|  4.81k|                                    i++;
  922|  4.81k|                                }
  923|  3.87k|                                strbuf[o++] = (char)chr;
  924|  3.87k|                            }   break;
  925|  1.21k|                            case 'U': {
  ------------------
  |  Branch (925:29): [True: 1.21k, False: 6.98k]
  ------------------
  926|  1.21k|                                i++;
  927|       |                                // max 4 digits hex
  928|  1.21k|                                uint16_t wchr = 0;
  929|  1.21k|                                int maxd = 4;
  930|  3.02k|                                while ((i < slen) && isxdigit(p[i]) && maxd--) {
  ------------------
  |  Branch (930:40): [True: 2.72k, False: 307]
  |  Branch (930:54): [True: 1.84k, False: 878]
  |  Branch (930:72): [True: 1.81k, False: 30]
  ------------------
  931|  1.81k|                                    wchr = (wchr << 4) + ((p[i] <= '9') ? (p[i] - '0') : ((p[i] <= 'F') ? (p[i] - 'A' + 10) : (p[i] - 'a' + 10)));
  ------------------
  |  Branch (931:59): [True: 445, False: 1.36k]
  |  Branch (931:91): [True: 1.04k, False: 327]
  ------------------
  932|  1.81k|                                    i++;
  933|  1.81k|                                }
  934|  1.21k|                                if (wchr >= 0x800) {
  ------------------
  |  Branch (934:37): [True: 366, False: 849]
  ------------------
  935|    366|                                    strbuf[o++] = (char)(0xE0 + ((wchr >> 12) & 0xF));
  936|    366|                                    strbuf[o++] = (char)(0x80 + ((wchr >> 6) & 0x3F));
  937|    366|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  938|    849|                                } else if (wchr >= 0x80) {
  ------------------
  |  Branch (938:44): [True: 219, False: 630]
  ------------------
  939|    219|                                    strbuf[o++] = (char)(0xC0 + ((wchr >> 6) & 0x1F));
  940|    219|                                    strbuf[o++] = (char)(0x80 + (wchr & 0x3F));
  941|    630|                                } else {
  942|    630|                                    strbuf[o++] = (char)(wchr & 0x7F);
  943|    630|                                }
  944|  1.21k|                            }   break;
  945|    216|                            case 'a': strbuf[o++] = '\a'; i++; break;
  ------------------
  |  Branch (945:29): [True: 216, False: 7.97k]
  ------------------
  946|    303|                            case 'b': strbuf[o++] = '\b'; i++; break;
  ------------------
  |  Branch (946:29): [True: 303, False: 7.89k]
  ------------------
  947|    223|                            case 'f': strbuf[o++] = '\f'; i++; break;
  ------------------
  |  Branch (947:29): [True: 223, False: 7.97k]
  ------------------
  948|    258|                            case 'n': strbuf[o++] = '\n'; i++; break;
  ------------------
  |  Branch (948:29): [True: 258, False: 7.93k]
  ------------------
  949|    206|                            case 'r': strbuf[o++] = '\r'; i++; break;
  ------------------
  |  Branch (949:29): [True: 206, False: 7.98k]
  ------------------
  950|    218|                            case 't': strbuf[o++] = '\t'; i++; break;
  ------------------
  |  Branch (950:29): [True: 218, False: 7.97k]
  ------------------
  951|    388|                            case 'v': strbuf[o++] = '\v'; i++; break;
  ------------------
  |  Branch (951:29): [True: 388, False: 7.80k]
  ------------------
  952|    243|                            case '"': strbuf[o++] = '"';  i++; break;
  ------------------
  |  Branch (952:29): [True: 243, False: 7.95k]
  ------------------
  953|    381|                            case '\'': strbuf[o++] = '\''; i++; break;
  ------------------
  |  Branch (953:29): [True: 381, False: 7.81k]
  ------------------
  954|    668|                            default:
  ------------------
  |  Branch (954:29): [True: 668, False: 7.52k]
  ------------------
  955|    668|                                break;
  956|  8.19k|                        }
  957|  23.0k|                    } else {
  958|  23.0k|                        strbuf[o++] = p[i++];
  959|  23.0k|                    }
  960|  31.2k|                }
  961|  1.04k|                strbuf[o] = '\0';
  962|  1.04k|                slen = o;
  963|  36.1k|            } else {
  964|  36.1k|                strncpy(strbuf, p, slen);
  965|  36.1k|                strbuf[slen] = '\0';
  966|  36.1k|            }
  967|  37.1k|            data->type = PLIST_STRING;
  968|  37.1k|            data->strval = strbuf;
  969|  37.1k|            data->length = slen;
  970|  37.1k|            *plist = plist_new_node(data);
  971|  37.1k|            parse_skip_ws(ctx);
  972|  37.1k|            break;
  973|   161k|        } else {
  974|       |            // unquoted string
  975|   161k|            size_t slen = 0;
  976|   161k|            parse_skip_ws(ctx);
  977|   161k|            p = ctx->pos;
  978|   395k|            while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (978:20): [True: 395k, False: 118]
  ------------------
  979|   395k|                if (!allowed_unquoted_chars[(uint8_t)*ctx->pos]) {
  ------------------
  |  Branch (979:21): [True: 161k, False: 233k]
  ------------------
  980|   161k|                    break;
  981|   161k|                }
  982|   233k|                ctx->pos++;
  983|   233k|            }
  984|   161k|            slen = ctx->pos-p;
  985|   161k|            if (slen > 0) {
  ------------------
  |  Branch (985:17): [True: 161k, False: 151]
  ------------------
  986|   161k|                data->type = PLIST_STRING;
  987|   161k|                data->strval = strndup(p, slen);
  988|   161k|                data->length = slen;
  989|   161k|                *plist = plist_new_node(data);
  990|   161k|                parse_skip_ws(ctx);
  991|   161k|                break;
  992|   161k|            } else {
  993|    151|                plist_free_data(data);
  994|    151|                PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|    151|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 151]
  |  |  ------------------
  ------------------
  995|    151|                ctx->err = PLIST_ERR_PARSE;
  996|    151|                break;
  997|    151|            }
  998|   161k|        }
  999|      0|        ctx->pos++;
 1000|      0|    }
 1001|   223k|    ctx->depth--;
 1002|       |
 1003|   237k|err_out:
 1004|   237k|    if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (1004:9): [True: 14.4k, False: 222k]
  ------------------
 1005|  14.4k|        plist_free(subnode);
 1006|  14.4k|        plist_free(*plist);
 1007|  14.4k|        *plist = NULL;
 1008|  14.4k|        return ctx->err;
 1009|  14.4k|    }
 1010|   222k|    return PLIST_ERR_SUCCESS;
 1011|   237k|}
oplist.c:parse_skip_ws:
  612|  1.00M|{
  613|  1.00M|    while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (613:12): [True: 1.00M, False: 505]
  ------------------
  614|       |        // skip comments
  615|  1.00M|        if (*ctx->pos == '/' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (615:13): [True: 814, False: 1.00M]
  |  Branch (615:33): [True: 790, False: 24]
  ------------------
  616|    790|            if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (616:17): [True: 381, False: 409]
  ------------------
  617|    381|                ctx->pos++;
  618|  1.75k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (618:24): [True: 1.73k, False: 20]
  ------------------
  619|  1.73k|                    if ((*ctx->pos == '\n') || (*ctx->pos == '\r')) {
  ------------------
  |  Branch (619:25): [True: 143, False: 1.58k]
  |  Branch (619:48): [True: 218, False: 1.36k]
  ------------------
  620|    361|                        break;
  621|    361|                    }
  622|  1.36k|                    ctx->pos++;
  623|  1.36k|                }
  624|    409|            } else if (*(ctx->pos+1) == '*') {
  ------------------
  |  Branch (624:24): [True: 354, False: 55]
  ------------------
  625|    354|                ctx->pos++;
  626|  9.71k|                while (ctx->pos < ctx->end) {
  ------------------
  |  Branch (626:24): [True: 9.68k, False: 32]
  ------------------
  627|  9.68k|                    if (*ctx->pos == '*' && (ctx->end - ctx->pos > 1)) {
  ------------------
  |  Branch (627:25): [True: 938, False: 8.74k]
  |  Branch (627:45): [True: 935, False: 3]
  ------------------
  628|    935|                        if (*(ctx->pos+1) == '/') {
  ------------------
  |  Branch (628:29): [True: 322, False: 613]
  ------------------
  629|    322|                            ctx->pos+=2;
  630|    322|                            break;
  631|    322|                        }
  632|    935|                    }
  633|  9.36k|                    ctx->pos++;
  634|  9.36k|                }
  635|    354|            }
  636|    790|            if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (636:17): [True: 54, False: 736]
  ------------------
  637|     54|                break;
  638|     54|            }
  639|    790|        }
  640|       |        // break on any char that's not white space
  641|  1.00M|        if (!(((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n')))) {
  ------------------
  |  Branch (641:16): [True: 339, False: 1.00M]
  |  Branch (641:40): [True: 249, False: 1.00M]
  |  Branch (641:65): [True: 285, False: 1.00M]
  |  Branch (641:90): [True: 326, False: 1.00M]
  ------------------
  642|  1.00M|            break;
  643|  1.00M|        }
  644|  1.19k|        ctx->pos++;
  645|  1.19k|    }
  646|  1.00M|}
oplist.c:parse_dict_data:
  653|  20.4k|{
  654|  20.4k|    plist_t key = NULL;
  655|  20.4k|    plist_t val = NULL;
  656|   107k|    while (ctx->pos < ctx->end && !ctx->err) {
  ------------------
  |  Branch (656:12): [True: 106k, False: 332]
  |  Branch (656:35): [True: 106k, False: 0]
  ------------------
  657|   106k|        parse_skip_ws(ctx);
  658|   106k|        if (ctx->pos >= ctx->end || *ctx->pos == '}') {
  ------------------
  |  Branch (658:13): [True: 3, False: 106k]
  |  Branch (658:37): [True: 7.49k, False: 99.1k]
  ------------------
  659|  7.49k|            break;
  660|  7.49k|        }
  661|  99.1k|        key = NULL;
  662|  99.1k|        ctx->err = node_from_openstep(ctx, &key);
  663|  99.1k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (663:13): [True: 11.8k, False: 87.3k]
  ------------------
  664|  11.8k|            break;
  665|  11.8k|        }
  666|  87.3k|        if (!PLIST_IS_STRING(key)) {
  ------------------
  |  | 1193|  87.3k|    #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
  |  |  ------------------
  |  |  |  | 1183|  87.3k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 87.3k, False: 1]
  |  |  |  |  |  Branch (1183:63): [True: 87.1k, False: 258]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  667|    259|            PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|    259|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 259]
  |  |  ------------------
  ------------------
  668|    259|            ctx->err = PLIST_ERR_PARSE;
  669|    259|            break;
  670|    259|        }
  671|  87.1k|        parse_skip_ws(ctx);
  672|  87.1k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (672:13): [True: 46, False: 87.0k]
  ------------------
  673|     46|            PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     46|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 46]
  |  |  ------------------
  ------------------
  674|     46|            ctx->err = PLIST_ERR_PARSE;
  675|     46|            break;
  676|     46|        }
  677|  87.0k|        if (*ctx->pos != '=') {
  ------------------
  |  Branch (677:13): [True: 24, False: 87.0k]
  ------------------
  678|     24|            PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|     24|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 24]
  |  |  ------------------
  ------------------
  679|     24|            ctx->err = PLIST_ERR_PARSE;
  680|     24|            break;
  681|     24|        }
  682|  87.0k|        ctx->pos++;
  683|  87.0k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (683:13): [True: 230, False: 86.8k]
  ------------------
  684|    230|            PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|    230|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 230]
  |  |  ------------------
  ------------------
  685|    230|            ctx->err = PLIST_ERR_PARSE;
  686|    230|            break;
  687|    230|        }
  688|  86.8k|        val = NULL;
  689|  86.8k|        ctx->err = node_from_openstep(ctx, &val);
  690|  86.8k|        if (ctx->err != PLIST_ERR_SUCCESS) {
  ------------------
  |  Branch (690:13): [True: 256, False: 86.5k]
  ------------------
  691|    256|            break;
  692|    256|        }
  693|  86.5k|        if (!val) {
  ------------------
  |  Branch (693:13): [True: 4, False: 86.5k]
  ------------------
  694|      4|            PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      4|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 4]
  |  |  ------------------
  ------------------
  695|      4|            ctx->err = PLIST_ERR_PARSE;
  696|      4|            break;
  697|      4|        }
  698|  86.5k|        parse_skip_ws(ctx);
  699|  86.5k|        if (ctx->pos >= ctx->end) {
  ------------------
  |  Branch (699:13): [True: 9, False: 86.5k]
  ------------------
  700|      9|            PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      9|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 9]
  |  |  ------------------
  ------------------
  701|      9|            ctx->err = PLIST_ERR_PARSE;
  702|      9|            break;
  703|      9|        }
  704|  86.5k|        if (*ctx->pos != ';') {
  ------------------
  |  Branch (704:13): [True: 3, False: 86.5k]
  ------------------
  705|      3|            PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
  ------------------
  |  |   47|      3|#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (47:34): [True: 0, False: 3]
  |  |  ------------------
  ------------------
  706|      3|            ctx->err = PLIST_ERR_PARSE;
  707|      3|            break;
  708|      3|        }
  709|       |
  710|  86.5k|        plist_dict_set_item(dict, plist_get_string_ptr(key, NULL), val);
  711|  86.5k|        plist_free(key);
  712|  86.5k|        key = NULL;
  713|  86.5k|        val = NULL;
  714|       |
  715|  86.5k|        ctx->pos++;
  716|  86.5k|    }
  717|  20.4k|    plist_free(key);
  718|  20.4k|    plist_free(val);
  719|  20.4k|}

plist.c:internal_plist_init:
  153|      2|{
  154|      2|    plist_bin_init();
  155|      2|    plist_xml_init();
  156|      2|    plist_json_init();
  157|      2|    plist_ostep_init();
  158|      2|    atexit(internal_plist_deinit);
  159|      2|}
plist_new_node:
  348|   322k|{
  349|       |    return (plist_t) node_create(NULL, data);
  350|   322k|}
plist_get_data:
  353|  31.9M|{
  354|  31.9M|    if (!node)
  ------------------
  |  Branch (354:9): [True: 0, False: 31.9M]
  ------------------
  355|      0|        return NULL;
  356|  31.9M|    return (plist_data_t)((node_t)node)->data;
  357|  31.9M|}
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|    892|{
  529|    892|    plist_data_t data = plist_new_plist_data();
  530|    892|    if (!data) {
  ------------------
  |  Branch (530:9): [True: 0, False: 892]
  ------------------
  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|    892|    data->type = PLIST_DICT;
  535|    892|    return plist_new_node(data);
  536|    892|}
plist_free:
  713|   177k|{
  714|   177k|    if (plist)
  ------------------
  |  Branch (714:9): [True: 103k, False: 73.7k]
  ------------------
  715|   103k|    {
  716|   103k|        plist_free_node((node_t)plist);
  717|   103k|    }
  718|   177k|}
plist_array_append_item:
 1080|  47.7k|{
 1081|  47.7k|    if (!PLIST_IS_ARRAY(node) || !item) {
  ------------------
  |  | 1195|  47.7k|    #define PLIST_IS_ARRAY(__plist)   _PLIST_IS_TYPE(__plist, ARRAY)
  |  |  ------------------
  |  |  |  | 1183|  95.5k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 47.7k, False: 0]
  |  |  |  |  |  Branch (1183:63): [True: 47.7k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1081:34): [True: 0, False: 47.7k]
  ------------------
 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;
 1084|      0|    }
 1085|  47.7k|    node_t it = (node_t)item;
 1086|  47.7k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1086:9): [True: 0, False: 47.7k]
  ------------------
 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;
 1090|      0|    }
 1091|       |
 1092|  47.7k|    int r = node_attach((node_t)node, (node_t)item);
 1093|  47.7k|    if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  47.7k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1093:9): [True: 0, False: 47.7k]
  ------------------
 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;
 1096|      0|    }
 1097|  47.7k|    _plist_array_post_insert(node, item, -1);
 1098|  47.7k|}
plist_dict_get_item:
 1275|  86.5k|{
 1276|  86.5k|    plist_t ret = NULL;
 1277|  86.5k|    if (!PLIST_IS_DICT(node) || !key) {
  ------------------
  |  | 1197|  86.5k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1183|   173k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 86.5k, False: 0]
  |  |  |  |  |  Branch (1183:63): [True: 86.5k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1277:33): [True: 0, False: 86.5k]
  ------------------
 1278|      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]
  |  |  ------------------
  ------------------
 1279|      0|        return NULL;
 1280|      0|    }
 1281|  86.5k|    plist_data_t data = plist_get_data(node);
 1282|  86.5k|    if (!data) {
  ------------------
  |  Branch (1282:9): [True: 0, False: 86.5k]
  ------------------
 1283|      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]
  |  |  ------------------
  ------------------
 1284|      0|        return NULL;
 1285|      0|    }
 1286|  86.5k|    size_t keylen = strlen(key);
 1287|  86.5k|    hashtable_t *ht = (hashtable_t*)data->hashtable;
 1288|  86.5k|    if (ht) {
  ------------------
  |  Branch (1288:9): [True: 1.21k, False: 85.3k]
  ------------------
 1289|  1.21k|        struct plist_data_s sdata = { 0 };
 1290|  1.21k|        sdata.strval = (char*)key;
 1291|  1.21k|        sdata.length = keylen;
 1292|  1.21k|        return (plist_t)hash_table_lookup(ht, &sdata);
 1293|  85.3k|    } else {
 1294|  85.3k|        plist_t k = NULL;
 1295|  10.4M|        for (k = (plist_t)node_first_child((node_t)node); k; ) {
  ------------------
  |  Branch (1295:59): [True: 10.3M, False: 84.3k]
  ------------------
 1296|  10.3M|            plist_t v = (plist_t)node_next_sibling(k);
 1297|  10.3M|            if (!v) break;
  ------------------
  |  Branch (1297:17): [True: 0, False: 10.3M]
  ------------------
 1298|  10.3M|            data = plist_get_data(k);
 1299|  10.3M|            assert(PLIST_IS_KEY(k));
  ------------------
  |  Branch (1299:13): [True: 0, False: 10.3M]
  |  Branch (1299:13): [True: 0, False: 0]
  |  Branch (1299:13): [True: 10.3M, False: 0]
  |  Branch (1299:13): [True: 10.3M, False: 0]
  ------------------
 1300|  10.3M|            if (!PLIST_IS_KEY(k) || !data || !data->strval) {
  ------------------
  |  | 1203|  10.3M|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1183|  20.6M|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 10.3M, False: 0]
  |  |  |  |  |  Branch (1183:63): [True: 10.3M, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1300:37): [True: 0, False: 10.3M]
  |  Branch (1300:46): [True: 0, False: 10.3M]
  ------------------
 1301|      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]
  |  |  ------------------
  ------------------
 1302|      0|                break;
 1303|      0|            }
 1304|  10.3M|            if (data->length == keylen && !memcmp(key, data->strval, keylen+1)) {
  ------------------
  |  Branch (1304:17): [True: 4.99M, False: 5.34M]
  |  Branch (1304:43): [True: 950, False: 4.99M]
  ------------------
 1305|    950|                ret = v;
 1306|    950|                break;
 1307|    950|            }
 1308|  10.3M|            k = node_next_sibling(v);
 1309|  10.3M|        }
 1310|  85.3k|    }
 1311|  85.3k|    return ret;
 1312|  86.5k|}
plist_dict_set_item:
 1315|  86.5k|{
 1316|  86.5k|    if (!PLIST_IS_DICT(node) || !key || !item) {
  ------------------
  |  | 1197|  86.5k|    #define PLIST_IS_DICT(__plist)    _PLIST_IS_TYPE(__plist, DICT)
  |  |  ------------------
  |  |  |  | 1183|   173k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 86.5k, False: 0]
  |  |  |  |  |  Branch (1183:63): [True: 86.5k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1316:33): [True: 0, False: 86.5k]
  |  Branch (1316:41): [True: 0, False: 86.5k]
  ------------------
 1317|      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]
  |  |  ------------------
  ------------------
 1318|      0|        return;
 1319|      0|    }
 1320|  86.5k|    node_t it = (node_t)item;
 1321|  86.5k|    if (it->parent != NULL) {
  ------------------
  |  Branch (1321:9): [True: 0, False: 86.5k]
  ------------------
 1322|      0|        assert(it->parent == NULL && "item already has a parent");
  ------------------
  |  Branch (1322:9): [True: 0, False: 0]
  |  Branch (1322:9): [True: 0, False: 0]
  |  Branch (1322:9): [True: 0, False: 0]
  |  Branch (1322:9): [True: 0, False: 0]
  ------------------
 1323|      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]
  |  |  ------------------
  ------------------
 1324|      0|        return;
 1325|      0|    }
 1326|       |
 1327|  86.5k|    hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
 1328|       |
 1329|  86.5k|    plist_t old_item = plist_dict_get_item(node, key);
 1330|  86.5k|    plist_t key_node = NULL;
 1331|       |
 1332|  86.5k|    if (old_item) {
  ------------------
  |  Branch (1332:9): [True: 1.63k, False: 84.9k]
  ------------------
 1333|       |        // --- REPLACE EXISTING VALUE ---
 1334|  1.63k|        node_t old_val = (node_t)old_item;
 1335|  1.63k|        node_t old_key = node_prev_sibling(old_val);
 1336|  1.63k|        if (!old_key) {
  ------------------
  |  Branch (1336:13): [True: 0, False: 1.63k]
  ------------------
 1337|      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]
  |  |  ------------------
  ------------------
 1338|      0|            return;
 1339|      0|        }
 1340|  1.63k|        if (!PLIST_IS_KEY((plist_t)old_key)) {
  ------------------
  |  | 1203|  1.63k|    #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
  |  |  ------------------
  |  |  |  | 1183|  1.63k|    #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1183:52): [True: 1.63k, False: 0]
  |  |  |  |  |  Branch (1183:63): [True: 1.63k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 1341|      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]
  |  |  ------------------
  ------------------
 1342|      0|            return;
 1343|      0|        }
 1344|       |
 1345|       |        // detach old value (do NOT free yet)
 1346|  1.63k|        int idx = node_detach((node_t)node, old_val);
 1347|  1.63k|        if (idx < 0) {
  ------------------
  |  Branch (1347:13): [True: 0, False: 1.63k]
  ------------------
 1348|      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]
  |  |  ------------------
  ------------------
 1349|      0|            return;
 1350|      0|        }
 1351|       |
 1352|       |        // insert new value at same position
 1353|  1.63k|        int r = node_insert((node_t)node, (unsigned)idx, (node_t)item);
 1354|  1.63k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  1.63k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1354:13): [True: 0, False: 1.63k]
  ------------------
 1355|       |            // rollback: reinsert old value
 1356|      0|            int rb = node_insert((node_t)node, (unsigned)idx, old_val);
 1357|      0|            if (rb == NODE_ERR_SUCCESS && ht) {
  ------------------
  |  |   36|      0|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1357:17): [True: 0, False: 0]
  |  Branch (1357:43): [True: 0, False: 0]
  ------------------
 1358|      0|                hash_table_insert(ht, ((node_t)old_key)->data, old_item);
 1359|      0|            }
 1360|      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]
  |  |  ------------------
  ------------------
 1361|      0|            return;
 1362|      0|        }
 1363|  1.63k|        key_node = old_key;
 1364|       |
 1365|       |        // update hash table
 1366|  1.63k|        if (ht) {
  ------------------
  |  Branch (1366:13): [True: 685, False: 950]
  ------------------
 1367|    685|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1368|    685|        }
 1369|       |
 1370|       |        // now it’s safe to free old value
 1371|  1.63k|        plist_free_node(old_val);
 1372|  84.9k|    } else {
 1373|       |        // --- INSERT NEW KEY/VALUE PAIR ---
 1374|  84.9k|        key_node = plist_new_key(key);
 1375|  84.9k|        if (!key_node) return;
  ------------------
  |  Branch (1375:13): [True: 0, False: 84.9k]
  ------------------
 1376|       |
 1377|  84.9k|        int r = node_attach((node_t)node, (node_t)key_node);
 1378|  84.9k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  84.9k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1378:13): [True: 0, False: 84.9k]
  ------------------
 1379|      0|            plist_free_node((node_t)key_node);
 1380|      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]
  |  |  ------------------
  ------------------
 1381|      0|            return;
 1382|      0|        }
 1383|  84.9k|        r = node_attach((node_t)node, (node_t)item);
 1384|  84.9k|        if (r != NODE_ERR_SUCCESS) {
  ------------------
  |  |   36|  84.9k|#define NODE_ERR_SUCCESS       0
  ------------------
  |  Branch (1384:13): [True: 0, False: 84.9k]
  ------------------
 1385|       |            // rollback key insertion
 1386|      0|            node_detach((node_t)node, (node_t)key_node);
 1387|      0|            plist_free_node((node_t)key_node);
 1388|      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]
  |  |  ------------------
  ------------------
 1389|      0|            return;
 1390|      0|        }
 1391|       |
 1392|  84.9k|        if (ht) {
  ------------------
  |  Branch (1392:13): [True: 534, False: 84.3k]
  ------------------
 1393|       |            // store pointer to item in hash table
 1394|    534|            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
 1395|  84.3k|        } else if (((node_t)node)->count > 500) {
  ------------------
  |  Branch (1395:20): [True: 321, False: 84.0k]
  ------------------
 1396|       |            // make new hash table
 1397|    321|            ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
 1398|       |            // calculate the hashes for all entries we have so far
 1399|    321|            plist_t current = NULL;
 1400|    321|            for (current = (plist_t)node_first_child((node_t)node);
 1401|  80.8k|                 ht && current;
  ------------------
  |  Branch (1401:18): [True: 80.8k, False: 0]
  |  Branch (1401:24): [True: 80.5k, False: 321]
  ------------------
 1402|  80.5k|                 current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
 1403|  80.5k|            {
 1404|  80.5k|                hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
 1405|  80.5k|            }
 1406|    321|            ((plist_data_t)((node_t)node)->data)->hashtable = ht;
 1407|    321|        }
 1408|  84.9k|    }
 1409|  86.5k|}
plist_get_node_type:
 1732|  21.0M|{
 1733|  21.0M|    if (node)
  ------------------
  |  Branch (1733:9): [True: 21.0M, False: 0]
  ------------------
 1734|  21.0M|    {
 1735|  21.0M|        plist_data_t data = plist_get_data(node);
 1736|  21.0M|        if (data)
  ------------------
  |  Branch (1736:13): [True: 21.0M, False: 0]
  ------------------
 1737|  21.0M|            return data->type;
 1738|  21.0M|    }
 1739|      0|    return PLIST_NONE;
 1740|  21.0M|}
plist_get_string_ptr:
 1771|  86.5k|{
 1772|  86.5k|    if (!node)
  ------------------
  |  Branch (1772:9): [True: 0, False: 86.5k]
  ------------------
 1773|      0|        return NULL;
 1774|  86.5k|    plist_type type = plist_get_node_type(node);
 1775|  86.5k|    if (PLIST_STRING != type)
  ------------------
  |  Branch (1775:9): [True: 0, False: 86.5k]
  ------------------
 1776|      0|        return NULL;
 1777|  86.5k|    plist_data_t data = plist_get_data(node);
 1778|  86.5k|    if (length)
  ------------------
  |  Branch (1778:9): [True: 0, False: 86.5k]
  ------------------
 1779|      0|        *length = data->length;
 1780|  86.5k|    return (const char*)data->strval;
 1781|  86.5k|}
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|  84.9k|        case PLIST_KEY:
  ------------------
  |  Branch (393:9): [True: 84.9k, False: 238k]
  ------------------
  394|   283k|        case PLIST_STRING:
  ------------------
  |  Branch (394:9): [True: 198k, False: 124k]
  ------------------
  395|   283k|            free(data->strval);
  396|   283k|            data->strval = NULL;
  397|   283k|            break;
  398|    293|        case PLIST_DATA:
  ------------------
  |  Branch (398:9): [True: 293, False: 322k]
  ------------------
  399|    293|            free(data->buff);
  400|    293|            data->buff = NULL;
  401|    293|            break;
  402|  18.3k|        case PLIST_ARRAY:
  ------------------
  |  Branch (402:9): [True: 18.3k, False: 304k]
  ------------------
  403|  18.3k|            ptr_array_free((ptrarray_t*)data->hashtable);
  404|  18.3k|            data->hashtable = NULL;
  405|  18.3k|            break;
  406|  20.5k|        case PLIST_DICT: {
  ------------------
  |  Branch (406:9): [True: 20.5k, False: 302k]
  ------------------
  407|  20.5k|            hashtable_t *ht = (hashtable_t*)data->hashtable;
  408|       |            // PLIST_DICT hashtables must not own/free values; values are freed via node tree.
  409|  20.5k|            assert(!ht || ht->free_func == NULL);
  ------------------
  |  Branch (409:13): [True: 20.5k, False: 0]
  |  Branch (409:13): [True: 0, False: 0]
  |  Branch (409:13): [True: 20.2k, False: 321]
  |  Branch (409:13): [True: 321, False: 0]
  ------------------
  410|  20.5k|            if (ht) ht->free_func = NULL;
  ------------------
  |  Branch (410:17): [True: 321, False: 20.2k]
  ------------------
  411|  20.5k|            hash_table_destroy(ht);
  412|  20.5k|            data->hashtable = NULL;
  413|  20.5k|            break;
  414|  20.5k|        }
  415|    211|        default:
  ------------------
  |  Branch (415:9): [True: 211, False: 322k]
  ------------------
  416|    211|            break;
  417|   322k|    }
  418|   322k|}
plist.c:plist_free_node:
  500|   105k|{
  501|   105k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (501:9): [True: 0, False: 105k]
  ------------------
  502|       |
  503|   105k|    int root_index = -1;
  504|       |
  505|   105k|    if (root->parent) {
  ------------------
  |  Branch (505:9): [True: 0, False: 105k]
  ------------------
  506|      0|        root_index = node_detach(root->parent, root);
  507|      0|        if (root_index < 0) {
  ------------------
  |  Branch (507:13): [True: 0, False: 0]
  ------------------
  508|      0|            return root_index;
  509|      0|        }
  510|      0|    }
  511|       |
  512|   105k|    int r = plist_free_children(root);
  513|   105k|    if (r < 0) {
  ------------------
  |  Branch (513:9): [True: 0, False: 105k]
  ------------------
  514|       |        // root is already detached; caller should treat as error.
  515|      0|        return r;
  516|      0|    }
  517|       |
  518|   105k|    plist_data_t data = plist_get_data(root);
  519|   105k|    plist_free_data(data);
  520|   105k|    root->data = NULL;
  521|       |
  522|   105k|    node_destroy(root);
  523|       |
  524|   105k|    return root_index;
  525|   105k|}
plist.c:plist_free_children:
  428|   105k|{
  429|   105k|    if (!root) return NODE_ERR_INVALID_ARG;
  ------------------
  |  |   37|      0|#define NODE_ERR_INVALID_ARG  -1
  ------------------
  |  Branch (429:9): [True: 0, False: 105k]
  ------------------
  430|       |
  431|   105k|    if (!node_first_child(root)) {
  ------------------
  |  Branch (431:9): [True: 103k, False: 1.20k]
  ------------------
  432|   103k|        return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|   103k|#define NODE_ERR_SUCCESS       0
  ------------------
  433|   103k|    }
  434|       |
  435|  1.20k|    size_t cap = 64, sp = 0;
  436|  1.20k|    node_t *stack = (node_t*)malloc(cap * sizeof(*stack));
  437|  1.20k|    if (!stack) return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  |  Branch (437:9): [True: 0, False: 1.20k]
  ------------------
  438|       |
  439|       |    // Push *direct* children onto the stack, detached from root.
  440|   189k|    for (;;) {
  441|   189k|        node_t ch = node_first_child(root);
  442|   189k|        if (!ch) break;
  ------------------
  |  Branch (442:13): [True: 1.20k, False: 188k]
  ------------------
  443|       |
  444|   188k|        int di = node_detach(root, ch);
  445|   188k|        if (di < 0) {
  ------------------
  |  Branch (445:13): [True: 0, False: 188k]
  ------------------
  446|      0|            free(stack);
  447|      0|            return di;
  448|      0|        }
  449|       |
  450|   188k|        if (sp == cap) {
  ------------------
  |  Branch (450:13): [True: 2.58k, False: 186k]
  ------------------
  451|  2.58k|            cap += 64;
  452|  2.58k|            node_t *tmp = (node_t*)realloc(stack, cap * sizeof(*stack));
  453|  2.58k|            if (!tmp) {
  ------------------
  |  Branch (453:17): [True: 0, False: 2.58k]
  ------------------
  454|      0|                free(stack);
  455|      0|                return NODE_ERR_NO_MEM;
  ------------------
  |  |   38|      0|#define NODE_ERR_NO_MEM       -2
  ------------------
  456|      0|            }
  457|  2.58k|            stack = tmp;
  458|  2.58k|        }
  459|   188k|        stack[sp++] = ch;
  460|   188k|    }
  461|       |
  462|       |    // Now free the detached subtree nodes (and their descendants).
  463|   247k|    while (sp) {
  ------------------
  |  Branch (463:12): [True: 246k, False: 1.20k]
  ------------------
  464|   246k|        node_t node = stack[sp - 1];
  465|   246k|        node_t ch = node_first_child(node);
  466|   246k|        if (ch) {
  ------------------
  |  Branch (466:13): [True: 28.8k, False: 217k]
  ------------------
  467|  28.8k|            int di = node_detach(node, ch);
  468|  28.8k|            if (di < 0) {
  ------------------
  |  Branch (468:17): [True: 0, False: 28.8k]
  ------------------
  469|      0|                free(stack);
  470|      0|                return di;
  471|      0|            }
  472|       |
  473|  28.8k|            if (sp == cap) {
  ------------------
  |  Branch (473:17): [True: 217, False: 28.6k]
  ------------------
  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|  28.8k|            stack[sp++] = ch;
  483|  28.8k|            continue;
  484|  28.8k|        }
  485|       |
  486|   217k|        plist_data_t data = plist_get_data(node);
  487|   217k|        plist_free_data(data);
  488|   217k|        node->data = NULL;
  489|       |
  490|   217k|        node_destroy(node);
  491|       |
  492|   217k|        sp--;
  493|   217k|    }
  494|       |
  495|  1.20k|    free(stack);
  496|  1.20k|    return NODE_ERR_SUCCESS;
  ------------------
  |  |   36|  1.20k|#define NODE_ERR_SUCCESS       0
  ------------------
  497|  1.20k|}
plist.c:_plist_array_post_insert:
  989|  47.7k|{
  990|  47.7k|    ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
  991|  47.7k|    if (pa) {
  ------------------
  |  Branch (991:9): [True: 13.3k, False: 34.4k]
  ------------------
  992|       |        /* store pointer to item in array */
  993|  13.3k|        ptr_array_insert(pa, item, n);
  994|  13.3k|        return;
  995|  13.3k|    }
  996|       |
  997|  34.4k|    if (((node_t)node)->count > 100) {
  ------------------
  |  Branch (997:9): [True: 144, False: 34.2k]
  ------------------
  998|       |       /* make new lookup array */
  999|    144|       pa = ptr_array_new(128);
 1000|    144|       plist_t current = NULL;
 1001|    144|       for (current = (plist_t)node_first_child((node_t)node);
 1002|  14.6k|            pa && current;
  ------------------
  |  Branch (1002:13): [True: 14.6k, False: 0]
  |  Branch (1002:19): [True: 14.5k, False: 144]
  ------------------
 1003|  14.5k|            current = (plist_t)node_next_sibling((node_t)current))
 1004|  14.5k|       {
 1005|  14.5k|           ptr_array_add(pa, current);
 1006|  14.5k|       }
 1007|    144|       ((plist_data_t)((node_t)node)->data)->hashtable = pa;
 1008|    144|    }
 1009|  34.4k|}
plist.c:plist_new_key:
  551|  84.9k|{
  552|  84.9k|    plist_data_t data = plist_new_plist_data();
  553|  84.9k|    if (!data) {
  ------------------
  |  Branch (553:9): [True: 0, False: 84.9k]
  ------------------
  554|      0|        PLIST_ERR("%s: failed to allocate plist data\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  555|      0|        return NULL;
  556|      0|    }
  557|  84.9k|    data->type = PLIST_KEY;
  558|  84.9k|    data->strval = strdup(val);
  559|  84.9k|    if (!data->strval) {
  ------------------
  |  Branch (559:9): [True: 0, False: 84.9k]
  ------------------
  560|      0|        plist_free_data(data);
  561|      0|        PLIST_ERR("%s: strdup failed\n", __func__);
  ------------------
  |  |   57|      0|#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
  |  |  ------------------
  |  |  |  Branch (57:28): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  562|      0|        return NULL;
  563|  84.9k|    } else {
  564|  84.9k|        data->length = strlen(val);
  565|  84.9k|    }
  566|  84.9k|    return plist_new_node(data);
  567|  84.9k|}
plist.c:dict_key_hash:
  365|  83.0k|{
  366|  83.0k|    plist_data_t keydata = (plist_data_t)data;
  367|  83.0k|    unsigned int hash = 5381;
  368|  83.0k|    size_t i;
  369|  83.0k|    char *str = keydata->strval;
  370|   244k|    for (i = 0; i < keydata->length; str++, i++) {
  ------------------
  |  Branch (370:17): [True: 161k, False: 83.0k]
  ------------------
  371|   161k|        hash = ((hash << 5) + hash) + *str;
  372|   161k|    }
  373|  83.0k|    return hash;
  374|  83.0k|}
plist.c:dict_key_compare:
  377|  4.31k|{
  378|  4.31k|    plist_data_t data_a = (plist_data_t)a;
  379|  4.31k|    plist_data_t data_b = (plist_data_t)b;
  380|  4.31k|    if (data_a->strval == NULL || data_b->strval == NULL) {
  ------------------
  |  Branch (380:9): [True: 0, False: 4.31k]
  |  Branch (380:35): [True: 0, False: 4.31k]
  ------------------
  381|      0|        return FALSE;
  ------------------
  |  |   32|      0|#define FALSE 0
  ------------------
  382|      0|    }
  383|  4.31k|    if (data_a->length != data_b->length) {
  ------------------
  |  Branch (383:9): [True: 1.26k, False: 3.05k]
  ------------------
  384|  1.26k|        return FALSE;
  ------------------
  |  |   32|  1.26k|#define FALSE 0
  ------------------
  385|  1.26k|    }
  386|  3.05k|    return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   28|  1.37k|#define TRUE 1
  ------------------
                  return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
  ------------------
  |  |   32|  1.68k|#define FALSE 0
  ------------------
  |  Branch (386:12): [True: 1.37k, False: 1.68k]
  ------------------
  387|  4.31k|}

ptr_array_new:
   25|    144|{
   26|    144|	ptrarray_t *pa = (ptrarray_t*)malloc(sizeof(ptrarray_t));
   27|    144|	pa->pdata = (void**)malloc(sizeof(void*) * capacity);
   28|    144|	pa->capacity = capacity;
   29|    144|	pa->capacity_step = (capacity > 4096) ? 4096 : capacity;
  ------------------
  |  Branch (29:22): [True: 0, False: 144]
  ------------------
   30|    144|	pa->len = 0;
   31|    144|	return pa;
   32|    144|}
ptr_array_free:
   35|  18.3k|{
   36|  18.3k|	if (!pa) return;
  ------------------
  |  Branch (36:6): [True: 18.2k, False: 144]
  ------------------
   37|    144|	if (pa->pdata) {
  ------------------
  |  Branch (37:6): [True: 144, False: 0]
  ------------------
   38|    144|		free(pa->pdata);
   39|    144|	}
   40|    144|	free(pa);
   41|    144|}
ptr_array_insert:
   44|  27.9k|{
   45|  27.9k|	if (!pa || !pa->pdata) return;
  ------------------
  |  Branch (45:6): [True: 0, False: 27.9k]
  |  Branch (45:13): [True: 0, False: 27.9k]
  ------------------
   46|  27.9k|	long remaining = pa->capacity-pa->len;
   47|  27.9k|	if (remaining == 0) {
  ------------------
  |  Branch (47:6): [True: 114, False: 27.7k]
  ------------------
   48|    114|		pa->pdata = (void**)realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step));
   49|    114|		pa->capacity += pa->capacity_step;
   50|    114|	}
   51|  27.9k|	if (array_index < 0 || array_index >= pa->len) {
  ------------------
  |  Branch (51:6): [True: 27.9k, False: 0]
  |  Branch (51:25): [True: 0, False: 0]
  ------------------
   52|  27.9k|		pa->pdata[pa->len] = data;
   53|  27.9k|	} 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|  27.9k|	pa->len++;
   58|  27.9k|}
ptr_array_add:
   61|  14.5k|{
   62|  14.5k|	ptr_array_insert(pa, data, -1);
   63|  14.5k|}

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

