diff options
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/bplist.c | 2 | ||||
| -rw-r--r-- | src/common.c | 115 | ||||
| -rw-r--r-- | src/common.h | 34 | ||||
| -rw-r--r-- | src/jplist.c | 74 | ||||
| -rw-r--r-- | src/oplist.c | 71 | ||||
| -rw-r--r-- | src/out-default.c | 87 | ||||
| -rw-r--r-- | src/out-limd.c | 87 | ||||
| -rw-r--r-- | src/out-plutil.c | 156 | ||||
| -rw-r--r-- | src/plist.c | 2 | ||||
| -rw-r--r-- | src/time64.h | 7 | ||||
| -rw-r--r-- | src/xplist.c | 71 |
12 files changed, 265 insertions, 442 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1a416ad..ce4f931 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,6 +21,7 @@ libplist_2_0_la_SOURCES = \ ptrarray.c ptrarray.h \ time64.c time64.h \ time64_limits.h \ + common.c common.h \ xplist.c \ bplist.c \ jsmn.c jsmn.h \ diff --git a/src/bplist.c b/src/bplist.c index 1187c7a..7b08532 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -854,7 +854,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node uint64_t node_offset = UINT_TO_HOST(idx_ptr, bplist->offset_size); if (node_offset > (uint64_t)bplist->size) { - PLIST_BIN_ERR("node offset overflow (%llu)\n", node_offset); + PLIST_BIN_ERR("node offset overflow (%" PRIu64 ")\n", node_offset); bplist->err = PLIST_ERR_PARSE; return NULL; } diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..810c2e0 --- /dev/null +++ b/src/common.c @@ -0,0 +1,115 @@ +/* + * common.c + * contains some common functions + * + * Copyright (c) 2026 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 + */ +#include <math.h> +#include <stdio.h> +#include <stdint.h> +#include "common.h" + +size_t dtostr(char *buf, size_t bufsize, double realval) +{ + int slen = 0; + if (isnan(realval)) { + slen = snprintf(buf, bufsize, "nan"); + } else if (isinf(realval)) { + slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); + } else if (realval == 0.0f) { + slen = snprintf(buf, bufsize, "0.0"); + } else { + slen = snprintf(buf, bufsize, "%.*g", 17, realval); + if (slen < 0) { + return 0; + } + if (!buf || bufsize == 0) { + return (size_t)slen; + } + size_t len = (size_t)slen; + if (len >= bufsize) { + len = bufsize - 1; + } + size_t i = 0; + for (i = 0; i < len; i++) { + if (buf[i] == ',') { + buf[i] = '.'; + break; + } else if (buf[i] == '.') { + break; + } + } + return len; + } + if (slen < 0) { + return 0; + } + return (size_t)slen; +} + +/* based on https://stackoverflow.com/a/4143288 */ +#define PO10i_LIMIT (INT64_MAX/10) +int num_digits_i(int64_t i) +{ + int n; + int64_t po10; + n=1; + if (i < 0) { + i = (i == INT64_MIN) ? INT64_MAX : -i; + n++; + } + po10=10; + while (i>=po10) { + n++; + if (po10 > PO10i_LIMIT) break; + po10*=10; + } + return n; +} +#undef PO10i_LIMIT + +/* based on https://stackoverflow.com/a/4143288 */ +#define PO10u_LIMIT (UINT64_MAX/10) +int num_digits_u(uint64_t i) +{ + int n; + uint64_t po10; + n=1; + po10=10; + while (i>=po10) { + n++; + if (po10 > PO10u_LIMIT) break; + po10*=10; + } + return n; +} +#undef PO10u_LIMIT + +int plist_real_to_time64(double realval, Time64_T *timev) +{ + if (!timev || !isfinite(realval)) { + return -1; + } + + if (realval < (double)TIME64_MIN - (double)MAC_EPOCH || + realval > (double)TIME64_MAX - (double)MAC_EPOCH) { + return -1; + } + + *timev = (Time64_T)realval + MAC_EPOCH; + return 0; +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..ffaa78c --- /dev/null +++ b/src/common.h @@ -0,0 +1,34 @@ +/* + * common.h + * contains some common functions + * + * Copyright (c) 2026 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 + */ +#ifndef COMMON_H +#define COMMON_H + +#include <stddef.h> +#include "time64.h" + +#define MAC_EPOCH 978307200 + +size_t dtostr(char *buf, size_t bufsize, double realval); +int num_digits_i(int64_t i); +int num_digits_u(uint64_t i); +int plist_real_to_time64(double realval, Time64_T *timev); + +#endif diff --git a/src/jplist.c b/src/jplist.c index 410d4b3..c29f760 100644 --- a/src/jplist.c +++ b/src/jplist.c @@ -41,8 +41,7 @@ #include "hashtable.h" #include "base64.h" #include "time64.h" - -#define MAC_EPOCH 978307200 +#include "common.h" #ifdef DEBUG static int plist_json_debug = 0; @@ -95,30 +94,6 @@ static char* strndup(const char* str, size_t len) #endif #endif -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - size_t len = 0; - if (isnan(realval)) { - len = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - len = snprintf(buf, bufsize, "0.0"); - } else { - size_t i = 0; - len = snprintf(buf, bufsize, "%.*g", 17, realval); - for (i = 0; buf && i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - } - return len; -} - static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t depth, int prettify, int coerce) { plist_data_t node_data = NULL; @@ -282,7 +257,11 @@ static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t dept break; case PLIST_DATE: if (coerce) { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { + PLIST_JSON_WRITE_ERR("Encountered invalid date value %f\n", node_data->realval); + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); char datebuf[32]; @@ -325,44 +304,6 @@ static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t dept return PLIST_ERR_SUCCESS; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited) { plist_data_t data; @@ -556,6 +497,7 @@ typedef struct { static int64_t parse_decimal(const char* str, const char* str_end, char** endp) { + const uint64_t po10i_limit = INT64_MAX / 10; uint64_t MAX = INT64_MAX; uint64_t x = 0; int is_neg = 0; @@ -571,7 +513,7 @@ static int64_t parse_decimal(const char* str, const char* str_end, char** endp) MAX++; } while (*endp < str_end && isdigit(**endp)) { - if (x > PO10i_LIMIT) { + if (x > po10i_limit) { x = MAX; break; } diff --git a/src/oplist.c b/src/oplist.c index 3c48b3a..77a99cd 100644 --- a/src/oplist.c +++ b/src/oplist.c @@ -39,8 +39,7 @@ #include "strbuf.h" #include "time64.h" #include "hashtable.h" - -#define MAC_EPOCH 978307200 +#include "common.h" #ifdef DEBUG static int plist_ostep_debug = 0; @@ -93,30 +92,6 @@ static char* strndup(const char* str, size_t len) #endif #endif -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - size_t len = 0; - if (isnan(realval)) { - len = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - len = snprintf(buf, bufsize, "0.0"); - } else { - size_t i = 0; - len = snprintf(buf, bufsize, "%.*g", 17, realval); - for (i = 0; buf && i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - } - return len; -} - static const char allowed_unquoted_chars[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -326,7 +301,11 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t break; case PLIST_DATE: if (coerce) { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { + PLIST_OSTEP_WRITE_ERR("Encountered invalid date value %f\n", node_data->realval); + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); char datebuf[32]; @@ -371,44 +350,6 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t return PLIST_ERR_SUCCESS; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited) { plist_data_t data; diff --git a/src/out-default.c b/src/out-default.c index 676a677..13b9d9c 100644 --- a/src/out-default.c +++ b/src/out-default.c @@ -39,46 +39,7 @@ #include "strbuf.h" #include "time64.h" #include "hashtable.h" - -#define MAC_EPOCH 978307200 - -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - int slen = 0; - if (isnan(realval)) { - slen = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - slen = snprintf(buf, bufsize, "0.0"); - } else { - slen = snprintf(buf, bufsize, "%.*g", 17, realval); - if (slen < 0) { - return 0; - } - if (!buf || bufsize == 0) { - return (size_t)slen; - } - size_t len = (size_t)slen; - if (len >= bufsize) { - len = bufsize - 1; - } - size_t i = 0; - for (i = 0; i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - return len; - } - if (slen < 0) { - return 0; - } - return (size_t)slen; -} +#include "common.h" static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent, int partial_data) { @@ -270,7 +231,13 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de break; case PLIST_DATE: { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { +#if DEBUG + fprintf(stderr, "libplist: ERROR: Encountered invalid date value %f\n", node_data->realval); +#endif + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); if (btime) { @@ -313,44 +280,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de return PLIST_ERR_SUCCESS; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data, hashtable_t *visited) { plist_data_t data; diff --git a/src/out-limd.c b/src/out-limd.c index 6d864cb..83a5e26 100644 --- a/src/out-limd.c +++ b/src/out-limd.c @@ -41,46 +41,7 @@ #include "time64.h" #include "base64.h" #include "hashtable.h" - -#define MAC_EPOCH 978307200 - -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - int slen = 0; - if (isnan(realval)) { - slen = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - slen = snprintf(buf, bufsize, "0.0"); - } else { - slen = snprintf(buf, bufsize, "%.*g", 17, realval); - if (slen < 0) { - return 0; - } - if (!buf || bufsize == 0) { - return (size_t)slen; - } - size_t len = (size_t)slen; - if (len >= bufsize) { - len = bufsize - 1; - } - size_t i = 0; - for (i = 0; i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - return len; - } - if (slen < 0) { - return 0; - } - return (size_t)slen; -} +#include "common.h" static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent) { @@ -259,7 +220,13 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de break; case PLIST_DATE: { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { +#if DEBUG + fprintf(stderr, "libplist: ERROR: Encountered invalid date value %f\n", node_data->realval); +#endif + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); if (btime) { @@ -304,44 +271,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de return PLIST_ERR_SUCCESS; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, hashtable_t *visited) { plist_data_t data; diff --git a/src/out-plutil.c b/src/out-plutil.c index bf9e72e..e603f31 100644 --- a/src/out-plutil.c +++ b/src/out-plutil.c @@ -39,46 +39,24 @@ #include "strbuf.h" #include "time64.h" #include "hashtable.h" - -#define MAC_EPOCH 978307200 - -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - size_t len = 0; - if (isnan(realval)) { - len = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - len = snprintf(buf, bufsize, "0.0"); - } else { - size_t i = 0; - len = snprintf(buf, bufsize, "%.*g", 17, realval); - for (i = 0; buf && i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - } - return len; -} +#include "common.h" static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth) { plist_data_t node_data = NULL; char *val = NULL; + int slen = 0; size_t val_len = 0; - uint32_t i = 0; - - if (!node) + if (!node || !outbuf || !*outbuf) { return PLIST_ERR_INVALID_ARG; + } node_data = plist_get_data(node); + if (!node_data) { + return PLIST_ERR_INVALID_ARG; + } switch (node_data->type) { @@ -98,17 +76,24 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de case PLIST_INT: val = (char*)malloc(64); + if (!val) return PLIST_ERR_NO_MEM; if (node_data->length == 16) { - val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); + slen = snprintf(val, 64, "%" PRIu64, node_data->intval); } else { - val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); + slen = snprintf(val, 64, "%" PRIi64, node_data->intval); + } + if (slen < 0) { + free(val); + return PLIST_ERR_UNKNOWN; } + val_len = (size_t)slen; str_buf_append(*outbuf, val, val_len); free(val); break; case PLIST_REAL: val = (char*)malloc(64); + if (!val) return PLIST_ERR_NO_MEM; val_len = dtostr(val, 64, node_data->realval); str_buf_append(*outbuf, val, val_len); free(val); @@ -116,6 +101,9 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de case PLIST_STRING: case PLIST_KEY: { + if (!node_data->strval && node_data->length > 0) { + return PLIST_ERR_INVALID_ARG; + } const char *charmap[32] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", @@ -124,8 +112,8 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de }; size_t j = 0; size_t len = 0; - off_t start = 0; - off_t cur = 0; + size_t start = 0; + size_t cur = 0; str_buf_append(*outbuf, "\"", 1); @@ -152,14 +140,18 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de str_buf_append(*outbuf, "[", 1); node_t ch; uint32_t cnt = 0; + uint32_t i; for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { str_buf_append(*outbuf, "\n", 1); for (i = 0; i <= depth; i++) { str_buf_append(*outbuf, " ", 2); } char indexbuf[16]; - int l = sprintf(indexbuf, "%u => ", cnt); - str_buf_append(*outbuf, indexbuf, l); + slen = snprintf(indexbuf, sizeof(indexbuf), "%u => ", cnt); + if (slen < 0) { + return PLIST_ERR_UNKNOWN; + } + str_buf_append(*outbuf, indexbuf, (size_t)slen); plist_err_t res = node_to_string(ch, outbuf, depth+1); if (res < 0) { return res; @@ -178,6 +170,7 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de str_buf_append(*outbuf, "{", 1); node_t ch; uint32_t cnt = 0; + uint32_t i; for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { if (cnt % 2 == 0) { str_buf_append(*outbuf, "\n", 1); @@ -204,27 +197,36 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de } break; case PLIST_DATA: { + if (!node_data->buff && node_data->length > 0) { + return PLIST_ERR_INVALID_ARG; + } val = (char*)calloc(1, 48); + if (!val) return PLIST_ERR_NO_MEM; size_t len = node_data->length; - size_t slen = snprintf(val, 48, "{length = %" PRIu64 ", bytes = 0x", (uint64_t)len); - str_buf_append(*outbuf, val, slen); + slen = snprintf(val, 48, "{length = %" PRIu64 ", bytes = 0x", (uint64_t)len); + if (slen < 0) { + free(val); + return PLIST_ERR_UNKNOWN; + } + str_buf_append(*outbuf, val, (size_t)slen); + size_t j; if (len <= 24) { - for (i = 0; i < len; i++) { - sprintf(val, "%02x", (unsigned char)node_data->buff[i]); + for (j = 0; j < len; j++) { + snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]); str_buf_append(*outbuf, val, 2); } } else { - for (i = 0; i < 16; i++) { - if (i > 0 && (i % 4 == 0)) + for (j = 0; j < 16; j++) { + if (j > 0 && (j % 4 == 0)) str_buf_append(*outbuf, " ", 1); - sprintf(val, "%02x", (unsigned char)node_data->buff[i]); + snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]); str_buf_append(*outbuf, val, 2); } str_buf_append(*outbuf, " ... ", 5); - for (i = len - 8; i < len; i++) { - sprintf(val, "%02x", (unsigned char)node_data->buff[i]); + for (j = len - 8; j < len; j++) { + snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]); str_buf_append(*outbuf, val, 2); - if (i > 0 && (i % 4 == 0)) + if (j > 0 && (j % 4 == 0)) str_buf_append(*outbuf, " ", 1); } } @@ -235,11 +237,18 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de break; case PLIST_DATE: { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { +#if DEBUG + fprintf(stderr, "libplist: ERROR: Encountered invalid date value %f\n", node_data->realval); +#endif + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); if (btime) { val = (char*)calloc(1, 26); + if (!val) return PLIST_ERR_NO_MEM; struct tm _tmcopy; copy_TM64_to_tm(btime, &_tmcopy); val_len = strftime(val, 26, "%Y-%m-%d %H:%M:%S +0000", &_tmcopy); @@ -253,11 +262,24 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de break; case PLIST_UID: { - val = (char*)malloc(88); - val_len = sprintf(val, "<CFKeyedArchiverUID %p [%p]>{value = %" PRIu64 "}", node, node_data, node_data->intval); +#define UID_FMT "<CFKeyedArchiverUID %p [%p]>{value = %" PRIu64 "}" + slen = snprintf(NULL, 0, UID_FMT, node, node_data, node_data->intval); + if (slen < 0) { + return PLIST_ERR_UNKNOWN; + } + val_len = (size_t)slen; + val = (char*)malloc(val_len + 1); + if (!val) return PLIST_ERR_NO_MEM; + slen = snprintf(val, val_len+1, UID_FMT, node, node_data, node_data->intval); + if (slen < 0 || (size_t)slen > val_len) { + free(val); + return PLIST_ERR_UNKNOWN; + } + val_len = (size_t)slen; str_buf_append(*outbuf, val, val_len); free(val); val = NULL; +#undef UID_FMT } break; default: @@ -267,44 +289,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de return PLIST_ERR_SUCCESS; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) { plist_data_t data; diff --git a/src/plist.c b/src/plist.c index 7def2b6..05af457 100644 --- a/src/plist.c +++ b/src/plist.c @@ -46,7 +46,7 @@ #include <hashtable.h> #include <ptrarray.h> -#define MAC_EPOCH 978307200 +#include "common.h" #ifdef _MSC_VER typedef SSIZE_T ssize_t; diff --git a/src/time64.h b/src/time64.h index 28968c0..2c20ffe 100644 --- a/src/time64.h +++ b/src/time64.h @@ -11,6 +11,13 @@ typedef long long Int64; typedef Int64 Time64_T; typedef Int64 Year; +#ifndef TIME64_MIN +#define TIME64_MIN ((Time64_T)INT64_MIN) +#endif + +#ifndef TIME64_MAX +#define TIME64_MAX ((Time64_T)INT64_MAX) +#endif /* A copy of the tm struct but with a 64 bit year */ struct TM64 { diff --git a/src/xplist.c b/src/xplist.c index de5227a..b2c134e 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -48,6 +48,7 @@ #include "strbuf.h" #include "time64.h" #include "hashtable.h" +#include "common.h" #define XPLIST_KEY "key" #define XPLIST_KEY_LEN 3 @@ -70,8 +71,6 @@ #define XPLIST_DICT "dict" #define XPLIST_DICT_LEN 4 -#define MAC_EPOCH 978307200 - #define MAX_DATA_BYTES_PER_LINE(__i) (((76 - ((__i) << 3)) >> 2) * 3) static const char XML_PLIST_PROLOG[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ @@ -111,30 +110,6 @@ void plist_xml_set_debug(int debug) #endif } -static size_t dtostr(char *buf, size_t bufsize, double realval) -{ - size_t len = 0; - if (isnan(realval)) { - len = snprintf(buf, bufsize, "nan"); - } else if (isinf(realval)) { - len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); - } else if (realval == 0.0f) { - len = snprintf(buf, bufsize, "0.0"); - } else { - size_t i = 0; - len = snprintf(buf, bufsize, "%.*g", 17, realval); - for (i = 0; buf && i < len; i++) { - if (buf[i] == ',') { - buf[i] = '.'; - break; - } else if (buf[i] == '.') { - break; - } - } - } - return len; -} - static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth) { plist_data_t node_data = NULL; @@ -217,7 +192,11 @@ static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth tag = XPLIST_DATE; tag_len = XPLIST_DATE_LEN; { - Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH; + Time64_T timev; + if (plist_real_to_time64(node_data->realval, &timev) < 0) { + PLIST_XML_WRITE_ERR("Encountered invalid date value %f\n", node_data->realval); + return PLIST_ERR_INVALID_ARG; + } struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); if (btime) { @@ -422,44 +401,6 @@ static int parse_date(const char *strval, struct TM *btime) return 0; } -#define PO10i_LIMIT (INT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_i(int64_t i) -{ - int n; - int64_t po10; - n=1; - if (i < 0) { - i = (i == INT64_MIN) ? INT64_MAX : -i; - n++; - } - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10i_LIMIT) break; - po10*=10; - } - return n; -} - -#define PO10u_LIMIT (UINT64_MAX/10) - -/* based on https://stackoverflow.com/a/4143288 */ -static int num_digits_u(uint64_t i) -{ - int n; - uint64_t po10; - n=1; - po10=10; - while (i>=po10) { - n++; - if (po10 > PO10u_LIMIT) break; - po10*=10; - } - return n; -} - static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) { plist_data_t data; |
