tools: Use new afc_get_file_info_plist/afc_get_device_info_plist functions
diff --git a/tools/afcclient.c b/tools/afcclient.c
index 1cddb36..a958c23 100644
--- a/tools/afcclient.c
+++ b/tools/afcclient.c
@@ -365,62 +365,55 @@
 
 static void handle_devinfo(afc_client_t afc, int argc, char** argv)
 {
-	char **info = NULL;
-	afc_error_t err = afc_get_device_info(afc, &info);
+	plist_t info = NULL;
+	afc_error_t err = afc_get_device_info_plist(afc, &info);
 	if (err == AFC_E_SUCCESS && info) {
-		int i;
-		for (i = 0; info[i]; i += 2) {
-			printf("%s: %s\n", info[i], info[i+1]);
+		if (argc > 0 && !strcmp(argv[0], "--plain")) {
+			plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
+		} else {
+			plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
 		}
 	} else {
 		printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err);
 	}
-	afc_dictionary_free(info);
+	plist_free(info);
 }
 
 static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf)
 {
-	char **info = NULL;
-	afc_error_t ret = afc_get_file_info(afc, path, &info);
+	plist_t info = NULL;
+	afc_error_t ret = afc_get_file_info_plist(afc, path, &info);
 	memset(stbuf, 0, sizeof(struct afc_file_stat));
 	if (ret != AFC_E_SUCCESS) {
 		return -1;
 	} else if (!info) {
 		return -1;
-	} else {
-		// get file attributes from info list
-		int i;
-		for (i = 0; info[i]; i += 2) {
-			if (!strcmp(info[i], "st_size")) {
-				stbuf->st_size = atoll(info[i+1]);
-			} else if (!strcmp(info[i], "st_blocks")) {
-				stbuf->st_blocks = atoi(info[i+1]);
-			} else if (!strcmp(info[i], "st_ifmt")) {
-				if (!strcmp(info[i+1], "S_IFREG")) {
-					stbuf->st_mode = S_IFREG;
-				} else if (!strcmp(info[i+1], "S_IFDIR")) {
-					stbuf->st_mode = S_IFDIR;
-				} else if (!strcmp(info[i+1], "S_IFLNK")) {
-					stbuf->st_mode = S_IFLNK;
-				} else if (!strcmp(info[i+1], "S_IFBLK")) {
-					stbuf->st_mode = S_IFBLK;
-				} else if (!strcmp(info[i+1], "S_IFCHR")) {
-					stbuf->st_mode = S_IFCHR;
-				} else if (!strcmp(info[i+1], "S_IFIFO")) {
-					stbuf->st_mode = S_IFIFO;
-				} else if (!strcmp(info[i+1], "S_IFSOCK")) {
-					stbuf->st_mode = S_IFSOCK;
-				}
-			} else if (!strcmp(info[i], "st_nlink")) {
-				stbuf->st_nlink = atoi(info[i+1]);
-			} else if (!strcmp(info[i], "st_mtime")) {
-				stbuf->st_mtime = (time_t)(atoll(info[i+1]) / 1000000000);
-			} else if (!strcmp(info[i], "st_birthtime")) { /* available on iOS 7+ */
-				stbuf->st_birthtime = (time_t)(atoll(info[i+1]) / 1000000000);
-			}
-		}
-		afc_dictionary_free(info);
 	}
+	stbuf->st_size = plist_dict_get_uint(info, "st_size");
+	stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks");
+	const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
+	if (s_ifmt) {
+		if (!strcmp(s_ifmt, "S_IFREG")) {
+			stbuf->st_mode = S_IFREG;
+		} else if (!strcmp(s_ifmt, "S_IFDIR")) {
+			stbuf->st_mode = S_IFDIR;
+		} else if (!strcmp(s_ifmt, "S_IFLNK")) {
+			stbuf->st_mode = S_IFLNK;
+		} else if (!strcmp(s_ifmt, "S_IFBLK")) {
+			stbuf->st_mode = S_IFBLK;
+		} else if (!strcmp(s_ifmt, "S_IFCHR")) {
+			stbuf->st_mode = S_IFCHR;
+		} else if (!strcmp(s_ifmt, "S_IFIFO")) {
+			stbuf->st_mode = S_IFIFO;
+		} else if (!strcmp(s_ifmt, "S_IFSOCK")) {
+			stbuf->st_mode = S_IFSOCK;
+		}
+	}
+	stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink");
+	stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000);
+	/* available on iOS 7+ */
+	stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000);
+	plist_free(info);
 	return 0;
 }
 
