Coverage Report

Created: 2025-07-18 06:49

/src/libplist/src/plist.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * plist.c
3
 * Builds plist XML structures
4
 *
5
 * Copyright (c) 2009-2023 Nikias Bassen, All Rights Reserved.
6
 * Copyright (c) 2010-2015 Martin Szulecki, All Rights Reserved.
7
 * Copyright (c) 2008 Zach C., All Rights Reserved.
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
 */
23
24
#ifdef HAVE_CONFIG_H
25
#include <config.h>
26
#endif
27
28
#define _GNU_SOURCE 1
29
#include <string.h>
30
#include "plist.h"
31
#include <stdlib.h>
32
#include <stdio.h>
33
#include <math.h>
34
#include <assert.h>
35
#include <limits.h>
36
#include <float.h>
37
#include <ctype.h>
38
#include <inttypes.h>
39
40
#ifdef WIN32
41
#include <windows.h>
42
#endif
43
44
#include <node.h>
45
#include <node_list.h>
46
#include <hashtable.h>
47
#include <ptrarray.h>
48
49
0
#define MAC_EPOCH 978307200
50
51
#ifdef _MSC_VER
52
typedef SSIZE_T ssize_t;
53
#endif
54
55
#ifdef DEBUG
56
static int plist_debug = 0;
57
0
#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
58
#else
59
#define PLIST_ERR(...)
60
#endif
61
62
#ifndef bswap16
63
#define bswap16(x)   ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
64
#endif
65
66
#ifndef bswap32
67
#define bswap32(x)   ((((x) & 0xFF000000) >> 24) \
68
                    | (((x) & 0x00FF0000) >>  8) \
69
                    | (((x) & 0x0000FF00) <<  8) \
70
                    | (((x) & 0x000000FF) << 24))
71
#endif
72
73
#ifndef bswap64
74
#define bswap64(x)   ((((x) & 0xFF00000000000000ull) >> 56) \
75
                    | (((x) & 0x00FF000000000000ull) >> 40) \
76
                    | (((x) & 0x0000FF0000000000ull) >> 24) \
77
                    | (((x) & 0x000000FF00000000ull) >>  8) \
78
                    | (((x) & 0x00000000FF000000ull) <<  8) \
79
                    | (((x) & 0x0000000000FF0000ull) << 24) \
80
                    | (((x) & 0x000000000000FF00ull) << 40) \
81
                    | (((x) & 0x00000000000000FFull) << 56))
82
#endif
83
84
#ifndef le16toh
85
#ifdef __BIG_ENDIAN__
86
#define le16toh(x) bswap16(x)
87
#else
88
#define le16toh(x) (x)
89
#endif
90
#endif
91
92
#ifndef le32toh
93
#ifdef __BIG_ENDIAN__
94
#define le32toh(x) bswap32(x)
95
#else
96
#define le32toh(x) (x)
97
#endif
98
#endif
99
100
#ifndef le64toh
101
#ifdef __BIG_ENDIAN__
102
#define le64toh(x) bswap64(x)
103
#else
104
#define le64toh(x) (x)
105
#endif
106
#endif
107
108
// Reference: https://stackoverflow.com/a/2390626/1806760
109
// Initializer/finalizer sample for MSVC and GCC/Clang.
110
// 2010-2016 Joe Lowe. Released into the public domain.
111
112
#ifdef __cplusplus
113
    #define INITIALIZER(f) \
114
        static void f(void); \
115
        struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
116
        static void f(void)
117
#elif defined(_MSC_VER)
118
    #pragma section(".CRT$XCU",read)
119
    #define INITIALIZER2_(f,p) \
120
        static void f(void); \
121
        __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
