summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dev/plutil.c87
-rw-r--r--src/plist.c799
-rw-r--r--src/plist.h48
3 files changed, 451 insertions, 483 deletions
diff --git a/dev/plutil.c b/dev/plutil.c
index d1c3ddd..d1f1cd4 100644
--- a/dev/plutil.c
+++ b/dev/plutil.c
@@ -10,85 +10,6 @@
10#include <stdio.h> 10#include <stdio.h>
11#include <stdlib.h> 11#include <stdlib.h>
12 12
13void print_nodes(bplist_node * root_node)
14{
15 // Yay, great. Let's print the list of nodes recursively...
16 int i = 0;
17 if (!root_node)
18 return; // or not, because the programmer's stupid.
19
20 switch (root_node->type) {
21 case BPLIST_DICT:
22 printf("Dictionary node.\nLength %lu\n", (long unsigned int) root_node->length);
23 for (i = 0; i < (root_node->length * 2); i += 2) {
24 // HI!
25 printf("Key: ");
26 print_nodes(root_node->subnodes[i]);
27 printf("Value: ");
28 print_nodes(root_node->subnodes[i + 1]);
29 }
30 printf("End dictionary node.\n\n");
31 break;
32
33 case BPLIST_ARRAY:
34 printf("Array node.\n");
35 for (i = 0; i < root_node->length; i++) {
36 printf("\tElement %i: ", i);
37 print_nodes(root_node->subnodes[i]);
38 }
39 break;
40
41 case BPLIST_INT:
42 if (root_node->length == sizeof(uint8_t)) {
43 printf("Integer: %i\n", root_node->intval8);
44 } else if (root_node->length == sizeof(uint16_t)) {
45 printf("Integer: %i\n", root_node->intval16);
46 } else if (root_node->length == sizeof(uint32_t)) {
47 printf("Integer: %i\n", root_node->intval32);
48 }
49 break;
50
51 case BPLIST_STRING:
52 printf("String: ");
53 fwrite(root_node->strval, sizeof(char), root_node->length, stdout);
54 fflush(stdout);
55 printf("\n");
56 break;
57
58 case BPLIST_DATA:
59 printf("Data: ");
60 char *data = g_base64_encode(root_node->strval, root_node->length);
61 fwrite(format_string(data, 60, 0), sizeof(char), strlen(data), stdout);
62 fflush(stdout);
63 printf("\n");
64 break;
65
66 case BPLIST_UNICODE:
67 printf("Unicode data, may appear crappy: ");
68 fwrite(root_node->unicodeval, sizeof(wchar_t), root_node->length, stdout);
69 fflush(stdout);
70 printf("\n");
71 break;
72
73 case BPLIST_TRUE:
74 printf("True.\n");
75 break;
76
77 case BPLIST_FALSE:
78 printf("False.\n");
79 break;
80
81 case BPLIST_REAL:
82 case BPLIST_DATE:
83 printf("Real(?): %f\n", root_node->realval);
84 break;
85
86 default:
87 printf("oops\nType set to %x and length is %lu\n", root_node->type, (long unsigned int) root_node->length);
88 break;
89 }
90}
91
92int main(int argc, char *argv[]) 13int main(int argc, char *argv[])
93{ 14{
94 struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); 15 struct stat *filestats = (struct stat *) malloc(sizeof(struct stat));
@@ -117,15 +38,17 @@ int main(int argc, char *argv[])
117 fclose(bplist); 38 fclose(bplist);
118 printf("or here?\n"); 39 printf("or here?\n");
119 // bplist_entire contains our stuff 40 // bplist_entire contains our stuff
120 bplist_node *root_node; 41 plist_t root_node = NULL;
121 root_node = parse_nodes(bplist_entire, filestats->st_size, &position); 42 bin_to_plist(bplist_entire, filestats->st_size, &root_node);
122 printf("plutil debug mode\n\n"); 43 printf("plutil debug mode\n\n");
123 printf("file size %i\n\n", (int) filestats->st_size); 44 printf("file size %i\n\n", (int) filestats->st_size);
124 if (!root_node) { 45 if (!root_node) {
125 printf("Invalid binary plist (or some other error occurred.)\n"); 46 printf("Invalid binary plist (or some other error occurred.)\n");
126 return 0; 47 return 0;
127 } 48 }
128 print_nodes(root_node); 49 char *plist_xml = NULL;
50 plist_to_xml(root_node, &plist_xml);
51 printf("%s\n", plist_xml);
129 return 0; 52 return 0;
130} 53}
131 54
diff --git a/src/plist.c b/src/plist.c
index 1553c1c..377646d 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -25,6 +25,7 @@
25#include <assert.h> 25#include <assert.h>
26#include "utils.h" 26#include "utils.h"
27#include "plist.h" 27#include "plist.h"
28#include <wchar.h>
28 29
29 30
30const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 31const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
@@ -285,147 +286,7 @@ void byte_convert(char *address, size_t size)
285 } 286 }
286} 287}
287 288
288bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size)
289{
290 if (!position || !bpbuffer || !bplength)
291 return NULL;
292
293 uint8_t modifier = 0;
294 bplist_node *new_node = (bplist_node *) malloc(sizeof(bplist_node));
295 bplist_node *length_stupidity = NULL;
296 memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct
297
298 int myPos = *position;
299 if (myPos == bplength || (myPos + 1) == bplength) {
300 free(new_node);
301 return NULL;
302 } // end of string
303
304 uint32_t length = 0;
305 if (!myPos) {
306 if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) {
307 return NULL; // badness!
308 }
309 myPos += strlen("bplist00");
310 }
311 // Get the node's type.
312 if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real
313 // better handling of date; basically interpret as real or double
314 new_node->type = BPLIST_DATE;
315 new_node->length = 8; // always 8 for "date" (Apple intended it, not me)
316 myPos++;
317 memcpy(&new_node->realval, bpbuffer + myPos, sizeof(new_node->realval));
318 byte_convert((char *) &new_node->realval, sizeof(new_node->realval));
319 myPos += new_node->length;
320 *position = myPos;
321 return new_node;
322 }
323
324 new_node->type = bpbuffer[myPos] & BPLIST_MASK;
325 new_node->length = bpbuffer[myPos] & BPLIST_FILL;
326 if (!new_node->type) {
327 // what? check if it's a boolean.
328 if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) {
329 // okay, so it is. Carry on.
330 new_node->type = bpbuffer[myPos];
331 new_node->length = 0;
332 } else {
333 // er, what? we have a bad type here. Return NULL.
334 free(new_node);
335 //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]);
336 return NULL;
337 }
338 }
339
340 myPos++; // puts us in the data.
341 if (new_node->length == BPLIST_FILL) { // Data happens to contain length...
342 // what? you're going to make me parse an int for the length. You suck.
343 *position = myPos;
344 length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size);
345 switch (length_stupidity->length) {
346 case sizeof(uint8_t):
347 new_node->length = length_stupidity->intval8;
348 break;
349 case sizeof(uint16_t):
350 new_node->length = length_stupidity->intval16;
351 break;
352 case sizeof(uint32_t):
353 new_node->length = length_stupidity->intval32;
354 break;
355 case sizeof(uint64_t):
356 new_node->length = length_stupidity->intval64;
357 break;
358 default:
359 free(new_node);
360 free(length_stupidity);
361 return NULL;
362 }
363 // There, we have our fucking length now.
364 *position = myPos;
365 free(length_stupidity); // cleanup
366 }
367 // Now we're in the data.
368 // Error-checking sorta
369 if ((myPos + new_node->length) >= bplength) {
370 new_node->length = bplength - myPos; // truncate the object
371 }
372 // And now for the greatest show on earth: the giant fucking switch statement.
373 switch (new_node->type) {
374 case BPLIST_INT:
375 new_node->length = uipow(2, new_node->length); // make length less misleading
376 switch (new_node->length) {
377 case sizeof(uint8_t):
378 new_node->intval8 = bpbuffer[myPos];
379 break;
380 case sizeof(uint16_t):
381 memcpy(&new_node->intval16, bpbuffer + myPos, sizeof(uint16_t));
382 new_node->intval16 = ntohs(new_node->intval16);
383 break;
384 case sizeof(uint32_t):
385 memcpy(&new_node->intval32, bpbuffer + myPos, sizeof(uint32_t));
386 new_node->intval32 = ntohl(new_node->intval32);
387 break;
388 case sizeof(uint64_t):
389 memcpy(&new_node->intval64, bpbuffer + myPos, sizeof(uint64_t));
390 byte_convert((char *) &new_node->intval64, sizeof(uint64_t));
391 break;
392 default:
393 free(new_node);
394 printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) new_node->length);
395 printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t));
396 return NULL;
397 }
398 break;
399 289
400 case BPLIST_REAL:
401 new_node->length = uipow(2, new_node->length);
402 memcpy(&new_node->realval, bpbuffer + myPos, new_node->length); // XXX: probable buffer overflow here
403 //new_node->realval = bpbuffer[myPos]; // why not
404 byte_convert((char *) &new_node->realval, sizeof(double));
405 break;
406
407 case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */
408 new_node->length = new_node->length * 2; // dicts lie
409 case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */
410 new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space.
411 case BPLIST_STRING:
412 case BPLIST_DATA:
413 default: /* made to hold raw data. */
414 modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1;
415 new_node->strval = (char *) malloc(sizeof(char) * (new_node->length * modifier));
416 memcpy(new_node->strval, bpbuffer + myPos, (new_node->length * modifier));
417 break;
418
419 case BPLIST_UNICODE:
420 new_node->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * new_node->length);
421 memcpy(new_node->unicodeval, bpbuffer + myPos, new_node->length);
422 break;
423 }
424
425 myPos += new_node->length;
426 *position = myPos;
427 return new_node;
428}
429 290
430void print_bytes(char *val, size_t size) 291void print_bytes(char *val, size_t size)
431{ 292{
@@ -435,180 +296,123 @@ void print_bytes(char *val, size_t size)
435 } 296 }
436} 297}
437 298
438bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position)
439{
440 bplist_node **nodeslist = NULL, **newaddr = NULL;
441 bplist_node *new_node = NULL, *root_node = NULL;
442
443 uint32_t nodeslength = 0;
444 uint8_t offset_size = 0, dict_param_size = 0;
445 offset_size = bpbuffer[bplength - 26];
446 dict_param_size = bpbuffer[bplength - 25];
447 uint64_t current_offset = 0;
448 //uint64_t num_objects = *(bpbuffer+(bplength-24)), root_object = *(bpbuffer+(bplength-16)), offset_table_index = *(bpbuffer+(bplength-8));
449 uint64_t num_objects = 0, root_object = 0, offset_table_index = 0;
450 memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t));
451 memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t));
452 memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t));
453 byte_convert((char *) &num_objects, sizeof(uint64_t));
454 byte_convert((char *) &root_object, sizeof(uint64_t));
455 byte_convert((char *) &offset_table_index, sizeof(uint64_t));
456
457 log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]);
458 log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]);
459 log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24));
460 log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16));
461 log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8));
462 log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t));
463
464 int i = 0, j = 0, k = 0, str_i = 0, str_j = 0;
465 uint32_t index1 = 0, index2 = 0;
466
467 nodeslist = (bplist_node **) malloc(sizeof(bplist_node *) * num_objects);
468 if (!nodeslist)
469 return NULL;
470
471 for (i = 0; i < num_objects; i++) {
472 memcpy(&current_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size);
473 //current_offset = (offset_size == 2) ? ntohs(current_offset) : (offset_size == 4) ? ntohl(current_offset) : current_offset;
474 //if (offset_size == 8) byte_convert(&current_offset, 8);
475 byte_convert((char *) &current_offset,
476 (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset));
477 log_debug_msg("parse_nodes: current_offset = %x\n", current_offset);
478 nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size);
479 log_debug_msg("parse_nodes: parse_raw_node done\n");
480 }
481
482
483 for (i = 0; i < num_objects; i++) {
484 // set elements for dicts and arrays and leave the rest alone
485 log_debug_msg("parse_nodes: on node %i\n", i);
486 switch (nodeslist[i]->type) {
487 case BPLIST_DICT:
488 log_debug_msg("parse_nodes: dictionary found\n");
489 nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length);
490 for (j = 0; j < (nodeslist[i]->length / 2); j++) {
491 str_i = j * nodeslist[i]->intval8;
492 str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8;
493
494 memcpy(&index1, nodeslist[i]->strval + str_i, nodeslist[i]->intval8);
495 memcpy(&index2, nodeslist[i]->strval + str_j, nodeslist[i]->intval8);
496 //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1;
497 //index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2;
498 byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2));
499 byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2));
500 //printf("parse_nodes: key index %i value %i\n", index1, index2);
501 //printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length);
502 //printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length);
503 nodeslist[i]->subnodes[k++] = nodeslist[index1];
504 nodeslist[i]->subnodes[k++] = nodeslist[index2];
505 }
506
507 nodeslist[i]->length = nodeslist[i]->length / 2;
508 free(nodeslist[i]->strval);
509 k = 0;
510 break;
511
512 case BPLIST_ARRAY:
513 log_debug_msg("parse_nodes: array found\n");
514 nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data
515
516 for (j = 0; j < nodeslist[i]->length; j++) {
517 log_debug_msg("parse_nodes: array index %i\n", j);
518 str_j = j * nodeslist[i]->intval8;
519 //index1 = nodeslist[i]->strval[j];
520 memcpy(&index1, nodeslist[i]->strval + str_j, nodeslist[i]->intval8);
521 log_debug_msg("parse_nodes: post-memcpy\n");
522 //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1;
523 byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1));
524 log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1);
525 nodeslist[i]->subnodes[j] = nodeslist[index1];
526 log_debug_msg("parse_nodes: post-assignment\n");
527 }
528 free(nodeslist[i]->strval);
529 break;
530 default:
531 //printf("lol... type %x\n", nodeslist[i]->type);
532 break;
533 } // those are the only two we need to correct for.
534 }
535 299
536 root_node = nodeslist[root_object];
537 return root_node;
538}
539 300
540struct plist_data { 301struct plist_data {
541 union { 302 union {
542 char boolval; 303 char boolval;
543 uint8_t intval8; 304 uint8_t intval8;
544 uint16_t intval16; 305 uint16_t intval16;
545 uint32_t intval32; 306 uint32_t intval32;
546 uint64_t intval64; 307 uint64_t intval64;
547 float realval32; 308 float realval32;
548 double realval64; 309 double realval64;
549 char *strval; 310 char *strval;
550 wchar_t *unicodeval; 311 wchar_t *unicodeval;
551 char *buff; 312 struct {
313 char *buff;
314 uint8_t ref_size;
315 };
552 }; 316 };
553 int index; 317 uint64_t length;
554 plist_type type; 318 plist_type type;
555}; 319};
556 320
557void plist_new_plist(plist_t* plist) 321enum {
322 BPLIST_TRUE = 0x08,
323 BPLIST_FALSE = 0x09,
324 BPLIST_FILL = 0x0F, /* will be used for length grabbing */
325 BPLIST_INT = 0x10,
326 BPLIST_REAL = 0x20,
327 BPLIST_DATE = 0x33,
328 BPLIST_DATA = 0x40,
329 BPLIST_STRING = 0x50,
330 BPLIST_UNICODE = 0x60,
331 BPLIST_UID = 0x70,
332 BPLIST_ARRAY = 0xA0,
333 BPLIST_SET = 0xC0,
334 BPLIST_DICT = 0xD0,
335 BPLIST_MASK = 0xF0
336};
337
338void plist_new_plist(plist_t * plist)
558{ 339{
559 if (*plist != NULL) return; 340 if (*plist != NULL)
560 struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 341 return;
342 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
561 data->type = PLIST_PLIST; 343 data->type = PLIST_PLIST;
562 *plist = g_node_new (data); 344 *plist = g_node_new(data);
563} 345}
564 346
565void plist_new_dict_in_plist(plist_t plist, dict_t* dict) 347void plist_new_dict_in_plist(plist_t plist, dict_t * dict)
566{ 348{
567 if (!plist || *dict) return; 349 if (!plist || *dict)
350 return;
568 351
569 struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 352 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
570 data->type = PLIST_DICT; 353 data->type = PLIST_DICT;
571 *dict = g_node_new (data); 354 *dict = g_node_new(data);
572 g_node_append(plist, *dict); 355 g_node_append(plist, *dict);
573} 356}
574 357
575void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array) 358void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array)
576{ 359{
577} 360}
578 361
579void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value) 362void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value)
580{ 363{
581 if (!dict || !key || !value) return; 364 if (!dict || !key || !value)
365 return;
582 366
583 struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 367 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
584 data->type = PLIST_KEY; 368 data->type = PLIST_KEY;
585 data->strval = strdup(key); 369 data->strval = strdup(key);
586 GNode* keynode = g_node_new (data); 370 GNode *keynode = g_node_new(data);
587 g_node_append(dict, keynode); 371 g_node_append(dict, keynode);
588 372
589 //now handle value 373 //now handle value
590 struct plist_data* val = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 374 struct plist_data *val = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
591 val->type = type; 375 val->type = type;
592 376
593 switch (type) { 377 switch (type) {
594 case PLIST_BOOLEAN : val->boolval = *((char*)value); break; 378 case PLIST_BOOLEAN:
595 case PLIST_UINT8 : val->intval8 = *((uint8_t*)value); break; 379 val->boolval = *((char *) value);
596 case PLIST_UINT16 : val->intval16 = *((uint16_t*)value); break; 380 break;
597 case PLIST_UINT32 : val->intval32 = *((uint32_t*)value); break; 381 case PLIST_UINT8:
598 case PLIST_UINT64 : val->intval64 = *((uint64_t*)value); break; 382 val->intval8 = *((uint8_t *) value);
599 case PLIST_FLOAT32 : val->realval32 = *((float*)value); break; 383 break;
600 case PLIST_FLOAT64 : val->realval64 = *((double*)value); break; 384 case PLIST_UINT16:
601 case PLIST_STRING : val->strval = strdup((char*) value); break; 385 val->intval16 = *((uint16_t *) value);
602 case PLIST_UNICODE : val->unicodeval = wcsdup((wchar_t*) value); break; 386 break;
603 case PLIST_DATA : val->buff = strdup((char*) value); break; 387 case PLIST_UINT32:
604 case PLIST_ARRAY : 388 val->intval32 = *((uint32_t *) value);
605 case PLIST_DICT : 389 break;
606 case PLIST_DATE : 390 case PLIST_UINT64:
607 case PLIST_PLIST : 391 val->intval64 = *((uint64_t *) value);
608 default: 392 break;
609 break; 393 case PLIST_FLOAT32:
394 val->realval32 = *((float *) value);
395 break;
396 case PLIST_FLOAT64:
397 val->realval64 = *((double *) value);
398 break;
399 case PLIST_STRING:
400 val->strval = strdup((char *) value);
401 break;
402 case PLIST_UNICODE:
403 val->unicodeval = wcsdup((wchar_t *) value);
404 break;
405 case PLIST_DATA:
406 val->buff = strdup((char *) value);
407 break;
408 case PLIST_ARRAY:
409 case PLIST_DICT:
410 case PLIST_DATE:
411 case PLIST_PLIST:
412 default:
413 break;
610 } 414 }
611 GNode* valnode = g_node_new (val); 415 GNode *valnode = g_node_new(val);
612 g_node_append(dict, valnode); 416 g_node_append(dict, valnode);
613} 417}
614 418
@@ -617,97 +421,98 @@ void plist_free(plist_t plist)
617 g_node_destroy(plist); 421 g_node_destroy(plist);
618} 422}
619 423
620void node_to_xml (GNode *node, gpointer data) 424void node_to_xml(GNode * node, gpointer data)
621{ 425{
622 if (!node) return; 426 if (!node)
427 return;
623 428
624 struct plist_data* node_data = (struct plist_data*)node->data; 429 struct plist_data *node_data = (struct plist_data *) node->data;
625 430
626 xmlNodePtr child_node = NULL; 431 xmlNodePtr child_node = NULL;
627 char isStruct = FALSE; 432 char isStruct = FALSE;
628 433
629 gchar* tag = NULL; 434 gchar *tag = NULL;
630 gchar* val = NULL; 435 gchar *val = NULL;
631 436
632 switch (node_data->type) { 437 switch (node_data->type) {
633 case PLIST_BOOLEAN : 438 case PLIST_BOOLEAN:
634 { 439 {
635 if (node_data->boolval) 440 if (node_data->boolval)
636 tag = "true"; 441 tag = "true";
637 else 442 else
638 tag = "false"; 443 tag = "false";
639 } 444 }
640 break; 445 break;
641 446
642 case PLIST_UINT8 : 447 case PLIST_UINT8:
643 tag = "integer"; 448 tag = "integer";
644 val = g_strdup_printf("%u", node_data->intval8); 449 val = g_strdup_printf("%u", node_data->intval8);
645 break; 450 break;
646 451
647 case PLIST_UINT16 : 452 case PLIST_UINT16:
648 tag = "integer"; 453 tag = "integer";
649 val = g_strdup_printf("%u", node_data->intval16); 454 val = g_strdup_printf("%u", node_data->intval16);
650 break; 455 break;
651 456
652 case PLIST_UINT32 : 457 case PLIST_UINT32:
653 tag = "integer"; 458 tag = "integer";
654 val = g_strdup_printf("%u", node_data->intval32); 459 val = g_strdup_printf("%u", node_data->intval32);
655 break; 460 break;
656 461
657 case PLIST_UINT64 : 462 case PLIST_UINT64:
658 tag = "integer"; 463 tag = "integer";
659 val = g_strdup_printf("%lu", (long unsigned int)node_data->intval64); 464 val = g_strdup_printf("%lu", (long unsigned int) node_data->intval64);
660 break; 465 break;
661 466
662 case PLIST_FLOAT32 : 467 case PLIST_FLOAT32:
663 tag = "real"; 468 tag = "real";
664 val = g_strdup_printf("%f", node_data->realval32); 469 val = g_strdup_printf("%f", node_data->realval32);
665 break; 470 break;
666 471
667 case PLIST_FLOAT64 : 472 case PLIST_FLOAT64:
668 tag = "real"; 473 tag = "real";
669 val = g_strdup_printf("%Lf", (long double)node_data->intval64); 474 val = g_strdup_printf("%Lf", (long double) node_data->intval64);
670 break; 475 break;
671 476
672 case PLIST_STRING : 477 case PLIST_STRING:
673 tag = "string"; 478 tag = "string";
674 val = g_strdup(node_data->strval); 479 val = g_strdup(node_data->strval);
675 break; 480 break;
676 481
677 case PLIST_UNICODE : 482 case PLIST_UNICODE:
678 tag = "string"; 483 tag = "string";
679 val = g_strdup((gchar*)node_data->unicodeval); 484 val = g_strdup((gchar *) node_data->unicodeval);
680 break; 485 break;
681 486
682 case PLIST_KEY : 487 case PLIST_KEY:
683 tag = "key"; 488 tag = "key";
684 val = g_strdup((gchar*)node_data->strval); 489 val = g_strdup((gchar *) node_data->strval);
685 break; 490 break;
686 491
687 case PLIST_DATA : 492 case PLIST_DATA:
688 tag = "data"; 493 tag = "data";
689 val = format_string(node_data->buff, 60, 0); 494 val = format_string(node_data->buff, 60, 0);
690 break; 495 break;
691 case PLIST_ARRAY : 496 case PLIST_ARRAY:
692 tag = "array"; 497 tag = "array";
693 isStruct = TRUE; 498 isStruct = TRUE;
694 break; 499 break;
695 case PLIST_DICT : 500 case PLIST_DICT:
696 tag = "dict"; 501 tag = "dict";
697 isStruct = TRUE; 502 isStruct = TRUE;
698 break; 503 break;
699 case PLIST_PLIST : 504 case PLIST_PLIST:
700 tag = "plist"; 505 tag = "plist";
701 isStruct = TRUE; 506 isStruct = TRUE;
702 break; 507 break;
703 case PLIST_DATE : //TODO : handle date tag 508 case PLIST_DATE: //TODO : handle date tag
704 default: 509 default:
705 break; 510 break;
706 } 511 }
707 return;
708 512
709 child_node = xmlNewChild(data, NULL, tag, val); 513 child_node = xmlNewChild(data, NULL, tag, val);
710 gfree(val); 514 xmlNodeAddContent(child_node, "\n");
515 g_free(val);
711 516
712 if (isStruct) 517 if (isStruct)
713 g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, child_node); 518 g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, child_node);
@@ -715,11 +520,11 @@ void node_to_xml (GNode *node, gpointer data)
715 return; 520 return;
716} 521}
717 522
718void xml_to_node (xmlNodePtr xml_node, GNode *plist_node) 523void xml_to_node(xmlNodePtr xml_node, GNode * plist_node)
719{ 524{
720 xmlNodePtr node = NULL; 525 xmlNodePtr node = NULL;
721 struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 526 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
722 GNode* subnode = g_node_new (data); 527 GNode *subnode = g_node_new(data);
723 g_node_append(plist_node, subnode); 528 g_node_append(plist_node, subnode);
724 529
725 for (node = xml_node->children; node; node = node->next) { 530 for (node = xml_node->children; node; node = node->next) {
@@ -737,21 +542,21 @@ void xml_to_node (xmlNodePtr xml_node, GNode *plist_node)
737 } 542 }
738 543
739 if (!xmlStrcmp(node->name, "integer")) { 544 if (!xmlStrcmp(node->name, "integer")) {
740 char* strval = xmlNodeGetContent(node); 545 char *strval = xmlNodeGetContent(node);
741 data->intval64 = atoi(strval); 546 data->intval64 = atoi(strval);
742 data->type = PLIST_UINT64; 547 data->type = PLIST_UINT64;
743 continue; 548 continue;
744 } 549 }
745 550
746 if (!xmlStrcmp(node->name, "real")){ 551 if (!xmlStrcmp(node->name, "real")) {
747 char* strval = xmlNodeGetContent(node); 552 char *strval = xmlNodeGetContent(node);
748 data->realval64 = atof(strval); 553 data->realval64 = atof(strval);
749 data->type = PLIST_FLOAT64; 554 data->type = PLIST_FLOAT64;
750 continue; 555 continue;
751 } 556 }
752 557
753 if (!xmlStrcmp(node->name, "date")) 558 if (!xmlStrcmp(node->name, "date"))
754 continue;//TODO : handle date tag 559 continue; //TODO : handle date tag
755 560
756 if (!xmlStrcmp(node->name, "string")) { 561 if (!xmlStrcmp(node->name, "string")) {
757 data->strval = strdup(xmlNodeGetContent(node)); 562 data->strval = strdup(xmlNodeGetContent(node));
@@ -773,45 +578,315 @@ void xml_to_node (xmlNodePtr xml_node, GNode *plist_node)
773 578
774 if (!xmlStrcmp(node->name, "array")) { 579 if (!xmlStrcmp(node->name, "array")) {
775 data->type = PLIST_ARRAY; 580 data->type = PLIST_ARRAY;
776 xml_to_node (node, subnode); 581 xml_to_node(node, subnode);
777 continue; 582 continue;
778 } 583 }
779 584
780 if (!xmlStrcmp(node->name, "dict")) { 585 if (!xmlStrcmp(node->name, "dict")) {
781 data->type = PLIST_DICT; 586 data->type = PLIST_DICT;
782 xml_to_node (node, subnode); 587 xml_to_node(node, subnode);
783 continue; 588 continue;
784 } 589 }
785 } 590 }
786} 591}
787 592
788void plist_to_xml(plist_t plist, char** plist_xml) 593void plist_to_xml(plist_t plist, char **plist_xml)
789{ 594{
790 if (!plist || !plist_xml || *plist_xml) return; 595 if (!plist || !plist_xml || *plist_xml)
596 return;
791 xmlDocPtr plist_doc = new_plist(); 597 xmlDocPtr plist_doc = new_plist();
792 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); 598 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
793 g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, root_node); 599 g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, root_node);
794 int size = 0; 600 int size = 0;
795 xmlDocDumpMemory (plist_doc, (xmlChar**)plist_xml, &size); 601 xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, &size);
796} 602}
797 603
604GNode *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size)
605{
606 if (!position || !bpbuffer || !bplength)
607 return NULL;
608
609 uint8_t modifier = 0;
610 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
611 GNode *new_node = g_node_new(data);
612 GNode *length_stupidity = NULL;
613
614 int myPos = *position;
615 if (myPos == bplength || (myPos + 1) == bplength) {
616 g_node_destroy(new_node);
617 return NULL;
618 } // end of string
619
620 uint32_t length = 0;
621 if (!myPos) {
622 if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) {
623 return NULL; // badness!
624 }
625 myPos += strlen("bplist00");
626 }
627 // Get the node's type.
628 if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real
629 // better handling of date; basically interpret as real or double
630 data->type = BPLIST_DATE;
631 length = 8; // always 8 for "date" (Apple intended it, not me)
632 myPos++;
633 memcpy(&data->realval64, bpbuffer + myPos, sizeof(data->realval64));
634 byte_convert((char *) &data->realval64, sizeof(data->realval64));
635 myPos += length;
636 *position = myPos;
637 return new_node;
638 }
639
640 int type = bpbuffer[myPos] & BPLIST_MASK;
641 data->length = bpbuffer[myPos] & BPLIST_FILL;
642
643 if (!type) {
644 // what? check if it's a boolean.
645 if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) {
646 // okay, so it is. Carry on.
647 data->type = PLIST_BOOLEAN;
648 data->boolval = TRUE;
649 data->length = 0;
650 } else {
651 // er, what? we have a bad type here. Return NULL.
652 g_node_destroy(new_node);
653 //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]);
654 return NULL;
655 }
656 }
657
658 myPos++; // puts us in the data.
659 if (length == BPLIST_FILL) { // Data happens to contain length...
660 // what? you're going to make me parse an int for the length. You suck.
661 *position = myPos;
662 length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size);
663 switch (((struct plist_data *) length_stupidity->data)->type) {
664 case PLIST_UINT8:
665 data->length = ((struct plist_data *) length_stupidity->data)->intval8;
666 break;
667 case PLIST_UINT16:
668 data->length = ((struct plist_data *) length_stupidity->data)->intval16;
669 break;
670 case PLIST_UINT32:
671 data->length = ((struct plist_data *) length_stupidity->data)->intval32;
672 break;
673 case PLIST_UINT64:
674 data->length = ((struct plist_data *) length_stupidity->data)->intval64;
675 break;
676 default:
677 g_node_destroy(new_node);
678 g_node_destroy(length_stupidity);
679 return NULL;
680 }
681 // There, we have our fucking length now.
682 *position = myPos;
683 g_node_destroy(length_stupidity); // cleanup
684 }
685 // Now we're in the data.
686 // Error-checking sorta
687 if ((myPos + data->length) >= bplength) {
688 data->length = bplength - myPos; // truncate the object
689 }
690 // And now for the greatest show on earth: the giant fucking switch statement.
691 switch (type) {
692 case BPLIST_INT:
693 data->length = uipow(2, data->length); // make length less misleading
694 switch (data->length) {
695 case sizeof(uint8_t):
696 data->type = PLIST_UINT8;
697 data->intval8 = bpbuffer[myPos];
698 break;
699 case sizeof(uint16_t):
700 data->type = PLIST_UINT16;
701 memcpy(&data->intval16, bpbuffer + myPos, sizeof(uint16_t));
702 data->intval16 = ntohs(data->intval16);
703 break;
704 case sizeof(uint32_t):
705 data->type = PLIST_UINT32;
706 memcpy(&data->intval32, bpbuffer + myPos, sizeof(uint32_t));
707 data->intval32 = ntohl(data->intval32);
708 break;
709 case sizeof(uint64_t):
710 data->type = PLIST_UINT64;
711 memcpy(&data->intval64, bpbuffer + myPos, sizeof(uint64_t));
712 byte_convert((char *) &data->intval64, sizeof(uint64_t));
713 break;
714 default:
715 g_node_destroy(new_node);
716 printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) length);
717 printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t));
718 return NULL;
719 }
720 break;
721
722 case BPLIST_REAL:
723 data->length = uipow(2, data->length);
724 switch (data->length) {
725 case sizeof(float):
726 data->type = PLIST_FLOAT32;
727 memcpy(&data->realval32, bpbuffer + myPos, data->length);
728 byte_convert((char *) &data->realval32, sizeof(float)); //necessary ??
729 break;
730 case sizeof(double):
731 data->type = PLIST_FLOAT64;
732 memcpy(&data->realval64, bpbuffer + myPos, data->length);
733 byte_convert((char *) &data->realval64, sizeof(double));
734 break;
735 default:
736 g_node_destroy(new_node);
737 printf("parse_raw_node: lol: invalid real: size given %lu\n", (long unsigned int) length);
738 printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t));
739 return NULL;
740 }
741 break;
742
743 case BPLIST_STRING:
744 data->type = PLIST_STRING;
745 data->strval = (char *) malloc(sizeof(char) * data->length);
746 memcpy(data->strval, bpbuffer + myPos, data->length);
747 break;
748
749 case BPLIST_UNICODE:
750 data->type = PLIST_UNICODE;
751 data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * data->length);
752 memcpy(data->unicodeval, bpbuffer + myPos, data->length);
753 break;
754
755 case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */
756 data->length = data->length * 2; // dicts lie
757 data->type = PLIST_DICT;
758
759 case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */
760 data->ref_size = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space.
761 if (data->type == 0)
762 data->type = PLIST_ARRAY;
763 case BPLIST_DATA:
764 if (data->type == 0)
765 data->type = PLIST_DATA;
766 default: /* made to hold raw data. */
767 modifier = (data->ref_size > 0) ? data->ref_size : 1;
768 data->buff = (char *) malloc(sizeof(char) * (data->length * modifier));
769 memcpy(data->buff, bpbuffer + myPos, (data->length * modifier));
770 break;
771
772 }
773
774 myPos += data->length;
775 *position = myPos;
776 return new_node;
777}
778
779plist_t parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position)
780{
781 plist_t *nodeslist = NULL, *newaddr = NULL;
782 plist_t new_node = NULL, root_node = NULL;
783
784 uint32_t nodeslength = 0;
785 uint8_t offset_size = 0, dict_param_size = 0;
786 offset_size = bpbuffer[bplength - 26];
787 dict_param_size = bpbuffer[bplength - 25];
788 uint64_t current_offset = 0;
789 uint64_t num_objects = 0, root_object = 0, offset_table_index = 0;
790 memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t));
791 memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t));
792 memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t));
793 byte_convert((char *) &num_objects, sizeof(uint64_t));
794 byte_convert((char *) &root_object, sizeof(uint64_t));
795 byte_convert((char *) &offset_table_index, sizeof(uint64_t));
796
797 log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]);
798 log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]);
799 log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24));
800 log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16));
801 log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8));
802 log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t));
803
804 int i = 0, j = 0, k = 0, str_i = 0, str_j = 0;
805 uint32_t index1 = 0, index2 = 0;
806
807 nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects);
808 if (!nodeslist)
809 return NULL;
810
811 for (i = 0; i < num_objects; i++) {
812 memcpy(&current_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size);
813 byte_convert((char *) &current_offset,
814 (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset));
815 log_debug_msg("parse_nodes: current_offset = %x\n", current_offset);
816 nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size);
817 log_debug_msg("parse_nodes: parse_raw_node done\n");
818 }
819
820
821 for (i = 0; i < num_objects; i++) {
822 // set elements for dicts and arrays and leave the rest alone
823 log_debug_msg("parse_nodes: on node %i\n", i);
824 struct plist_data *data = (struct plist_data *) nodeslist[i]->data;
825
826 switch (data->type) {
827 case PLIST_DICT:
828 log_debug_msg("parse_nodes: dictionary found\n");
829 for (j = 0; j < (data->length / 2); j++) {
830 str_i = j * data->ref_size;
831 str_j = (j + (data->length / 2)) * data->ref_size;
832
833 memcpy(&index1, data->buff + str_i, data->ref_size);
834 memcpy(&index2, data->buff + str_j, data->ref_size);
835
836 byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2));
837 byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2));
838
839 g_node_append(nodeslist[i], nodeslist[index1]);
840 g_node_append(nodeslist[i], nodeslist[index2]);
841 }
842
843 data->length = data->length / 2;
844 free(data->buff);
845 k = 0;
846 break;
847
848 case PLIST_ARRAY:
849 log_debug_msg("parse_nodes: array found\n");
850 for (j = 0; j < data->length; j++) {
851 log_debug_msg("parse_nodes: array index %i\n", j);
852 str_j = j * data->ref_size;
853 memcpy(&index1, data->buff + str_j, data->ref_size);
854 log_debug_msg("parse_nodes: post-memcpy\n");
855 byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1));
856 log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1);
857 g_node_append(nodeslist[i], nodeslist[index1]);
858 log_debug_msg("parse_nodes: post-assignment\n");
859 }
860 free(data->buff);
861 break;
862 default:
863 //printf("lol... type %x\n", nodeslist[i]->type);
864 break;
865 } // those are the only two we need to correct for.
866 }
867
868 root_node = nodeslist[root_object];
869 return root_node;
870}
798 871
799void plist_to_bin(plist_t plist, char** plist_bin) 872void plist_to_bin(plist_t plist, char **plist_bin, int *length)
800{ 873{
801} 874}
802 875
803void xml_to_plist(const char* plist_xml, plist_t* plist) 876void xml_to_plist(const char *plist_xml, plist_t * plist)
804{ 877{
805 xmlDocPtr plist_doc = xmlReadMemory(plist_xml, strlen(plist_xml), NULL, NULL, 0); 878 xmlDocPtr plist_doc = xmlReadMemory(plist_xml, strlen(plist_xml), NULL, NULL, 0);
806 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); 879 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
807 880
808 struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); 881 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
809 *plist = g_node_new (data); 882 *plist = g_node_new(data);
810 data->type = PLIST_PLIST; 883 data->type = PLIST_PLIST;
811 xml_to_node (root_node, *plist); 884 xml_to_node(root_node, *plist);
812 885
813} 886}
814 887
815void bin_to_plist(const char* plist_bin, plist_t* plist) 888void bin_to_plist(const char *plist_bin, int length, plist_t * plist)
816{ 889{
890 uint32_t pos = 0;
891 *plist = parse_nodes(plist_bin, length, &pos);
817} 892}
diff --git a/src/plist.h b/src/plist.h
index 4586d6f..1ca55f9 100644
--- a/src/plist.h
+++ b/src/plist.h
@@ -46,38 +46,8 @@ void free_dictionary(char **dictionary);
46 46
47/* Binary plist stuff */ 47/* Binary plist stuff */
48 48
49enum {
50 BPLIST_TRUE = 0x08,
51 BPLIST_FALSE = 0x09,
52 BPLIST_FILL = 0x0F, /* will be used for length grabbing */
53 BPLIST_INT = 0x10,
54 BPLIST_REAL = 0x20,
55 BPLIST_DATE = 0x33,
56 BPLIST_DATA = 0x40,
57 BPLIST_STRING = 0x50,
58 BPLIST_UNICODE = 0x60,
59 BPLIST_UID = 0x70,
60 BPLIST_ARRAY = 0xA0,
61 BPLIST_SET = 0xC0,
62 BPLIST_DICT = 0xD0,
63 BPLIST_MASK = 0xF0
64};
65 49
66typedef struct _bplist_node { 50typedef enum {
67 struct _bplist_node *next, **subnodes; // subnodes is for arrays, dicts and (potentially) sets.
68 uint64_t length, intval64;
69 uint32_t intval32; // length = subnodes
70 uint16_t intval16;
71 uint8_t intval8;
72 uint8_t type, *indexes; // indexes for array-types; essentially specify the order in which to access for key => value pairs
73 char *strval;
74 double realval;
75 wchar_t *unicodeval;
76} bplist_node;
77
78bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position);
79
80typedef enum {
81 PLIST_BOOLEAN, 51 PLIST_BOOLEAN,
82 PLIST_UINT8, 52 PLIST_UINT8,
83 PLIST_UINT16, 53 PLIST_UINT16,
@@ -100,15 +70,15 @@ typedef GNode *plist_t;
100typedef GNode *dict_t; 70typedef GNode *dict_t;
101typedef GNode *array_t; 71typedef GNode *array_t;
102 72
103void plist_new_plist(plist_t* plist); 73void plist_new_plist(plist_t * plist);
104void plist_new_dict_in_plist(plist_t plist, dict_t* dict); 74void plist_new_dict_in_plist(plist_t plist, dict_t * dict);
105void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array); 75void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array);
106void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value); 76void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value);
107void plist_free(plist_t plist); 77void plist_free(plist_t plist);
108 78
109void plist_to_xml(plist_t plist, char** plist_xml); 79void plist_to_xml(plist_t plist, char **plist_xml);
110void plist_to_bin(plist_t plist, char** plist_bin); 80void plist_to_bin(plist_t plist, char **plist_bin, int *length);
111 81
112void xml_to_plist(const char* plist_xml, plist_t* plist); 82void xml_to_plist(const char *plist_xml, plist_t * plist);
113void bin_to_plist(const char* plist_bin, plist_t* plist); 83void bin_to_plist(const char *plist_bin, int length, plist_t * plist);
114#endif 84#endif