summaryrefslogtreecommitdiffstats
path: root/src/plist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plist.c')
-rw-r--r--src/plist.c809
1 files changed, 596 insertions, 213 deletions
diff --git a/src/plist.c b/src/plist.c
index 27f90b1..2078520 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -2,7 +2,7 @@
* plist.c
* Builds plist XML structures
*
- * Copyright (c) 2009-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2009-2023 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2010-2015 Martin Szulecki, All Rights Reserved.
* Copyright (c) 2008 Zach C., All Rights Reserved.
*
@@ -34,6 +34,7 @@
#include <assert.h>
#include <limits.h>
#include <float.h>
+#include <ctype.h>
#ifdef WIN32
#include <windows.h>
@@ -42,28 +43,40 @@
#endif
#include <node.h>
+#include <node_list.h>
#include <hashtable.h>
#include <ptrarray.h>
+#ifdef _MSC_VER
+typedef SSIZE_T ssize_t;
+#endif
+
extern void plist_xml_init(void);
extern void plist_xml_deinit(void);
extern void plist_bin_init(void);
extern void plist_bin_deinit(void);
+extern void plist_json_init(void);
+extern void plist_json_deinit(void);
+extern void plist_ostep_init(void);
+extern void plist_ostep_deinit(void);
static void internal_plist_init(void)
{
plist_bin_init();
plist_xml_init();
+ plist_json_init();
+ plist_ostep_init();
}
static void internal_plist_deinit(void)
{
plist_bin_deinit();
plist_xml_deinit();
+ plist_json_deinit();
+ plist_ostep_deinit();
}
#ifdef WIN32
-
typedef volatile struct {
LONG lock;
int state;
@@ -72,7 +85,7 @@ typedef volatile struct {
static thread_once_t init_once = {0, 0};
static thread_once_t deinit_once = {0, 0};
-void thread_once(thread_once_t *once_control, void (*init_routine)(void))
+static void thread_once(thread_once_t *once_control, void (*init_routine)(void))
{
while (InterlockedExchange(&(once_control->lock), 1) != 0) {
Sleep(1);
@@ -83,7 +96,29 @@ void thread_once(thread_once_t *once_control, void (*init_routine)(void))
}
InterlockedExchange(&(once_control->lock), 0);
}
+#else
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_once_t deinit_once = PTHREAD_ONCE_INIT;
+#define thread_once pthread_once
+#endif
+
+#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
+ #if defined(__llvm__) || defined(__GNUC__)
+ #define HAVE_ATTRIBUTE_CONSTRUCTOR
+ #endif
+#endif
+
+#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
+static void __attribute__((constructor)) libplist_initialize(void)
+{
+ thread_once(&init_once, internal_plist_init);
+}
+static void __attribute__((destructor)) libplist_deinitialize(void)
+{
+ thread_once(&deinit_once, internal_plist_deinit);
+}
+#elif defined(WIN32)
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason) {
@@ -98,22 +133,8 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
}
return 1;
}
-
#else
-
-static pthread_once_t init_once = PTHREAD_ONCE_INIT;
-static pthread_once_t deinit_once = PTHREAD_ONCE_INIT;
-
-static void __attribute__((constructor)) libplist_initialize(void)
-{
- pthread_once(&init_once, internal_plist_init);
-}
-
-static void __attribute__((destructor)) libplist_deinitialize(void)
-{
- pthread_once(&deinit_once, internal_plist_deinit);
-}
-
+#warning No compiler support for constructor/destructor attributes, some features might not be available.
#endif
#ifndef HAVE_MEMMEM
@@ -166,7 +187,7 @@ void* memmem(const void* haystack, size_t haystack_len, const void* needle, size
}
#endif
-PLIST_API int plist_is_binary(const char *plist_data, uint32_t length)
+int plist_is_binary(const char *plist_data, uint32_t length)
{
if (length < 8) {
return 0;
@@ -175,19 +196,131 @@ PLIST_API int plist_is_binary(const char *plist_data, uint32_t length)
return (memcmp(plist_data, "bplist00", 8) == 0);
}
+#define SKIP_WS(blob, pos, len) \
+ while (pos < len && ((blob[pos] == ' ') || (blob[pos] == '\t') || (blob[pos] == '\r') || (blob[pos] == '\n'))) pos++;
+#define FIND_NEXT(blob, pos, len, chr) \
+ while (pos < len && (blob[pos] != chr)) pos++;
-PLIST_API void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist)
+plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format)
{
- if (length < 8) {
- *plist = NULL;
- return;
+ plist_err_t res = PLIST_ERR_UNKNOWN;
+ if (!plist) {
+ return PLIST_ERR_INVALID_ARG;
}
-
+ *plist = NULL;
+ if (!plist_data || length == 0) {
+ return PLIST_ERR_INVALID_ARG;
+ }
+ plist_format_t fmt = PLIST_FORMAT_NONE;
+ if (format) *format = PLIST_FORMAT_NONE;
if (plist_is_binary(plist_data, length)) {
- plist_from_bin(plist_data, length, plist);
+ res = plist_from_bin(plist_data, length, plist);
+ fmt = PLIST_FORMAT_BINARY;
} else {
- plist_from_xml(plist_data, length, plist);
+ uint32_t pos = 0;
+ int is_json = 0;
+ int is_xml = 0;
+ /* skip whitespace */
+ SKIP_WS(plist_data, pos, length);
+ if (pos >= length) {
+ return PLIST_ERR_PARSE;
+ }
+ if (plist_data[pos] == '<' && (length-pos > 3) && !isxdigit(plist_data[pos+1]) && !isxdigit(plist_data[pos+2]) && !isxdigit(plist_data[pos+3])) {
+ is_xml = 1;
+ } else if (plist_data[pos] == '[') {
+ /* only valid for json */
+ is_json = 1;
+ } else if (plist_data[pos] == '(') {
+ /* only valid for openstep */
+ } else if (plist_data[pos] == '{') {
+ /* this could be json or openstep */
+ pos++;
+ SKIP_WS(plist_data, pos, length);
+ if (pos >= length) {
+ return PLIST_ERR_PARSE;
+ }
+ if (plist_data[pos] == '"') {
+ /* still could be both */
+ pos++;
+ while (pos < length) {
+ FIND_NEXT(plist_data, pos, length, '"');
+ if (plist_data[pos-1] != '\\') {
+ break;
+ }
+ pos++;
+ }
+ if (pos >= length) {
+ return PLIST_ERR_PARSE;
+ }
+ if (plist_data[pos] == '"') {
+ pos++;
+ SKIP_WS(plist_data, pos, length);
+ if (pos >= length) {
+ return PLIST_ERR_PARSE;
+ }
+ if (plist_data[pos] == ':') {
+ /* this is definitely json */
+ is_json = 1;
+ }
+ }
+ }
+ }
+ if (is_xml) {
+ res = plist_from_xml(plist_data, length, plist);
+ fmt = PLIST_FORMAT_XML;
+ } else if (is_json) {
+ res = plist_from_json(plist_data, length, plist);
+ fmt = PLIST_FORMAT_JSON;
+ } else {
+ res = plist_from_openstep(plist_data, length, plist);
+ fmt = PLIST_FORMAT_OSTEP;
+ }
+ }
+ if (format && res == PLIST_ERR_SUCCESS) {
+ *format = fmt;
+ }
+ return res;
+}
+
+plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format)
+{
+ if (!filename || !plist) {
+ return PLIST_ERR_INVALID_ARG;
+ }
+ FILE *f = fopen(filename, "rb");
+ if (!f) {
+ return PLIST_ERR_IO;
+ }
+ struct stat fst;
+ fstat(fileno(f), &fst);
+ if ((uint64_t)fst.st_size > UINT32_MAX) {
+ return PLIST_ERR_NO_MEM;
+ }
+ uint32_t total = (uint32_t)fst.st_size;
+ if (total == 0) {
+ return PLIST_ERR_PARSE;
+ }
+ char *buf = (char*)malloc(total);
+ if (!buf) {
+ fclose(f);
+ return PLIST_ERR_NO_MEM;
}
+ uint32_t done = 0;
+ while (done < total) {
+ ssize_t r = fread(buf + done, 1, total - done, f);
+ if (r <= 0) {
+ break;
+ }
+ done += r;
+ }
+ fclose(f);
+ if (done < total) {
+ free(buf);
+ return PLIST_ERR_IO;
+ }
+ plist_err_t res = plist_from_memory(buf, total, plist, format);
+ free(buf);
+ return res;
}
plist_t plist_new_node(plist_data_t data)
@@ -195,11 +328,11 @@ plist_t plist_new_node(plist_data_t data)
return (plist_t) node_create(NULL, data);
}
-plist_data_t plist_get_data(const plist_t node)
+plist_data_t plist_get_data(plist_t node)
{
if (!node)
return NULL;
- return ((node_t*)node)->data;
+ return (plist_data_t)((node_t)node)->data;
}
plist_data_t plist_new_plist_data(void)
@@ -247,10 +380,10 @@ void plist_free_data(plist_data_t data)
free(data->buff);
break;
case PLIST_ARRAY:
- ptr_array_free(data->hashtable);
+ ptr_array_free((ptrarray_t*)data->hashtable);
break;
case PLIST_DICT:
- hash_table_destroy(data->hashtable);
+ hash_table_destroy((hashtable_t*)data->hashtable);
break;
default:
break;
@@ -259,7 +392,7 @@ void plist_free_data(plist_data_t data)
}
}
-static int plist_free_node(node_t* node)
+static int plist_free_node(node_t node)
{
plist_data_t data = NULL;
int node_index = node_detach(node->parent, node);
@@ -267,9 +400,9 @@ static int plist_free_node(node_t* node)
plist_free_data(data);
node->data = NULL;
- node_t *ch;
+ node_t ch;
for (ch = node_first_child(node); ch; ) {
- node_t *next = node_next_sibling(ch);
+ node_t next = node_next_sibling(ch);
plist_free_node(ch);
ch = next;
}
@@ -279,14 +412,14 @@ static int plist_free_node(node_t* node)
return node_index;
}
-PLIST_API plist_t plist_new_dict(void)
+plist_t plist_new_dict(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DICT;
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_array(void)
+plist_t plist_new_array(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_ARRAY;
@@ -303,7 +436,7 @@ static plist_t plist_new_key(const char *val)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_string(const char *val)
+plist_t plist_new_string(const char *val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_STRING;
@@ -312,7 +445,7 @@ PLIST_API plist_t plist_new_string(const char *val)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_bool(uint8_t val)
+plist_t plist_new_bool(uint8_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_BOOLEAN;
@@ -321,16 +454,25 @@ PLIST_API plist_t plist_new_bool(uint8_t val)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_uint(uint64_t val)
+plist_t plist_new_uint(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
- data->type = PLIST_UINT;
+ data->type = PLIST_INT;
+ data->intval = val;
+ data->length = (val > INT_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t);
+ return plist_new_node(data);
+}
+
+plist_t plist_new_int(int64_t val)
+{
+ plist_data_t data = plist_new_plist_data();
+ data->type = PLIST_INT;
data->intval = val;
data->length = sizeof(uint64_t);
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_uid(uint64_t val)
+plist_t plist_new_uid(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_UID;
@@ -339,7 +481,7 @@ PLIST_API plist_t plist_new_uid(uint64_t val)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_real(double val)
+plist_t plist_new_real(double val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_REAL;
@@ -348,7 +490,7 @@ PLIST_API plist_t plist_new_real(double val)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_data(const char *val, uint64_t length)
+plist_t plist_new_data(const char *val, uint64_t length)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATA;
@@ -358,7 +500,7 @@ PLIST_API plist_t plist_new_data(const char *val, uint64_t length)
return plist_new_node(data);
}
-PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec)
+plist_t plist_new_date(int32_t sec, int32_t usec)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATE;
@@ -367,15 +509,32 @@ PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec)
return plist_new_node(data);
}
-PLIST_API void plist_free(plist_t plist)
+plist_t plist_new_null(void)
+{
+ plist_data_t data = plist_new_plist_data();
+ data->type = PLIST_NULL;
+ data->intval = 0;
+ data->length = 0;
+ return plist_new_node(data);
+}
+
+void plist_free(plist_t plist)
{
if (plist)
{
- plist_free_node(plist);
+ plist_free_node((node_t)plist);
+ }
+}
+
+void plist_mem_free(void* ptr)
+{
+ if (ptr)
+ {
+ free(ptr);
}
}
-static plist_t plist_copy_node(node_t *node)
+static plist_t plist_copy_node(node_t node)
{
plist_type node_type = PLIST_NONE;
plist_t newnode = NULL;
@@ -395,7 +554,7 @@ static plist_t plist_copy_node(node_t *node)
break;
case PLIST_KEY:
case PLIST_STRING:
- newdata->strval = strdup((char *) data->strval);
+ newdata->strval = strdup(data->strval);
break;
case PLIST_ARRAY:
if (data->hashtable) {
@@ -416,13 +575,13 @@ static plist_t plist_copy_node(node_t *node)
}
newnode = plist_new_node(newdata);
- node_t *ch;
+ node_t ch;
unsigned int node_index = 0;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
/* copy child node */
plist_t newch = plist_copy_node(ch);
/* attach to new parent node */
- node_attach(newnode, newch);
+ node_attach((node_t)newnode, (node_t)newch);
/* if needed, add child node to lookup table of parent node */
switch (node_type) {
case PLIST_ARRAY:
@@ -432,7 +591,7 @@ static plist_t plist_copy_node(node_t *node)
break;
case PLIST_DICT:
if (newdata->hashtable && (node_index % 2 != 0)) {
- hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t*)newch))->data, newch);
+ hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t)newch))->data, newch);
}
break;
default:
@@ -443,136 +602,140 @@ static plist_t plist_copy_node(node_t *node)
return newnode;
}
-PLIST_API plist_t plist_copy(plist_t node)
+plist_t plist_copy(plist_t node)
{
- return node ? plist_copy_node(node) : NULL;
+ return node ? plist_copy_node((node_t)node) : NULL;
}
-PLIST_API uint32_t plist_array_get_size(plist_t node)
+uint32_t plist_array_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
- ret = node_n_children(node);
+ ret = node_n_children((node_t)node);
}
return ret;
}
-PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n)
+plist_t plist_array_get_item(plist_t node, uint32_t n)
{
plist_t ret = NULL;
if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
{
- ptrarray_t *pa = ((plist_data_t)((node_t*)node)->data)->hashtable;
+ ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
if (pa) {
ret = (plist_t)ptr_array_index(pa, n);
} else {
- ret = (plist_t)node_nth_child(node, n);
+ ret = (plist_t)node_nth_child((node_t)node, n);
}
}
return ret;
}
-PLIST_API uint32_t plist_array_get_item_index(plist_t node)
+uint32_t plist_array_get_item_index(plist_t node)
{
plist_t father = plist_get_parent(node);
if (PLIST_ARRAY == plist_get_node_type(father))
{
- return node_child_position(father, node);
+ return node_child_position((node_t)father, (node_t)node);
}
return UINT_MAX;
}
static void _plist_array_post_insert(plist_t node, plist_t item, long n)
{
- ptrarray_t *pa = ((plist_data_t)((node_t*)node)->data)->hashtable;
+ ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
if (pa) {
/* store pointer to item in array */
ptr_array_insert(pa, item, n);
} else {
- if (((node_t*)node)->count > 100) {
+ if (((node_t)node)->count > 100) {
/* make new lookup array */
pa = ptr_array_new(128);
plist_t current = NULL;
- for (current = (plist_t)node_first_child(node);
+ for (current = (plist_t)node_first_child((node_t)node);
pa && current;
- current = (plist_t)node_next_sibling(current))
+ current = (plist_t)node_next_sibling((node_t)current))
{
ptr_array_add(pa, current);
}
- ((plist_data_t)((node_t*)node)->data)->hashtable = pa;
+ ((plist_data_t)((node_t)node)->data)->hashtable = pa;
}
}
}
-PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n)
+void plist_array_set_item(plist_t node, plist_t item, uint32_t n)
{
+ if (!item) {
+ return;
+ }
if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
- int idx = plist_free_node(old_item);
+ int idx = plist_free_node((node_t)old_item);
assert(idx >= 0);
if (idx < 0) {
return;
- } else {
- node_insert(node, idx, item);
- ptrarray_t* pa = ((plist_data_t)((node_t*)node)->data)->hashtable;
- if (pa) {
- ptr_array_set(pa, item, idx);
- }
+ }
+ node_insert((node_t)node, idx, (node_t)item);
+ ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
+ if (pa) {
+ ptr_array_set(pa, item, idx);
}
}
}
- return;
}
-PLIST_API void plist_array_append_item(plist_t node, plist_t item)
+void plist_array_append_item(plist_t node, plist_t item)
{
+ if (!item) {
+ return;
+ }
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
- node_attach(node, item);
+ node_attach((node_t)node, (node_t)item);
_plist_array_post_insert(node, item, -1);
}
- return;
}
-PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n)
+void plist_array_insert_item(plist_t node, plist_t item, uint32_t n)
{
+ if (!item) {
+ return;
+ }
if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
{
- node_insert(node, n, item);
+ node_insert((node_t)node, n, (node_t)item);
_plist_array_post_insert(node, item, (long)n);
}
- return;
}
-PLIST_API void plist_array_remove_item(plist_t node, uint32_t n)
+void plist_array_remove_item(plist_t node, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
- ptrarray_t* pa = ((plist_data_t)((node_t*)node)->data)->hashtable;
+ ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
if (pa) {
ptr_array_remove(pa, n);
}
plist_free(old_item);
}
}
- return;
}
-PLIST_API void plist_array_item_remove(plist_t node)
+void plist_array_item_remove(plist_t node)
{
plist_t father = plist_get_parent(node);
if (PLIST_ARRAY == plist_get_node_type(father))
{
- int n = node_child_position(father, node);
+ int n = node_child_position((node_t)father, (node_t)node);
if (n < 0) return;
- ptrarray_t* pa = ((plist_data_t)((node_t*)father)->data)->hashtable;
+ ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)father)->data)->hashtable;
if (pa) {
ptr_array_remove(pa, n);
}
@@ -580,19 +743,18 @@ PLIST_API void plist_array_item_remove(plist_t node)
}
}
-PLIST_API void plist_array_new_iter(plist_t node, plist_array_iter *iter)
+void plist_array_new_iter(plist_t node, plist_array_iter *iter)
{
if (iter)
{
- *iter = malloc(sizeof(node_t*));
- *((node_t**)(*iter)) = node_first_child(node);
+ *iter = malloc(sizeof(node_t));
+ *((node_t*)(*iter)) = node_first_child((node_t)node);
}
- return;
}
-PLIST_API void plist_array_next_item(plist_t node, plist_array_iter iter, plist_t *item)
+void plist_array_next_item(plist_t node, plist_array_iter iter, plist_t *item)
{
- node_t** iter_node = (node_t**)iter;
+ node_t* iter_node = (node_t*)iter;
if (item)
{
@@ -607,32 +769,30 @@ PLIST_API void plist_array_next_item(plist_t node, plist_array_iter iter, plist_
}
*iter_node = node_next_sibling(*iter_node);
}
- return;
}
-PLIST_API uint32_t plist_dict_get_size(plist_t node)
+uint32_t plist_dict_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_DICT == plist_get_node_type(node))
{
- ret = node_n_children(node) / 2;
+ ret = node_n_children((node_t)node) / 2;
}
return ret;
}
-PLIST_API void plist_dict_new_iter(plist_t node, plist_dict_iter *iter)
+void plist_dict_new_iter(plist_t node, plist_dict_iter *iter)
{
if (iter)
{
- *iter = malloc(sizeof(node_t*));
- *((node_t**)(*iter)) = node_first_child(node);
+ *iter = malloc(sizeof(node_t));
+ *((node_t*)(*iter)) = node_first_child((node_t)node);
}
- return;
}
-PLIST_API void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val)
+void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val)
{
- node_t** iter_node = (node_t**)iter;
+ node_t* iter_node = (node_t*)iter;
if (key)
{
@@ -656,30 +816,29 @@ PLIST_API void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **k
}
*iter_node = node_next_sibling(*iter_node);
}
- return;
}
-PLIST_API void plist_dict_get_item_key(plist_t node, char **key)
+void plist_dict_get_item_key(plist_t node, char **key)
{
plist_t father = plist_get_parent(node);
if (PLIST_DICT == plist_get_node_type(father))
{
- plist_get_key_val( (plist_t) node_prev_sibling(node), key);
+ plist_get_key_val( (plist_t) node_prev_sibling((node_t)node), key);
}
}
-PLIST_API plist_t plist_dict_item_get_key(plist_t node)
+plist_t plist_dict_item_get_key(plist_t node)
{
plist_t ret = NULL;
plist_t father = plist_get_parent(node);
if (PLIST_DICT == plist_get_node_type(father))
{
- ret = (plist_t)node_prev_sibling(node);
+ ret = (plist_t)node_prev_sibling((node_t)node);
}
return ret;
}
-PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
+plist_t plist_dict_get_item(plist_t node, const char* key)
{
plist_t ret = NULL;
@@ -694,16 +853,16 @@ PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
ret = (plist_t)hash_table_lookup(ht, &sdata);
} else {
plist_t current = NULL;
- for (current = (plist_t)node_first_child(node);
+ for (current = (plist_t)node_first_child((node_t)node);
current;
- current = (plist_t)node_next_sibling(node_next_sibling(current)))
+ current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
{
data = plist_get_data(current);
assert( PLIST_KEY == plist_get_node_type(current) );
if (data && !strcmp(key, data->strval))
{
- ret = (plist_t)node_next_sibling(current);
+ ret = (plist_t)node_next_sibling((node_t)current);
break;
}
}
@@ -712,74 +871,69 @@ PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
return ret;
}
-PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item)
+void plist_dict_set_item(plist_t node, const char* key, plist_t item)
{
+ if (!item) {
+ return;
+ }
if (node && PLIST_DICT == plist_get_node_type(node)) {
- node_t* old_item = plist_dict_get_item(node, key);
+ plist_t old_item = plist_dict_get_item(node, key);
plist_t key_node = NULL;
if (old_item) {
- int idx = plist_free_node(old_item);
+ int idx = plist_free_node((node_t)old_item);
assert(idx >= 0);
if (idx < 0) {
return;
- } else {
- node_insert(node, idx, item);
}
- key_node = node_prev_sibling(item);
+ node_insert((node_t)node, idx, (node_t)item);
+ key_node = node_prev_sibling((node_t)item);
} else {
key_node = plist_new_key(key);
- node_attach(node, key_node);
- node_attach(node, item);
+ node_attach((node_t)node, (node_t)key_node);
+ node_attach((node_t)node, (node_t)item);
}
- hashtable_t *ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
+ hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
if (ht) {
/* store pointer to item in hash table */
- hash_table_insert(ht, (plist_data_t)((node_t*)key_node)->data, item);
+ hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
} else {
- if (((node_t*)node)->count > 500) {
+ if (((node_t)node)->count > 500) {
/* make new hash table */
ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
/* calculate the hashes for all entries we have so far */
plist_t current = NULL;
- for (current = (plist_t)node_first_child(node);
+ for (current = (plist_t)node_first_child((node_t)node);
ht && current;
- current = (plist_t)node_next_sibling(node_next_sibling(current)))
+ current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
{
- hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
+ hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
}
- ((plist_data_t)((node_t*)node)->data)->hashtable = ht;
+ ((plist_data_t)((node_t)node)->data)->hashtable = ht;
}
}
}
- return;
}
-PLIST_API void plist_dict_insert_item(plist_t node, const char* key, plist_t item)
-{
- plist_dict_set_item(node, key, item);
-}
-
-PLIST_API void plist_dict_remove_item(plist_t node, const char* key)
+void plist_dict_remove_item(plist_t node, const char* key)
{
if (node && PLIST_DICT == plist_get_node_type(node))
{
plist_t old_item = plist_dict_get_item(node, key);
if (old_item)
{
- plist_t key_node = node_prev_sibling(old_item);
- hashtable_t* ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
+ plist_t key_node = node_prev_sibling((node_t)old_item);
+ hashtable_t* ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
if (ht) {
- hash_table_remove(ht, ((node_t*)key_node)->data);
+ hash_table_remove(ht, ((node_t)key_node)->data);
}
plist_free(key_node);
plist_free(old_item);
}
}
- return;
}
-PLIST_API void plist_dict_merge(plist_t *target, plist_t source)
+void plist_dict_merge(plist_t *target, plist_t source)
{
if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT))
return;
@@ -800,10 +954,10 @@ PLIST_API void plist_dict_merge(plist_t *target, plist_t source)
free(key);
key = NULL;
} while (1);
- free(it);
+ free(it);
}
-PLIST_API plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
+plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
{
plist_t current = plist;
plist_type type = PLIST_NONE;
@@ -827,7 +981,7 @@ PLIST_API plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
return current;
}
-PLIST_API plist_t plist_access_path(plist_t plist, uint32_t length, ...)
+plist_t plist_access_path(plist_t plist, uint32_t length, ...)
{
plist_t ret = NULL;
va_list v;
@@ -855,7 +1009,7 @@ static void plist_get_type_and_value(plist_t node, plist_type * type, void *valu
case PLIST_BOOLEAN:
*((char *) value) = data->boolval;
break;
- case PLIST_UINT:
+ case PLIST_INT:
case PLIST_UID:
*((uint64_t *) value) = data->intval;
break;
@@ -878,12 +1032,12 @@ static void plist_get_type_and_value(plist_t node, plist_type * type, void *valu
}
}
-PLIST_API plist_t plist_get_parent(plist_t node)
+plist_t plist_get_parent(plist_t node)
{
- return node ? (plist_t) ((node_t*) node)->parent : NULL;
+ return node ? (plist_t) ((node_t) node)->parent : NULL;
}
-PLIST_API plist_type plist_get_node_type(plist_t node)
+plist_type plist_get_node_type(plist_t node)
{
if (node)
{
@@ -894,7 +1048,7 @@ PLIST_API plist_type plist_get_node_type(plist_t node)
return PLIST_NONE;
}
-PLIST_API void plist_get_key_val(plist_t node, char **val)
+void plist_get_key_val(plist_t node, char **val)
{
if (!node || !val)
return;
@@ -908,7 +1062,7 @@ PLIST_API void plist_get_key_val(plist_t node, char **val)
assert(length == strlen(*val));
}
-PLIST_API void plist_get_string_val(plist_t node, char **val)
+void plist_get_string_val(plist_t node, char **val)
{
if (!node || !val)
return;
@@ -922,7 +1076,7 @@ PLIST_API void plist_get_string_val(plist_t node, char **val)
assert(length == strlen(*val));
}
-PLIST_API const char* plist_get_string_ptr(plist_t node, uint64_t* length)
+const char* plist_get_string_ptr(plist_t node, uint64_t* length)
{
if (!node)
return NULL;
@@ -935,7 +1089,7 @@ PLIST_API const char* plist_get_string_ptr(plist_t node, uint64_t* length)
return (const char*)data->strval;
}
-PLIST_API void plist_get_bool_val(plist_t node, uint8_t * val)
+void plist_get_bool_val(plist_t node, uint8_t * val)
{
if (!node || !val)
return;
@@ -947,19 +1101,24 @@ PLIST_API void plist_get_bool_val(plist_t node, uint8_t * val)
assert(length == sizeof(uint8_t));
}
-PLIST_API void plist_get_uint_val(plist_t node, uint64_t * val)
+void plist_get_uint_val(plist_t node, uint64_t * val)
{
if (!node || !val)
return;
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
- if (PLIST_UINT != type)
+ if (PLIST_INT != type)
return;
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint64_t) || length == 16);
}
-PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val)
+void plist_get_int_val(plist_t node, int64_t * val)
+{
+ plist_get_uint_val(node, (uint64_t*)val);
+}
+
+void plist_get_uid_val(plist_t node, uint64_t * val)
{
if (!node || !val)
return;
@@ -971,7 +1130,7 @@ PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val)
assert(length == sizeof(uint64_t));
}
-PLIST_API void plist_get_real_val(plist_t node, double *val)
+void plist_get_real_val(plist_t node, double *val)
{
if (!node || !val)
return;
@@ -983,7 +1142,7 @@ PLIST_API void plist_get_real_val(plist_t node, double *val)
assert(length == sizeof(double));
}
-PLIST_API void plist_get_data_val(plist_t node, char **val, uint64_t * length)
+void plist_get_data_val(plist_t node, char **val, uint64_t * length)
{
if (!node || !val || !length)
return;
@@ -993,7 +1152,7 @@ PLIST_API void plist_get_data_val(plist_t node, char **val, uint64_t * length)
plist_get_type_and_value(node, &type, (void *) val, length);
}
-PLIST_API const char* plist_get_data_ptr(plist_t node, uint64_t* length)
+const char* plist_get_data_ptr(plist_t node, uint64_t* length)
{
if (!node || !length)
return NULL;
@@ -1005,7 +1164,7 @@ PLIST_API const char* plist_get_data_ptr(plist_t node, uint64_t* length)
return (const char*)data->buff;
}
-PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
+void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
{
if (!node)
return;
@@ -1019,7 +1178,10 @@ PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
if (sec)
*sec = (int32_t)val;
if (usec)
- *usec = (int32_t)fabs((val - (int64_t)val) * 1000000);
+ {
+ val = fabs((val - (int64_t)val) * 1000000);
+ *usec = (int32_t)val;
+ }
}
int plist_data_compare(const void *a, const void *b)
@@ -1030,7 +1192,7 @@ int plist_data_compare(const void *a, const void *b)
if (!a || !b)
return FALSE;
- if (!((node_t*) a)->data || !((node_t*) b)->data)
+ if (!((node_t) a)->data || !((node_t) b)->data)
return FALSE;
val_a = plist_get_data((plist_t) a);
@@ -1042,46 +1204,36 @@ int plist_data_compare(const void *a, const void *b)
switch (val_a->type)
{
case PLIST_BOOLEAN:
- case PLIST_UINT:
+ case PLIST_NULL:
+ case PLIST_INT:
case PLIST_REAL:
case PLIST_DATE:
case PLIST_UID:
if (val_a->length != val_b->length)
return FALSE;
- if (val_a->intval == val_b->intval) //it is an union so this is sufficient
- return TRUE;
- else
- return FALSE;
+ return val_a->intval == val_b->intval; //it is an union so this is sufficient
case PLIST_KEY:
case PLIST_STRING:
- if (!strcmp(val_a->strval, val_b->strval))
- return TRUE;
- else
- return FALSE;
+ return strcmp(val_a->strval, val_b->strval) == 0;
case PLIST_DATA:
if (val_a->length != val_b->length)
return FALSE;
- if (!memcmp(val_a->buff, val_b->buff, val_a->length))
- return TRUE;
- else
- return FALSE;
+ return memcmp(val_a->buff, val_b->buff, val_a->length) == 0;
+
case PLIST_ARRAY:
case PLIST_DICT:
//compare pointer
- if (a == b)
- return TRUE;
- else
- return FALSE;
- break;
+ return a == b;
+
default:
break;
}
return FALSE;
}
-PLIST_API char plist_compare_node_value(plist_t node_l, plist_t node_r)
+char plist_compare_node_value(plist_t node_l, plist_t node_r)
{
return plist_data_compare(node_l, node_r);
}
@@ -1117,7 +1269,7 @@ static void plist_set_element_val(plist_t node, plist_type type, const void *val
case PLIST_BOOLEAN:
data->boolval = *((char *) value);
break;
- case PLIST_UINT:
+ case PLIST_INT:
case PLIST_UID:
data->intval = *((uint64_t *) value);
break;
@@ -1140,7 +1292,7 @@ static void plist_set_element_val(plist_t node, plist_type type, const void *val
}
}
-PLIST_API void plist_set_key_val(plist_t node, const char *val)
+void plist_set_key_val(plist_t node, const char *val)
{
plist_t father = plist_get_parent(node);
plist_t item = plist_dict_get_item(father, val);
@@ -1150,43 +1302,48 @@ PLIST_API void plist_set_key_val(plist_t node, const char *val)
plist_set_element_val(node, PLIST_KEY, val, strlen(val));
}
-PLIST_API void plist_set_string_val(plist_t node, const char *val)
+void plist_set_string_val(plist_t node, const char *val)
{
plist_set_element_val(node, PLIST_STRING, val, strlen(val));
}
-PLIST_API void plist_set_bool_val(plist_t node, uint8_t val)
+void plist_set_bool_val(plist_t node, uint8_t val)
{
plist_set_element_val(node, PLIST_BOOLEAN, &val, sizeof(uint8_t));
}
-PLIST_API void plist_set_uint_val(plist_t node, uint64_t val)
+void plist_set_uint_val(plist_t node, uint64_t val)
+{
+ plist_set_element_val(node, PLIST_INT, &val, (val > INT64_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t));
+}
+
+void plist_set_int_val(plist_t node, int64_t val)
{
- plist_set_element_val(node, PLIST_UINT, &val, sizeof(uint64_t));
+ plist_set_element_val(node, PLIST_INT, &val, sizeof(uint64_t));
}
-PLIST_API void plist_set_uid_val(plist_t node, uint64_t val)
+void plist_set_uid_val(plist_t node, uint64_t val)
{
plist_set_element_val(node, PLIST_UID, &val, sizeof(uint64_t));
}
-PLIST_API void plist_set_real_val(plist_t node, double val)
+void plist_set_real_val(plist_t node, double val)
{
plist_set_element_val(node, PLIST_REAL, &val, sizeof(double));
}
-PLIST_API void plist_set_data_val(plist_t node, const char *val, uint64_t length)
+void plist_set_data_val(plist_t node, const char *val, uint64_t length)
{
plist_set_element_val(node, PLIST_DATA, val, length);
}
-PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
+void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
{
double val = (double)sec + (double)usec / 1000000;
plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval));
}
-PLIST_API int plist_bool_val_is_true(plist_t boolnode)
+int plist_bool_val_is_true(plist_t boolnode)
{
if (!PLIST_IS_BOOLEAN(boolnode)) {
return 0;
@@ -1196,23 +1353,58 @@ PLIST_API int plist_bool_val_is_true(plist_t boolnode)
return (bv == 1);
}
-PLIST_API int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval)
+int plist_int_val_is_negative(plist_t intnode)
+{
+ if (!PLIST_IS_INT(intnode)) {
+ return 0;
+ }
+ plist_data_t data = plist_get_data(intnode);
+ if (data->length == 16) {
+ return 0;
+ }
+ if ((int64_t)data->intval < 0) {
+ return 1;
+ }
+ return 0;
+}
+
+int plist_int_val_compare(plist_t uintnode, int64_t cmpval)
+{
+ if (!PLIST_IS_INT(uintnode)) {
+ return -1;
+ }
+ int64_t uintval = 0;
+ plist_get_int_val(uintnode, &uintval);
+ if (uintval == cmpval) {
+ return 0;
+ }
+
+ if (uintval < cmpval) {
+ return -1;
+ }
+
+ return 1;
+}
+
+int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval)
{
- if (!PLIST_IS_UINT(uintnode)) {
+ if (!PLIST_IS_INT(uintnode)) {
return -1;
}
uint64_t uintval = 0;
plist_get_uint_val(uintnode, &uintval);
if (uintval == cmpval) {
return 0;
- } else if (uintval < cmpval) {
+ }
+
+ if (uintval < cmpval) {
return -1;
- } else {
- return 1;
}
+
+ return 1;
}
-PLIST_API int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval)
+int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval)
{
if (!PLIST_IS_UID(uidnode)) {
return -1;
@@ -1221,14 +1413,16 @@ PLIST_API int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval)
plist_get_uid_val(uidnode, &uidval);
if (uidval == cmpval) {
return 0;
- } else if (uidval < cmpval) {
+ }
+
+ if (uidval < cmpval) {
return -1;
- } else {
- return 1;
}
+
+ return 1;
}
-PLIST_API int plist_real_val_compare(plist_t realnode, double cmpval)
+int plist_real_val_compare(plist_t realnode, double cmpval)
{
if (!PLIST_IS_REAL(realnode)) {
return -1;
@@ -1241,23 +1435,29 @@ PLIST_API int plist_real_val_compare(plist_t realnode, double cmpval)
double diff = fabs(a - b);
if (a == b) {
return 0;
- } else if (a == 0 || b == 0 || (abs_a + abs_b < DBL_MIN)) {
+ }
+
+ if (a == 0 || b == 0 || (abs_a + abs_b < DBL_MIN)) {
if (diff < (DBL_EPSILON * DBL_MIN)) {
return 0;
- } else if (a < b) {
+ }
+
+ if (a < b) {
return -1;
}
} else {
if ((diff / fmin(abs_a + abs_b, DBL_MAX)) < DBL_EPSILON) {
return 0;
- } else if (a < b) {
+ }
+
+ if (a < b) {
return -1;
}
}
return 1;
}
-PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec)
+int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec)
{
if (!PLIST_IS_DATE(datenode)) {
return -1;
@@ -1269,14 +1469,16 @@ PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t c
uint64_t cmpval = ((int64_t)cmpsec << 32) | cmpusec;
if (dateval == cmpval) {
return 0;
- } else if (dateval < cmpval) {
+ }
+
+ if (dateval < cmpval) {
return -1;
- } else {
- return 1;
}
+
+ return 1;
}
-PLIST_API int plist_string_val_compare(plist_t strnode, const char* cmpval)
+int plist_string_val_compare(plist_t strnode, const char* cmpval)
{
if (!PLIST_IS_STRING(strnode)) {
return -1;
@@ -1285,7 +1487,7 @@ PLIST_API int plist_string_val_compare(plist_t strnode, const char* cmpval)
return strcmp(data->strval, cmpval);
}
-PLIST_API int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n)
+int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n)
{
if (!PLIST_IS_STRING(strnode)) {
return -1;
@@ -1294,7 +1496,7 @@ PLIST_API int plist_string_val_compare_with_size(plist_t strnode, const char* cm
return strncmp(data->strval, cmpval, n);
}
-PLIST_API int plist_string_val_contains(plist_t strnode, const char* substr)
+int plist_string_val_contains(plist_t strnode, const char* substr)
{
if (!PLIST_IS_STRING(strnode)) {
return 0;
@@ -1303,7 +1505,7 @@ PLIST_API int plist_string_val_contains(plist_t strnode, const char* substr)
return (strstr(data->strval, substr) != NULL);
}
-PLIST_API int plist_key_val_compare(plist_t keynode, const char* cmpval)
+int plist_key_val_compare(plist_t keynode, const char* cmpval)
{
if (!PLIST_IS_KEY(keynode)) {
return -1;
@@ -1312,7 +1514,7 @@ PLIST_API int plist_key_val_compare(plist_t keynode, const char* cmpval)
return strcmp(data->strval, cmpval);
}
-PLIST_API int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n)
+int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n)
{
if (!PLIST_IS_KEY(keynode)) {
return -1;
@@ -1321,7 +1523,7 @@ PLIST_API int plist_key_val_compare_with_size(plist_t keynode, const char* cmpva
return strncmp(data->strval, cmpval, n);
}
-PLIST_API int plist_key_val_contains(plist_t keynode, const char* substr)
+int plist_key_val_contains(plist_t keynode, const char* substr)
{
if (!PLIST_IS_KEY(keynode)) {
return 0;
@@ -1330,7 +1532,7 @@ PLIST_API int plist_key_val_contains(plist_t keynode, const char* substr)
return (strstr(data->strval, substr) != NULL);
}
-PLIST_API int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n)
+int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n)
{
if (!PLIST_IS_DATA(datanode)) {
return -1;
@@ -1338,13 +1540,16 @@ PLIST_API int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, si
plist_data_t data = plist_get_data(datanode);
if (data->length < n) {
return -1;
- } else if (data->length > n) {
+ }
+
+ if (data->length > n) {
return 1;
}
+
return memcmp(data->buff, cmpval, n);
}
-PLIST_API int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n)
+int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n)
{
if (!PLIST_IS_DATA(datanode)) {
return -1;
@@ -1356,7 +1561,7 @@ PLIST_API int plist_data_val_compare_with_size(plist_t datanode, const uint8_t*
return memcmp(data->buff, cmpval, n);
}
-PLIST_API int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n)
+int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n)
{
if (!PLIST_IS_DATA(datanode)) {
return -1;
@@ -1364,3 +1569,181 @@ PLIST_API int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, s
plist_data_t data = plist_get_data(datanode);
return (memmem(data->buff, data->length, cmpval, n) != NULL);
}
+
+extern void plist_xml_set_debug(int debug);
+extern void plist_bin_set_debug(int debug);
+extern void plist_json_set_debug(int debug);
+extern void plist_ostep_set_debug(int debug);
+
+void plist_set_debug(int debug)
+{
+ plist_xml_set_debug(debug);
+ plist_bin_set_debug(debug);
+ plist_json_set_debug(debug);
+ plist_ostep_set_debug(debug);
+}
+
+void plist_sort(plist_t plist)
+{
+ if (!plist) {
+ return;
+ }
+ if (PLIST_IS_ARRAY(plist)) {
+ uint32_t n = plist_array_get_size(plist);
+ uint32_t i = 0;
+ for (i = 0; i < n; i++) {
+ plist_sort(plist_array_get_item(plist, i));
+ }
+ } else if (PLIST_IS_DICT(plist)) {
+ node_t node = (node_t)plist;
+ node_t ch;
+ for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
+ ch = node_next_sibling(ch);
+ plist_sort((plist_t)ch);
+ }
+ #define KEY_DATA(x) (x->data)
+ #define NEXT_KEY(x) (x->next->next)
+ #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval
+ int swapped = 0;
+ do {
+ swapped = 0;
+ node_t lptr = NULL;
+ node_t cur_key = node_first_child((node_t)plist);
+
+ while (NEXT_KEY(cur_key) != lptr) {
+ node_t next_key = NEXT_KEY(cur_key);
+ if (strcmp(KEY_STRVAL(cur_key), KEY_STRVAL(next_key)) > 0) {
+ node_t cur_val = cur_key->next;
+ node_t next_val = next_key->next;
+ // we need to swap 2 consecutive nodes with the 2 after them
+ // a -> b -> [c] -> [d] -> [e] -> [f] -> g -> h
+ // cur next
+ // swapped:
+ // a -> b -> [e] -> [f] -> [c] -> [d] -> g -> h
+ // next cur
+ node_t tmp_prev = cur_key->prev;
+ node_t tmp_next = next_val->next;
+ cur_key->prev = next_val;
+ cur_val->next = tmp_next;
+ next_val->next = cur_key;
+ next_key->prev = tmp_prev;
+ if (tmp_prev) {
+ tmp_prev->next = next_key;
+ } else {
+ ((node_t)plist)->children->begin = next_key;
+ }
+ if (tmp_next) {
+ tmp_next->prev = cur_val;
+ } else {
+ ((node_t)plist)->children->end = cur_val;
+ }
+ cur_key = next_key;
+ swapped = 1;
+ }
+ cur_key = NEXT_KEY(cur_key);
+ }
+ lptr = cur_key;
+ } while (swapped);
+ }
+}
+
+plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length, plist_format_t format, plist_write_options_t options)
+{
+ plist_err_t err = PLIST_ERR_UNKNOWN;
+ switch (format) {
+ case PLIST_FORMAT_XML:
+ err = plist_to_xml(plist, output, length);
+ break;
+ case PLIST_FORMAT_JSON:
+ err = plist_to_json(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0));
+ break;
+ case PLIST_FORMAT_OSTEP:
+ err = plist_to_openstep(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0));
+ break;
+ case PLIST_FORMAT_PRINT:
+ err = plist_write_to_string_default(plist, output, length, options);
+ break;
+ case PLIST_FORMAT_LIMD:
+ err = plist_write_to_string_limd(plist, output, length, options);
+ break;
+ case PLIST_FORMAT_PLUTIL:
+ err = plist_write_to_string_plutil(plist, output, length, options);
+ break;
+ default:
+ // unsupported output format
+ err = PLIST_ERR_FORMAT;
+ break;
+ }
+ return err;
+}
+
+plist_err_t plist_write_to_stream(plist_t plist, FILE *stream, plist_format_t format, plist_write_options_t options)
+{
+ if (!plist || !stream) {
+ return PLIST_ERR_INVALID_ARG;
+ }
+ plist_err_t err = PLIST_ERR_UNKNOWN;
+ char *output = NULL;
+ uint32_t length = 0;
+ switch (format) {
+ case PLIST_FORMAT_BINARY:
+ err = plist_to_bin(plist, &output, &length);
+ break;
+ case PLIST_FORMAT_XML:
+ err = plist_to_xml(plist, &output, &length);
+ break;
+ case PLIST_FORMAT_JSON:
+ err = plist_to_json(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0));
+ break;
+ case PLIST_FORMAT_OSTEP:
+ err = plist_to_openstep(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0));
+ break;
+ case PLIST_FORMAT_PRINT:
+ err = plist_write_to_stream_default(plist, stream, options);
+ break;
+ case PLIST_FORMAT_LIMD:
+ err = plist_write_to_stream_limd(plist, stream, options);
+ break;
+ case PLIST_FORMAT_PLUTIL:
+ err = plist_write_to_stream_plutil(plist, stream, options);
+ break;
+ default:
+ // unsupported output format
+ err = PLIST_ERR_FORMAT;
+ break;
+ }
+ if (output && err == PLIST_ERR_SUCCESS) {
+ if (fwrite(output, 1, length, stream) < length) {
+ err = PLIST_ERR_IO;
+ }
+ free(output);
+ }
+ return err;
+}
+
+plist_err_t plist_write_to_file(plist_t plist, const char* filename, plist_format_t format, plist_write_options_t options)
+{
+ if (!plist || !filename) {
+ return PLIST_ERR_INVALID_ARG;
+ }
+ FILE* f = fopen(filename, "wb");
+ if (!f) {
+ return PLIST_ERR_IO;
+ }
+ plist_err_t err = plist_write_to_stream(plist, f, format, options);
+ fclose(f);
+ return err;
+}
+
+void plist_print(plist_t plist)
+{
+ plist_write_to_stream(plist, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_PARTIAL_DATA);
+}
+
+const char* libplist_version()
+{
+#ifndef PACKAGE_VERSION
+#error PACKAGE_VERSION is not defined!
+#endif
+ return PACKAGE_VERSION;
+}