122
        __pragma(comment(linker,"/include:" p #f "_")) \
123
        static void f(void)
124
    #ifdef _WIN64
125
        #define INITIALIZER(f) INITIALIZER2_(f,"")
126
    #else
127
        #define INITIALIZER(f) INITIALIZER2_(f,"_")
128
    #endif
129
#else
130
    #define INITIALIZER(f) \
131
        static void f(void) __attribute__((__constructor__)); \
132
        static void f(void)
133
#endif
134
135
extern void plist_xml_init(void);
136
extern void plist_xml_deinit(void);
137
extern void plist_bin_init(void);
138
extern void plist_bin_deinit(void);
139
extern void plist_json_init(void);
140
extern void plist_json_deinit(void);
141
extern void plist_ostep_init(void);
142
extern void plist_ostep_deinit(void);
143
144
static void internal_plist_deinit(void)
145
0
{
146
0
    plist_bin_deinit();
147
0
    plist_xml_deinit();
148
0
    plist_json_deinit();
149
0
    plist_ostep_deinit();
150
0
}
151
152
INITIALIZER(internal_plist_init)
153
2
{
154
2
    plist_bin_init();
155
2
    plist_xml_init();
156
2
    plist_json_init();
157
2
    plist_ostep_init();
158
2
    atexit(internal_plist_deinit);
159
2
}
160
161
#ifndef HAVE_MEMMEM
162
// see https://sourceware.org/legacy-ml/libc-alpha/2007-12/msg00000.html
163
164
#ifndef _LIBC
165
# define __builtin_expect(expr, val)   (expr)
166
#endif
167
168
#undef memmem
169
170
/* Return the first occurrence of NEEDLE in HAYSTACK. */
171
void* memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len)
172
{
173
    /* not really Rabin-Karp, just using additive hashing */
174
    char* haystack_ = (char*)haystack;
175
    char* needle_ = (char*)needle;
176
    int hash = 0;  /* this is the static hash value of the needle */
177
    int hay_hash = 0;  /* rolling hash over the haystack */
178
    char* last;
179
    size_t i;
180
181
    if (haystack_len < needle_len)
182
        return NULL;
183
184
    if (!needle_len)
185
        return haystack_;
186
187
    /* initialize hashes */
188
    for (i = needle_len; i; --i) {
189
        hash += *needle_++;
190
        hay_hash += *haystack_++;
191
    }
192
193
    /* iterate over the haystack */
194
    haystack_ = (char*)haystack;
195
    needle_ = (char*)needle;
196
    last = haystack_+(haystack_len - needle_len + 1);
197
    for (; haystack_ < last; ++haystack_) {
198
        if (__builtin_expect(hash == hay_hash, 0)
199
              && *haystack_ == *needle_ /* prevent calling memcmp, was a optimization from existing glibc */
200
              && !memcmp (haystack_, needle_, needle_len)) {
201
            return haystack_;
202
        }
203
        /* roll the hash */
204
        hay_hash -= *haystack_;
205
        hay_hash += *(haystack_+needle_len);
206
    }
207
    return NULL;
208
}
209
#endif
210
211
int plist_is_binary(const char *plist_data, uint32_t length)
212
0
{
213
0
    if (length < 8) {
214
0
        return 0;
215
0
    }
216
217
0
    return (memcmp(plist_data, "bplist00", 8) == 0);
218
0
}
219
220
#define SKIP_WS(blob, pos, len) \
221
0
    while (pos < len && ((blob[pos] == ' ') || (blob[pos] == '\t') || (blob[pos] == '\r') || (blob[pos] == '\n'))) pos++;
222
#define FIND_NEXT(blob, pos, len, chr) \
223
0
    while (pos < len && (blob[pos] != chr)) pos++;
224
225
plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format)
226
0
{
227
0
    plist_err_t res = PLIST_ERR_UNKNOWN;
228
0
    if (!plist) {
229
0
        return PLIST_ERR_INVALID_ARG;
230
0
    }
231
0
    *plist = NULL;
232
0
    if (!plist_data || length == 0) {
233
0
        return PLIST_ERR_INVALID_ARG;
234
0
    }
235
0
    plist_format_t fmt = PLIST_FORMAT_NONE;
236
0
    if (format) *format = PLIST_FORMAT_NONE;
237
0
    if (plist_is_binary(plist_data, length)) {
238
0
        res = plist_from_bin(plist_data, length, plist);
239
0
        fmt = PLIST_FORMAT_BINARY;
240
0
    } else {
241
0
        uint32_t pos = 0;
242
0
        int is_json = 0;
243
0
        int is_xml = 0;
244
        /* skip whitespace */
245
0
        SKIP_WS(plist_data, pos, length);
246
0
        if (pos >= length) {
247
0
            return PLIST_ERR_PARSE;
248
0
        }
249
0
        if (plist_data[pos] == '<' && (length-pos > 3) && !isxdigit(plist_data[pos+1]) && !isxdigit(plist_data[pos+2]) && !isxdigit(plist_data[pos+3])) {
250
0
            is_xml = 1;
251
0
        } else if (plist_data[pos] == '[') {
252
            /* only valid for json */
253
0
            is_json = 1;
254
0
        } else if (plist_data[pos] == '(') {
255
            /* only valid for openstep */
256
0
        } else if (plist_data[pos] == '{') {
257
            /* this could be json or openstep */
258
0
            pos++;
259
0
            SKIP_WS(plist_data, pos, length);
260
0
            if (pos >= length) {
261
0
                return PLIST_ERR_PARSE;
262
0
            }
263
0
            if (plist_data[pos] == '"') {
264
                /* still could be both */
265
0
                pos++;
266
0
                while (pos < length) {
267
0
                    FIND_NEXT(plist_data, pos, length, '"');
268
0
                    if (plist_data[pos-1] != '\\') {
269
0
                        break;
270
0
                    }
271
0
                    pos++;
272
0
                }
273
0
                if (pos >= length) {
274
0
                    return PLIST_ERR_PARSE;
275
0
                }
276
0
                if (plist_data[pos] == '"') {
277
0
                    pos++;
278
0
                    SKIP_WS(plist_data, pos, length);
279
0
                    if (pos >= length) {
280
0
                        return PLIST_ERR_PARSE;
281
0
                    }
282
0
                    if (plist_data[pos] == ':') {
283
                        /* this is definitely json */
284
0
                        is_json = 1;
285
0
                    }
286
0
                }
287
0
            }
288
0
        }
289
0
        if (is_xml) {
290
0
            res = plist_from_xml(plist_data, length, plist);
291
0
            fmt = PLIST_FORMAT_XML;
292
0
        } else if (is_json) {
293
0
            res = plist_from_json(plist_data, length, plist);
294
0
            fmt = PLIST_FORMAT_JSON;
295
0
        } else {
296
0
            res = plist_from_openstep(plist_data, length, plist);
297
0
            fmt = PLIST_FORMAT_OSTEP;
298
0
        }
299
0
    }
300
0
    if (format && res == PLIST_ERR_SUCCESS) {
301
0
        *format = fmt;
302
0
    }
303
0
    return res;
304
0
}
305
306
plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format)
307
0
{
308
0
    if (!filename || !plist) {
309
0
        return PLIST_ERR_INVALID_ARG;
310
0
    }
311
0
    FILE *f = fopen(filename, "rb");
312
0
    if (!f) {
313
0
        return PLIST_ERR_IO;
314
0
    }
315
0
    struct stat fst;
316
0
    fstat(fileno(f), &fst);
317
0
    if ((uint64_t)fst.st_size > UINT32_MAX) {
318
0
        return PLIST_ERR_NO_MEM;
319
0
    }
320
0
    uint32_t total = (uint32_t)fst.st_size;
321
0
    if (total == 0) {
322
0
        return PLIST_ERR_PARSE;
323
0
    }
324
0
    char *buf = (char*)malloc(total);
325
0
    if (!buf) {
326
0
        fclose(f);
327
0
        return PLIST_ERR_NO_MEM;
328
0
    }
329
0
    uint32_t done = 0;
330
0
    while (done < total) {
331
0
        ssize_t r = fread(buf + done, 1, total - done, f);
332
0
        if (r <= 0) {
333
0
            break;
334
0
        }
335
0
        done += r;
336
0
    }
337
0
    fclose(f);
338
0
    if (done < total) {
339
0
        free(buf);
340
0
        return PLIST_ERR_IO;
341
0
    }
342
0
    plist_err_t res = plist_from_memory(buf, total, plist, format);
343
0
    free(buf);
344
0
    return res;
345
0
}
346
347
plist_t plist_new_node(plist_data_t data)
348
165k
{
349
165k
    return (plist_t) node_create(NULL, data);
350
165k
}
351
352
plist_data_t plist_get_data(plist_t node)
353
13.0M
{
354
13.0M
    if (!node)
355
0
        return NULL;
356
13.0M
    return (plist_data_t)((node_t)node)->data;
357
13.0M
}
358
359
plist_data_t plist_new_plist_data(void)
360
165k
{
361
165k
    plist_data_t data = (plist_data_t) calloc(sizeof(struct plist_data_s), 1);
362
165k
    return data;
363
165k
}
364
365
static unsigned int dict_key_hash(const void *data)
366
51.3k
{
367
51.3k
    plist_data_t keydata = (plist_data_t)data;
368
51.3k
    unsigned int hash = 5381;
369
51.3k
    size_t i;
370
51.3k
    char *str = keydata->strval;
371
142k
    for (i = 0; i < keydata->length; str++, i++) {
372
90.9k
        hash = ((hash << 5) + hash) + *str;
373
90.9k
    }
374
51.3k
    return hash;
375
51.3k
}
376
377
static int dict_key_compare(const void* a, const void* b)
378
3.18k
{
379
3.18k
    plist_data_t data_a = (plist_data_t)a;
380
3.18k
    plist_data_t data_b = (plist_data_t)b;
381
3.18k
    if (data_a->strval == NULL || data_b->strval == NULL) {
382
0
        return FALSE;
383
0
    }
384
3.18k
    if (data_a->length != data_b->length) {
385
1.72k
        return FALSE;
386
1.72k
    }
387
1.46k
    return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
388
3.18k
}
389
390
void plist_free_data(plist_data_t data)
391
165k
{
392
165k
    if (data)
393
165k
    {
394
165k
        switch (data->type)
395
165k
        {
396
52.6k
        case PLIST_KEY:
397
81.8k
        case PLIST_STRING:
398
81.8k
            free(data->strval);
399
81.8k
            break;
400
0
        case PLIST_DATA:
401
0
            free(data->buff);
402
0
            break;
403
50.3k
        case PLIST_ARRAY:
404
50.3k
            ptr_array_free((ptrarray_t*)data->hashtable);
405
50.3k
            break;
406
10.4k
        case PLIST_DICT:
407
10.4k
            hash_table_destroy((hashtable_t*)data->hashtable);
408
10.4k
            break;
409
23.1k
        default:
410
23.1k
            break;
411
165k
        }
412
165k
        free(data);
413
165k
    }
414
165k
}
415
416
static int plist_free_node(node_t node)
417
165k
{
418
165k
    plist_data_t data = NULL;
419
165k
    int node_index = node_detach(node->parent, node);
420
165k
    data = plist_get_data(node);
421
165k
    plist_free_data(data);
422
165k
    node->data = NULL;
423
424
165k
    node_t ch;
425
316k
    for (ch = node_first_child(node); ch; ) {
426
150k
        node_t next = node_next_sibling(ch);
427
150k
        plist_free_node(ch);
428
150k
        ch = next;
429
150k
    }
430
431
165k
    node_destroy(node);
432
433
165k
    return node_index;
434
165k
}
435
436
plist_t plist_new_dict(void)
437
10.4k
{
438
10.4k
    plist_data_t data = plist_new_plist_data();
439
10.4k
    data->type = PLIST_DICT;
440
10.4k
    return plist_new_node(data);
441
10.4k
}
442
443
plist_t plist_new_array(void)
444
50.3k
{
445
50.3k
    plist_data_t data = plist_new_plist_data();
446
50.3k
    data->type = PLIST_ARRAY;
447
50.3k
    return plist_new_node(data);
448
50.3k
}
449
450
//These nodes should not be handled by users
451
static plist_t plist_new_key(const char *val)
452
52.6k
{
453
52.6k
    plist_data_t data = plist_new_plist_data();
454
52.6k
    data->type = PLIST_KEY;
455
52.6k
    data->strval = strdup(val);
456
52.6k
    data->length = strlen(val);
457
52.6k
    return plist_new_node(data);
458
52.6k
}
459
460
plist_t plist_new_string(const char *val)
461
0
{
462
0
    plist_data_t data = plist_new_plist_data();
463
0
    data->type = PLIST_STRING;
464
0
    data->strval = strdup(val);
465
0
    data->length = strlen(val);
466
0
    return plist_new_node(data);
467
0
}
468
469
plist_t plist_new_bool(uint8_t val)
470
9.83k
{
471
9.83k
    plist_data_t data = plist_new_plist_data();
472
9.83k
    data->type = PLIST_BOOLEAN;
473
9.83k
    data->boolval = val;
474
9.83k
    data->length = sizeof(uint8_t);
475
9.83k
    return plist_new_node(data);
476
9.83k
}
477
478
plist_t plist_new_uint(uint64_t val)
479
0
{
480
0
    plist_data_t data = plist_new_plist_data();
481
0
    data->type = PLIST_INT;
482
0
    data->intval = val;
483
0
    data->length = (val > INT_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t);
484
0
    return plist_new_node(data);
485
0
}
486
487
plist_t plist_new_int(int64_t val)
488
3.29k
{
489
3.29k
    plist_data_t data = plist_new_plist_data();
490
3.29k
    data->type = PLIST_INT;
491
3.29k
    data->intval = val;
492
3.29k
    data->length = sizeof(uint64_t);
493
3.29k
    return plist_new_node(data);
494
3.29k
}
495
496
plist_t plist_new_uid(uint64_t val)
497
0
{
498
0
    plist_data_t data = plist_new_plist_data();
499
0
    data->type = PLIST_UID;
500
0
    data->intval = val;
501
0
    data->length = sizeof(uint64_t);
502
0
    return plist_new_node(data);
503
0
}
504
505
plist_t plist_new_real(double val)
506
2.08k
{
507
2.08k
    plist_data_t data = plist_new_plist_data();
508
2.08k
    data->type = PLIST_REAL;
509
2.08k
    data->realval = val;
510
2.08k
    data->length = sizeof(double);
511
2.08k
    return plist_new_node(data);
512
2.08k
}
513
514
plist_t plist_new_data(const char *val, uint64_t length)
515
0
{
516
0
    plist_data_t data = plist_new_plist_data();
517
0
    data->type = PLIST_DATA;
518
0
    data->buff = (uint8_t *) malloc(length);
519
0
    memcpy(data->buff, val, length);
520
0
    data->length = length;
521
0
    return plist_new_node(data);
522
0
}
523
524
plist_t plist_new_date(int32_t sec, int32_t usec)
525
0
{
526
0
    plist_data_t data = plist_new_plist_data();
527
0
    data->type = PLIST_DATE;
528
0
    data->realval = (double)sec + (double)usec / 1000000;
529
0
    data->length = sizeof(double);
530
0
    return plist_new_node(data);
531
0
}
532
533
plist_t plist_new_unix_date(int64_t sec)
534
0
{
535
0
    plist_data_t data = plist_new_plist_data();
536
0
    data->type = PLIST_DATE;
537
0
    data->realval = (double)sec - MAC_EPOCH;
538
0
    data->length = sizeof(double);
539
0
    return plist_new_node(data);
540
0
}
541
542
plist_t plist_new_null(void)
543
0
{
544
0
    plist_data_t data = plist_new_plist_data();
545
0
    data->type = PLIST_NULL;
546
0
    data->intval = 0;
547
0
    data->length = 0;
548
0
    return plist_new_node(data);
549
0
}
550
551
void plist_free(plist_t plist)
552
11.5k
{
553
11.5k
    if (plist)
554
10.7k
    {
555
10.7k
        plist_free_node((node_t)plist);
556
10.7k
    }
557
11.5k
}
558
559
void plist_mem_free(void* ptr)
560
0
{
561
0
    if (ptr)
562
0
    {
563
0
        free(ptr);
564
0
    }
565
0
}
566
567
static plist_t plist_copy_node(node_t node)
568
0
{
569
0
    plist_type node_type = PLIST_NONE;
570
0
    plist_t newnode = NULL;
571
0
    plist_data_t data = plist_get_data(node);
572
0
    plist_data_t newdata = plist_new_plist_data();
573
574
0
    assert(data);       // plist should always have data
575
0
    assert(newdata);
576
577
0
    memcpy(newdata, data, sizeof(struct plist_data_s));
578
579
0
    node_type = plist_get_node_type(node);
580
0
    switch (node_type) {
581
0
        case PLIST_DATA:
582
0
            newdata->buff = (uint8_t *) malloc(data->length);
583
0
            memcpy(newdata->buff, data->buff, data->length);
584
0
            break;
585
0
        case PLIST_KEY:
586
0
        case PLIST_STRING:
587
0
            newdata->strval = strdup(data->strval);
588
0
            break;
589
0
        case PLIST_ARRAY:
590
0
            if (data->hashtable) {
591
0
                ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity);
592
0
                assert(pa);
593
0
                newdata->hashtable = pa;
594
0
            }
595
0
            break;
596
0
        case PLIST_DICT:
597
0
            if (data->hashtable) {
598
0
                hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
599
0
                assert(ht);
600
0
                newdata->hashtable = ht;
601
0
            }
602
0
            break;
603
0
        default:
604
0
            break;
605
0
    }
