diff options
| author | 2023-04-21 17:19:13 +0200 | |
|---|---|---|
| committer | 2023-04-21 17:19:13 +0200 | |
| commit | f1ff5caef3732062c62fdfdf38f4087fff15adb0 (patch) | |
| tree | d308192e163c2c29abb34dbbc0d8b164a656aa2c /src | |
| parent | ac69c93e9985fc588270edd50b9749e490c98210 (diff) | |
| download | ideviceinstaller-f1ff5caef3732062c62fdfdf38f4087fff15adb0.tar.gz ideviceinstaller-f1ff5caef3732062c62fdfdf38f4087fff15adb0.tar.bz2 | |
Add support for JSON output
Diffstat (limited to 'src')
| -rw-r--r-- | src/ideviceinstaller.c | 90 |
1 files changed, 73 insertions, 17 deletions
diff --git a/src/ideviceinstaller.c b/src/ideviceinstaller.c index caba7f0..4b1b3d7 100644 --- a/src/ideviceinstaller.c +++ b/src/ideviceinstaller.c | |||
| @@ -121,7 +121,9 @@ int err_occurred = 0; | |||
| 121 | int notified = 0; | 121 | int notified = 0; |
| 122 | plist_t bundle_ids = NULL; | 122 | plist_t bundle_ids = NULL; |
| 123 | plist_t return_attrs = NULL; | 123 | plist_t return_attrs = NULL; |
| 124 | int xml_mode = 0; | 124 | #define FORMAT_XML 1 |
| 125 | #define FORMAT_JSON 2 | ||
| 126 | int output_format = 0; | ||
| 125 | int opt_list_user = 0; | 127 | int opt_list_user = 0; |
| 126 | int opt_list_system = 0; | 128 | int opt_list_system = 0; |
| 127 | char *copy_path = NULL; | 129 | char *copy_path = NULL; |
| @@ -469,7 +471,8 @@ enum numerical_opts { | |||
| 469 | ARCHIVE_DOCS_ONLY, | 471 | ARCHIVE_DOCS_ONLY, |
| 470 | ARCHIVE_COPY_PATH, | 472 | ARCHIVE_COPY_PATH, |
| 471 | ARCHIVE_COPY_REMOVE, | 473 | ARCHIVE_COPY_REMOVE, |
| 472 | OUTPUT_XML | 474 | OUTPUT_XML, |
| 475 | OUTPUT_JSON | ||
| 473 | }; | 476 | }; |
| 474 | 477 | ||
| 475 | static void parse_opts(int argc, char **argv) | 478 | static void parse_opts(int argc, char **argv) |
| @@ -487,6 +490,7 @@ static void parse_opts(int argc, char **argv) | |||
| 487 | { "system", no_argument, NULL, LIST_SYSTEM }, | 490 | { "system", no_argument, NULL, LIST_SYSTEM }, |
| 488 | { "all", no_argument, NULL, LIST_ALL }, | 491 | { "all", no_argument, NULL, LIST_ALL }, |
| 489 | { "xml", no_argument, NULL, OUTPUT_XML }, | 492 | { "xml", no_argument, NULL, OUTPUT_XML }, |
| 493 | { "json", no_argument, NULL, OUTPUT_JSON }, | ||
| 490 | { "uninstall", no_argument, NULL, ARCHIVE_UNINSTALL }, | 494 | { "uninstall", no_argument, NULL, ARCHIVE_UNINSTALL }, |
| 491 | { "app-only", no_argument, NULL, ARCHIVE_APP_ONLY }, | 495 | { "app-only", no_argument, NULL, ARCHIVE_APP_ONLY }, |
| 492 | { "docs-only", no_argument, NULL, ARCHIVE_DOCS_ONLY }, | 496 | { "docs-only", no_argument, NULL, ARCHIVE_DOCS_ONLY }, |
| @@ -559,7 +563,10 @@ static void parse_opts(int argc, char **argv) | |||
| 559 | opt_list_system = 1; | 563 | opt_list_system = 1; |
| 560 | break; | 564 | break; |
| 561 | case OUTPUT_XML: | 565 | case OUTPUT_XML: |
| 562 | xml_mode = 1; | 566 | output_format = FORMAT_XML; |
| 567 | break; | ||
| 568 | case OUTPUT_JSON: | ||
| 569 | output_format = FORMAT_JSON; | ||
| 563 | break; | 570 | break; |
| 564 | case ARCHIVE_UNINSTALL: | 571 | case ARCHIVE_UNINSTALL: |
| 565 | skip_uninstall = 0; | 572 | skip_uninstall = 0; |
| @@ -852,7 +859,7 @@ run_again: | |||
| 852 | plist_dict_set_item(client_opts, "BundleIDs", plist_copy(bundle_ids)); | 859 | plist_dict_set_item(client_opts, "BundleIDs", plist_copy(bundle_ids)); |
| 853 | } | 860 | } |
| 854 | 861 | ||
| 855 | if (!xml_mode) { | 862 | if (!output_format && !return_attrs) { |
| 856 | return_attrs = plist_new_array(); | 863 | return_attrs = plist_new_array(); |
| 857 | plist_array_append_item(return_attrs, plist_new_string("CFBundleIdentifier")); | 864 | plist_array_append_item(return_attrs, plist_new_string("CFBundleIdentifier")); |
| 858 | plist_array_append_item(return_attrs, plist_new_string("CFBundleShortVersionString")); | 865 | plist_array_append_item(return_attrs, plist_new_string("CFBundleShortVersionString")); |
| @@ -863,20 +870,59 @@ run_again: | |||
| 863 | instproxy_client_options_add(client_opts, "ReturnAttributes", return_attrs, NULL); | 870 | instproxy_client_options_add(client_opts, "ReturnAttributes", return_attrs, NULL); |
| 864 | } | 871 | } |
| 865 | 872 | ||
| 866 | if (xml_mode) { | 873 | if (output_format) { |
| 867 | err = instproxy_browse(ipc, client_opts, &apps); | 874 | err = instproxy_browse(ipc, client_opts, &apps); |
| 868 | 875 | ||
| 869 | if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { | 876 | if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { |
| 870 | fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n"); | 877 | fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n"); |
| 871 | goto leave_cleanup; | 878 | goto leave_cleanup; |
| 872 | } | 879 | } |
| 873 | char *xml = NULL; | 880 | char *buf = NULL; |
| 874 | uint32_t len = 0; | 881 | uint32_t len = 0; |
| 875 | 882 | if (output_format == FORMAT_XML) { | |
| 876 | plist_to_xml(apps, &xml, &len); | 883 | plist_err_t perr = plist_to_xml(apps, &buf, &len); |
| 877 | if (xml) { | 884 | if (perr != PLIST_ERR_SUCCESS) { |
| 878 | puts(xml); | 885 | fprintf(stderr, "ERROR: Failed to convert data to XML format (%d).\n", perr); |
| 879 | free(xml); | 886 | } |
| 887 | } else if (output_format == FORMAT_JSON) { | ||
| 888 | /* for JSON, we need to convert some stuff since it doesn't support PLIST_DATA nodes */ | ||
| 889 | plist_array_iter aiter = NULL; | ||
| 890 | plist_array_new_iter(apps, &aiter); | ||
| 891 | plist_t entry = NULL; | ||
| 892 | do { | ||
| 893 | plist_array_next_item(apps, aiter, &entry); | ||
| 894 | if (!entry) break; | ||
| 895 | plist_t items = plist_dict_get_item(entry, "UIApplicationShortcutItems"); | ||
| 896 | plist_array_iter inner = NULL; | ||
| 897 | plist_array_new_iter(items, &inner); | ||
| 898 | plist_t item = NULL; | ||
| 899 | do { | ||
| 900 | plist_array_next_item(items, inner, &item); | ||
| 901 | if (!item) break; | ||
| 902 | plist_t userinfo = plist_dict_get_item(item, "UIApplicationShortcutItemUserInfo"); | ||
| 903 | if (userinfo) { | ||
| 904 | plist_t data_node = plist_dict_get_item(userinfo, "data"); | ||
| 905 | |||
| 906 | if (data_node) { | ||
| 907 | char *strbuf = NULL; | ||
| 908 | uint32_t buflen = 0; | ||
| 909 | plist_write_to_string(data_node, &strbuf, &buflen, PLIST_FORMAT_LIMD, PLIST_OPT_NO_NEWLINE); | ||
| 910 | plist_set_string_val(data_node, strbuf); | ||
| 911 | free(strbuf); | ||
| 912 | } | ||
| 913 | } | ||
| 914 | } while (item); | ||
| 915 | free(inner); | ||
| 916 | } while (entry); | ||
| 917 | free(aiter); | ||
| 918 | plist_err_t perr = plist_to_json(apps, &buf, &len, 1); | ||
| 919 | if (perr != PLIST_ERR_SUCCESS) { | ||
| 920 | fprintf(stderr, "ERROR: Failed to convert data to JSON format (%d).\n", perr); | ||
| 921 | } | ||
| 922 | } | ||
| 923 | if (buf) { | ||
| 924 | puts(buf); | ||
| 925 | free(buf); | ||
| 880 | } | 926 | } |
| 881 | plist_free(apps); | 927 | plist_free(apps); |
| 882 | goto leave_cleanup; | 928 | goto leave_cleanup; |
| @@ -1265,13 +1311,23 @@ run_again: | |||
| 1265 | goto leave_cleanup; | 1311 | goto leave_cleanup; |
| 1266 | } | 1312 | } |
| 1267 | 1313 | ||
| 1268 | if (xml_mode) { | 1314 | if (output_format) { |
| 1269 | char *xml = NULL; | 1315 | char *buf = NULL; |
| 1270 | uint32_t len = 0; | 1316 | uint32_t len = 0; |
| 1271 | plist_to_xml(dict, &xml, &len); | 1317 | if (output_format == FORMAT_XML) { |
| 1272 | if (xml) { | 1318 | plist_err_t perr = plist_to_xml(dict, &buf, &len); |
| 1273 | puts(xml); | 1319 | if (perr != PLIST_ERR_SUCCESS) { |
| 1274 | free(xml); | 1320 | fprintf(stderr, "ERROR: Failed to convert data to XML format (%d).\n", perr); |
| 1321 | } | ||
| 1322 | } else if (output_format == FORMAT_JSON) { | ||
| 1323 | plist_err_t perr = plist_to_json(dict, &buf, &len, 1); | ||
| 1324 | if (perr != PLIST_ERR_SUCCESS) { | ||
| 1325 | fprintf(stderr, "ERROR: Failed to convert data to JSON format (%d).\n", perr); | ||
| 1326 | } | ||
| 1327 | } | ||
| 1328 | if (buf) { | ||
| 1329 | puts(buf); | ||
| 1330 | free(buf); | ||
| 1275 | } | 1331 | } |
| 1276 | plist_free(dict); | 1332 | plist_free(dict); |
| 1277 | goto leave_cleanup; | 1333 | goto leave_cleanup; |