@@ -431,22 +424,23 @@
 		return;
 	}
 
-	char **info = NULL;
+	plist_t info = NULL;
 	char* abspath = get_absolute_path(argv[0]);
 	if (!abspath) {
 		printf("Error: Invalid argument\n");
 		return;
 	}
-	afc_error_t err = afc_get_file_info(afc, abspath, &info);
+	afc_error_t err = afc_get_file_info_plist(afc, abspath, &info);
 	if (err == AFC_E_SUCCESS && info) {
-		int i;
-		for (i = 0; info[i]; i += 2) {
-			printf("%s: %s\n", info[i], info[i+1]);
+		if (argc > 1 && !strcmp(argv[1], "--plain")) {
+			plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
+		} else {
+			plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
 		}
 	} else {
 		printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err);
 	}
-	afc_dictionary_free(info);
+	plist_free(info);
 	free(abspath);
 }
 
@@ -784,28 +778,19 @@
 
 static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get)
 {
-	char **info = NULL;
+	plist_t info = NULL;
 	uint64_t file_size = 0;
-	afc_error_t err = afc_get_file_info(afc, srcpath, &info);
+	afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info);
 	if (err == AFC_E_OBJECT_NOT_FOUND) {
 		printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
 		return 0;
 	}
 	uint8_t is_dir = 0;
 	if (info) {
-		char **p = info;
-		while (p && *p) {
-			if (!strcmp(*p, "st_size")) {
-				p++;
-				file_size = (uint64_t) strtoull(*p, NULL, 10);
-			}
-			if (!strcmp(*p, "st_ifmt")) {
-				p++;
-				is_dir = !strcmp(*p, "S_IFDIR");
-			}
-			p++;
-		}
-		afc_dictionary_free(info);
+		file_size = plist_dict_get_uint(info, "st_size");
+		const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
+		is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
+		plist_free(info);
 	}
 	uint8_t succeed = 1;
 	if (is_dir) {
@@ -945,11 +930,11 @@
 
 static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite)
 {
-	char **info = NULL;
-	afc_error_t ret = afc_get_file_info(afc, dstpath, &info);
+	plist_t info = NULL;
+	afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info);
 	// file exists, only overwrite with '-f' option was set
 	if (ret == AFC_E_SUCCESS && info) {
-		afc_dictionary_free(info);
+		plist_free(info);
 		if (!force_overwrite) {
 			printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath);
 			return 0;
@@ -1030,10 +1015,11 @@
 			printf("Error: Failed to put directory without '-r' option: %s\n", srcpath);
 			return 0;
 		}
-		char **info = NULL;
-		afc_error_t err = afc_get_file_info(afc, dstpath, &info);
+		plist_t info = NULL;
+		afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
 		//create if target directory does not exist
-		afc_dictionary_free(info);
+		plist_free(info);
+		info = NULL;
 		if (err == AFC_E_OBJECT_NOT_FOUND) {
 			err = afc_make_directory(afc, dstpath);
 			if (err != AFC_E_SUCCESS) {
@@ -1044,19 +1030,12 @@
 			printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath);
 			return 0;
 		}
-		afc_get_file_info(afc, dstpath, &info);
+		afc_get_file_info_plist(afc, dstpath, &info);
 		uint8_t is_dir = 0;
 		if (info) {
-			char **p = info;
-			while (p && *p) {
-				if (!strcmp(*p, "st_ifmt")) {
-					p++;
-					is_dir = !strcmp(*p, "S_IFDIR");
-					break;
-				}
-				p++;
-			}
-			afc_dictionary_free(info);
+			const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
+			is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
+			plist_free(info);
 		}
 		if (!is_dir) {
 			printf("Error: Failed to create or access directory: '%s'\n", dstpath);
@@ -1148,8 +1127,8 @@
 		printf("Error: Invalid number of arguments\n");
 		return;
 	}