606
0
    newnode = plist_new_node(newdata);
607
608
0
    node_t ch;
609
0
    unsigned int node_index = 0;
610
0
    for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
611
        /* copy child node */
612
0
        plist_t newch = plist_copy_node(ch);
613
        /* attach to new parent node */
614
0
        node_attach((node_t)newnode, (node_t)newch);
615
        /* if needed, add child node to lookup table of parent node */
616
0
        switch (node_type) {
617
0
            case PLIST_ARRAY:
618
0
                if (newdata->hashtable) {
619
0
                    ptr_array_add((ptrarray_t*)newdata->hashtable, newch);
620
0
                }
621
0
                break;
622
0
            case PLIST_DICT:
623
0
                if (newdata->hashtable && (node_index % 2 != 0)) {
624
0
                    hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t)newch))->data, newch);
625
0
                }
626
0
                break;
627
0
            default:
628
0
                break;
629
0
        }
630
0
        node_index++;
631
0
    }
632
0
    return newnode;
633
0
}
634
635
plist_t plist_copy(plist_t node)
636
0
{
637
0
    return node ? plist_copy_node((node_t)node) : NULL;
638
0
}
639
640
uint32_t plist_array_get_size(plist_t node)
641
0
{
642
0
    uint32_t ret = 0;
643
0
    if (node && PLIST_ARRAY == plist_get_node_type(node))
644
0
    {
645
0
        ret = node_n_children((node_t)node);
646
0
    }
647
0
    return ret;
648
0
}
649
650
plist_t plist_array_get_item(plist_t node, uint32_t n)
651
0
{
652
0
    plist_t ret = NULL;
653
0
    if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
654
0
    {
655
0
        ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
656
0
        if (pa) {
657
0
            ret = (plist_t)ptr_array_index(pa, n);
658
0
        } else {
659
0
            ret = (plist_t)node_nth_child((node_t)node, n);
660
0
        }
661
0
    }
662
0
    return ret;
663
0
}
664
665
uint32_t plist_array_get_item_index(plist_t node)
666
0
{
667
0
    plist_t father = plist_get_parent(node);
668
0
    if (PLIST_ARRAY == plist_get_node_type(father))
669
0
    {
670
0
        return node_child_position((node_t)father, (node_t)node);
671
0
    }
672
0
    return UINT_MAX;
673
0
}
674
675
static void _plist_array_post_insert(plist_t node, plist_t item, long n)
676
45.4k
{
677
45.4k
    ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
678
45.4k
    if (pa) {
679
        /* store pointer to item in array */
680
8.73k
        ptr_array_insert(pa, item, n);
681
36.6k
    } else {
682
36.6k
        if (((node_t)node)->count > 100) {
683
            /* make new lookup array */
684
103
            pa = ptr_array_new(128);
685
103
            plist_t current = NULL;
686
103
            for (current = (plist_t)node_first_child((node_t)node);
687
10.5k
                 pa && current;
688
10.4k
                 current = (plist_t)node_next_sibling((node_t)current))
689
10.4k
            {
690
10.4k
                ptr_array_add(pa, current);
691
10.4k
            }
692
103
            ((plist_data_t)((node_t)node)->data)->hashtable = pa;
693
103
        }
694
36.6k
    }
695
45.4k
}
696
697
void plist_array_set_item(plist_t node, plist_t item, uint32_t n)
698
0
{
699
0
    if (!item) {
700
0
        return;
701
0
    }
702
0
    if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
703
0
    {
704
0
        plist_t old_item = plist_array_get_item(node, n);
705
0
        if (old_item)
706
0
        {
707
0
            int idx = plist_free_node((node_t)old_item);
708
0
            assert(idx >= 0);
709
0
            if (idx < 0) {
710
0
                return;
711
0
            }
712
0
            node_insert((node_t)node, idx, (node_t)item);
713
0
            ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
714
0
            if (pa) {
715
0
                ptr_array_set(pa, item, idx);
716
0
            }
717
0
        }
718
0
    }
719
0
}
720
721
void plist_array_append_item(plist_t node, plist_t item)
722
45.4k
{
723
45.4k
    if (!item) {
724
0
        return;
725
0
    }
726
45.4k
    if (node && PLIST_ARRAY == plist_get_node_type(node))
727
45.4k
    {
728
45.4k
        node_attach((node_t)node, (node_t)item);
729
45.4k
        _plist_array_post_insert(node, item, -1);
730
45.4k
    }
731
45.4k
}
732
733
void plist_array_insert_item(plist_t node, plist_t item, uint32_t n)
734
0
{
735
0
    if (!item) {
736
0
        return;
737
0
    }
738
0
    if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
739
0
    {
740
0
        node_insert((node_t)node, n, (node_t)item);
741
0
        _plist_array_post_insert(node, item, (long)n);
742
0
    }
743
0
}
744
745
void plist_array_remove_item(plist_t node, uint32_t n)
746
0
{
747
0
    if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX)
748
0
    {
749
0
        plist_t old_item = plist_array_get_item(node, n);
750
0
        if (old_item)
751
0
        {
752
0
            ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable;
753
0
            if (pa) {
754
0
                ptr_array_remove(pa, n);
755
0
            }
756
0
            plist_free(old_item);
757
0
        }
758
0
    }
759
0
}
760
761
void plist_array_item_remove(plist_t node)
762
0
{
763
0
    plist_t father = plist_get_parent(node);
764
0
    if (PLIST_ARRAY == plist_get_node_type(father))
765
0
    {
766
0
        int n = node_child_position((node_t)father, (node_t)node);
767
0
        if (n < 0) return;
768
0
        ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)father)->data)->hashtable;
769
0
        if (pa) {
770
0
            ptr_array_remove(pa, n);
771
0
        }
772
0
        plist_free(node);
773
0
    }
