summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/oplist.c143
-rw-r--r--src/plist.c4
2 files changed, 117 insertions, 30 deletions
diff --git a/src/oplist.c b/src/oplist.c
index 0eea27a..3c48b3a 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -37,8 +37,11 @@
37 37
38#include "plist.h" 38#include "plist.h"
39#include "strbuf.h" 39#include "strbuf.h"
40#include "time64.h"
40#include "hashtable.h" 41#include "hashtable.h"
41 42
43#define MAC_EPOCH 978307200
44
42#ifdef DEBUG 45#ifdef DEBUG
43static int plist_ostep_debug = 0; 46static int plist_ostep_debug = 0;
44#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); } 47#define PLIST_OSTEP_ERR(...) if (plist_ostep_debug) { fprintf(stderr, "libplist[ostepparser] ERROR: " __VA_ARGS__); }
@@ -144,7 +147,7 @@ static int str_needs_quotes(const char* str, size_t len)
144 return 0; 147 return 0;
145} 148}
146 149
147static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t depth, int prettify) 150static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t depth, int prettify, int coerce)
148{ 151{
149 plist_data_t node_data = NULL; 152 plist_data_t node_data = NULL;
150 153
@@ -235,7 +238,7 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t
235 str_buf_append(*outbuf, " ", 2); 238 str_buf_append(*outbuf, " ", 2);
236 } 239 }
237 } 240 }
238 plist_err_t res = node_to_openstep(ch, outbuf, depth+1, prettify); 241 plist_err_t res = node_to_openstep(ch, outbuf, depth+1, prettify, coerce);
239 if (res < 0) { 242 if (res < 0) {
240 return res; 243 return res;
241 } 244 }
@@ -263,7 +266,7 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t
263 str_buf_append(*outbuf, " ", 2); 266 str_buf_append(*outbuf, " ", 2);
264 } 267 }
265 } 268 }
266 plist_err_t res = node_to_openstep(ch, outbuf, depth+1, prettify); 269 plist_err_t res = node_to_openstep(ch, outbuf, depth+1, prettify, coerce);
267 if (res < 0) { 270 if (res < 0) {
268 return res; 271 return res;
269 } 272 }
@@ -302,19 +305,65 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t
302 str_buf_append(*outbuf, ">", 1); 305 str_buf_append(*outbuf, ">", 1);
303 } break; 306 } break;
304 case PLIST_BOOLEAN: 307 case PLIST_BOOLEAN:
305 PLIST_OSTEP_WRITE_ERR("PLIST_BOOLEAN type is not valid for OpenStep format\n"); 308 if (coerce) {
306 return PLIST_ERR_FORMAT; 309 if (node_data->boolval) {
310 str_buf_append(*outbuf, "1", 1);
311 } else {
312 str_buf_append(*outbuf, "0", 1);
313 }
314 } else {
315 PLIST_OSTEP_WRITE_ERR("PLIST_BOOLEAN type is not valid for OpenStep format\n");
316 return PLIST_ERR_FORMAT;
317 }
318 break;
307 case PLIST_NULL: 319 case PLIST_NULL:
308 PLIST_OSTEP_WRITE_ERR("PLIST_NULL type is not valid for OpenStep format\n"); 320 if (coerce) {
309 return PLIST_ERR_FORMAT; 321 str_buf_append(*outbuf, "NULL", 4);
322 } else {
323 PLIST_OSTEP_WRITE_ERR("PLIST_NULL type is not valid for OpenStep format\n");
324 return PLIST_ERR_FORMAT;
325 }
326 break;
310 case PLIST_DATE: 327 case PLIST_DATE:
311 // NOT VALID FOR OPENSTEP 328 if (coerce) {
312 PLIST_OSTEP_WRITE_ERR("PLIST_DATE type is not valid for OpenStep format\n"); 329 Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
313 return PLIST_ERR_FORMAT; 330 struct TM _btime;
331 struct TM *btime = gmtime64_r(&timev, &_btime);
332 char datebuf[32];
333 size_t datelen = 0;
334 if (btime) {
335 struct tm _tmcopy;
336 copy_TM64_to_tm(btime, &_tmcopy);
337 datelen = strftime(datebuf, sizeof(datebuf), "%Y-%m-%dT%H:%M:%SZ", &_tmcopy);
338 }
339 if (datelen <= 0) {
340 datelen = snprintf(datebuf, sizeof(datebuf), "1970-01-01T00:00:00Z");
341 }
342 str_buf_append(*outbuf, "\"", 1);
343 str_buf_append(*outbuf, datebuf, datelen);
344 str_buf_append(*outbuf, "\"", 1);
345 } else {
346 // NOT VALID FOR OPENSTEP
347 PLIST_OSTEP_WRITE_ERR("PLIST_DATE type is not valid for OpenStep format\n");
348 return PLIST_ERR_FORMAT;
349 }
350 break;
314 case PLIST_UID: 351 case PLIST_UID:
315 // NOT VALID FOR OPENSTEP 352 if (coerce) {
316 PLIST_OSTEP_WRITE_ERR("PLIST_UID type is not valid for OpenStep format\n"); 353 val = (char*)malloc(64);
317 return PLIST_ERR_FORMAT; 354 if (node_data->length == 16) {
355 val_len = snprintf(val, 64, "%" PRIu64, node_data->intval);
356 } else {
357 val_len = snprintf(val, 64, "%" PRIi64, node_data->intval);
358 }
359 str_buf_append(*outbuf, val, val_len);
360 free(val);
361 } else {
362 // NOT VALID FOR OPENSTEP
363 PLIST_OSTEP_WRITE_ERR("PLIST_UID type is not valid for OpenStep format\n");
364 return PLIST_ERR_FORMAT;
365 }
366 break;
318 default: 367 default:
319 return PLIST_ERR_UNKNOWN; 368 return PLIST_ERR_UNKNOWN;
320 } 369 }
@@ -360,7 +409,7 @@ static int num_digits_u(uint64_t i)
360 return n; 409 return n;
361} 410}
362 411
363static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, hashtable_t *visited) 412static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce, hashtable_t *visited)
364{ 413{
365 plist_data_t data; 414 plist_data_t data;
366 if (!node) { 415 if (!node) {
@@ -385,7 +434,7 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
385 node_t ch; 434 node_t ch;
386 unsigned int n_children = node_n_children(node); 435 unsigned int n_children = node_n_children(node);
387 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { 436 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
388 plist_err_t res = _node_estimate_size(ch, size, depth + 1, prettify, visited); 437 plist_err_t res = _node_estimate_size(ch, size, depth + 1, prettify, coerce, visited);
389 if (res < 0) { 438 if (res < 0) {
390 return res; 439 return res;
391 } 440 }
@@ -442,17 +491,46 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
442 *size += data->length/4; 491 *size += data->length/4;
443 break; 492 break;
444 case PLIST_BOOLEAN: 493 case PLIST_BOOLEAN:
445 // NOT VALID FOR OPENSTEP 494 if (coerce) {
446 PLIST_OSTEP_WRITE_ERR("PLIST_BOOLEAN type is not valid for OpenStep format\n"); 495 *size += 1;
447 return PLIST_ERR_FORMAT; 496 } else {
497 // NOT VALID FOR OPENSTEP
498 PLIST_OSTEP_WRITE_ERR("PLIST_BOOLEAN type is not valid for OpenStep format\n");
499 return PLIST_ERR_FORMAT;
500 }
501 break;
448 case PLIST_DATE: 502 case PLIST_DATE:
449 // NOT VALID FOR OPENSTEP 503 if (coerce) {
450 PLIST_OSTEP_WRITE_ERR("PLIST_DATE type is not valid for OpenStep format\n"); 504 // ISO 8601 string: "YYYY-MM-DDTHH:MM:SSZ" = 22 chars max
451 return PLIST_ERR_FORMAT; 505 *size += 24;
506 } else {
507 // NOT VALID FOR OPENSTEP
508 PLIST_OSTEP_WRITE_ERR("PLIST_DATE type is not valid for OpenStep format\n");
509 return PLIST_ERR_FORMAT;
510 }
511 break;
452 case PLIST_UID: 512 case PLIST_UID:
453 // NOT VALID FOR OPENSTEP 513 if (coerce) {
454 PLIST_OSTEP_WRITE_ERR("PLIST_UID type is not valid for OpenStep format\n"); 514 if (data->length == 16) {
455 return PLIST_ERR_FORMAT; 515 *size += num_digits_u(data->intval);
516 } else {
517 *size += num_digits_i((int64_t)data->intval);
518 }
519 } else {
520 // NOT VALID FOR OPENSTEP
521 PLIST_OSTEP_WRITE_ERR("PLIST_UID type is not valid for OpenStep format\n");
522 return PLIST_ERR_FORMAT;
523 }
524 break;
525 case PLIST_NULL:
526 if (coerce) {
527 *size += 4;
528 } else {
529 // NOT VALID FOR OPENSTEP
530 PLIST_OSTEP_WRITE_ERR("PLIST_NULL type is not valid for OpenStep format\n");
531 return PLIST_ERR_FORMAT;
532 }
533 break;
456 default: 534 default:
457 PLIST_OSTEP_WRITE_ERR("invalid node type encountered\n"); 535 PLIST_OSTEP_WRITE_ERR("invalid node type encountered\n");
458 return PLIST_ERR_UNKNOWN; 536 return PLIST_ERR_UNKNOWN;
@@ -461,17 +539,23 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
461 return PLIST_ERR_SUCCESS; 539 return PLIST_ERR_SUCCESS;
462} 540}
463 541
464static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify) 542static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, int coerce)
465{ 543{
466 hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); 544 hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
467 if (!visited) return PLIST_ERR_NO_MEM; 545 if (!visited) return PLIST_ERR_NO_MEM;
468 plist_err_t err = _node_estimate_size(node, size, depth, prettify, visited); 546 plist_err_t err = _node_estimate_size(node, size, depth, prettify, coerce, visited);
469 hash_table_destroy(visited); 547 hash_table_destroy(visited);
470 return err; 548 return err;
471} 549}
472 550
473plist_err_t plist_to_openstep(plist_t plist, char **openstep, uint32_t* length, int prettify) 551plist_err_t plist_to_openstep(plist_t plist, char **openstep, uint32_t* length, int prettify)
474{ 552{
553 plist_write_options_t opts = prettify ? PLIST_OPT_NONE : PLIST_OPT_COMPACT;
554 return plist_to_openstep_with_options(plist, openstep, length, opts);
555}
556
557plist_err_t plist_to_openstep_with_options(plist_t plist, char **openstep, uint32_t* length, plist_write_options_t options)
558{
475 uint64_t size = 0; 559 uint64_t size = 0;
476 plist_err_t res; 560 plist_err_t res;
477 561
@@ -479,7 +563,10 @@ plist_err_t plist_to_openstep(plist_t plist, char **openstep, uint32_t* length,
479 return PLIST_ERR_INVALID_ARG; 563 return PLIST_ERR_INVALID_ARG;
480 } 564 }
481 565
482 res = node_estimate_size((node_t)plist, &size, 0, prettify); 566 int prettify = !(options & PLIST_OPT_COMPACT);
567 int coerce = options & PLIST_OPT_COERCE;
568
569 res = node_estimate_size((node_t)plist, &size, 0, prettify, coerce);
483 if (res < 0) { 570 if (res < 0) {
484 return res; 571 return res;
485 } 572 }
@@ -490,7 +577,7 @@ plist_err_t plist_to_openstep(plist_t plist, char **openstep, uint32_t* length,
490 return PLIST_ERR_NO_MEM; 577 return PLIST_ERR_NO_MEM;
491 } 578 }
492 579
493 res = node_to_openstep((node_t)plist, &outbuf, 0, prettify); 580 res = node_to_openstep((node_t)plist, &outbuf, 0, prettify, coerce);
494 if (res < 0) { 581 if (res < 0) {
495 str_buf_free(outbuf); 582 str_buf_free(outbuf);
496 *openstep = NULL; 583 *openstep = NULL;
diff --git a/src/plist.c b/src/plist.c
index a6d3547..2ad1b0a 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -2407,7 +2407,7 @@ plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length
2407 err = plist_to_json_with_options(plist, output, length, options); 2407 err = plist_to_json_with_options(plist, output, length, options);
2408 break; 2408 break;
2409 case PLIST_FORMAT_OSTEP: 2409 case PLIST_FORMAT_OSTEP:
2410 err = plist_to_openstep(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0)); 2410 err = plist_to_openstep_with_options(plist, output, length, options);
2411 break; 2411 break;
2412 case PLIST_FORMAT_PRINT: 2412 case PLIST_FORMAT_PRINT:
2413 err = plist_write_to_string_default(plist, output, length, options); 2413 err = plist_write_to_string_default(plist, output, length, options);
@@ -2445,7 +2445,7 @@ plist_err_t plist_write_to_stream(plist_t plist, FILE *stream, plist_format_t fo
2445 err = plist_to_json_with_options(plist, &output, &length, options); 2445 err = plist_to_json_with_options(plist, &output, &length, options);
2446 break; 2446 break;
2447 case PLIST_FORMAT_OSTEP: 2447 case PLIST_FORMAT_OSTEP:
2448 err = plist_to_openstep(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0)); 2448 err = plist_to_openstep_with_options(plist, &output, &length, options);
2449 break; 2449 break;
2450 case PLIST_FORMAT_PRINT: 2450 case PLIST_FORMAT_PRINT:
2451 err = plist_write_to_stream_default(plist, stream, options); 2451 err = plist_write_to_stream_default(plist, stream, options);