summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-05-22 18:46:02 +0200
committerGravatar Nikias Bassen2026-05-22 18:46:02 +0200
commit9711459dbed7d60bb00c7d2c052623e8489c88e1 (patch)
tree550cceb133bbff047ad5b8d7e0334596b252f7f2 /src
parent389fab9a07baf3913c4214425e86cca588d559a1 (diff)
downloadlibplist-9711459dbed7d60bb00c7d2c052623e8489c88e1.tar.gz
libplist-9711459dbed7d60bb00c7d2c052623e8489c88e1.tar.bz2
refactor: centralize formatting helpers and harden out-plutil
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/common.c100
-rw-r--r--src/common.h32
-rw-r--r--src/jplist.c68
-rw-r--r--src/oplist.c65
-rw-r--r--src/out-default.c79
-rw-r--r--src/out-limd.c79
-rw-r--r--src/out-plutil.c148
-rw-r--r--src/plist.c2
-rw-r--r--src/xplist.c65
10 files changed, 204 insertions, 435 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 = \
21 ptrarray.c ptrarray.h \ 21 ptrarray.c ptrarray.h \
22 time64.c time64.h \ 22 time64.c time64.h \
23 time64_limits.h \ 23 time64_limits.h \
24 common.c common.h \
24 xplist.c \ 25 xplist.c \
25 bplist.c \ 26 bplist.c \
26 jsmn.c jsmn.h \ 27 jsmn.c jsmn.h \
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..0b11d57
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,100 @@
1/*
2 * common.c
3 * contains some common functions
4 *
5 * Copyright (c) 2026 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#include <math.h>
22#include <stdio.h>
23#include <stdint.h>
24#include "common.h"
25
26size_t dtostr(char *buf, size_t bufsize, double realval)
27{
28 int slen = 0;
29 if (isnan(realval)) {
30 slen = snprintf(buf, bufsize, "nan");
31 } else if (isinf(realval)) {
32 slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
33 } else if (realval == 0.0f) {
34 slen = snprintf(buf, bufsize, "0.0");
35 } else {
36 slen = snprintf(buf, bufsize, "%.*g", 17, realval);
37 if (slen < 0) {
38 return 0;
39 }
40 if (!buf || bufsize == 0) {
41 return (size_t)slen;
42 }
43 size_t len = (size_t)slen;
44 if (len >= bufsize) {
45 len = bufsize - 1;
46 }
47 size_t i = 0;
48 for (i = 0; i < len; i++) {
49 if (buf[i] == ',') {
50 buf[i] = '.';
51 break;
52 } else if (buf[i] == '.') {
53 break;
54 }
55 }
56 return len;
57 }
58 if (slen < 0) {
59 return 0;
60 }
61 return (size_t)slen;
62}
63
64/* based on https://stackoverflow.com/a/4143288 */
65#define PO10i_LIMIT (INT64_MAX/10)
66int num_digits_i(int64_t i)
67{
68 int n;
69 int64_t po10;
70 n=1;
71 if (i < 0) {
72 i = (i == INT64_MIN) ? INT64_MAX : -i;
73 n++;
74 }
75 po10=10;
76 while (i>=po10) {
77 n++;
78 if (po10 > PO10i_LIMIT) break;
79 po10*=10;
80 }
81 return n;
82}
83#undef PO10i_LIMIT
84
85/* based on https://stackoverflow.com/a/4143288 */
86#define PO10u_LIMIT (UINT64_MAX/10)
87int num_digits_u(uint64_t i)
88{
89 int n;
90 uint64_t po10;
91 n=1;
92 po10=10;
93 while (i>=po10) {
94 n++;
95 if (po10 > PO10u_LIMIT) break;
96 po10*=10;
97 }
98 return n;
99}
100#undef PO10u_LIMIT
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..7e5aff7
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,32 @@
1/*
2 * common.h
3 * contains some common functions
4 *
5 * Copyright (c) 2026 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#ifndef COMMON_H
22#define COMMON_H
23
24#include <stddef.h>
25
26#define MAC_EPOCH 978307200
27
28size_t dtostr(char *buf, size_t bufsize, double realval);
29int num_digits_i(int64_t i);
30int num_digits_u(uint64_t i);
31
32#endif
diff --git a/src/jplist.c b/src/jplist.c
index 410d4b3..cc1cd1b 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -41,8 +41,7 @@
41#include "hashtable.h" 41#include "hashtable.h"
42#include "base64.h" 42#include "base64.h"
43#include "time64.h" 43#include "time64.h"
44 44#include "common.h"
45#define MAC_EPOCH 978307200
46 45
47#ifdef DEBUG 46#ifdef DEBUG
48static int plist_json_debug = 0; 47static int plist_json_debug = 0;
@@ -95,30 +94,6 @@ static char* strndup(const char* str, size_t len)
95#endif 94#endif
96#endif 95#endif
97 96
98static size_t dtostr(char *buf, size_t bufsize, double realval)
99{
100 size_t len = 0;
101 if (isnan(realval)) {
102 len = snprintf(buf, bufsize, "nan");
103 } else if (isinf(realval)) {
104 len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
105 } else if (realval == 0.0f) {
106 len = snprintf(buf, bufsize, "0.0");
107 } else {
108 size_t i = 0;
109 len = snprintf(buf, bufsize, "%.*g", 17, realval);
110 for (i = 0; buf && i < len; i++) {
111 if (buf[i] == ',') {
112 buf[i] = '.';
113 break;
114 } else if (buf[i] == '.') {
115 break;
116 }
117 }
118 }
119 return len;
120}
121
122static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t depth, int prettify, int coerce) 97static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t depth, int prettify, int coerce)
123{ 98{
124 plist_data_t node_data = NULL; 99 plist_data_t node_data = NULL;
@@ -325,44 +300,6 @@ static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t dept
325 return PLIST_ERR_SUCCESS; 300 return PLIST_ERR_SUCCESS;
326} 301}
327 302
328#define PO10i_LIMIT (INT64_MAX/10)
329
330/* based on https://stackoverflow.com/a/4143288 */
331static int num_digits_i(int64_t i)
332{
333 int n;
334 int64_t po10;
335 n=1;
336 if (i < 0) {
337 i = (i == INT64_MIN) ? INT64_MAX : -i;
338 n++;
339 }
340 po10=10;
341 while (i>=po10) {
342 n++;
343 if (po10 > PO10i_LIMIT) break;
344 po10*=10;
345 }
346 return n;
347}
348
349#define PO10u_LIMIT (UINT64_MAX/10)
350
351/* based on https://stackoverflow.com/a/4143288 */
352static int num_digits_u(uint64_t i)
353{
354 int n;
355 uint64_t po10;
356 n=1;
357 po10=10;
358 while (i>=po10) {
359 n++;
360 if (po10 > PO10u_LIMIT) break;
361 po10*=10;
362 }
363 return n;
364}
365
366static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited) 303static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited)
367{ 304{
368 plist_data_t data; 305 plist_data_t data;
@@ -556,6 +493,7 @@ typedef struct {
556 493
557static int64_t parse_decimal(const char* str, const char* str_end, char** endp) 494static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
558{ 495{
496 const uint64_t po10i_limit = INT64_MAX / 10;
559 uint64_t MAX = INT64_MAX; 497 uint64_t MAX = INT64_MAX;
560 uint64_t x = 0; 498 uint64_t x = 0;
561 int is_neg = 0; 499 int is_neg = 0;
@@ -571,7 +509,7 @@ static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
571 MAX++; 509 MAX++;
572 } 510 }
573 while (*endp < str_end && isdigit(**endp)) { 511 while (*endp < str_end && isdigit(**endp)) {
574 if (x > PO10i_LIMIT) { 512 if (x > po10i_limit) {
575 x = MAX; 513 x = MAX;
576 break; 514 break;
577 } 515 }
diff --git a/src/oplist.c b/src/oplist.c
index 3c48b3a..292467f 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -39,8 +39,7 @@
39#include "strbuf.h" 39#include "strbuf.h"
40#include "time64.h" 40#include "time64.h"
41#include "hashtable.h" 41#include "hashtable.h"
42 42#include "common.h"
43#define MAC_EPOCH 978307200
44 43
45#ifdef DEBUG 44#ifdef DEBUG
46static int plist_ostep_debug = 0; 45static int plist_ostep_debug = 0;
@@ -93,30 +92,6 @@ static char* strndup(const char* str, size_t len)
93#endif 92#endif
94#endif 93#endif
95 94
96static size_t dtostr(char *buf, size_t bufsize, double realval)
97{
98 size_t len = 0;
99 if (isnan(realval)) {
100 len = snprintf(buf, bufsize, "nan");
101 } else if (isinf(realval)) {
102 len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
103 } else if (realval == 0.0f) {
104 len = snprintf(buf, bufsize, "0.0");
105 } else {
106 size_t i = 0;
107 len = snprintf(buf, bufsize, "%.*g", 17, realval);
108 for (i = 0; buf && i < len; i++) {
109 if (buf[i] == ',') {
110 buf[i] = '.';
111 break;
112 } else if (buf[i] == '.') {
113 break;
114 }
115 }
116 }
117 return len;
118}
119
120static const char allowed_unquoted_chars[256] = { 95static const char allowed_unquoted_chars[256] = {
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -371,44 +346,6 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t
371 return PLIST_ERR_SUCCESS; 346 return PLIST_ERR_SUCCESS;
372} 347}
373 348
374#define PO10i_LIMIT (INT64_MAX/10)
375
376/* based on https://stackoverflow.com/a/4143288 */
377static int num_digits_i(int64_t i)
378{
379 int n;
380 int64_t po10;
381 n=1;
382 if (i < 0) {
383 i = (i == INT64_MIN) ? INT64_MAX : -i;
384 n++;
385 }
386 po10=10;
387 while (i>=po10) {
388 n++;
389 if (po10 > PO10i_LIMIT) break;
390 po10*=10;
391 }
392 return n;
393}
394
395#define PO10u_LIMIT (UINT64_MAX/10)
396
397/* based on https://stackoverflow.com/a/4143288 */
398static int num_digits_u(uint64_t i)
399{
400 int n;
401 uint64_t po10;
402 n=1;
403 po10=10;
404 while (i>=po10) {
405 n++;
406 if (po10 > PO10u_LIMIT) break;
407 po10*=10;
408 }
409 return n;
410}
411
412static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited) 349static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited)
413{ 350{
414 plist_data_t data; 351 plist_data_t data;
diff --git a/src/out-default.c b/src/out-default.c
index 676a677..5d4b6fc 100644
--- a/src/out-default.c
+++ b/src/out-default.c
@@ -39,46 +39,7 @@
39#include "strbuf.h" 39#include "strbuf.h"
40#include "time64.h" 40#include "time64.h"
41#include "hashtable.h" 41#include "hashtable.h"
42 42#include "common.h"
43#define MAC_EPOCH 978307200
44
45static size_t dtostr(char *buf, size_t bufsize, double realval)
46{
47 int slen = 0;
48 if (isnan(realval)) {
49 slen = snprintf(buf, bufsize, "nan");
50 } else if (isinf(realval)) {
51 slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
52 } else if (realval == 0.0f) {
53 slen = snprintf(buf, bufsize, "0.0");
54 } else {
55 slen = snprintf(buf, bufsize, "%.*g", 17, realval);
56 if (slen < 0) {
57 return 0;
58 }
59 if (!buf || bufsize == 0) {
60 return (size_t)slen;
61 }
62 size_t len = (size_t)slen;
63 if (len >= bufsize) {
64 len = bufsize - 1;
65 }
66 size_t i = 0;
67 for (i = 0; i < len; i++) {
68 if (buf[i] == ',') {
69 buf[i] = '.';
70 break;
71 } else if (buf[i] == '.') {
72 break;
73 }
74 }
75 return len;
76 }
77 if (slen < 0) {
78 return 0;
79 }
80 return (size_t)slen;
81}
82 43
83static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent, int partial_data) 44static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent, int partial_data)
84{ 45{
@@ -313,44 +274,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
313 return PLIST_ERR_SUCCESS; 274 return PLIST_ERR_SUCCESS;
314} 275}
315 276
316#define PO10i_LIMIT (INT64_MAX/10)
317
318/* based on https://stackoverflow.com/a/4143288 */
319static int num_digits_i(int64_t i)
320{
321 int n;
322 int64_t po10;
323 n=1;
324 if (i < 0) {
325 i = (i == INT64_MIN) ? INT64_MAX : -i;
326 n++;
327 }
328 po10=10;
329 while (i>=po10) {
330 n++;
331 if (po10 > PO10i_LIMIT) break;
332 po10*=10;
333 }
334 return n;
335}
336
337#define PO10u_LIMIT (UINT64_MAX/10)
338
339/* based on https://stackoverflow.com/a/4143288 */
340static int num_digits_u(uint64_t i)
341{
342 int n;
343 uint64_t po10;
344 n=1;
345 po10=10;
346 while (i>=po10) {
347 n++;
348 if (po10 > PO10u_LIMIT) break;
349 po10*=10;
350 }
351 return n;
352}
353
354static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data, hashtable_t *visited) 277static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data, hashtable_t *visited)
355{ 278{
356 plist_data_t data; 279 plist_data_t data;
diff --git a/src/out-limd.c b/src/out-limd.c
index 6d864cb..b01f966 100644
--- a/src/out-limd.c
+++ b/src/out-limd.c
@@ -41,46 +41,7 @@
41#include "time64.h" 41#include "time64.h"
42#include "base64.h" 42#include "base64.h"
43#include "hashtable.h" 43#include "hashtable.h"
44 44#include "common.h"
45#define MAC_EPOCH 978307200
46
47static size_t dtostr(char *buf, size_t bufsize, double realval)
48{
49 int slen = 0;
50 if (isnan(realval)) {
51 slen = snprintf(buf, bufsize, "nan");
52 } else if (isinf(realval)) {
53 slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
54 } else if (realval == 0.0f) {
55 slen = snprintf(buf, bufsize, "0.0");
56 } else {
57 slen = snprintf(buf, bufsize, "%.*g", 17, realval);
58 if (slen < 0) {
59 return 0;
60 }
61 if (!buf || bufsize == 0) {
62 return (size_t)slen;
63 }
64 size_t len = (size_t)slen;
65 if (len >= bufsize) {
66 len = bufsize - 1;
67 }
68 size_t i = 0;
69 for (i = 0; i < len; i++) {
70 if (buf[i] == ',') {
71 buf[i] = '.';
72 break;
73 } else if (buf[i] == '.') {
74 break;
75 }
76 }
77 return len;
78 }
79 if (slen < 0) {
80 return 0;
81 }
82 return (size_t)slen;
83}
84 45
85static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent) 46static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent)
86{ 47{
@@ -304,44 +265,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
304 return PLIST_ERR_SUCCESS; 265 return PLIST_ERR_SUCCESS;
305} 266}
306 267
307#define PO10i_LIMIT (INT64_MAX/10)
308
309/* based on https://stackoverflow.com/a/4143288 */
310static int num_digits_i(int64_t i)
311{
312 int n;
313 int64_t po10;
314 n=1;
315 if (i < 0) {
316 i = (i == INT64_MIN) ? INT64_MAX : -i;
317 n++;
318 }
319 po10=10;
320 while (i>=po10) {
321 n++;
322 if (po10 > PO10i_LIMIT) break;
323 po10*=10;
324 }
325 return n;
326}
327
328#define PO10u_LIMIT (UINT64_MAX/10)
329
330/* based on https://stackoverflow.com/a/4143288 */
331static int num_digits_u(uint64_t i)
332{
333 int n;
334 uint64_t po10;
335 n=1;
336 po10=10;
337 while (i>=po10) {
338 n++;
339 if (po10 > PO10u_LIMIT) break;
340 po10*=10;
341 }
342 return n;
343}
344
345static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, hashtable_t *visited) 268static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, hashtable_t *visited)
346{ 269{
347 plist_data_t data; 270 plist_data_t data;
diff --git a/src/out-plutil.c b/src/out-plutil.c
index bf9e72e..9f7968e 100644
--- a/src/out-plutil.c
+++ b/src/out-plutil.c
@@ -39,46 +39,24 @@
39#include "strbuf.h" 39#include "strbuf.h"
40#include "time64.h" 40#include "time64.h"
41#include "hashtable.h" 41#include "hashtable.h"
42 42#include "common.h"
43#define MAC_EPOCH 978307200
44
45static size_t dtostr(char *buf, size_t bufsize, double realval)
46{
47 size_t len = 0;
48 if (isnan(realval)) {
49 len = snprintf(buf, bufsize, "nan");
50 } else if (isinf(realval)) {
51 len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
52 } else if (realval == 0.0f) {
53 len = snprintf(buf, bufsize, "0.0");
54 } else {
55 size_t i = 0;
56 len = snprintf(buf, bufsize, "%.*g", 17, realval);
57 for (i = 0; buf && i < len; i++) {
58 if (buf[i] == ',') {
59 buf[i] = '.';
60 break;
61 } else if (buf[i] == '.') {
62 break;
63 }
64 }
65 }
66 return len;
67}
68 43
69static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth) 44static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth)
70{ 45{
71 plist_data_t node_data = NULL; 46 plist_data_t node_data = NULL;
72 47
73 char *val = NULL; 48 char *val = NULL;
49 int slen = 0;
74 size_t val_len = 0; 50 size_t val_len = 0;
75 51
76 uint32_t i = 0; 52 if (!node || !outbuf || !*outbuf) {
77
78 if (!node)
79 return PLIST_ERR_INVALID_ARG; 53 return PLIST_ERR_INVALID_ARG;
54 }
80 55
81 node_data = plist_get_data(node); 56 node_data = plist_get_data(node);
57 if (!node_data) {
58 return PLIST_ERR_INVALID_ARG;
59 }
82 60
83 switch (node_data->type) 61 switch (node_data->type)
84 { 62 {
@@ -98,17 +76,24 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
98 76
99 case PLIST_INT: 77 case PLIST_INT:
100 val = (char*)malloc(64); 78 val = (char*)malloc(64);
79 if (!val) return PLIST_ERR_NO_MEM;
101 if (node_data->length == 16) { 80 if (node_data->length == 16) {
102 val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); 81 slen = snprintf(val, 64, "%" PRIu64, node_data->intval);
103 } else { 82 } else {
104 val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); 83 slen = snprintf(val, 64, "%" PRIi64, node_data->intval);
84 }
85 if (slen < 0) {
86 free(val);
87 return PLIST_ERR_UNKNOWN;
105 } 88 }
89 val_len = (size_t)slen;
106 str_buf_append(*outbuf, val, val_len); 90 str_buf_append(*outbuf, val, val_len);
107 free(val); 91 free(val);
108 break; 92 break;
109 93
110 case PLIST_REAL: 94 case PLIST_REAL:
111 val = (char*)malloc(64); 95 val = (char*)malloc(64);
96 if (!val) return PLIST_ERR_NO_MEM;
112 val_len = dtostr(val, 64, node_data->realval); 97 val_len = dtostr(val, 64, node_data->realval);
113 str_buf_append(*outbuf, val, val_len); 98 str_buf_append(*outbuf, val, val_len);
114 free(val); 99 free(val);
@@ -116,6 +101,9 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
116 101
117 case PLIST_STRING: 102 case PLIST_STRING:
118 case PLIST_KEY: { 103 case PLIST_KEY: {
104 if (!node_data->strval && node_data->length > 0) {
105 return PLIST_ERR_INVALID_ARG;
106 }
119 const char *charmap[32] = { 107 const char *charmap[32] = {
120 "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", 108 "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
121 "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", 109 "\\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
124 }; 112 };
125 size_t j = 0; 113 size_t j = 0;
126 size_t len = 0; 114 size_t len = 0;
127 off_t start = 0; 115 size_t start = 0;
128 off_t cur = 0; 116 size_t cur = 0;
129 117
130 str_buf_append(*outbuf, "\"", 1); 118 str_buf_append(*outbuf, "\"", 1);
131 119
@@ -152,14 +140,18 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
152 str_buf_append(*outbuf, "[", 1); 140 str_buf_append(*outbuf, "[", 1);
153 node_t ch; 141 node_t ch;
154 uint32_t cnt = 0; 142 uint32_t cnt = 0;
143 uint32_t i;
155 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { 144 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
156 str_buf_append(*outbuf, "\n", 1); 145 str_buf_append(*outbuf, "\n", 1);
157 for (i = 0; i <= depth; i++) { 146 for (i = 0; i <= depth; i++) {
158 str_buf_append(*outbuf, " ", 2); 147 str_buf_append(*outbuf, " ", 2);
159 } 148 }
160 char indexbuf[16]; 149 char indexbuf[16];
161 int l = sprintf(indexbuf, "%u => ", cnt); 150 slen = snprintf(indexbuf, sizeof(indexbuf), "%u => ", cnt);
162 str_buf_append(*outbuf, indexbuf, l); 151 if (slen < 0) {
152 return PLIST_ERR_UNKNOWN;
153 }
154 str_buf_append(*outbuf, indexbuf, (size_t)slen);
163 plist_err_t res = node_to_string(ch, outbuf, depth+1); 155 plist_err_t res = node_to_string(ch, outbuf, depth+1);
164 if (res < 0) { 156 if (res < 0) {
165 return res; 157 return res;
@@ -178,6 +170,7 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
178 str_buf_append(*outbuf, "{", 1); 170 str_buf_append(*outbuf, "{", 1);
179 node_t ch; 171 node_t ch;
180 uint32_t cnt = 0; 172 uint32_t cnt = 0;
173 uint32_t i;
181 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { 174 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
182 if (cnt % 2 == 0) { 175 if (cnt % 2 == 0) {
183 str_buf_append(*outbuf, "\n", 1); 176 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
204 } break; 197 } break;
205 case PLIST_DATA: 198 case PLIST_DATA:
206 { 199 {
200 if (!node_data->buff && node_data->length > 0) {
201 return PLIST_ERR_INVALID_ARG;
202 }
207 val = (char*)calloc(1, 48); 203 val = (char*)calloc(1, 48);
204 if (!val) return PLIST_ERR_NO_MEM;
208 size_t len = node_data->length; 205 size_t len = node_data->length;
209 size_t slen = snprintf(val, 48, "{length = %" PRIu64 ", bytes = 0x", (uint64_t)len); 206 slen = snprintf(val, 48, "{length = %" PRIu64 ", bytes = 0x", (uint64_t)len);
210 str_buf_append(*outbuf, val, slen); 207 if (slen < 0) {
208 free(val);
209 return PLIST_ERR_UNKNOWN;
210 }
211 str_buf_append(*outbuf, val, (size_t)slen);
212 size_t j;
211 if (len <= 24) { 213 if (len <= 24) {
212 for (i = 0; i < len; i++) { 214 for (j = 0; j < len; j++) {
213 sprintf(val, "%02x", (unsigned char)node_data->buff[i]); 215 snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]);
214 str_buf_append(*outbuf, val, 2); 216 str_buf_append(*outbuf, val, 2);
215 } 217 }
216 } else { 218 } else {
217 for (i = 0; i < 16; i++) { 219 for (j = 0; j < 16; j++) {
218 if (i > 0 && (i % 4 == 0)) 220 if (j > 0 && (j % 4 == 0))
219 str_buf_append(*outbuf, " ", 1); 221 str_buf_append(*outbuf, " ", 1);
220 sprintf(val, "%02x", (unsigned char)node_data->buff[i]); 222 snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]);
221 str_buf_append(*outbuf, val, 2); 223 str_buf_append(*outbuf, val, 2);
222 } 224 }
223 str_buf_append(*outbuf, " ... ", 5); 225 str_buf_append(*outbuf, " ... ", 5);
224 for (i = len - 8; i < len; i++) { 226 for (j = len - 8; j < len; j++) {
225 sprintf(val, "%02x", (unsigned char)node_data->buff[i]); 227 snprintf(val, 4, "%02x", (unsigned char)node_data->buff[j]);
226 str_buf_append(*outbuf, val, 2); 228 str_buf_append(*outbuf, val, 2);
227 if (i > 0 && (i % 4 == 0)) 229 if (j > 0 && (j % 4 == 0))
228 str_buf_append(*outbuf, " ", 1); 230 str_buf_append(*outbuf, " ", 1);
229 } 231 }
230 } 232 }
@@ -240,6 +242,7 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
240 struct TM *btime = gmtime64_r(&timev, &_btime); 242 struct TM *btime = gmtime64_r(&timev, &_btime);
241 if (btime) { 243 if (btime) {
242 val = (char*)calloc(1, 26); 244 val = (char*)calloc(1, 26);
245 if (!val) return PLIST_ERR_NO_MEM;
243 struct tm _tmcopy; 246 struct tm _tmcopy;
244 copy_TM64_to_tm(btime, &_tmcopy); 247 copy_TM64_to_tm(btime, &_tmcopy);
245 val_len = strftime(val, 26, "%Y-%m-%d %H:%M:%S +0000", &_tmcopy); 248 val_len = strftime(val, 26, "%Y-%m-%d %H:%M:%S +0000", &_tmcopy);
@@ -253,11 +256,24 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
253 break; 256 break;
254 case PLIST_UID: 257 case PLIST_UID:
255 { 258 {
256 val = (char*)malloc(88); 259#define UID_FMT "<CFKeyedArchiverUID %p [%p]>{value = %" PRIu64 "}"
257 val_len = sprintf(val, "<CFKeyedArchiverUID %p [%p]>{value = %" PRIu64 "}", node, node_data, node_data->intval); 260 slen = snprintf(NULL, 0, UID_FMT, node, node_data, node_data->intval);
261 if (slen < 0) {
262 return PLIST_ERR_UNKNOWN;
263 }
264 val_len = (size_t)slen;
265 val = (char*)malloc(val_len + 1);
266 if (!val) return PLIST_ERR_NO_MEM;
267 slen = snprintf(val, val_len+1, UID_FMT, node, node_data, node_data->intval);
268 if (slen < 0 || (size_t)slen > val_len) {
269 free(val);
270 return PLIST_ERR_UNKNOWN;
271 }
272 val_len = (size_t)slen;
258 str_buf_append(*outbuf, val, val_len); 273 str_buf_append(*outbuf, val, val_len);
259 free(val); 274 free(val);
260 val = NULL; 275 val = NULL;
276#undef UID_FMT
261 } 277 }
262 break; 278 break;
263 default: 279 default:
@@ -267,44 +283,6 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
267 return PLIST_ERR_SUCCESS; 283 return PLIST_ERR_SUCCESS;
268} 284}
269 285
270#define PO10i_LIMIT (INT64_MAX/10)
271
272/* based on https://stackoverflow.com/a/4143288 */
273static int num_digits_i(int64_t i)
274{
275 int n;
276 int64_t po10;
277 n=1;
278 if (i < 0) {
279 i = (i == INT64_MIN) ? INT64_MAX : -i;
280 n++;
281 }
282 po10=10;
283 while (i>=po10) {
284 n++;
285 if (po10 > PO10i_LIMIT) break;
286 po10*=10;
287 }
288 return n;
289}
290
291#define PO10u_LIMIT (UINT64_MAX/10)
292
293/* based on https://stackoverflow.com/a/4143288 */
294static int num_digits_u(uint64_t i)
295{
296 int n;
297 uint64_t po10;
298 n=1;
299 po10=10;
300 while (i>=po10) {
301 n++;
302 if (po10 > PO10u_LIMIT) break;
303 po10*=10;
304 }
305 return n;
306}
307
308static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) 286static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited)
309{ 287{
310 plist_data_t data; 288 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 @@
46#include <hashtable.h> 46#include <hashtable.h>
47#include <ptrarray.h> 47#include <ptrarray.h>
48 48
49#define MAC_EPOCH 978307200 49#include "common.h"
50 50
51#ifdef _MSC_VER 51#ifdef _MSC_VER
52typedef SSIZE_T ssize_t; 52typedef SSIZE_T ssize_t;
diff --git a/src/xplist.c b/src/xplist.c
index de5227a..8f5cb15 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -48,6 +48,7 @@
48#include "strbuf.h" 48#include "strbuf.h"
49#include "time64.h" 49#include "time64.h"
50#include "hashtable.h" 50#include "hashtable.h"
51#include "common.h"
51 52
52#define XPLIST_KEY "key" 53#define XPLIST_KEY "key"
53#define XPLIST_KEY_LEN 3 54#define XPLIST_KEY_LEN 3
@@ -70,8 +71,6 @@
70#define XPLIST_DICT "dict" 71#define XPLIST_DICT "dict"
71#define XPLIST_DICT_LEN 4 72#define XPLIST_DICT_LEN 4
72 73
73#define MAC_EPOCH 978307200
74
75#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - ((__i) << 3)) >> 2) * 3) 74#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - ((__i) << 3)) >> 2) * 3)
76 75
77static const char XML_PLIST_PROLOG[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 76static const char XML_PLIST_PROLOG[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
@@ -111,30 +110,6 @@ void plist_xml_set_debug(int debug)
111#endif 110#endif
112} 111}
113 112
114static size_t dtostr(char *buf, size_t bufsize, double realval)
115{
116 size_t len = 0;
117 if (isnan(realval)) {
118 len = snprintf(buf, bufsize, "nan");
119 } else if (isinf(realval)) {
120 len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
121 } else if (realval == 0.0f) {
122 len = snprintf(buf, bufsize, "0.0");
123 } else {
124 size_t i = 0;
125 len = snprintf(buf, bufsize, "%.*g", 17, realval);
126 for (i = 0; buf && i < len; i++) {
127 if (buf[i] == ',') {
128 buf[i] = '.';
129 break;
130 } else if (buf[i] == '.') {
131 break;
132 }
133 }
134 }
135 return len;
136}
137
138static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth) 113static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth)
139{ 114{
140 plist_data_t node_data = NULL; 115 plist_data_t node_data = NULL;
@@ -422,44 +397,6 @@ static int parse_date(const char *strval, struct TM *btime)
422 return 0; 397 return 0;
423} 398}
424 399
425#define PO10i_LIMIT (INT64_MAX/10)
426
427/* based on https://stackoverflow.com/a/4143288 */
428static int num_digits_i(int64_t i)
429{
430 int n;
431 int64_t po10;
432 n=1;
433 if (i < 0) {
434 i = (i == INT64_MIN) ? INT64_MAX : -i;
435 n++;
436 }
437 po10=10;
438 while (i>=po10) {
439 n++;
440 if (po10 > PO10i_LIMIT) break;
441 po10*=10;
442 }
443 return n;
444}
445
446#define PO10u_LIMIT (UINT64_MAX/10)
447
448/* based on https://stackoverflow.com/a/4143288 */
449static int num_digits_u(uint64_t i)
450{
451 int n;
452 uint64_t po10;
453 n=1;
454 po10=10;
455 while (i>=po10) {
456 n++;
457 if (po10 > PO10u_LIMIT) break;
458 po10*=10;
459 }
460 return n;
461}
462
463static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) 400static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited)
464{ 401{
465 plist_data_t data; 402 plist_data_t data;