774
0
}
775
776
void plist_array_new_iter(plist_t node, plist_array_iter *iter)
777
0
{
778
0
    if (iter)
779
0
    {
780
0
        *iter = malloc(sizeof(node_t));
781
0
        *((node_t*)(*iter)) = node_first_child((node_t)node);
782
0
    }
783
0
}
784
785
void plist_array_next_item(plist_t node, plist_array_iter iter, plist_t *item)
786
0
{
787
0
    node_t* iter_node = (node_t*)iter;
788
789
0
    if (item)
790
0
    {
791
0
        *item = NULL;
792
0
    }
793
794
0
    if (node && PLIST_ARRAY == plist_get_node_type(node) && *iter_node)
795
0
    {
796
0
        if (item)
797
0
        {
798
0
            *item = (plist_t)(*iter_node);
799
0
        }
800
0
        *iter_node = node_next_sibling(*iter_node);
801
0
    }
802
0
}
803
804
uint32_t plist_dict_get_size(plist_t node)
805
0
{
806
0
    uint32_t ret = 0;
807
0
    if (node && PLIST_DICT == plist_get_node_type(node))
808
0
    {
809
0
        ret = node_n_children((node_t)node) / 2;
810
0
    }
811
0
    return ret;
812
0
}
813
814
void plist_dict_new_iter(plist_t node, plist_dict_iter *iter)
815
0
{
816
0
    if (iter)
817
0
    {
818
0
        *iter = malloc(sizeof(node_t));
819
0
        *((node_t*)(*iter)) = node_first_child((node_t)node);
820
0
    }
821
0
}
822
823
void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val)
824
0
{
825
0
    node_t* iter_node = (node_t*)iter;
826
827
0
    if (key)
828
0
    {
829
0
        *key = NULL;
830
0
    }
831
0
    if (val)
832
0
    {
833
0
        *val = NULL;
834
0
    }
835
836
0
    if (node && PLIST_DICT == plist_get_node_type(node) && *iter_node)
837
0
    {
838
0
        if (key)
839
0
        {
840
0
            plist_get_key_val((plist_t)(*iter_node), key);
841
0
        }
842
0
        *iter_node = node_next_sibling(*iter_node);
843
0
        if (val)
844
0
        {
845
0
            *val = (plist_t)(*iter_node);
846
0
        }
847
0
        *iter_node = node_next_sibling(*iter_node);
848
0
    }
849
0
}
850
851
void plist_dict_get_item_key(plist_t node, char **key)
852
0
{
853
0
    plist_t father = plist_get_parent(node);
854
0
    if (PLIST_DICT == plist_get_node_type(father))
855
0
    {
856
0
        plist_get_key_val( (plist_t) node_prev_sibling((node_t)node), key);
857
0
    }
858
0
}
859
860
plist_t plist_dict_item_get_key(plist_t node)
861
0
{
862
0
    plist_t ret = NULL;
863
0
    plist_t father = plist_get_parent(node);
864
0
    if (PLIST_DICT == plist_get_node_type(father))
865
0
    {
866
0
        ret = (plist_t)node_prev_sibling((node_t)node);
867
0
    }
868
0
    return ret;
869
0
}
870
871
plist_t plist_dict_get_item(plist_t node, const char* key)
872
57.0k
{
873
57.0k
    plist_t ret = NULL;
874
875
57.0k
    if (node && PLIST_DICT == plist_get_node_type(node))
876
57.0k
    {
877
57.0k
        plist_data_t data = plist_get_data(node);
878
57.0k
        hashtable_t *ht = (hashtable_t*)data->hashtable;
879
57.0k
        if (ht) {
880
940
            struct plist_data_s sdata;
881
940
            sdata.strval = (char*)key;
882
940
            sdata.length = strlen(key);
883
940
            ret = (plist_t)hash_table_lookup(ht, &sdata);
884
56.1k
        } else {
885
56.1k
            plist_t current = NULL;
886
56.1k
            for (current = (plist_t)node_first_child((node_t)node);
887
6.37M
                current;
888
6.31M
                current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
889
6.32M
            {
890
6.32M
                data = plist_get_data(current);
891
6.32M
                assert( PLIST_KEY == plist_get_node_type(current) );
892
893
6.32M
                if (data && !strcmp(key, data->strval))
894
3.91k
                {
895
3.91k
                    ret = (plist_t)node_next_sibling((node_t)current);
896
3.91k
                    break;
897
3.91k
                }
898
6.32M
            }
899
56.1k
        }
900
57.0k
    }
901
57.0k
    return ret;
902
57.0k
}
903
904
void plist_dict_set_item(plist_t node, const char* key, plist_t item)
905
57.0k
{
906
57.0k
    if (!item) {
907
0
        return;
908
0
    }
909
57.0k
    if (node && PLIST_DICT == plist_get_node_type(node)) {
910
57.0k
        plist_t old_item = plist_dict_get_item(node, key);
911
57.0k
        plist_t key_node = NULL;
912
57.0k
        if (old_item) {
913
4.43k
            int idx = plist_free_node((node_t)old_item);
914
4.43k
            assert(idx >= 0);
915
4.43k
            if (idx < 0) {
916
0
                return;
917
0
            }
918
4.43k
            node_insert((node_t)node, idx, (node_t)item);
919
4.43k
            key_node = node_prev_sibling((node_t)item);
920
52.6k
        } else {
921
52.6k
            key_node = plist_new_key(key);
922
52.6k
            node_attach((node_t)node, (node_t)key_node);
923
52.6k
            node_attach((node_t)node, (node_t)item);
924
52.6k
        }
925
926
57.0k
        hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
927
57.0k
        if (ht) {
928
            /* store pointer to item in hash table */
929
940
            hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item);
930
56.1k
        } else {
931
56.1k
            if (((node_t)node)->count > 500) {
932
                /* make new hash table */
933
197
                ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
934
                /* calculate the hashes for all entries we have so far */
935
197
                plist_t current = NULL;
936
197
                for (current = (plist_t)node_first_child((node_t)node);
937
49.6k
                     ht && current;
938
49.4k
                     current = (plist_t)node_next_sibling(node_next_sibling((node_t)current)))
939
49.4k
                {
940
49.4k
                    hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current));
941
49.4k
                }
942
197
                ((plist_data_t)((node_t)node)->data)->hashtable = ht;
943
197
            }
944
56.1k
        }
945
57.0k
    }
946
57.0k
}
947
948
void plist_dict_remove_item(plist_t node, const char* key)
949
0
{
950
0
    if (node && PLIST_DICT == plist_get_node_type(node))
951
0
    {
952
0
        plist_t old_item = plist_dict_get_item(node, key);
953
0
        if (old_item)
954
0
        {
955
0
            plist_t key_node = node_prev_sibling((node_t)old_item);
956
0
            hashtable_t* ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable;
957
0
            if (ht) {
958
0
                hash_table_remove(ht, ((node_t)key_node)->data);
959
0
            }
960
0
            plist_free(key_node);
961
0
            plist_free(old_item);
962
0
        }
963
0
    }
964
0
}
965
966
void plist_dict_merge(plist_t *target, plist_t source)
967
0
{
968
0
  if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT))
969
0
    return;
970
971
0
  char* key = NULL;
972
0
  plist_dict_iter it = NULL;
973
0
  plist_t subnode = NULL;
974
0
  plist_dict_new_iter(source, &it);
975
0
  if (!it)
976
0
    return;
977
978
0
  do {
979
0
    plist_dict_next_item(source, it, &key, &subnode);
980
0
    if (!key)
981
0
      break;
982
983
0
    plist_dict_set_item(*target, key, plist_copy(subnode));
984
0
    free(key);
985
0
    key = NULL;
986
0
  } while (1);
987
0
  free(it);
