summaryrefslogtreecommitdiffstats
path: root/src/out-plutil.c
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/out-plutil.c
parent389fab9a07baf3913c4214425e86cca588d559a1 (diff)
downloadlibplist-9711459dbed7d60bb00c7d2c052623e8489c88e1.tar.gz
libplist-9711459dbed7d60bb00c7d2c052623e8489c88e1.tar.bz2
refactor: centralize formatting helpers and harden out-plutil
Diffstat (limited to 'src/out-plutil.c')
-rw-r--r--src/out-plutil.c148
1 files changed, 63 insertions, 85 deletions
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;