summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/cbuf.c6
-rw-r--r--src/collection.c12
-rw-r--r--src/common.h18
-rw-r--r--src/glue.c8
-rw-r--r--src/nskeyedarchive.c1228
-rw-r--r--src/opack.c10
-rw-r--r--src/socket.c394
-rw-r--r--src/termcolors.c10
-rw-r--r--src/thread.c45
-rw-r--r--src/tlv.c14
-rw-r--r--src/utils.c256
12 files changed, 1590 insertions, 412 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b709103..0db7ede 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,6 +12,7 @@ libimobiledevice_glue_1_0_la_SOURCES = \
socket.c \
thread.c \
utils.c \
+ nskeyedarchive.c \
collection.c \
termcolors.c \
cbuf.c \
diff --git a/src/cbuf.c b/src/cbuf.c
index c7c931f..0beeb2a 100644
--- a/src/cbuf.c
+++ b/src/cbuf.c
@@ -30,7 +30,7 @@
#include "common.h"
#include "libimobiledevice-glue/cbuf.h"
-LIBIMOBILEDEVICE_GLUE_API struct char_buf* char_buf_new()
+struct char_buf* char_buf_new()
{
struct char_buf* cbuf = (struct char_buf*)malloc(sizeof(struct char_buf));
cbuf->capacity = 256;
@@ -39,7 +39,7 @@ LIBIMOBILEDEVICE_GLUE_API struct char_buf* char_buf_new()
return cbuf;
}
-LIBIMOBILEDEVICE_GLUE_API void char_buf_free(struct char_buf* cbuf)
+void char_buf_free(struct char_buf* cbuf)
{
if (cbuf) {
free(cbuf->data);
@@ -47,7 +47,7 @@ LIBIMOBILEDEVICE_GLUE_API void char_buf_free(struct char_buf* cbuf)
}
}
-LIBIMOBILEDEVICE_GLUE_API void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data)
+void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data)
{
if (!cbuf || !cbuf->data) {
return;
diff --git a/src/collection.c b/src/collection.c
index ef47217..0744427 100644
--- a/src/collection.c
+++ b/src/collection.c
@@ -37,7 +37,7 @@
#define CAPACITY_STEP 8
-LIBIMOBILEDEVICE_GLUE_API void collection_init(struct collection *col)
+void collection_init(struct collection *col)
{
col->list = malloc(sizeof(void *) * CAPACITY_STEP);
assert(col->list);
@@ -45,14 +45,14 @@ LIBIMOBILEDEVICE_GLUE_API void collection_init(struct collection *col)
col->capacity = CAPACITY_STEP;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_free(struct collection *col)
+void collection_free(struct collection *col)
{
free(col->list);
col->list = NULL;
col->capacity = 0;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_add(struct collection *col, void *element)
+void collection_add(struct collection *col, void *element)
{
int i;
for(i=0; i<col->capacity; i++) {
@@ -69,7 +69,7 @@ LIBIMOBILEDEVICE_GLUE_API void collection_add(struct collection *col, void *elem
col->capacity += CAPACITY_STEP;
}
-LIBIMOBILEDEVICE_GLUE_API int collection_remove(struct collection *col, void *element)
+int collection_remove(struct collection *col, void *element)
{
int i;
for(i=0; i<col->capacity; i++) {
@@ -82,7 +82,7 @@ LIBIMOBILEDEVICE_GLUE_API int collection_remove(struct collection *col, void *el
return -1;
}
-LIBIMOBILEDEVICE_GLUE_API int collection_count(struct collection *col)
+int collection_count(struct collection *col)
{
int i, cnt = 0;
for(i=0; i<col->capacity; i++) {
@@ -92,7 +92,7 @@ LIBIMOBILEDEVICE_GLUE_API int collection_count(struct collection *col)
return cnt;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_copy(struct collection *dest, struct collection *src)
+void collection_copy(struct collection *dest, struct collection *src)
{
if (!dest || !src) return;
dest->capacity = src->capacity;
diff --git a/src/common.h b/src/common.h
index bd22e3d..94b5fdd 100644
--- a/src/common.h
+++ b/src/common.h
@@ -25,14 +25,18 @@
#include <config.h>
#endif
-#ifdef WIN32
-#define LIBIMOBILEDEVICE_GLUE_API __declspec( dllexport )
+#ifdef LIMD_GLUE_STATIC
+ #define LIMD_GLUE_API
+#elif defined(_WIN32)
+ #define LIMD_GLUE_API __declspec( dllexport )
#else
-#ifdef HAVE_FVISIBILITY
-#define LIBIMOBILEDEVICE_GLUE_API __attribute__((visibility("default")))
-#else
-#define LIBIMOBILEDEVICE_GLUE_API
-#endif
+ #if __GNUC__ >= 4
+ #define LIMD_GLUE_API __attribute__((visibility("default")))
+ #else
+ #define LIMD_GLUE_API
+ #endif
#endif
+#include "libimobiledevice-glue/glue.h"
+
#endif
diff --git a/src/glue.c b/src/glue.c
index 7970679..1499a0d 100644
--- a/src/glue.c
+++ b/src/glue.c
@@ -78,3 +78,11 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
#else
#warning No compiler support for constructor/destructor attributes, some features might not be available.
#endif
+
+const char* libimobiledevice_glue_version()
+{
+#ifndef PACKAGE_VERSION
+#error PACKAGE_VERSION is not defined!
+#endif
+ return PACKAGE_VERSION;
+}
diff --git a/src/nskeyedarchive.c b/src/nskeyedarchive.c
new file mode 100644
index 0000000..b3dbdc4
--- /dev/null
+++ b/src/nskeyedarchive.c
@@ -0,0 +1,1228 @@
+/*
+ * nskeyedarchive.c
+ * Helper code to work with plist files containing NSKeyedArchiver data.
+ *
+ * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <plist/plist.h>
+#include "common.h"
+#include "libimobiledevice-glue/nskeyedarchive.h"
+
+#define NS_KEYED_ARCHIVER_NAME "NSKeyedArchiver"
+#define NS_KEYED_ARCHIVER_VERSION 100000
+
+struct nskeyedarchive_st {
+ plist_t dict;
+ uint64_t uid;
+};
+
+nskeyedarchive_t nskeyedarchive_new(void)
+{
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "$version", plist_new_uint(NS_KEYED_ARCHIVER_VERSION));
+ plist_t objects = plist_new_array();
+ plist_array_append_item(objects, plist_new_string("$null"));
+ plist_dict_set_item(dict, "$objects", objects);
+ plist_dict_set_item(dict, "$archiver", plist_new_string(NS_KEYED_ARCHIVER_NAME));
+
+ nskeyedarchive_t nskeyed = (nskeyedarchive_t)malloc(sizeof(struct nskeyedarchive_st));
+ nskeyed->dict = dict;
+ nskeyed->uid = 1;
+ return nskeyed;
+}
+
+void nskeyedarchive_free(nskeyedarchive_t ka)
+{
+ if (ka) {
+ if (ka->dict) {
+ plist_free(ka->dict);
+ }
+ free(ka);
+ }
+}
+
+void nskeyedarchive_set_top_ref_key_name(nskeyedarchive_t ka, const char* keyname)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (top) {
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(top, &iter);
+ if (iter) {
+ plist_t node = NULL;
+ char* keyn = NULL;
+ plist_dict_next_item(top, iter, &keyn, &node);
+ plist_t keynode = plist_dict_item_get_key(node);
+ plist_set_key_val(keynode, keyname);
+ free(keyn);
+ free(iter);
+ }
+ }
+}
+
+plist_t nskeyedarchive_get_objects(nskeyedarchive_t ka)
+{
+ plist_t objects = plist_dict_get_item(ka->dict, "$objects");
+ if (!objects || (plist_get_node_type(objects) != PLIST_ARRAY)) {
+ fprintf(stderr, "ERROR: $objects node not found!\n");
+ return NULL;
+ }
+
+ return objects;
+}
+
+plist_t nskeyedarchive_get_object_by_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t objects = nskeyedarchive_get_objects(ka);
+ if (!objects) {
+ return NULL;
+ }
+
+ plist_t obj = plist_array_get_item(objects, (uint32_t)uid);
+ if (!obj) {
+ fprintf(stderr, "ERROR: unable to get object node with uid %llu\n", (long long)uid);
+ return NULL;
+ }
+
+ return obj;
+}
+
+plist_t nskeyedarchive_get_class_by_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t ret = nskeyedarchive_get_object_by_uid(ka, uid);
+ if (ret && (plist_get_node_type(ret) != PLIST_DICT)) {
+ fprintf(stderr, "ERROR: the uid %llu does not reference a valid class with node type PLIST_DICT!\n", (long long)uid);
+ return NULL;
+ }
+
+ return ret;
+}
+
+void nskeyedarchive_append_object(nskeyedarchive_t ka, plist_t object)
+{
+ plist_t objects = nskeyedarchive_get_objects(ka);
+ if (objects && plist_get_node_type(objects) != PLIST_ARRAY) {
+ fprintf(stderr, "ERROR: unable to append object\n");
+ return;
+ }
+
+ plist_array_append_item(objects, object);
+}
+
+static void nskeyedarchive_append_class_v(nskeyedarchive_t ka, const char* classname, va_list* va)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return;
+ }
+
+ char* arg = NULL;
+ plist_t classes = NULL;
+ do {
+ arg = (char*)va_arg(*va, char*);
+ if (!arg) {
+ break;
+ }
+ if (!classes) {
+ classes = plist_new_array();
+ plist_array_append_item(classes, plist_new_string(classname));
+ }
+ plist_array_append_item(classes, plist_new_string(arg));
+ } while (arg);
+
+ plist_t cls = plist_new_dict();
+ plist_dict_set_item(cls, "$class", plist_new_uid(++ka->uid));
+
+ nskeyedarchive_append_object(ka, cls);
+
+ cls = plist_new_dict();
+ if (classes) {
+ plist_dict_set_item(cls, "$classes", classes);
+ }
+ plist_dict_set_item(cls, "$classname", plist_new_string(classname));
+
+ nskeyedarchive_append_object(ka, cls);
+}
+
+void nskeyedarchive_append_class(nskeyedarchive_t ka, const char* classname, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return;
+ }
+
+ va_list va;
+ va_start(va, classname);
+ nskeyedarchive_append_class_v(ka, classname, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_add_top_class_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(uid));
+ plist_dict_set_item(ka->dict, "$top", top);
+ } else {
+ uint32_t num = plist_dict_get_size(top);
+ char newkey[8];
+ sprintf(newkey, "$%d", num);
+ plist_dict_set_item(top, newkey, plist_new_uid(uid));
+ }
+}
+
+uint64_t nskeyedarchive_add_top_class(nskeyedarchive_t ka, const char* classname, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return 0;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return 0;
+ }
+
+ uint64_t uid = ka->uid;
+
+ va_list va;
+ va_start(va, classname);
+ nskeyedarchive_append_class_v(ka, classname, &va);
+ va_end(va);
+
+ nskeyedarchive_add_top_class_uid(ka, uid);
+ return uid;
+}
+
+static void nskeyedarchive_set_class_property_v(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, va_list* va);
+
+static void nskeyedarchive_nsarray_append(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, ...);
+
+static void nskeyedarchive_nsarray_append_v(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, va_list* va)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!array) {
+ fprintf(stderr, "%s: ERROR: missing plist!\n", __func__);
+ return;
+ }
+
+ uint64_t newuid;
+
+ switch (type) {
+ case NSTYPE_INTEGER:
+ plist_array_append_item(array, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_INTREF:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ plist_array_append_item(array, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_STRING:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_REAL:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_real(va_arg(*va, double)));
+ break;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLESTRING) {
+ nskeyedarchive_append_class(ka, "NSMutableString", "NSString", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSString", "NSObject", NULL);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.string", NSTYPE_CHARS, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEARRAY) {
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSArray", "NSObject", NULL);
+ }
+ {
+ plist_t arr = plist_new_array();
+ do {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append_v(ka, arr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ plist_free(arr);
+ }
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEDICTIONARY) {
+ nskeyedarchive_append_class(ka, "NSMutableDictionary", "NSDictionary", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+ }
+ {
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+ do {
+ char* key = va_arg(*va, char*);
+ if (!key)
+ break;
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, valarr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ }
+ break;
+ case NSTYPE_NSDATE:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDate", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.time", NSTYPE_REAL, va_arg(*va, double));
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableData", "NSData", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.data", NSTYPE_DATA, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSURL:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSURL", "NSObject", NULL);
+ {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.base", ptype, va);
+ ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.relative", ptype, va);
+ }
+ break;
+ case NSTYPE_NSKEYEDARCHIVE:
+ {
+ nskeyedarchive_t pka = va_arg(*va, nskeyedarchive_t);
+ if (!pka) {
+ fprintf(stderr, "%s: ERROR: no nskeyedarchive argument given for type NSTYPE_NSKEYEDARCHIVE\n", __func__);
+ return;
+ }
+ uint64_t top = nskeyedarchive_get_class_uid(pka, NULL);
+ if (top != 0) {
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+
+ plist_t object = nskeyedarchive_get_object_by_uid(pka, top);
+ if (!object) {
+ fprintf(stderr, "%s: ERROR: can't get object for uid %lld\n", __func__, (long long)top);
+ return;
+ }
+
+ plist_t objcopy = plist_copy(object);
+ nskeyedarchive_append_object(ka, objcopy);
+ nskeyedarchive_merge_object(ka, pka, objcopy);
+ }
+ }
+ break;
+ case NSTYPE_FROM_PLIST:
+ {
+ plist_t plist = va_arg(*va, plist_t);
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: no plist argument given for NSTYPE_PLIST\n", __func__);
+ return;
+ }
+ switch (plist_get_node_type(plist)) {
+ case PLIST_STRING:
+ {
+ char* str = NULL;
+ plist_get_string_val(plist, &str);
+ nskeyedarchive_nsarray_append(ka, array, NSTYPE_NSMUTABLESTRING, str, NULL);
+ } break;
+ case PLIST_DICT:
+ {
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(plist, &iter);
+
+ char *key = NULL;
+ plist_t node = NULL;
+
+ do {
+ plist_dict_next_item(plist, iter, &key, &node);
+ if (key) {
+ int ptype = 0;
+ uint8_t bv = 0;
+ uint64_t u64val = 0;
+ int intval = 0;
+ char *str = NULL;
+ void *val = NULL;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ switch (plist_get_node_type(node)) {
+ case PLIST_BOOLEAN: {
+ ptype = NSTYPE_BOOLEAN;
+ plist_get_bool_val(node, &bv);
+ intval = bv;
+ val = &intval;
+ } break;
+ case PLIST_UINT:
+ ptype = NSTYPE_INTEGER;
+ plist_get_uint_val(node, &u64val);
+ val = &u64val;
+ break;
+ case PLIST_STRING:
+ ptype = NSTYPE_STRING;
+ plist_get_string_val(node, &str);
+ val = str;
+ break;
+ default:
+ fprintf(stderr, "Unhandled plist type when parsing plist_dict\n");
+ break;
+ }
+ nskeyedarchive_nsarray_append(ka, valarr, ptype, val);
+ }
+ free(key);
+ } while (node);
+
+ free(iter);
+
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ } break;
+ default:
+ fprintf(stderr, "%s: ERROR: unhandled plist type %d\n", __func__, plist_get_node_type(plist));
+ return;
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: unexpected type %d\n", __func__, type);
+ break;
+ }
+}
+
+static void nskeyedarchive_nsarray_append(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, ...)
+{
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append_v(ka, array, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_nsarray_append_item(nskeyedarchive_t ka, uint64_t uid, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t objects = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &objects);
+ if (!objects) {
+ fprintf(stderr, "ERROR: invalid NSArray object in archive: missing NS.objects property\n");
+ return;
+ }
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append_v(ka, objects, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_nsdictionary_add_item(nskeyedarchive_t ka, uint64_t uid, const char* key, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t keys = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.keys", &keys);
+ if (!keys) {
+ fprintf(stderr, "ERROR: invalid NSDictionary object in archive: missing NS.keys property\n");
+ return;
+ }
+ plist_t objects = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &objects);
+ if (!objects) {
+ fprintf(stderr, "ERROR: invalid NSDictionary object in archive: missing NS.objects property\n");
+ return;
+ }
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append(ka, keys, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, objects, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_append_class_type_v(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, va_list* va)
+{
+ uint64_t newuid = 0;
+
+ switch (type) {
+ case NSTYPE_INTEGER:
+ fprintf(stderr, "%s: ERROR: NSTYPE_INTEGER is not an object type, can't add it as class!.\n", __func__);
+ break;
+ case NSTYPE_INTREF:
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ fprintf(stderr, "%s: ERROR: NSTYPE_CHARS is not an object type, can't add it as class!\n", __func__);
+ break;
+ case NSTYPE_STRING:
+ {
+ char* strval = va_arg(*va, char*);
+ if (strval) {
+ if (strcmp(strval, "$null") != 0) {
+ nskeyedarchive_append_object(ka, plist_new_string(strval));
+ } else {
+ // make $null the top class if required
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(0));
+ plist_dict_set_item(ka->dict, "$top", top);
+ }
+ }
+ }
+ }
+ break;
+ case NSTYPE_REAL:
+ nskeyedarchive_append_object(ka, plist_new_real(va_arg(*va, double)));
+ break;
+ case NSTYPE_ARRAY:
+ fprintf(stderr, "%s: ERROR: NSTYPE_ARRAY is not an object type, can't add it as class!\n", __func__);
+ return;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLESTRING) {
+ nskeyedarchive_append_class(ka, "NSMutableString", "NSString", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSString", "NSObject", NULL);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.string", NSTYPE_STRING, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEARRAY) {
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSArray", "NSObject", NULL);
+ }
+ {
+ plist_t arr = plist_new_array();
+ do {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append_v(ka, arr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ plist_free(arr);
+ }
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEDICTIONARY) {
+ nskeyedarchive_append_class(ka, "NSMutableDictionary", "NSDictionary", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+ }
+ {
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+ do {
+ char* key = va_arg(*va, char*);
+ if (!key)
+ break;
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, valarr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ }
+ break;
+ case NSTYPE_NSDATE:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDate", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.time", NSTYPE_REAL, va_arg(*va, double));
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableData", "NSData", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.data", NSTYPE_DATA, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSURL:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSURL", "NSObject", NULL);
+ {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.base", ptype, va);
+ ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.relative", ptype, va);
+ }
+ break;
+ default:
+ fprintf(stderr, "unexpected class type %d\n", type);
+ return;
+ }
+
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(1));
+ plist_dict_set_item(ka->dict, "$top", top);
+ }
+}
+
+void nskeyedarchive_append_class_type(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!type) {
+ fprintf(stderr, "%s: ERROR: invalid class type!\n", __func__);
+ return;
+ }
+
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_append_class_type_v(ka, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_merge_object(nskeyedarchive_t ka, nskeyedarchive_t pka, plist_t object)
+{
+ if (!ka || !pka || !object) {
+ return;
+ }
+
+ switch (plist_get_node_type(object)) {
+ case PLIST_DICT:
+ {
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(object, &iter);
+ if (iter) {
+ plist_t val;
+ char* key;
+ do {
+ key = NULL;
+ val = NULL;
+ plist_dict_next_item(object, iter, &key, &val);
+ if (key) {
+ switch (plist_get_node_type(val)) {
+ case PLIST_UID:
+ {
+ uint64_t thisuid = 0;
+ plist_get_uid_val(val, &thisuid);
+ if (thisuid > 0) {
+ // remap thisuid to ka->uid+1
+ plist_t nextobj = nskeyedarchive_get_object_by_uid(pka, thisuid);
+ plist_set_uid_val(val, ++ka->uid);
+ plist_t nextcopy = plist_copy(nextobj);
+ nskeyedarchive_append_object(ka, nextcopy);
+ nskeyedarchive_merge_object(ka, pka, nextcopy);
+ }
+ }
+ break;
+ case PLIST_DICT:
+ case PLIST_ARRAY:
+ nskeyedarchive_merge_object(ka, pka, val);
+ break;
+ default:
+ break;
+ }
+ free(key);
+ }
+ } while (val);
+ free(iter);
+ }
+ }
+ break;
+ case PLIST_ARRAY:
+ {
+ uint32_t i;
+ for (i = 0; i < plist_array_get_size(object); i++) {
+ plist_t val = plist_array_get_item(object, i);
+ switch (plist_get_node_type(val)) {
+ case PLIST_UID:
+ {
+ uint64_t thisuid = 0;
+ plist_get_uid_val(val, &thisuid);
+ if (thisuid > 0) {
+ // remap thisuid to ka->uid+1
+ plist_t nextobj = nskeyedarchive_get_object_by_uid(pka, thisuid);
+ plist_set_uid_val(val, ++ka->uid);
+ plist_t nextcopy = plist_copy(nextobj);
+ nskeyedarchive_append_object(ka, nextcopy);
+ nskeyedarchive_merge_object(ka, pka, nextcopy);
+ }
+ }
+ break;
+ case PLIST_ARRAY:
+ case PLIST_DICT:
+ nskeyedarchive_merge_object(ka, pka, val);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void nskeyedarchive_set_class_property_v(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, va_list* va)
+{
+ plist_t a = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (a == NULL)
+ return;
+
+ uint64_t newuid;
+
+ switch (proptype) {
+ case NSTYPE_INTEGER:
+ plist_dict_set_item(a, propname, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_INTREF:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ plist_dict_set_item(a, propname, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_STRING:
+ {
+ char* strval = va_arg(*va, char*);
+ if (strval && (strcmp(strval, "$null") == 0)) {
+ plist_dict_set_item(a, propname, plist_new_uid(0));
+ } else {
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_string(strval));
+ }
+ }
+ break;
+ case NSTYPE_REAL:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_ARRAY:
+ plist_dict_set_item(a, propname, plist_copy(va_arg(*va, plist_t)));
+ break;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSDATE:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSURL:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSKEYEDARCHIVE:
+ {
+ nskeyedarchive_t pka = va_arg(*va, nskeyedarchive_t);
+ if (!pka) {
+ fprintf(stderr, "%s: ERROR: no nskeyedarchive argument given for type NSTYPE_NSKEYEDARCHIVE\n", __func__);
+ return;
+ }
+ uint64_t top = nskeyedarchive_get_class_uid(pka, NULL);
+ if (top != 0) {
+ plist_t object = nskeyedarchive_get_object_by_uid(pka, top);
+ if (!object) {
+ fprintf(stderr, "%s: ERROR: can't get object for uid %lld\n", __func__, (long long)top);
+ return;
+ }
+
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ plist_t objcopy = plist_copy(object);
+ nskeyedarchive_append_object(ka, objcopy);
+ nskeyedarchive_merge_object(ka, pka, objcopy);
+ } else {
+ plist_dict_set_item(a, propname, plist_new_uid(0));
+ }
+ }
+ break;
+ case NSTYPE_FROM_PLIST:
+ {
+ plist_t plist = va_arg(*va, plist_t);
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: no plist argument given for NSTYPE_PLIST\n", __func__);
+ return;
+ }
+ switch (plist_get_node_type(plist)) {
+ case PLIST_ARRAY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ {
+ plist_t arr = plist_new_array();
+ uint32_t ai;
+ for (ai = 0; ai < plist_array_get_size(plist); ai++) {
+ plist_t ae = plist_array_get_item(plist, ai);
+ nskeyedarchive_nsarray_append(ka, arr, NSTYPE_FROM_PLIST, ae);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: sorry, plist type %d is not implemented for conversion.\n", __func__, plist_get_node_type(plist));
+ break;
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "unexpected property type %d\n", proptype);
+ break;
+ }
+}
+
+void nskeyedarchive_set_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, ...)
+{
+ plist_t a = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (a == NULL) {
+ return;
+ }
+
+ va_list va;
+ va_start(va, proptype);
+ nskeyedarchive_set_class_property_v(ka, uid, propname, proptype, &va);
+ va_end(va);
+}
+
+
+void nskeyedarchive_print(nskeyedarchive_t ka)
+{
+ char* xml = NULL;
+ uint32_t xlen = 0;
+ plist_to_xml(ka->dict, &xml, &xlen);
+ puts(xml);
+ free(xml);
+}
+
+plist_t nskeyedarchive_get_plist_ref(nskeyedarchive_t ka)
+{
+ return ka->dict;
+}
+
+nskeyedarchive_t nskeyedarchive_new_from_plist(plist_t plist)
+{
+ if (!plist || (plist_get_node_type(plist) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: invalid parameter, PLIST_DICT expected\n", __func__);
+ return NULL;
+ }
+
+ plist_t node;
+ char* strval = NULL;
+ uint64_t uintval = 0;
+
+ // check for $archiver key
+ node = plist_dict_get_item(plist, "$archiver");
+ if (node && (plist_get_node_type(node) == PLIST_STRING)) {
+ plist_get_string_val(node, &strval);
+ }
+ if (!strval || (strcmp(strval, "NSKeyedArchiver") != 0)) {
+ fprintf(stderr, "%s: ERROR: plist is not in NSKeyedArchiver format ($archiver key not found or invalid)!\n", __func__);
+ if (strval)
+ free(strval);
+ return NULL;
+ }
+ if (strval)
+ free(strval);
+ strval = NULL;
+
+ // check for $version key
+ node = plist_dict_get_item(plist, "$version");
+ if (node && (plist_get_node_type(node) == PLIST_UINT)) {
+ plist_get_uint_val(node, &uintval);
+ }
+ if (uintval != 100000) {
+ fprintf(stderr, "%s: ERROR: unexpected NSKeyedArchiver version encountered (%lld != 100000)!\n", __func__, (long long int)uintval);
+ return NULL;
+ }
+ uintval = 0;
+
+ // check for $top key
+ node = plist_dict_get_item(plist, "$top");
+ if (!node || (plist_get_node_type(node) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: $top node not found\n", __func__);
+ return NULL;
+ }
+ plist_t topuid = plist_dict_get_item(node, "$0");
+ if (!topuid) {
+ topuid = plist_dict_get_item(node, "root");
+ }
+ if (!topuid || (plist_get_node_type(topuid) != PLIST_UID)) {
+ fprintf(stderr, "%s: ERROR: uid '$0' or 'root' not found in $top dict!\n", __func__);
+ return NULL;
+ }
+
+ uintval = -1LL;
+ plist_get_uid_val(topuid, (uint64_t*)&uintval);
+
+ if (uintval == (uint64_t)-1LL) {
+ fprintf(stderr, "%s: ERROR: could not get UID value.\n", __func__);
+ return NULL;
+ }
+
+ // check for $objects key
+ plist_t objects = plist_dict_get_item(plist, "$objects");
+ if (!objects || (plist_get_node_type(objects) != PLIST_ARRAY)) {
+ fprintf(stderr, "%s: ERROR: $objects node not found!\n", __func__);
+ return NULL;
+ }
+ plist_t obj = plist_array_get_item(objects, (uint32_t)uintval);
+ if (!obj) {
+ fprintf(stderr, "%s: ERROR: can't get object node\n", __func__);
+ return NULL;
+ }
+
+ nskeyedarchive_t archive = (nskeyedarchive_t)malloc(sizeof(struct nskeyedarchive_st));
+ archive->dict = plist_copy(plist);
+ archive->uid = plist_array_get_size(objects) - 1;
+
+ return archive;
+}
+
+nskeyedarchive_t nskeyedarchive_new_from_data(const void* data, uint32_t size)
+{
+ if (!data || (size < 8)) {
+ fprintf(stderr, "%s: ERROR: invalid parameter\n", __func__);
+ return NULL;
+ }
+
+
+ plist_t plist = NULL;
+ if (memcmp(data, "bplist00", 8) == 0) {
+ plist_from_bin(data, size, &plist);
+ } else if ((memcmp(data, "<?xml", 5) == 0) || (memcmp(data, "<plist", 6) == 0)) {
+ plist_from_xml(data, size, &plist);
+ } else {
+ // fail silently
+ return NULL;
+ }
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: Can't parse plist from data\n", __func__);
+ return NULL;
+ }
+
+ nskeyedarchive_t ka = nskeyedarchive_new_from_plist(plist);
+ plist_free(plist);
+ return ka;
+}
+
+uint64_t nskeyedarchive_get_class_uid(nskeyedarchive_t ka, const char* classref)
+{
+ uint64_t uintval = -1LL;
+ if (!ka) {
+ return uintval;
+ }
+ if (!ka->dict) {
+ return uintval;
+ }
+
+ plist_t node;
+
+ node = plist_dict_get_item(ka->dict, "$top");
+ if (!node || (plist_get_node_type(node) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: $top node not found\n", __func__);
+ return 0;
+ }
+ plist_t topuid = plist_dict_get_item(node, (classref) ? classref : "$0");
+ if (!topuid && !classref) {
+ topuid = plist_dict_get_item(node, "root");
+ }
+ if (!topuid || (plist_get_node_type(topuid) != PLIST_UID)) {
+ fprintf(stderr, "%s: ERROR: uid for '%s' not found in $top dict!\n", __func__, classref);
+ return 0;
+ }
+
+ plist_get_uid_val(topuid, (uint64_t*)&uintval);
+
+ return uintval;
+}
+
+const char* nskeyedarchive_get_classname(nskeyedarchive_t ka, uint64_t uid)
+{
+ if (!ka) {
+ return NULL;
+ }
+ if (!ka->dict) {
+ return NULL;
+ }
+
+ plist_t obj = nskeyedarchive_get_object_by_uid(ka, uid);
+ if (!obj) {
+ return NULL;
+ }
+
+ plist_t classuid = plist_dict_get_item(obj, "$class");
+ if (plist_get_node_type(classuid) != PLIST_UID) {
+ fprintf(stderr, "ERROR: $class is not a uid node\n");
+ return NULL;
+ }
+
+ uint64_t uintval = 0;
+ plist_get_uid_val(classuid, &uintval);
+ if (uintval == 0) {
+ fprintf(stderr, "ERROR: can't get $class uid val\n");
+ return NULL;
+ }
+
+ plist_t cls = nskeyedarchive_get_class_by_uid(ka, uintval);
+ if (!cls) {
+ return NULL;
+ }
+
+ plist_t classname = plist_dict_get_item(cls, "$classname");
+ if (!classname || (plist_get_node_type(classname) != PLIST_STRING)) {
+ fprintf(stderr, "ERROR: invalid $classname in class dict\n");
+ return NULL;
+ }
+
+ return plist_get_string_ptr(classname, NULL);
+}
+
+int nskeyedarchive_get_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, plist_t* value)
+{
+ if (!ka || !ka->dict || !value) {
+ return -1;
+ }
+
+ plist_t obj = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (!obj) {
+ return -1;
+ }
+
+ *value = plist_dict_get_item(obj, propname);
+ if (!*value) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int nskeyedarchive_get_class_uint64_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, uint64_t* value)
+{
+ plist_t prop = NULL;
+
+ nskeyedarchive_get_class_property(ka, uid, propname, &prop);
+ if (!prop) {
+ fprintf(stderr, "%s: ERROR: no such property '%s'\n", __func__, propname);
+ return -1;
+ }
+
+ if (plist_get_node_type(prop) == PLIST_UID) {
+ uint64_t uintval = 0;
+ plist_get_uid_val(prop, &uintval);
+ prop = nskeyedarchive_get_object_by_uid(ka, uintval);
+ }
+
+ if (plist_get_node_type(prop) != PLIST_UINT) {
+ fprintf(stderr, "%s: ERROR: property '%s' is not of type integer.\n", __func__, propname);
+ return -1;
+ }
+
+ plist_get_uint_val(prop, value);
+
+ return 0;
+}
+
+int nskeyedarchive_get_class_int_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, int* value)
+{
+ uint64_t uintval = 0;
+ int res = nskeyedarchive_get_class_uint64_property(ka, uid, propname, &uintval);
+ if (res < 0) {
+ return res;
+ }
+ *value = (int)uintval;
+ return 0;
+}
+
+int nskeyedarchive_get_class_string_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, char** value)
+{
+ plist_t node = NULL;
+
+ nskeyedarchive_get_class_property(ka, uid, propname, &node);
+ if (!node || (plist_get_node_type(node) != PLIST_UID)) {
+ return -1;
+ }
+
+ uint64_t uintval = 0;
+ plist_get_uid_val(node, &uintval);
+
+ plist_t prop = nskeyedarchive_get_object_by_uid(ka, uintval);
+ if (!prop || (plist_get_node_type(prop) != PLIST_STRING)) {
+ fprintf(stderr, "%s: ERROR: property '%s' is not a string\n", __func__, propname);
+ return -1;
+ }
+
+ plist_get_string_val(prop, value);
+
+ return 0;
+}
+
+static plist_t _nska_parse_object(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t obj = nskeyedarchive_get_object_by_uid(ka, uid);
+ switch (plist_get_node_type(obj)) {
+ case PLIST_BOOLEAN:
+ case PLIST_INT:
+ case PLIST_STRING:
+ return plist_copy(obj);
+ default:
+ break;
+ }
+
+ const char* clsn = nskeyedarchive_get_classname(ka, uid);
+ plist_t pl = NULL;
+ if (!strcmp(clsn, "NSMutableDictionary") || !strcmp(clsn, "NSDictionary")) {
+ plist_t keys = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.keys", &keys);
+ plist_t vals = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &vals);
+
+ uint32_t count = plist_array_get_size(keys);
+ if (count != plist_array_get_size(vals)) {
+ printf("ERROR: %s: inconsistent number of keys vs. values in dictionary object\n", __func__);
+ return NULL;
+ }
+ pl = plist_new_dict();
+ uint32_t i = 0;
+ for (i = 0; i < count; i++) {
+ plist_t knode = plist_array_get_item(keys, i);
+ plist_t vnode = plist_array_get_item(vals, i);
+
+ uint64_t subuid = 0;
+ plist_get_uid_val(knode, &subuid);
+ plist_t newkey = _nska_parse_object(ka, subuid);
+
+ subuid = 0;
+ plist_get_uid_val(vnode, &subuid);
+ plist_t newval = _nska_parse_object(ka, subuid);
+
+ if (!PLIST_IS_STRING(newkey)) {
+ printf("ERROR: %s: key node is not of string type.\n", __func__);
+ return NULL;
+ }
+
+ plist_dict_set_item(pl, plist_get_string_ptr(newkey, NULL), newval);
+ plist_free(newkey);
+ }
+ } else if (!strcmp(clsn, "NSMutableArray") || !strcmp(clsn, "NSArray")) {
+ plist_t vals = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &vals);
+
+ uint32_t count = plist_array_get_size(vals);
+ pl = plist_new_array();
+ uint32_t i = 0;
+ for (i = 0; i < count; i++) {
+ plist_t vnode = plist_array_get_item(vals, i);
+ uint64_t subuid = 0;
+ plist_get_uid_val(vnode, &subuid);
+ plist_t newval = _nska_parse_object(ka, subuid);
+ plist_array_append_item(pl, newval);
+ }
+ } else {
+ printf("ERROR: %s: unhandled class type '%s'\n", __func__, clsn);
+ }
+ return pl;
+}
+
+plist_t nskeyedarchive_to_plist(nskeyedarchive_t ka)
+{
+ uint64_t obj_uid = nskeyedarchive_get_class_uid(ka, NULL);
+ return _nska_parse_object(ka, obj_uid);
+}
diff --git a/src/opack.c b/src/opack.c
index 9e7fa73..8a9264a 100644
--- a/src/opack.c
+++ b/src/opack.c
@@ -206,7 +206,7 @@ static void opack_encode_node(plist_t node, struct char_buf* cbuf)
if (len >> 32) {
uint8_t blen = 0x94;
char_buf_append(cbuf, 1, &blen);
- uint32_t u64val = htole64(len);
+ uint64_t u64val = htole64(len);
char_buf_append(cbuf, 8, (unsigned char*)&u64val);
} else {
uint8_t blen = 0x93;
@@ -237,7 +237,7 @@ static void opack_encode_node(plist_t node, struct char_buf* cbuf)
}
}
-LIBIMOBILEDEVICE_GLUE_API void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len)
+void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len)
{
if (!plist || !out || !out_len) {
return;
@@ -304,11 +304,11 @@ static int opack_decode_obj(unsigned char** p, unsigned char* end, plist_t* plis
} else if (type == 0x32) {
uint32_t u32val = *(uint32_t*)*p;
value = (int32_t)le32toh(u32val);
- (p)+=4;
+ (*p)+=4;
} else if (type == 0x33) {
uint64_t u64val = *(uint64_t*)*p;
value = le64toh(u64val);
- (p)+=8;
+ (*p)+=8;
} else {
fprintf(stderr, "%s: ERROR: Invalid encoded byte '%02x'\n", __func__, type);
*p = end;
@@ -462,7 +462,7 @@ static int opack_decode_obj(unsigned char** p, unsigned char* end, plist_t* plis
return 0;
}
-LIBIMOBILEDEVICE_GLUE_API int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out)
+int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out)
{
if (!buf || buf_len == 0 || !plist_out) {
return -1;
diff --git a/src/socket.c b/src/socket.c
index 1029a71..3375e5b 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -55,7 +55,7 @@ static int wsa_init = 0;
#ifdef AF_INET6
#include <net/if.h>
#include <ifaddrs.h>
-#if defined (__APPLE__) || defined (__FreeBSD__)
+#if defined (__APPLE__) || defined (__FreeBSD__) || defined (__HAIKU__)
#include <net/if_dl.h>
#endif
#ifdef __linux__
@@ -65,6 +65,9 @@ static int wsa_init = 0;
#endif
#include "common.h"
#include "libimobiledevice-glue/socket.h"
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
#define RECV_TIMEOUT 20000
#define SEND_TIMEOUT 10000
@@ -82,12 +85,12 @@ static int wsa_init = 0;
static int verbose = 0;
-LIBIMOBILEDEVICE_GLUE_API void socket_set_verbose(int level)
+void socket_set_verbose(int level)
{
verbose = level;
}
-LIBIMOBILEDEVICE_GLUE_API const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
+const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
{
#ifdef WIN32
WSADATA wsa_data;
@@ -140,8 +143,186 @@ LIBIMOBILEDEVICE_GLUE_API const char *socket_addr_to_string(struct sockaddr *add
return NULL;
}
+enum poll_status
+{
+ poll_status_success,
+ poll_status_timeout,
+ poll_status_error
+};
+
+#ifdef WIN32
+static inline __attribute__((always_inline)) int WSAError_to_errno(int wsaerr)
+{
+ switch (wsaerr) {
+ case WSAEINVAL:
+ return EINVAL;
+ case WSAENOTSOCK:
+ return ENOTSOCK;
+ case WSAENOTCONN:
+ return ENOTCONN;
+ case WSAESHUTDOWN:
+ return ENOTCONN;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAECONNABORTED:
+ return ECONNABORTED;
+ case WSAECONNREFUSED:
+ return ECONNREFUSED;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAENETRESET:
+ return ENETRESET;
+ case WSAEHOSTUNREACH:
+ return EHOSTUNREACH;
+ case WSAETIMEDOUT:
+ return ETIMEDOUT;
+ case WSAEWOULDBLOCK:
+ return EWOULDBLOCK;
+ case WSAEINPROGRESS:
+ return EINPROGRESS;
+ case WSAENOBUFS:
+ return ENOBUFS;
+ case WSAEINTR:
+ return EINTR;
+ case WSAEACCES:
+ return EACCES;
+ case WSAEFAULT:
+ return EFAULT;
+ default:
+ break;
+ }
+ return wsaerr;
+}
+#endif
+
+// timeout of -1 means infinity
+static inline __attribute__((always_inline)) enum poll_status poll_wrapper(int fd, fd_mode mode, int timeout)
+{
+#ifdef HAVE_POLL
+ // https://man7.org/linux/man-pages/man2/select.2.html
+ // Correspondence between select() and poll() notifications
+ // #define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN |
+ // EPOLLHUP | EPOLLERR)
+ // /* Ready for reading */
+ // #define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT |
+ // EPOLLERR)
+ // /* Ready for writing */
+ // #define POLLEX_SET (EPOLLPRI)
+ // /* Exceptional condition */
+
+ short events;
+ switch (mode) {
+ case FDM_READ:
+ events = POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR;
+ break;
+ case FDM_WRITE:
+ events = POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR;
+ break;
+ case FDM_EXCEPT:
+ events = POLLPRI;
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: fd_mode %d unsupported\n", __func__, mode);
+ return poll_status_error;
+ }
+ while (1) {
+ struct pollfd pfd = {
+ .fd = fd,
+ .events = events,
+ };
+ switch (poll(&pfd, 1, timeout)) {
+ case 1:
+ if((pfd.revents & (POLLNVAL | POLLERR)) != 0)
+ {
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll unexpected events: %d\n", __func__, (int)pfd.revents);
+ return poll_status_error;
+ }
+ return poll_status_success;
+ case 0:
+ return poll_status_timeout;
+ case -1:
+ if(errno == EINTR)
+ {
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EINTR\n", __func__);
+ continue;
+ }
+ // fallthrough
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll failed: %s\n", __func__, strerror(errno));
+ return poll_status_error;
+ }
+ }
+#else
+ fd_set fds;
+ int sret;
+ int eagain;
+ struct timeval to;
+ struct timeval *pto;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ sret = poll_status_error;
+
+ do {
+ if (timeout > 0) {
+ to.tv_sec = (time_t) (timeout / 1000);
+ to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
+ pto = &to;
+ } else {
+ pto = NULL;
+ }
+ eagain = 0;
+ switch (mode) {
+ case FDM_READ:
+ sret = select(fd + 1, &fds, NULL, NULL, pto);
+ break;
+ case FDM_WRITE:
+ sret = select(fd + 1, NULL, &fds, NULL, pto);
+ break;
+ case FDM_EXCEPT:
+ sret = select(fd + 1, NULL, NULL, &fds, pto);
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: fd_mode %d unsupported\n", __func__, mode);
+ return poll_status_error;
+ }
+
+ if (sret == 1) {
+ return poll_status_success;
+ } else if (sret == 0) {
+ return poll_status_timeout;
+ } else {
+ switch (errno) {
+ case EINTR:
+ // interrupt signal in select
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EINTR\n", __func__);
+ eagain = 1;
+ break;
+ case EAGAIN:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EAGAIN\n", __func__);
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: select failed: %s\n", __func__, strerror(errno));
+ return poll_status_error;
+ }
+ }
+ } while (eagain);
+
+ return sret;
+#endif
+}
+
#ifndef WIN32
-LIBIMOBILEDEVICE_GLUE_API int socket_create_unix(const char *filename)
+int socket_create_unix(const char *filename)
{
struct sockaddr_un name;
int sock;
@@ -187,7 +368,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create_unix(const char *filename)
return sock;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
+int socket_connect_unix(const char *filename)
{
struct sockaddr_un name;
int sfd = -1;
@@ -246,20 +427,22 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
break;
}
if (errno == EINPROGRESS) {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
if (so_error == 0) {
+ errno = 0;
break;
}
+ errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -276,10 +459,11 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
}
#endif
-LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
+int socket_create(const char* addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
+ int no = 0;
struct addrinfo hints;
struct addrinfo *result, *rp;
char portstr[8];
@@ -303,9 +487,6 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
sprintf(portstr, "%d", port);
- if (!addr) {
- addr = "localhost";
- }
res = getaddrinfo(addr, portstr, &hints, &result);
if (res != 0) {
fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
@@ -334,7 +515,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
#if defined(AF_INET6) && defined(IPV6_V6ONLY)
if (rp->ai_family == AF_INET6) {
- if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
+ if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (addr) ? (void*)&yes : (void*)&no, sizeof(int)) == -1) {
perror("setsockopt() IPV6_V6ONLY");
}
}
@@ -699,7 +880,7 @@ static int getifaddrs(struct ifaddrs** ifap)
#endif
#endif
-LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf[6])
+int get_primary_mac_address(unsigned char mac_addr_buf[6])
{
int result = -1;
struct ifaddrs *ifaddr = NULL, *ifa = NULL;
@@ -714,13 +895,13 @@ LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf
if (ifa->ifa_flags & IFF_LOOPBACK) {
continue;
}
-#if defined(__APPLE__) || defined (__FreeBSD__)
+#if defined(__APPLE__) || defined (__FreeBSD__) || defined (__HAIKU__)
if (ifa->ifa_addr->sa_family != AF_LINK) {
continue;
}
#if defined (__APPLE__)
if (!strcmp(ifa->ifa_name, "en0")) {
-#elif defined (__FreeBSD__)
+#elif defined (__FreeBSD__) || defined (__HAIKU__)
{
#endif
memcpy(mac_addr_buf, (unsigned char *)LLADDR((struct sockaddr_dl *)(ifa)->ifa_addr), 6);
@@ -742,6 +923,12 @@ LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf
result = 0;
break;
}
+#elif defined(__CYGWIN__)
+ if (ifa->ifa_data) {
+ memcpy(mac_addr_buf, ((struct ifaddrs_hwdata *)ifa->ifa_data)->ifa_hwaddr.sa_data, 6);
+ result = 0;
+ break;
+ }
#else
#error get_primary_mac_address is not supported on this platform.
#endif
@@ -787,10 +974,12 @@ static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
continue;
}
+#ifndef __HAIKU__
/* skip if not running */
if ((ifa->ifa_flags & IFF_RUNNING) == 0) {
continue;
}
+#endif
struct sockaddr_in6* addr_in = (struct sockaddr_in6*)ifa->ifa_addr;
@@ -840,7 +1029,7 @@ static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
}
#endif
-LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_t port)
+int socket_connect_addr(struct sockaddr* addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
@@ -924,14 +1113,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
if (errno == EINPROGRESS)
#endif
{
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
@@ -939,7 +1121,20 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
errno = 0;
break;
}
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -970,7 +1165,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
return sfd;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
+int socket_connect(const char *addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
@@ -993,11 +1188,6 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
int flags = 0;
#endif
- if (!addr) {
- errno = EINVAL;
- return -1;
- }
-
memset(&hints, '\0', sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
@@ -1048,20 +1238,28 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
if (errno == EINPROGRESS)
#endif
{
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
if (so_error == 0) {
+ errno = 0;
break;
}
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -1090,75 +1288,39 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
return sfd;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
+int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
{
- fd_set fds;
- int sret;
- int eagain;
- struct timeval to;
- struct timeval *pto;
-
if (fd < 0) {
if (verbose >= 2)
fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
- return -1;
+ return -EINVAL;
}
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- sret = -1;
-
- do {
- if (timeout > 0) {
- to.tv_sec = (time_t) (timeout / 1000);
- to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
- pto = &to;
- } else {
- pto = NULL;
- }
- eagain = 0;
- switch (fdm) {
- case FDM_READ:
- sret = select(fd + 1, &fds, NULL, NULL, pto);
- break;
- case FDM_WRITE:
- sret = select(fd + 1, NULL, &fds, NULL, pto);
- break;
- case FDM_EXCEPT:
- sret = select(fd + 1, NULL, NULL, &fds, pto);
- break;
- default:
- return -1;
- }
+ int timeout_ms;
+ if (timeout > 0) {
+ timeout_ms = (int)timeout;
+ if (timeout_ms <= 0)
+ timeout_ms = -1;
+ } else {
+ timeout_ms = -1;
+ }
- if (sret < 0) {
- switch (errno) {
- case EINTR:
- // interrupt signal in select
- if (verbose >= 2)
- fprintf(stderr, "%s: EINTR\n", __func__);
- eagain = 1;
- break;
- case EAGAIN:
- if (verbose >= 2)
- fprintf(stderr, "%s: EAGAIN\n", __func__);
- break;
- default:
- if (verbose >= 2)
- fprintf(stderr, "%s: select failed: %s\n", __func__,
- strerror(errno));
- return -1;
- }
- } else if (sret == 0) {
+ switch (poll_wrapper(fd, fdm, timeout_ms)) {
+ case poll_status_success:
+ return 1;
+ case poll_status_timeout:
return -ETIMEDOUT;
- }
- } while (eagain);
+ case poll_status_error:
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll_wrapper failed\n", __func__);
+ return -ECONNRESET;
+ }
- return sret;
+ return -ECONNRESET;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_accept(int fd, uint16_t port)
+int socket_accept(int fd, uint16_t port)
{
#ifdef WIN32
int addr_len;
@@ -1174,12 +1336,12 @@ LIBIMOBILEDEVICE_GLUE_API int socket_accept(int fd, uint16_t port)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_shutdown(int fd, int how)
+int socket_shutdown(int fd, int how)
{
return shutdown(fd, how);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_close(int fd) {
+int socket_close(int fd) {
#ifdef WIN32
return closesocket(fd);
#else
@@ -1187,17 +1349,17 @@ LIBIMOBILEDEVICE_GLUE_API int socket_close(int fd) {
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int socket_receive(int fd, void *data, size_t length)
+int socket_receive(int fd, void *data, size_t length)
{
return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_peek(int fd, void *data, size_t length)
+int socket_peek(int fd, void *data, size_t length)
{
return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout)
+int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout)
{
int res;
int result;
@@ -1209,19 +1371,22 @@ LIBIMOBILEDEVICE_GLUE_API int socket_receive_timeout(int fd, void *data, size_t
}
// if we get here, there _is_ data available
result = recv(fd, data, length, flags);
- if (res > 0 && result == 0) {
+ if (result == 0) {
// but this is an error condition
if (verbose >= 3)
fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
return -ECONNRESET;
}
if (result < 0) {
+#ifdef WIN32
+ errno = WSAError_to_errno(WSAGetLastError());
+#endif
return -errno;
}
return result;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_send(int fd, void *data, size_t length)
+int socket_send(int fd, void *data, size_t length)
{
int flags = 0;
int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT);
@@ -1231,10 +1396,17 @@ LIBIMOBILEDEVICE_GLUE_API int socket_send(int fd, void *data, size_t length)
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
#endif
- return send(fd, data, length, flags);
+ int s = (int)send(fd, data, length, flags);
+ if (s < 0) {
+#ifdef WIN32
+ errno = WSAError_to_errno(WSAGetLastError());
+#endif
+ return -errno;
+ }
+ return s;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_get_socket_port(int fd, uint16_t *port)
+int socket_get_socket_port(int fd, uint16_t *port)
{
#ifdef WIN32
int addr_len;
diff --git a/src/termcolors.c b/src/termcolors.c
index 710c9df..5c436f2 100644
--- a/src/termcolors.c
+++ b/src/termcolors.c
@@ -92,7 +92,7 @@ static int bgcolor_map[8] = {
static int WIN32_LEGACY_MODE = 0;
#endif
-LIBIMOBILEDEVICE_GLUE_API void term_colors_init()
+void term_colors_init()
{
#ifdef WIN32
DWORD conmode = 0;
@@ -126,12 +126,12 @@ LIBIMOBILEDEVICE_GLUE_API void term_colors_init()
}
}
-LIBIMOBILEDEVICE_GLUE_API void term_colors_set_enabled(int en)
+void term_colors_set_enabled(int en)
{
use_colors = en;
}
-LIBIMOBILEDEVICE_GLUE_API int cvfprintf(FILE* stream, const char* fmt, va_list vargs)
+int cvfprintf(FILE* stream, const char* fmt, va_list vargs)
{
int res = 0;
int colorize = use_colors;
@@ -298,7 +298,7 @@ LIBIMOBILEDEVICE_GLUE_API int cvfprintf(FILE* stream, const char* fmt, va_list v
return res;
}
-LIBIMOBILEDEVICE_GLUE_API int cfprintf(FILE* stream, const char* fmt, ...)
+int cfprintf(FILE* stream, const char* fmt, ...)
{
int res = 0;
va_list va;
@@ -308,7 +308,7 @@ LIBIMOBILEDEVICE_GLUE_API int cfprintf(FILE* stream, const char* fmt, ...)
return res;
}
-LIBIMOBILEDEVICE_GLUE_API int cprintf(const char* fmt, ...)
+int cprintf(const char* fmt, ...)
{
int res = 0;
va_list va;
diff --git a/src/thread.c b/src/thread.c
index 6efacec..50639dd 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -22,13 +22,16 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#ifdef WIN32
+#include <windows.h>
+#endif
#include "common.h"
#include "libimobiledevice-glue/thread.h"
-LIBIMOBILEDEVICE_GLUE_API int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
+int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
{
#ifdef WIN32
- HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
+ HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(void*)thread_func, data, 0, NULL);
if (th == NULL) {
return -1;
}
@@ -40,7 +43,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_new(THREAD_T *thread, thread_func_t thread_
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_detach(THREAD_T thread)
+void thread_detach(THREAD_T thread)
{
#ifdef WIN32
CloseHandle(thread);
@@ -49,14 +52,14 @@ LIBIMOBILEDEVICE_GLUE_API void thread_detach(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_free(THREAD_T thread)
+void thread_free(THREAD_T thread)
{
#ifdef WIN32
CloseHandle(thread);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_join(THREAD_T thread)
+int thread_join(THREAD_T thread)
{
/* wait for thread to complete */
#ifdef WIN32
@@ -66,7 +69,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_join(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_alive(THREAD_T thread)
+int thread_alive(THREAD_T thread)
{
if (!thread)
return 0;
@@ -77,7 +80,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_alive(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_cancel(THREAD_T thread)
+int thread_cancel(THREAD_T thread)
{
#ifdef WIN32
return -1;
@@ -90,43 +93,43 @@ LIBIMOBILEDEVICE_GLUE_API int thread_cancel(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_init(mutex_t* mutex)
+void mutex_init(mutex_t* mutex)
{
#ifdef WIN32
- InitializeCriticalSection(mutex);
+ InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_init(mutex, NULL);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_destroy(mutex_t* mutex)
+void mutex_destroy(mutex_t* mutex)
{
#ifdef WIN32
- DeleteCriticalSection(mutex);
+ DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_destroy(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_lock(mutex_t* mutex)
+void mutex_lock(mutex_t* mutex)
{
#ifdef WIN32
- EnterCriticalSection(mutex);
+ EnterCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_lock(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_unlock(mutex_t* mutex)
+void mutex_unlock(mutex_t* mutex)
{
#ifdef WIN32
- LeaveCriticalSection(mutex);
+ LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_unlock(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_once(thread_once_t *once_control, void (*init_routine)(void))
+void thread_once(thread_once_t *once_control, void (*init_routine)(void))
{
#ifdef WIN32
while (InterlockedExchange(&(once_control->lock), 1) != 0) {
@@ -142,7 +145,7 @@ LIBIMOBILEDEVICE_GLUE_API void thread_once(thread_once_t *once_control, void (*i
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void cond_init(cond_t* cond)
+void cond_init(cond_t* cond)
{
#ifdef WIN32
cond->sem = CreateSemaphore(NULL, 0, 32767, NULL);
@@ -151,7 +154,7 @@ LIBIMOBILEDEVICE_GLUE_API void cond_init(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void cond_destroy(cond_t* cond)
+void cond_destroy(cond_t* cond)
{
#ifdef WIN32
CloseHandle(cond->sem);
@@ -160,7 +163,7 @@ LIBIMOBILEDEVICE_GLUE_API void cond_destroy(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_signal(cond_t* cond)
+int cond_signal(cond_t* cond)
{
#ifdef WIN32
int result = 0;
@@ -173,7 +176,7 @@ LIBIMOBILEDEVICE_GLUE_API int cond_signal(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_wait(cond_t* cond, mutex_t* mutex)
+int cond_wait(cond_t* cond, mutex_t* mutex)
{
#ifdef WIN32
mutex_unlock(mutex);
@@ -189,7 +192,7 @@ LIBIMOBILEDEVICE_GLUE_API int cond_wait(cond_t* cond, mutex_t* mutex)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms)
+int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms)
{
#ifdef WIN32
mutex_unlock(mutex);
diff --git a/src/tlv.c b/src/tlv.c
index d08c8f3..f209a37 100644
--- a/src/tlv.c
+++ b/src/tlv.c
@@ -32,7 +32,7 @@
#include "libimobiledevice-glue/tlv.h"
#include "endianness.h"
-LIBIMOBILEDEVICE_GLUE_API tlv_buf_t tlv_buf_new()
+tlv_buf_t tlv_buf_new()
{
tlv_buf_t tlv = malloc(sizeof(struct tlv_buf));
tlv->capacity = 1024;
@@ -41,7 +41,7 @@ LIBIMOBILEDEVICE_GLUE_API tlv_buf_t tlv_buf_new()
return tlv;
}
-LIBIMOBILEDEVICE_GLUE_API void tlv_buf_free(tlv_buf_t tlv)
+void tlv_buf_free(tlv_buf_t tlv)
{
if (tlv) {
free(tlv->data);
@@ -49,7 +49,7 @@ LIBIMOBILEDEVICE_GLUE_API void tlv_buf_free(tlv_buf_t tlv)
}
}
-LIBIMOBILEDEVICE_GLUE_API void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data)
+void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data)
{
if (!tlv || !tlv->data) {
return;
@@ -86,7 +86,7 @@ LIBIMOBILEDEVICE_GLUE_API void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsign
tlv->length = p - tlv->data;
}
-LIBIMOBILEDEVICE_GLUE_API unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length)
+unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length)
{
unsigned char* p = (unsigned char*)tlv_data;
unsigned char* end = (unsigned char*)tlv_end;
@@ -102,7 +102,7 @@ LIBIMOBILEDEVICE_GLUE_API unsigned char* tlv_get_data_ptr(const void* tlv_data,
return NULL;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value)
+int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value)
{
if (!tlv_data || tlv_length < 2 || !value) {
return 0;
@@ -136,7 +136,7 @@ LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint(const void* tlv_data, unsigned i
return 1;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value)
+int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value)
{
if (!tlv_data || tlv_length < 2 || !value) {
return 0;
@@ -156,7 +156,7 @@ LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint8(const void* tlv_data, unsigned
return 1;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len)
+int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len)
{
if (!tlv_data || tlv_length < 2 || !out || !out_len) {
return 0;
diff --git a/src/utils.c b/src/utils.c
index 9baef7e..ad8e9c4 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -3,7 +3,7 @@
* Miscellaneous utilities for string manipulation,
* file I/O and plist helper.
*
- * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2014-2023 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
* Copyright (c) 2013 Federico Mena Quintero
*
@@ -75,7 +75,7 @@ char *stpcpy(char *s1, const char *s2)
* @return a newly allocated string, or NULL if @str is NULL. This will also
* return NULL and set errno to ENOMEM if memory is exhausted.
*/
-LIBIMOBILEDEVICE_GLUE_API char *string_concat(const char *str, ...)
+char *string_concat(const char *str, ...)
{
size_t len;
va_list args;
@@ -119,7 +119,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_concat(const char *str, ...)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_append(char* str, ...)
+char *string_append(char* str, ...)
{
size_t len = 0;
size_t slen;
@@ -163,7 +163,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_append(char* str, ...)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_build_path(const char *elem, ...)
+char *string_build_path(const char *elem, ...)
{
if (!elem)
return NULL;
@@ -191,7 +191,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_build_path(const char *elem, ...)
return out;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_format_size(uint64_t size)
+char *string_format_size(uint64_t size)
{
char buf[80];
double sz;
@@ -213,7 +213,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_format_size(uint64_t size)
return strdup(buf);
}
-LIBIMOBILEDEVICE_GLUE_API char *string_toupper(char* str)
+char *string_toupper(char* str)
{
char *res = strdup(str);
size_t i;
@@ -229,7 +229,7 @@ static int get_rand(int min, int max)
return retval;
}
-LIBIMOBILEDEVICE_GLUE_API char *generate_uuid()
+char *generate_uuid()
{
const char *chars = "ABCDEF0123456789";
int i = 0;
@@ -251,7 +251,7 @@ LIBIMOBILEDEVICE_GLUE_API char *generate_uuid()
return uuid;
}
-LIBIMOBILEDEVICE_GLUE_API int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
+int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
{
FILE *f;
uint64_t size;
@@ -295,7 +295,7 @@ LIBIMOBILEDEVICE_GLUE_API int buffer_read_from_filename(const char *filename, ch
return ret;
}
-LIBIMOBILEDEVICE_GLUE_API int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
+int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
{
FILE *f;
@@ -318,241 +318,3 @@ LIBIMOBILEDEVICE_GLUE_API int buffer_write_to_filename(const char *filename, con
return 0;
}
}
-
-LIBIMOBILEDEVICE_GLUE_API int plist_read_from_filename(plist_t *plist, const char *filename)
-{
- char *buffer = NULL;
- uint64_t length;
-
- if (!filename)
- return 0;
-
- if (!buffer_read_from_filename(filename, &buffer, &length)) {
- return 0;
- }
-
- plist_from_memory(buffer, length, plist);
-
- free(buffer);
-
- return 1;
-}
-
-LIBIMOBILEDEVICE_GLUE_API int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
-{
- char *buffer = NULL;
- uint32_t length;
-
- if (!plist || !filename)
- return 0;
-
- if (format == PLIST_FORMAT_XML)
- plist_to_xml(plist, &buffer, &length);
- else if (format == PLIST_FORMAT_BINARY)
- plist_to_bin(plist, &buffer, &length);
- else
- return 0;
-
- int res = buffer_write_to_filename(filename, buffer, length);
-
- free(buffer);
-
- return res;
-}
-
-static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char base64_pad = '=';
-
-static char *base64encode(const unsigned char *buf, size_t size)
-{
- if (!buf || !(size > 0)) return NULL;
- int outlen = (size / 3) * 4;
- char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0'
- size_t n = 0;
- size_t m = 0;
- unsigned char input[3];
- unsigned int output[4];
- while (n < size) {
- input[0] = buf[n];
- input[1] = (n+1 < size) ? buf[n+1] : 0;
- input[2] = (n+2 < size) ? buf[n+2] : 0;
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
- output[3] = input[2] & 63;
- outbuf[m++] = base64_str[(int)output[0]];
- outbuf[m++] = base64_str[(int)output[1]];
- outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
- outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
- n+=3;
- }
- outbuf[m] = 0; // 0-termination!
- return outbuf;
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream);
-
-static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over items */
- int i, count;
- plist_t subnode = NULL;
-
- count = plist_array_get_size(node);
-
- for (i = 0; i < count; i++) {
- subnode = plist_array_get_item(node, i);
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%d: ", i);
- plist_node_print_to_stream(subnode, indent_level, stream);
- }
-}
-
-static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over key/value pairs */
- plist_dict_iter it = NULL;
-
- char* key = NULL;
- plist_t subnode = NULL;
- plist_dict_new_iter(node, &it);
- plist_dict_next_item(node, it, &key, &subnode);
- while (subnode)
- {
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%s", key);
- if (plist_get_node_type(subnode) == PLIST_ARRAY)
- fprintf(stream, "[%d]: ", plist_array_get_size(subnode));
- else
- fprintf(stream, ": ");
- free(key);
- key = NULL;
- plist_node_print_to_stream(subnode, indent_level, stream);
- plist_dict_next_item(node, it, &key, &subnode);
- }
- free(it);
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- char *s = NULL;
- char *data = NULL;
- double d;
- uint8_t b;
- uint64_t u = 0;
- struct timeval tv = { 0, 0 };
-
- plist_type t;
-
- if (!node)
- return;
-
- t = plist_get_node_type(node);
-
- switch (t) {
- case PLIST_BOOLEAN:
- plist_get_bool_val(node, &b);
- fprintf(stream, "%s\n", (b ? "true" : "false"));
- break;
-
- case PLIST_UINT:
- plist_get_uint_val(node, &u);
- fprintf(stream, "%"PRIu64"\n", u);
- break;
-
- case PLIST_REAL:
- plist_get_real_val(node, &d);
- fprintf(stream, "%f\n", d);
- break;
-
- case PLIST_STRING:
- plist_get_string_val(node, &s);
- fprintf(stream, "%s\n", s);
- free(s);
- break;
-
- case PLIST_KEY:
- plist_get_key_val(node, &s);
- fprintf(stream, "%s: ", s);
- free(s);
- break;
-
- case PLIST_DATA:
- plist_get_data_val(node, &data, &u);
- if (u > 0) {
- s = base64encode((unsigned char*)data, u);
- free(data);
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_DATE:
- plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec);
- {
- time_t ti = (time_t)tv.tv_sec + MAC_EPOCH;
- struct tm *btime = localtime(&ti);
- if (btime) {
- s = (char*)malloc(24);
- memset(s, 0, 24);
- if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) {
- free (s);
- s = NULL;
- }
- }
- }
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_ARRAY:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_array_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- case PLIST_DICT:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_dict_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- default:
- break;
- }
-}
-
-LIBIMOBILEDEVICE_GLUE_API void plist_print_to_stream_with_indentation(plist_t plist, FILE* stream, unsigned int indentation)
-{
- if (!plist || !stream)
- return;
-
- int indent = indentation;
- switch (plist_get_node_type(plist)) {
- case PLIST_DICT:
- plist_dict_print_to_stream(plist, &indent, stream);
- break;
- case PLIST_ARRAY:
- plist_array_print_to_stream(plist, &indent, stream);
- break;
- default:
- plist_node_print_to_stream(plist, &indent, stream);
- }
-}
-
-LIBIMOBILEDEVICE_GLUE_API void plist_print_to_stream(plist_t plist, FILE* stream)
-{
- plist_print_to_stream_with_indentation(plist, stream, 0);
-}