988
0
}
989
990
uint8_t plist_dict_get_bool(plist_t dict, const char *key)
991
0
{
992
0
  uint8_t bval = 0;
993
0
  uint64_t uintval = 0;
994
0
  const char *strval = NULL;
995
0
  uint64_t strsz = 0;
996
0
  plist_t node = plist_dict_get_item(dict, key);
997
0
  if (!node) {
998
0
    return 0;
999
0
  }
1000
0
  switch (plist_get_node_type(node)) {
1001
0
  case PLIST_BOOLEAN:
1002
0
    plist_get_bool_val(node, &bval);
1003
0
    break;
1004
0
  case PLIST_INT:
1005
0
    plist_get_uint_val(node, &uintval);
1006
0
    bval = (uintval) ? 1 : 0;
1007
0
    break;
1008
0
  case PLIST_STRING:
1009
0
    strval = plist_get_string_ptr(node, NULL);
1010
0
    if (strval) {
1011
0
      if (strcmp(strval, "true")) {
1012
0
        bval = 1;
1013
0
      } else if (strcmp(strval, "false")) {
1014
0
        bval = 0;
1015
0
      } else {
1016
0
        PLIST_ERR("%s: invalid string '%s' for string to boolean conversion\n", __func__, strval);
1017
0
      }
1018
0
    }
1019
0
    break;
1020
0
  case PLIST_DATA:
1021
0
    strval = (const char*)plist_get_data_ptr(node, &strsz);
1022
0
    if (strval) {
1023
0
      if (strsz == 1) {
1024
0
        bval = (strval[0]) ? 1 : 0;
1025
0
      } else {
1026
0
        PLIST_ERR("%s: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
1027
0
      }
1028
0
    }
1029
0
    break;
1030
0
  default:
1031
0
    break;
1032
0
  }
1033
0
  return bval;
1034
0
}
1035
1036
int64_t plist_dict_get_int(plist_t dict, const char *key)
1037
0
{
1038
0
  int64_t intval = 0;
1039
0
  const char *strval = NULL;
1040
0
  uint64_t strsz = 0;
1041
0
  plist_t node = plist_dict_get_item(dict, key);
1042
0
  if (!node) {
1043
0
    return intval;
1044
0
  }
1045
0
  switch (plist_get_node_type(node)) {
1046
0
  case PLIST_INT:
1047
0
    plist_get_int_val(node, &intval);
1048
0
    break;
1049
0
  case PLIST_STRING:
1050
0
    strval = plist_get_string_ptr(node, NULL);
1051
0
    if (strval) {
1052
0
      intval = strtoll(strval, NULL, 0);
1053
0
    }
1054
0
    break;
1055
0
  case PLIST_DATA:
1056
0
    strval = (const char*)plist_get_data_ptr(node, &strsz);
1057
0
    if (strval) {
1058
0
      if (strsz == 8) {
1059
0
        intval = le64toh(*(int64_t*)strval);
1060
0
      } else if (strsz == 4) {
1061
0
        intval = le32toh(*(int32_t*)strval);
1062
0
      } else if (strsz == 2) {
1063
0
        intval = le16toh(*(int16_t*)strval);
1064
0
      } else if (strsz == 1) {
1065
0
        intval = strval[0];
1066
0
      } else {
1067
0
        PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
1068
0
      }
1069
0
    }
1070
0
    break;
1071
0
  default:
1072
0
    break;
1073
0
  }
1074
0
  return intval;
1075
0
}
1076
1077
1078
uint64_t plist_dict_get_uint(plist_t dict, const char *key)
1079
0
{
1080
0
  uint64_t uintval = 0;
1081
0
  const char *strval = NULL;
1082
0
  uint64_t strsz = 0;
1083
0
  plist_t node = plist_dict_get_item(dict, key);
1084
0
  if (!node) {
1085
0
    return uintval;
1086
0
  }
1087
0
  switch (plist_get_node_type(node)) {
1088
0
  case PLIST_INT:
1089
0
    plist_get_uint_val(node, &uintval);
1090
0
    break;
1091
0
  case PLIST_STRING:
1092
0
    strval = plist_get_string_ptr(node, NULL);
1093
0
    if (strval) {
1094
0
      uintval = strtoull(strval, NULL, 0);
1095
0
    }
1096
0
    break;
1097
0
  case PLIST_DATA:
1098
0
    strval = (const char*)plist_get_data_ptr(node, &strsz);
1099
0
    if (strval) {
1100
0
      if (strsz == 8) {
1101
0
        uintval = le64toh(*(uint64_t*)strval);
1102
0
      } else if (strsz == 4) {
1103
0
        uintval = le32toh(*(uint32_t*)strval);
1104
0
      } else if (strsz == 2) {
1105
0
        uintval = le16toh(*(uint16_t*)strval);
1106
0
      } else if (strsz == 1) {
1107
0
        uintval = strval[0];
1108
0
      } else {
1109
0
        PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
1110
0
      }
1111
0
    }
1112
0
    break;
1113
0
  default:
1114
0
    break;
1115
0
  }
1116
0
  return uintval;
1117
0
}
1118
1119
plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1120
0
{
1121
0
  plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1122
0
  if (!node) {
1123
0
    return PLIST_ERR_INVALID_ARG;
1124
0
  }
1125
0
  plist_dict_set_item(target_dict, key, plist_copy(node));
1126
0
  return PLIST_ERR_SUCCESS;
1127
0
}
1128
1129
plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1130
0
{
1131
0
  if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1132
0
    return PLIST_ERR_INVALID_ARG;
1133
0
  }
1134
0
  uint8_t bval = plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key);
1135
0
  plist_dict_set_item(target_dict, key, plist_new_bool(bval));
1136
0
  return PLIST_ERR_SUCCESS;
1137
0
}
1138
1139
plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1140
0
{
1141
0
  if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1142
0
    return PLIST_ERR_INVALID_ARG;
1143
0
  }
1144
0
  int64_t i64val = plist_dict_get_int(source_dict, (alt_source_key) ? alt_source_key : key);
1145
0
  plist_dict_set_item(target_dict, key, plist_new_int(i64val));
1146
0
  return PLIST_ERR_SUCCESS;
1147
0
}
1148
1149
plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1150
0
{
1151
0
  if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1152
0
    return PLIST_ERR_INVALID_ARG;
1153
0
  }
1154
0
  uint64_t u64val = plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key);
1155
0
  plist_dict_set_item(target_dict, key, plist_new_uint(u64val));
1156
0
  return PLIST_ERR_SUCCESS;