-	char **info = NULL;
-	afc_error_t err = afc_get_file_info(afc, dstpath, &info);
+	plist_t info = NULL;
+	afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
 	// target does not exist, put directly
 	if (err == AFC_E_OBJECT_NOT_FOUND) {
 		put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
@@ -1158,16 +1137,9 @@
 	} else {
 		uint8_t is_dir = 0;
 		if (info) {
-			char **p = info;
-			while (p && *p) {
-				if (!strcmp(*p, "st_ifmt")) {
-					p++;
-					is_dir = !strcmp(*p, "S_IFDIR");
-					break;
-				}
-				p++;
-			}
-			afc_dictionary_free(info);
+			const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
+			is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
+			plist_free(info);
 		}
 		// target is a directory, try to put under this directory
 		if (is_dir) {
@@ -1228,19 +1200,12 @@
 
 	char* path = get_realpath(argv[0]);
 	int is_dir = 0;
-	char **info = NULL;
-	afc_error_t err = afc_get_file_info(afc, path, &info);
+	plist_t info = NULL;
+	afc_error_t err = afc_get_file_info_plist(afc, path, &info);
 	if (err == AFC_E_SUCCESS && info) {
-		int i;
-		for (i = 0; info[i]; i += 2) {
-			if (!strcmp(info[i], "st_ifmt")) {
-				if (!strcmp(info[i+1], "S_IFDIR")) {
-					is_dir = 1;
-				}
-				break;
-			}
-		}
-		afc_dictionary_free(info);
+		const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
+		is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
+		plist_free(info);
 	} else {
 		printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err);
 		free(path);
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index cdce515..12d6083 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -131,21 +131,15 @@
 		return;
 	}
 
-	char **fileinfo = NULL;
+	plist_t fileinfo = NULL;
 	uint32_t fsize = 0;
 
-	afc_get_file_info(afc, filename, &fileinfo);
+	afc_get_file_info_plist(afc, filename, &fileinfo);
 	if (!fileinfo) {
 		return;
 	}
-	int i;
-	for (i = 0; fileinfo[i]; i+=2) {
-		if (!strcmp(fileinfo[i], "st_size")) {
-			fsize = atol(fileinfo[i+1]);
-			break;
-		}
-	}
-	afc_dictionary_free(fileinfo);
+	fsize = plist_dict_get_uint(fileinfo, "st_size");
+	plist_free(fileinfo);
 
 	if (fsize == 0) {
 		return;
diff --git a/tools/idevicecrashreport.c b/tools/idevicecrashreport.c
index ced5be2..b9869ae 100644
--- a/tools/idevicecrashreport.c
+++ b/tools/idevicecrashreport.c
@@ -146,7 +146,7 @@
 			continue;
 		}
 
-		char **fileinfo = NULL;
+		plist_t fileinfo = NULL;
 		struct stat stbuf;
 		memset(&stbuf, '\0', sizeof(struct stat));
 
@@ -173,70 +173,67 @@
 		}
 
 		/* get file information */
-		afc_get_file_info(afc, source_filename, &fileinfo);
+		afc_get_file_info_plist(afc, source_filename, &fileinfo);
 		if (!fileinfo) {
 			printf("Failed to read information for '%s'. Skipping...\n", source_filename);
 			continue;
 		}
 
 		/* parse file information */
