From ce9ce43efd707a85cc792ff2cc417603a53d4d1d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Apr 2023 17:49:07 +0200 Subject: Add plist_read_from_file() to interface, update plist_from_memory() plist_read_from_file() is a convenience function that will open a given file, checks its size, allocates a buffer large enough to hold the full contents, and reads from file to fill the buffer. Then, it calls plist_from_memory() to convert the data to plist format. A (breaking) change had to be made so that plist_from_memory() will also return the parsed format in its 4th argument (if non-NULL). --- include/plist/plist.h | 23 +++++++++++++++++++++-- src/plist.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- test/plist_cmp.c | 46 ++------------------------------------------- tools/plistutil.c | 2 +- 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/include/plist/plist.h b/include/plist/plist.h index b635996..9b16c58 100644 --- a/include/plist/plist.h +++ b/include/plist/plist.h @@ -44,6 +44,7 @@ extern "C" #include #endif +/*{{{ deprecation macros */ #ifdef __llvm__ #if defined(__has_extension) #if (__has_extension(attribute_deprecated_with_message)) @@ -72,6 +73,7 @@ extern "C" #define PLIST_WARN_DEPRECATED(x) #pragma message("WARNING: You need to implement DEPRECATED for this compiler") #endif +/*}}}*/ #include #include @@ -819,7 +821,8 @@ extern "C" /** * Import the #plist_t structure from memory data. - * This method will look at the first bytes of plist_data + * + * This function will look at the first bytes of plist_data * to determine if plist_data contains a binary, JSON, OpenStep, or XML plist * and tries to parse the data in the appropriate format. * @note This is just a convenience function and the format detection is @@ -831,9 +834,25 @@ extern "C" * @param plist_data A pointer to the memory buffer containing plist data. * @param length Length of the buffer to read. * @param plist A pointer to the imported plist. + * @param format If non-NULL, the #plist_format_t value pointed to will be set to the parsed format. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format); + + /** + * Import the #plist_t structure directly from file. + * + * This function will look at the first bytes of the file data + * to determine if it contains a binary, JSON, OpenStep, or XML plist + * and tries to parse the data in the appropriate format. + * Uses #plist_read_from_data() internally. + * + * @param filename The name of the file to parse. + * @param plist A pointer to the imported plist. + * @param format If non-NULL, the #plist_format_t value pointed to will be set to the parsed format. * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure */ - plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist); + plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format); /** * Write the #plist_t structure to a NULL-terminated string using the given format and options. diff --git a/src/plist.c b/src/plist.c index 01e44df..48b012b 100644 --- a/src/plist.c +++ b/src/plist.c @@ -197,7 +197,7 @@ PLIST_API int plist_is_binary(const char *plist_data, uint32_t length) #define FIND_NEXT(blob, pos, len, chr) \ while (pos < len && (blob[pos] != chr)) pos++; -PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist) +PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format) { int res = -1; if (!plist) { @@ -207,8 +207,11 @@ PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, if (!plist_data || length == 0) { return PLIST_ERR_INVALID_ARG; } + plist_format_t fmt = 0; + if (format) *format = 0; if (plist_is_binary(plist_data, length)) { res = plist_from_bin(plist_data, length, plist); + fmt = PLIST_FORMAT_BINARY; } else { uint32_t pos = 0; int is_json = 0; @@ -248,12 +251,59 @@ PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, } if (is_xml) { res = plist_from_xml(plist_data, length, plist); + fmt = PLIST_FORMAT_XML; } else if (is_json) { res = plist_from_json(plist_data, length, plist); + fmt = PLIST_FORMAT_JSON; } else { res = plist_from_openstep(plist_data, length, plist); + fmt = PLIST_FORMAT_OSTEP; } } + if (format && res == PLIST_ERR_SUCCESS) { + *format = fmt; + } + return res; +} + +PLIST_API plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format) +{ + if (!filename || !plist) { + return PLIST_ERR_INVALID_ARG; + } + FILE *f = fopen(filename, "rb"); + if (!f) { + return PLIST_ERR_IO; + } + struct stat fst; + fstat(fileno(f), &fst); + if (fst.st_size > UINT32_MAX) { + return PLIST_ERR_NO_MEM; + } + uint32_t total = (uint32_t)fst.st_size; + if (total == 0) { + return PLIST_ERR_PARSE; + } + char *buf = malloc(total); + if (!buf) { + fclose(f); + return PLIST_ERR_NO_MEM; + } + uint32_t done = 0; + while (done < total) { + ssize_t r = fread(buf + done, 1, total - done, f); + if (r <= 0) { + break; + } + done += r; + } + fclose(f); + if (done < total) { + free(buf); + return PLIST_ERR_IO; + } + plist_err_t res = plist_from_memory(buf, total, plist, format); + free(buf); return res; } diff --git a/test/plist_cmp.c b/test/plist_cmp.c index 4947276..c452032 100644 --- a/test/plist_cmp.c +++ b/test/plist_cmp.c @@ -75,21 +75,12 @@ static char compare_plist(plist_t node_l, plist_t node_r) int main(int argc, char *argv[]) { - FILE *iplist1 = NULL; - FILE *iplist2 = NULL; plist_t root_node1 = NULL; plist_t root_node2 = NULL; - char *plist_1 = NULL; - char *plist_2 = NULL; - int size_in1 = 0; - int size_in2 = 0; char *file_in1 = NULL; char *file_in2 = NULL; int res = 0; - struct stat *filestats1 = (struct stat *) malloc(sizeof(struct stat)); - struct stat *filestats2 = (struct stat *) malloc(sizeof(struct stat)); - if (argc!= 3) { printf("Wrong input\n"); @@ -99,36 +90,8 @@ int main(int argc, char *argv[]) file_in1 = argv[1]; file_in2 = argv[2]; - //read input file - iplist1 = fopen(file_in1, "rb"); - iplist2 = fopen(file_in2, "rb"); - - if (!iplist1 || !iplist2) - { - printf("File does not exists\n"); - return 2; - } - - stat(file_in1, filestats1); - stat(file_in2, filestats2); - - size_in1 = filestats1->st_size; - size_in2 = filestats2->st_size; - - plist_1 = (char *) malloc(sizeof(char) * (size_in1 + 1)); - plist_2 = (char *) malloc(sizeof(char) * (size_in2 + 1)); - - fread(plist_1, sizeof(char), size_in1, iplist1); - fread(plist_2, sizeof(char), size_in2, iplist2); - - fclose(iplist1); - fclose(iplist2); - - plist_1[size_in1] = '\0'; - plist_2[size_in2] = '\0'; - - plist_from_memory(plist_1, size_in1, &root_node1); - plist_from_memory(plist_2, size_in2, &root_node2); + plist_read_from_file(file_in1, &root_node1, NULL); + plist_read_from_file(file_in2, &root_node2, NULL); if (!root_node1 || !root_node2) { @@ -142,11 +105,6 @@ int main(int argc, char *argv[]) plist_free(root_node1); plist_free(root_node2); - free(plist_1); - free(plist_2); - free(filestats1); - free(filestats2); - return !res; } diff --git a/tools/plistutil.c b/tools/plistutil.c index e339b8b..6da53e4 100644 --- a/tools/plistutil.c +++ b/tools/plistutil.c @@ -284,7 +284,7 @@ int main(int argc, char *argv[]) } else { - input_res = plist_from_memory(plist_entire, read_size, &root_node); + input_res = plist_from_memory(plist_entire, read_size, &root_node, NULL); if (input_res == PLIST_ERR_SUCCESS) { if (options->flags & OPT_SORT) { plist_sort(root_node); -- cgit v1.1-32-gdbae