1157
0
}
1158
1159
plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1160
0
{
1161
0
  plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1162
0
  if (!PLIST_IS_DATA(node)) {
1163
0
    return PLIST_ERR_INVALID_ARG;
1164
0
  }
1165
0
  plist_dict_set_item(target_dict, key, plist_copy(node));
1166
0
  return PLIST_ERR_SUCCESS;
1167
0
}
1168
1169
plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1170
0
{
1171
0
  plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1172
0
  if (!PLIST_IS_STRING(node)) {
1173
0
    return PLIST_ERR_INVALID_ARG;
1174
0
  }
1175
0
  plist_dict_set_item(target_dict, key, plist_copy(node));
1176
0
  return PLIST_ERR_SUCCESS;
1177
0
}
1178
1179
plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
1180
0
{
1181
0
    plist_t current = plist;
1182
0
    plist_type type = PLIST_NONE;
1183
0
    uint32_t i = 0;
1184
1185
0
    for (i = 0; i < length && current; i++)
1186
0
    {
1187
0
        type = plist_get_node_type(current);
1188
1189
0
        if (type == PLIST_ARRAY)
1190
0
        {
1191
0
            uint32_t n = va_arg(v, uint32_t);
1192
0
            current = plist_array_get_item(current, n);
1193
0
        }
1194
0
        else if (type == PLIST_DICT)
1195
0
        {
1196
0
            const char* key = va_arg(v, const char*);
1197
0
            current = plist_dict_get_item(current, key);
1198
0
        }
1199
0
    }
1200
0
    return current;
1201
0
}
1202
1203
plist_t plist_access_path(plist_t plist, uint32_t length, ...)
1204
0
{
1205
0
    plist_t ret = NULL;
1206
0
    va_list v;
1207
1208
0
    va_start(v, length);
1209
0
    ret = plist_access_pathv(plist, length, v);
1210
0
    va_end(v);
1211
0
    return ret;
1212
0
}
1213
1214
static void plist_get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length)
1215
0
{
1216
0
    plist_data_t data = NULL;
1217
1218
0
    if (!node)
1219
0
        return;
1220
1221
0
    data = plist_get_data(node);
1222
1223
0
    *type = data->type;
1224
0
    *length = data->length;
1225
1226
0
    switch (*type)
1227
0
    {
1228
0
    case PLIST_BOOLEAN:
1229
0
        *((char *) value) = data->boolval;
1230
0
        break;
1231
0
    case PLIST_INT:
1232
0
    case PLIST_UID:
1233
0
        *((uint64_t *) value) = data->intval;
1234
0
        break;
1235
0
    case PLIST_REAL:
1236
0
    case PLIST_DATE:
1237
0
        *((double *) value) = data->realval;
1238
0
        break;
1239
0
    case PLIST_KEY:
1240
0
    case PLIST_STRING:
1241
0
        *((char **) value) = strdup(data->strval);
1242
0
        break;
1243
0
    case PLIST_DATA:
1244
0
        *((uint8_t **) value) = (uint8_t *) malloc(*length * sizeof(uint8_t));
1245
0
        memcpy(*((uint8_t **) value), data->buff, *length * sizeof(uint8_t));
1246
0
        break;
1247
0
    case PLIST_ARRAY:
1248
0
    case PLIST_DICT:
1249
0
    default:
1250
0
        break;
1251
0
    }
1252
0
}
1253
1254
plist_t plist_get_parent(plist_t node)
1255
0
{
1256
0
    return node ? (plist_t) ((node_t) node)->parent : NULL;
1257
0
}
1258
1259
plist_type plist_get_node_type(plist_t node)
1260
6.48M
{
1261
6.48M
    if (node)
1262
6.48M
    {
1263
6.48M
        plist_data_t data = plist_get_data(node);
1264
6.48M
        if (data)
1265
6.48M
            return data->type;
1266
6.48M
    }
1267
0
    return PLIST_NONE;
1268
6.48M
}
1269
1270
void plist_get_key_val(plist_t node, char **val)
1271
0
{
1272
0
    if (!node || !val)
1273
0
        return;
1274
0
    plist_type type = plist_get_node_type(node);
1275
0
    uint64_t length = 0;
1276
0
    if (PLIST_KEY != type)
1277
0
        return;
1278
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1279
0
    if (!*val)
1280
0
        return;
1281
0
    assert(length == strlen(*val));
1282
0
}
1283
1284
void plist_get_string_val(plist_t node, char **val)
1285
0
{
1286
0
    if (!node || !val)
1287
0
        return;
1288
0
    plist_type type = plist_get_node_type(node);
1289
0
    uint64_t length = 0;
1290
0
    if (PLIST_STRING != type)
1291
0
        return;
1292
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1293
0
    if (!*val)
1294
0
        return;
1295
0
    assert(length == strlen(*val));
1296
0
}
1297
1298
const char* plist_get_string_ptr(plist_t node, uint64_t* length)
1299
0
{
1300
0
    if (!node)
1301
0
        return NULL;
1302
0
    plist_type type = plist_get_node_type(node);
1303
0
    if (PLIST_STRING != type)
1304
0
        return NULL;
1305
0
    plist_data_t data = plist_get_data(node);
1306
0
    if (length)
1307
0
        *length = data->length;
1308
0
    return (const char*)data->strval;
1309
0
}
1310
1311
void plist_get_bool_val(plist_t node, uint8_t * val)
1312
0
{
1313
0
    if (!node || !val)
1314
0
        return;
1315
0
    plist_type type = plist_get_node_type(node);
1316
0
    uint64_t length = 0;
1317
0
    if (PLIST_BOOLEAN != type)
1318
0
        return;
1319
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1320
0
    assert(length == sizeof(uint8_t));
1321
0
}
1322
1323
void plist_get_uint_val(plist_t node, uint64_t * val)
1324
0
{
1325
0
    if (!node || !val)
1326
0
        return;
1327
0
    plist_type type = plist_get_node_type(node);
1328
0
    uint64_t length = 0;
1329
0
    if (PLIST_INT != type)
1330
0
        return;
1331
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1332
0
    assert(length == sizeof(uint64_t) || length == 16);
1333
0
}
1334
1335
void plist_get_int_val(plist_t node, int64_t * val)
1336
0
{
1337
0
    plist_get_uint_val(node, (uint64_t*)val);
1338
0
}
1339
1340
void plist_get_uid_val(plist_t node, uint64_t * val)
1341
0
{
1342
0
    if (!node || !val)
1343
0
        return;
1344
0
    plist_type type = plist_get_node_type(node);
1345
0
    uint64_t length = 0;
1346
0
    if (PLIST_UID != type)
1347
0
        return;
1348
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1349
0
    assert(length == sizeof(uint64_t));
1350
0
}
1351
1352
void plist_get_real_val(plist_t node, double *val)
1353
0
{
1354
0
    if (!node || !val)
1355
0
        return;
1356
0
    plist_type type = plist_get_node_type(node);
1357
0
    uint64_t length = 0;
1358
0
    if (PLIST_REAL != type)
1359
0
        return;
1360
0
    plist_get_type_and_value(node, &type, (void *) val, &length);
1361
0
    assert(length == sizeof(double));
1362
0
}
1363
1364
void plist_get_data_val(plist_t node, char **val, uint64_t * length)
1365
0
{
1366
0
    if (!node || !val || !length)
1367
0
        return;
1368
0
    plist_type type = plist_get_node_type(node);
1369
0
    if (PLIST_DATA != type)
1370
0
        return;
1371
0
    plist_get_type_and_value(node, &type, (void *) val, length);
1372
0
}
1373
1374
const char* plist_get_data_ptr(plist_t node, uint64_t* length)
1375
0
{
1376
0
    if (!node || !length)
1377
0
        return NULL;
1378
0
    plist_type type = plist_get_node_type(node);
1379
0
    if (PLIST_DATA != type)
1380
0
        return NULL;
1381
0
    plist_data_t data = plist_get_data(node);
1382
0
    *length = data->length;
1383
0
    return (const char*)data->buff;
1384
0
}
1385
1386
void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
1387
0
{
1388
0
    if (!node)
1389
0
        return;
1390
0
    plist_type type = plist_get_node_type(node);
1391
0
    uint64_t length = 0;
1392
0
    double val = 0;
1393
0
    if (PLIST_DATE != type)
1394
0
        return;
1395
0
    plist_get_type_and_value(node, &type, (void *) &val, &length);
1396
0
    assert(length == sizeof(double));
1397
0
    if (sec)
1398
0
        *sec = (int32_t)val;
1399
0
    if (usec)
1400
0
    {
1401
0
  val = fabs((val - (int64_t)val) * 1000000);
1402
0
        *usec = (int32_t)val;
1403
0
    }
1404
0
}
1405
1406
void plist_get_unix_date_val(plist_t node, int64_t *sec)
1407
0
{
1408
0
    if (!node || !sec)
1409
0
        return;
1410
0
    plist_type type = plist_get_node_type(node);
1411
0
    uint64_t length = 0;
1412
0
    double val = 0;
1413
0
    if (PLIST_DATE != type)
1414
0
        return;
1415
0
    plist_get_type_and_value(node, &type, (void *) &val, &length);
1416
0
    assert(length == sizeof(double));
1417
0
    *sec = (int64_t)val + MAC_EPOCH;
1418
0
}
1419
1420
int plist_data_compare(const void *a, const void *b)
1421
0
{
1422
0
    plist_data_t val_a = NULL;
1423
0
    plist_data_t val_b = NULL;
1424
1425
0
    if (!a || !b)
1426
0
        return FALSE;
1427
1428
0
    if (!((node_t) a)->data || !((node_t) b)->data)
1429
0
        return FALSE;
1430
1431
0
    val_a = plist_get_data((plist_t) a);
1432
0
    val_b = plist_get_data((plist_t) b);
1433
1434
0
    if (val_a->type != val_b->type)
1435
0
        return FALSE;
1436
1437
0
    switch (val_a->type)
1438
0
    {
1439
0
    case PLIST_BOOLEAN:
1440
0
    case PLIST_NULL:
1441
0
    case PLIST_INT:
1442
0
    case PLIST_REAL:
1443
0
    case PLIST_DATE:
1444
0
    case PLIST_UID:
1445
0
        if (val_a->length != val_b->length)
1446
0
            return FALSE;
1447
0
        return val_a->intval == val_b->intval; //it is an union so this is sufficient
1448
1449
0
    case PLIST_KEY:
1450
0
    case PLIST_STRING:
1451
0
        return strcmp(val_a->strval, val_b->strval) == 0;
1452
1453
0
    case PLIST_DATA:
1454
0
        if (val_a->length != val_b->length)
1455
0
            return FALSE;
1456
0
        return memcmp(val_a->buff, val_b->buff, val_a->length) == 0;
1457
1458
0
    case PLIST_ARRAY:
1459
0
    case PLIST_DICT:
1460
        //compare pointer
1461
0
        return a == b;
1462
1463
0
    default:
1464
0
        break;
1465
0
    }
1466
0
    return FALSE;
1467
0
}
1468
1469
char plist_compare_node_value(plist_t node_l, plist_t node_r)
1470
0
{
1471
0
    return plist_data_compare(node_l, node_r);
1472
0
}
1473
1474
static void plist_set_element_val(plist_t node, plist_type type, const void *value, uint64_t length)
1475
0
{
1476
    //free previous allocated buffer
1477
0
    plist_data_t data = plist_get_data(node);
1478
0
    assert(data);       // a node should always have data attached
1479
1480
0
    switch (data->type)
1481
0
    {
1482
0
    case PLIST_KEY:
1483
0
    case PLIST_STRING:
1484
0
        free(data->strval);
1485
0
        data->strval = NULL;
1486
0
        break;
1487
0
    case PLIST_DATA:
1488
0
        free(data->buff);
1489
0
        data->buff = NULL;
1490
0
        break;
1491
0
    default:
1492
0
        break;
1493
0
    }
1494
1495
    //now handle value
1496
1497
0
    data->type = type;
1498
0
    data->length = length;
1499
1500
0
    switch (type)
1501
0
    {
1502
0
    case PLIST_BOOLEAN:
1503
0
        data->boolval = *((char *) value);
1504
0
        break;
1505
0
    case PLIST_INT:
1506
0
    case PLIST_UID:
1507
0
        data->intval = *((uint64_t *) value);
1508
0
        break;
1509
0
    case PLIST_REAL:
1510
0
    case PLIST_DATE:
1511
0
        data->realval = *((double *) value);
1512
0
        break;
1513
0
    case PLIST_KEY:
1514
0
    case PLIST_STRING:
1515
0
        data->strval = strdup((char *) value);
1516
0
        break;
1517
0
    case PLIST_DATA:
1518
0
        data->buff = (uint8_t *) malloc(length);
1519
0
        memcpy(data->buff, value, length);
1520
0
        break;
1521
0
    case PLIST_ARRAY:
1522
0
    case PLIST_DICT:
1523
0
    default:
1524
0
        break;
1525
0
    }
1526
0
}
1527
1528
void plist_set_key_val(plist_t node, const char *val)
1529
0
{
1530
0
    plist_t father = plist_get_parent(node);
1531
0
    plist_t item = plist_dict_get_item(father, val);
1532
0
    if (item) {
1533
0
        return;
1534
0
    }
1535
0
    plist_set_element_val(node, PLIST_KEY, val, strlen(val));
1536
0
}
1537
1538
void plist_set_string_val(plist_t node, const char *val)
1539
0
{
1540
0
    plist_set_element_val(node, PLIST_STRING, val, strlen(val));
1541
0
}
1542
1543
void plist_set_bool_val(plist_t node, uint8_t val)
1544
0
{
1545
0
    plist_set_element_val(node, PLIST_BOOLEAN, &val, sizeof(uint8_t));
1546
0
}
1547
1548
void plist_set_uint_val(plist_t node, uint64_t val)
1549
0
{
1550
0
    plist_set_element_val(node, PLIST_INT, &val, (val > INT64_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t));
1551
0
}
1552
1553
void plist_set_int_val(plist_t node, int64_t val)
1554
0
{
1555
0
    plist_set_element_val(node, PLIST_INT, &val, sizeof(uint64_t));
1556
0
}
1557
1558
void plist_set_uid_val(plist_t node, uint64_t val)
1559
0
{
1560
0
    plist_set_element_val(node, PLIST_UID, &val, sizeof(uint64_t));
1561
0
}
1562
1563
void plist_set_real_val(plist_t node, double val)
1564
0
{
1565
0
    plist_set_element_val(node, PLIST_REAL, &val, sizeof(double));
1566
0
}
1567
1568
void plist_set_data_val(plist_t node, const char *val, uint64_t length)
1569
0
{
1570
0
    plist_set_element_val(node, PLIST_DATA, val, length);
1571
0
}
1572
1573
void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
1574
0
{
1575
0
    double val = (double)sec + (double)usec / 1000000;
1576
0
    plist_set_element_val(node, PLIST_DATE, &val, sizeof(double));
1577
0
}
1578
1579
void plist_set_unix_date_val(plist_t node, int64_t sec)
1580
0
{
1581
0
    double val = (double)(sec - MAC_EPOCH);
1582
0
    plist_set_element_val(node, PLIST_DATE, &val, sizeof(double));
1583
0
}
1584
1585
int plist_bool_val_is_true(plist_t boolnode)
1586
0
{
1587
0
    if (!PLIST_IS_BOOLEAN(boolnode)) {
1588
0
        return 0;
1589
0
    }
1590
0
    uint8_t bv = 0;
1591
0
    plist_get_bool_val(boolnode, &bv);
1592
0
    return (bv == 1);
1593
0
}
1594
1595
int plist_int_val_is_negative(plist_t intnode)
1596
0
{
1597
0
    if (!PLIST_IS_INT(intnode)) {
1598
0
        return 0;
1599
0
    }
1600
0
    plist_data_t data = plist_get_data(intnode);
1601
0
    if (data->length == 16) {
1602
0
        return 0;
1603
0
    }
1604
0
    if ((int64_t)data->intval < 0) {
1605
0
        return 1;
1606
0
    }
1607
0
    return 0;
1608
0
}
1609
1610
int plist_int_val_compare(plist_t uintnode, int64_t cmpval)
1611
0
{
1612
0
    if (!PLIST_IS_INT(uintnode)) {
1613
0
        return -1;
1614
0
    }
1615
0
    int64_t uintval = 0;
1616
0
    plist_get_int_val(uintnode, &uintval);
1617
0
    if (uintval == cmpval) {
1618
0
        return 0;
1619
0
    }
1620
1621
0
    if (uintval < cmpval) {
1622
0
        return -1;
1623
0
    }
1624
1625
0
    return 1;
1626
0
}
1627
1628
int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval)
1629
0
{
1630
0
    if (!PLIST_IS_INT(uintnode)) {
1631
0
        return -1;
1632
0
    }
1633
0
    uint64_t uintval = 0;
1634
0
    plist_get_uint_val(uintnode, &uintval);
1635
0
    if (uintval == cmpval) {
1636
0
        return 0;
1637
0
    }
1638
1639
0
    if (uintval < cmpval) {
1640
0
        return -1;
1641
0
    }
1642
1643
0
    return 1;
1644
0
}
1645
1646
int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval)
1647
0
{
1648
0
    if (!PLIST_IS_UID(uidnode)) {
1649
0
        return -1;
1650
0
    }
1651
0
    uint64_t uidval = 0;
1652
0
    plist_get_uid_val(uidnode, &uidval);
1653
0
    if (uidval == cmpval) {
1654
0
        return 0;
1655
0
    }
1656
1657
0
    if (uidval < cmpval) {
1658
0
        return -1;
1659
0
    }
1660
1661
0
    return 1;
1662
0
}
1663
1664
int plist_real_val_compare(plist_t realnode, double cmpval)
1665
0
{
1666
0
    if (!PLIST_IS_REAL(realnode)) {
1667
0
        return -1;
1668
0
    }
1669
0
    double a = 0;
1670
0
    double b = cmpval;
1671
0
    plist_get_real_val(realnode, &a);
1672
0
    double abs_a = fabs(a);
1673
0
    double abs_b = fabs(b);
1674
0
    double diff = fabs(a - b);
1675
0
    if (a == b) {
1676
0
        return 0;
1677
0
    }
1678
1679
0
    if (a == 0 || b == 0 || (abs_a + abs_b < DBL_MIN)) {
1680
0
        if (diff < (DBL_EPSILON * DBL_MIN)) {
1681
0
            return 0;
1682
0
        }
1683
1684
0
        if (a < b) {
1685
0
            return -1;
1686
0
        }
1687
0
    } else {
1688
0
        if ((diff / fmin(abs_a + abs_b, DBL_MAX)) < DBL_EPSILON) {
1689
0
            return 0;
1690
0
        }
1691
1692
0
        if (a < b) {
1693
0
            return -1;
1694
0
        }
1695
0
    }
1696
0
    return 1;
1697
0
}
1698
1699
int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec)
1700
0
{
1701
0
    if (!PLIST_IS_DATE(datenode)) {
1702
0
        return -1;
1703
0
    }
1704
0
    plist_data_t data = plist_get_data(datenode);
1705
0
    assert(data->length == sizeof(double));
1706
0
    double val = data->realval;
1707
0
    int32_t sec = (int32_t)val;
1708
0
    val = fabs((val - (int64_t)val) * 1000000);
1709
0
    int32_t usec = (int32_t)val;
1710
0
    uint64_t dateval = ((int64_t)sec << 32) | usec;
1711
0
    uint64_t cmpval = ((int64_t)cmpsec << 32) | cmpusec;
1712
0
    if (dateval == cmpval) {
1713
0
        return 0;
1714
0
    }
1715
1716
0
    if (dateval < cmpval) {
1717
0
        return -1;
1718
0
    }
1719
1720
0
    return 1;
1721
0
}
1722
1723
int plist_unix_date_val_compare(plist_t datenode, int64_t cmpval)
1724
0
{
1725
0
    if (!PLIST_IS_DATE(datenode)) {
1726
0
        return -1;
1727
0
    }
1728
0
    int64_t dateval = 0;
1729
0
    plist_get_unix_date_val(datenode, &dateval);
1730
0
    if (dateval == cmpval) {
1731
0
        return 0;
1732
0
    }
1733
1734
0
    if (dateval < cmpval) {
1735
0
        return -1;
1736
0
    }
1737
1738
0
    return 1;
1739
0
}
1740
1741
int plist_string_val_compare(plist_t strnode, const char* cmpval)
1742
0
{
1743
0
    if (!PLIST_IS_STRING(strnode)) {
1744
0
        return -1;
1745
0
    }
1746
0
    plist_data_t data = plist_get_data(strnode);
1747
0
    return strcmp(data->strval, cmpval);
1748
0
}
1749
1750
int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n)
1751
0
{
1752
0
    if (!PLIST_IS_STRING(strnode)) {
1753
0
        return -1;
1754
0
    }
1755
0
    plist_data_t data = plist_get_data(strnode);
1756
0
    return strncmp(data->strval, cmpval, n);
1757
0
}
1758
1759
int plist_string_val_contains(plist_t strnode, const char* substr)
1760
0
{
1761
0
    if (!PLIST_IS_STRING(strnode)) {
1762
0
        return 0;
1763
0
    }
1764
0
    plist_data_t data = plist_get_data(strnode);
1765
0
    return (strstr(data->strval, substr) != NULL);
1766
0
}
1767
1768
int plist_key_val_compare(plist_t keynode, const char* cmpval)
1769
0
{
1770
0
    if (!PLIST_IS_KEY(keynode)) {
1771
0
        return -1;
1772
0
    }
1773
0
    plist_data_t data = plist_get_data(keynode);
1774
0
    return strcmp(data->strval, cmpval);
1775
0
}
1776
1777
int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n)
1778
0
{
1779
0
    if (!PLIST_IS_KEY(keynode)) {
1780
0
        return -1;
1781
0
    }
1782
0
    plist_data_t data = plist_get_data(keynode);
1783
0
    return strncmp(data->strval, cmpval, n);
1784
0
}
1785
1786
int plist_key_val_contains(plist_t keynode, const char* substr)
1787
0
{
1788
0
    if (!PLIST_IS_KEY(keynode)) {
1789
0
        return 0;
1790
0
    }
1791
0
    plist_data_t data = plist_get_data(keynode);
1792
0
    return (strstr(data->strval, substr) != NULL);
1793
0
}
1794
1795
int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n)
1796
0
{
1797
0
    if (!PLIST_IS_DATA(datanode)) {
1798
0
        return -1;
1799
0
    }
1800
0
    plist_data_t data = plist_get_data(datanode);
1801
0
    if (data->length < n) {
1802
0
        return -1;
1803
0
    }
1804
1805
0
    if (data->length > n) {
1806
0
        return 1;
1807
0
    }
1808
1809
0
    return memcmp(data->buff, cmpval, n);
1810
0
}
1811
1812
int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n)
1813
0
{
1814
0
    if (!PLIST_IS_DATA(datanode)) {
1815
0
        return -1;
1816
0
    }
1817
0
    plist_data_t data = plist_get_data(datanode);
1818
0
    if (data->length < n) {
1819
0
        return -1;
1820
0
    }
1821
0
    return memcmp(data->buff, cmpval, n);
1822
0
}
1823
1824
int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n)
1825
0
{
1826
0
    if (!PLIST_IS_DATA(datanode)) {
1827
0
        return -1;
1828
0
    }
1829
0
    plist_data_t data = plist_get_data(datanode);
1830
0
    return (memmem(data->buff, data->length, cmpval, n) != NULL);
1831
0
}
1832
1833
extern void plist_xml_set_debug(int debug);
1834
extern void plist_bin_set_debug(int debug);
1835
extern void plist_json_set_debug(int debug);
1836
extern void plist_ostep_set_debug(int debug);
1837
1838
void plist_set_debug(int debug)
1839
0
{
1840
0
#if DEBUG
1841
0
    plist_debug = debug;
1842
0
#endif
1843
0
    plist_xml_set_debug(debug);
1844
0
    plist_bin_set_debug(debug);
1845
0
    plist_json_set_debug(debug);
1846
0
    plist_ostep_set_debug(debug);
1847
0
}
1848
1849
void plist_sort(plist_t plist)
1850
0
{
1851
0
    if (!plist) {
1852
0
        return;
1853
0
    }
1854
0
    if (PLIST_IS_ARRAY(plist)) {
1855
0
        uint32_t n = plist_array_get_size(plist);
1856
0
        uint32_t i = 0;
1857
0
        for (i = 0; i < n; i++) {
1858
0
            plist_sort(plist_array_get_item(plist, i));
1859
0
        }
1860
0
    } else if (PLIST_IS_DICT(plist)) {
1861
0
        node_t node = (node_t)plist;
1862
0
        node_t ch;
1863
0
        if (!node_first_child(node)) {
1864
0
            return;
1865
0
        }
1866
0
        for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
1867
0
            ch = node_next_sibling(ch);
1868
0
            plist_sort((plist_t)ch);
1869
0
        }
1870
0
        #define KEY_DATA(x) (x->data)
1871
0
        #define NEXT_KEY(x) (x->next->next)
1872
0
        #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval
1873
0
        int swapped = 0;
1874
0
        do {
1875
0
            swapped = 0;
1876
0
            node_t lptr = NULL;
1877
0
            node_t cur_key = node_first_child((node_t)plist);
1878
1879
0
            while (NEXT_KEY(cur_key) != lptr) {
1880
0
                node_t next_key = NEXT_KEY(cur_key);
1881
0
                if (strcmp(KEY_STRVAL(cur_key), KEY_STRVAL(next_key)) > 0) {
1882
0
                    node_t cur_val = cur_key->next;
1883
0
                    node_t next_val = next_key->next;
1884
                    // we need to swap 2 consecutive nodes with the 2 after them
1885
                    // a -> b -> [c] -> [d] -> [e] -> [f] -> g -> h
1886
                    //              cur           next
1887
                    // swapped:
1888
                    // a -> b -> [e] -> [f] -> [c] -> [d] -> g -> h
1889
                    //              next           cur
1890
0
                    node_t tmp_prev = cur_key->prev;
1891
0
                    node_t tmp_next = next_val->next;
1892
0
                    cur_key->prev = next_val;
1893
0
                    cur_val->next = tmp_next;
1894
0
                    next_val->next = cur_key;
1895
0
                    next_key->prev = tmp_prev;
1896
0
                    if (tmp_prev) {
1897
0
                        tmp_prev->next = next_key;
1898
0
                    } else {
1899
0
                        ((node_t)plist)->children->begin = next_key;
1900
0
                    }
1901
0
                    if (tmp_next) {
1902
0
                        tmp_next->prev = cur_val;
1903
0
                    } else {
1904
0
                        ((node_t)plist)->children->end = cur_val;
1905
0
                    }
1906
0
                    cur_key = next_key;
1907
0
                    swapped = 1;
1908
0
                }
1909
0
                cur_key = NEXT_KEY(cur_key);
1910
0
            }
1911
0
            lptr = cur_key;
1912
0
        } while (swapped);
1913
0
    }