-		int i;
-		for (i = 0; fileinfo[i]; i+=2) {
-			if (!strcmp(fileinfo[i], "st_size")) {
-				stbuf.st_size = atoll(fileinfo[i+1]);
-			} else if (!strcmp(fileinfo[i], "st_ifmt")) {
-				if (!strcmp(fileinfo[i+1], "S_IFREG")) {
-					stbuf.st_mode = S_IFREG;
-				} else if (!strcmp(fileinfo[i+1], "S_IFDIR")) {
-					stbuf.st_mode = S_IFDIR;
-				} else if (!strcmp(fileinfo[i+1], "S_IFLNK")) {
-					stbuf.st_mode = S_IFLNK;
-				} else if (!strcmp(fileinfo[i+1], "S_IFBLK")) {
-					stbuf.st_mode = S_IFBLK;
-				} else if (!strcmp(fileinfo[i+1], "S_IFCHR")) {
-					stbuf.st_mode = S_IFCHR;
-				} else if (!strcmp(fileinfo[i+1], "S_IFIFO")) {
-					stbuf.st_mode = S_IFIFO;
-				} else if (!strcmp(fileinfo[i+1], "S_IFSOCK")) {
-					stbuf.st_mode = S_IFSOCK;
-				}
-			} else if (!strcmp(fileinfo[i], "st_nlink")) {
-				stbuf.st_nlink = atoi(fileinfo[i+1]);
-			} else if (!strcmp(fileinfo[i], "st_mtime")) {
-				stbuf.st_mtime = (time_t)(atoll(fileinfo[i+1]) / 1000000000);
-			} else if (!strcmp(fileinfo[i], "LinkTarget") && !remove_all) {
-				/* report latest crash report filename */
-				printf("Link: %s\n", (char*)target_filename + strlen(target_directory));
+		stbuf.st_size = plist_dict_get_uint(fileinfo, "st_size");
+		const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(fileinfo, "st_ifmt"), NULL);
+		if (s_ifmt) {
+			if (!strcmp(s_ifmt, "S_IFREG")) {
+				stbuf.st_mode = S_IFREG;
+			} else if (!strcmp(s_ifmt, "S_IFDIR")) {
+				stbuf.st_mode = S_IFDIR;
+			} else if (!strcmp(s_ifmt, "S_IFLNK")) {
+				stbuf.st_mode = S_IFLNK;
+			} else if (!strcmp(s_ifmt, "S_IFBLK")) {
+				stbuf.st_mode = S_IFBLK;
+			} else if (!strcmp(s_ifmt, "S_IFCHR")) {
+				stbuf.st_mode = S_IFCHR;
+			} else if (!strcmp(s_ifmt, "S_IFIFO")) {
+				stbuf.st_mode = S_IFIFO;
+			} else if (!strcmp(s_ifmt, "S_IFSOCK")) {
+				stbuf.st_mode = S_IFSOCK;
+			}
+		}
+		stbuf.st_nlink = plist_dict_get_uint(fileinfo, "st_nlink");
+		stbuf.st_mtime = (time_t)(plist_dict_get_uint(fileinfo, "st_mtime") / 1000000000);
+		const char* linktarget = plist_get_string_ptr(plist_dict_get_item(fileinfo, "LinkTarget"), NULL);
+		if (linktarget && !remove_all) {
+			/* report latest crash report filename */
+			printf("Link: %s\n", (char*)target_filename + strlen(target_directory));
 
-				/* remove any previous symlink */
-				if (file_exists(target_filename)) {
-					remove(target_filename);
-				}
+			/* remove any previous symlink */
+			if (file_exists(target_filename)) {
+				remove(target_filename);
+			}
 
 #ifndef _WIN32
-				/* use relative filename */
-				char* b = strrchr(fileinfo[i+1], '/');
-				if (b == NULL) {
-					b = fileinfo[i+1];
+			/* use relative filename */
+			const char* b = strrchr(linktarget, '/');
+			if (b == NULL) {
+				b = linktarget;
 				} else {
-					b++;
-				}
+				b++;
+			}
 
-				/* create a symlink pointing to latest log */
-				if (symlink(b, target_filename) < 0) {
-					fprintf(stderr, "Can't create symlink to %s\n", b);
-				}
+			/* create a symlink pointing to latest log */
+			if (symlink(b, target_filename) < 0) {
+				fprintf(stderr, "Can't create symlink to %s\n", b);
+			}
 #endif
 
-				if (!keep_crash_reports)
-					afc_remove_path(afc, source_filename);
+			if (!keep_crash_reports)
+				afc_remove_path(afc, source_filename);
 
-				res = 0;
-			}
+			res = 0;
 		}
 
 		/* free file information */
-		afc_dictionary_free(fileinfo);
+		plist_free(fileinfo);
 
 		/* recurse into child directories */
 		if (S_ISDIR(stbuf.st_mode)) {
diff --git a/tools/ideviceimagemounter.c b/tools/ideviceimagemounter.c
index 90c5190..b319d05 100644
--- a/tools/ideviceimagemounter.c
+++ b/tools/ideviceimagemounter.c
@@ -598,20 +598,13 @@
 			case DISK_IMAGE_UPLOAD_TYPE_AFC:
 			default:
 				printf("Uploading %s --> afc:///%s\n", image_path, targetname);
-				char **strs = NULL;
-				if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) {
+				plist_t fileinfo = NULL;
+				if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) != AFC_E_SUCCESS) {
 					if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
 						fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH);
 					}
 				}
-				if (strs) {
-					int i = 0;
-					while (strs[i]) {
-						free(strs[i]);
-						i++;
-					}
-					free(strs);
-				}
+				plist_free(fileinfo);
 
 				uint64_t af = 0;
 				if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) !=