1914
0
}
1915
1916
plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length, plist_format_t format, plist_write_options_t options)
1917
0
{
1918
0
    plist_err_t err = PLIST_ERR_UNKNOWN;
1919
0
    switch (format) {
1920
0
        case PLIST_FORMAT_XML:
1921
0
            err = plist_to_xml(plist, output, length);
1922
0
            break;
1923
0
        case PLIST_FORMAT_JSON:
1924
0
            err = plist_to_json(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0));
1925
0
            break;
1926
0
        case PLIST_FORMAT_OSTEP:
1927
0
            err = plist_to_openstep(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0));
1928
0
            break;
1929
0
        case PLIST_FORMAT_PRINT:
1930
0
            err = plist_write_to_string_default(plist, output, length, options);
1931
0
            break;
1932
0
        case PLIST_FORMAT_LIMD:
1933
0
            err = plist_write_to_string_limd(plist, output, length, options);
1934
0
            break;
1935
0
        case PLIST_FORMAT_PLUTIL:
1936
0
            err = plist_write_to_string_plutil(plist, output, length, options);
1937
0
            break;
1938
0
        default:
1939
            // unsupported output format
1940
0
            err = PLIST_ERR_FORMAT;
1941
0
            break;
1942
0
    }
1943
0
    return err;
1944
0
}
1945
1946
plist_err_t plist_write_to_stream(plist_t plist, FILE *stream, plist_format_t format, plist_write_options_t options)
1947
0
{
1948
0
    if (!plist || !stream) {
1949
0
        return PLIST_ERR_INVALID_ARG;
1950
0
    }
1951
0
    plist_err_t err = PLIST_ERR_UNKNOWN;
1952
0
    char *output = NULL;
1953
0
    uint32_t length = 0;
1954
0
    switch (format) {
1955
0
        case PLIST_FORMAT_BINARY:
1956
0
            err = plist_to_bin(plist, &output, &length);
1957
0
            break;
1958
0
        case PLIST_FORMAT_XML:
1959
0
            err = plist_to_xml(plist, &output, &length);
1960
0
            break;
1961
0
        case PLIST_FORMAT_JSON:
1962
0
            err = plist_to_json(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0));
1963
0
            break;
1964
0
        case PLIST_FORMAT_OSTEP:
1965
0
            err = plist_to_openstep(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0));
1966
0
            break;
1967
0
        case PLIST_FORMAT_PRINT:
1968
0
            err = plist_write_to_stream_default(plist, stream, options);
1969
0
            break;
1970
0
        case PLIST_FORMAT_LIMD:
1971
0
            err = plist_write_to_stream_limd(plist, stream, options);
1972
0
            break;
1973
0
        case PLIST_FORMAT_PLUTIL:
1974
0
            err = plist_write_to_stream_plutil(plist, stream, options);
1975
0
            break;
1976
0
        default:
1977
            // unsupported output format
1978
0
            err = PLIST_ERR_FORMAT;
1979
0
            break;
1980
0
    }
1981
0
    if (output && err == PLIST_ERR_SUCCESS) {
1982
0
        if (fwrite(output, 1, length, stream) < length) {
1983
0
            err = PLIST_ERR_IO;
1984
0
        }
1985
0
        free(output);
1986
0
    }
1987
0
    return err;
1988
0
}
1989
1990
plist_err_t plist_write_to_file(plist_t plist, const char* filename, plist_format_t format, plist_write_options_t options)
1991
0
{
1992
0
    if (!plist || !filename) {
1993
0
        return PLIST_ERR_INVALID_ARG;
1994
0
    }
1995
0
    FILE* f = fopen(filename, "wb");
1996
0
    if (!f) {
1997
0
        return PLIST_ERR_IO;
1998
0
    }
1999
0
    plist_err_t err = plist_write_to_stream(plist, f, format, options);
2000
0
    fclose(f);
2001
0
    return err;
2002
0
}
2003
2004
void plist_print(plist_t plist)
2005
0
{
2006
0
     plist_write_to_stream(plist, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_PARTIAL_DATA);
2007
0
}
2008
2009
const char* libplist_version()
2010
0
{
2011
#ifndef PACKAGE_VERSION
2012
#error PACKAGE_VERSION is not defined!
2013
#endif
2014
0
  return PACKAGE_VERSION;
2015
0
}