diff options
Diffstat (limited to 'src/plist.c')
| -rw-r--r-- | src/plist.c | 1118 |
1 files changed, 7 insertions, 1111 deletions
diff --git a/src/plist.c b/src/plist.c index 2a6d4bc..76ae954 100644 --- a/src/plist.c +++ b/src/plist.c | |||
| @@ -28,101 +28,6 @@ | |||
| 28 | #include <stdlib.h> | 28 | #include <stdlib.h> |
| 29 | #include <stdio.h> | 29 | #include <stdio.h> |
| 30 | 30 | ||
| 31 | /********************************************** | ||
| 32 | * * | ||
| 33 | * Abstract Plist stuff * | ||
| 34 | * * | ||
| 35 | **********************************************/ | ||
| 36 | |||
| 37 | |||
| 38 | |||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | /** Formats a block of text to be a given indentation and width. | ||
| 44 | * | ||
| 45 | * The total width of the return string will be depth + cols. | ||
| 46 | * | ||
| 47 | * @param buf The string to format. | ||
| 48 | * @param cols The number of text columns for returned block of text. | ||
| 49 | * @param depth The number of tabs to indent the returned block of text. | ||
| 50 | * | ||
| 51 | * @return The formatted string. | ||
| 52 | */ | ||
| 53 | char *format_string(const char *buf, int cols, int depth) | ||
| 54 | { | ||
| 55 | int colw = depth + cols + 1; | ||
| 56 | int len = strlen(buf); | ||
| 57 | int nlines = len / cols + 1; | ||
| 58 | char *new_buf = (char *) malloc(nlines * colw + depth + 1); | ||
| 59 | int i = 0; | ||
| 60 | int j = 0; | ||
| 61 | |||
| 62 | assert(cols >= 0); | ||
| 63 | assert(depth >= 0); | ||
| 64 | |||
| 65 | // Inserts new lines and tabs at appropriate locations | ||
| 66 | for (i = 0; i < nlines; i++) { | ||
| 67 | new_buf[i * colw] = '\n'; | ||
| 68 | for (j = 0; j < depth; j++) | ||
| 69 | new_buf[i * colw + 1 + j] = '\t'; | ||
| 70 | memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols); | ||
| 71 | } | ||
| 72 | new_buf[len + (1 + depth) * nlines] = '\n'; | ||
| 73 | |||
| 74 | // Inserts final row of indentation and termination character | ||
| 75 | for (j = 0; j < depth; j++) | ||
| 76 | new_buf[len + (1 + depth) * nlines + 1 + j] = '\t'; | ||
| 77 | new_buf[len + (1 + depth) * nlines + depth + 1] = '\0'; | ||
| 78 | |||
| 79 | return new_buf; | ||
| 80 | } | ||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | |||
| 85 | /* | ||
| 86 | * Binary propertylist code follows | ||
| 87 | */ | ||
| 88 | |||
| 89 | |||
| 90 | /* | ||
| 91 | * This is how parsing a bplist is going to have to work: | ||
| 92 | * - The entire binary plist is going to have to be in memory. | ||
| 93 | * - A function, parse_nodes(), will have to be a recursive function | ||
| 94 | * which iterates over the binary plist and reads in elements into bplist_node structs | ||
| 95 | * and handles them accordingly. The end result should be a somewhat-hierarchical layout | ||
| 96 | * of bplist_nodes. | ||
| 97 | * - parse_nodes() will return the first node it encounters, which is usually the "root" node. | ||
| 98 | */ | ||
| 99 | |||
| 100 | |||
| 101 | |||
| 102 | void print_bytes(char *val, size_t size) | ||
| 103 | { | ||
| 104 | int i = 0; | ||
| 105 | for (i = 0; i < size; i++) { | ||
| 106 | printf("Byte %i: 0x%x\n", i, val[i]); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | struct plist_data { | ||
| 113 | union { | ||
| 114 | char boolval; | ||
| 115 | uint64_t intval; | ||
| 116 | double realval; | ||
| 117 | char *strval; | ||
| 118 | wchar_t *unicodeval; | ||
| 119 | char *buff; | ||
| 120 | }; | ||
| 121 | uint64_t length; | ||
| 122 | plist_type type; | ||
| 123 | }; | ||
| 124 | |||
| 125 | |||
| 126 | 31 | ||
| 127 | void plist_new_plist(plist_t * plist) | 32 | void plist_new_plist(plist_t * plist) |
| 128 | { | 33 | { |
| @@ -205,683 +110,6 @@ void plist_free(plist_t plist) | |||
| 205 | g_node_destroy(plist); | 110 | g_node_destroy(plist); |
| 206 | } | 111 | } |
| 207 | 112 | ||
| 208 | /********************************************** | ||
| 209 | * * | ||
| 210 | * Xml Plist stuff * | ||
| 211 | * * | ||
| 212 | **********************************************/ | ||
| 213 | |||
| 214 | #include <libxml/parser.h> | ||
| 215 | #include <libxml/tree.h> | ||
| 216 | |||
| 217 | |||
| 218 | const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ | ||
| 219 | <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\ | ||
| 220 | <plist version=\"1.0\">\n\ | ||
| 221 | </plist>\0"; | ||
| 222 | |||
| 223 | struct xml_node { | ||
| 224 | xmlNodePtr xml; | ||
| 225 | uint32_t depth; | ||
| 226 | }; | ||
| 227 | |||
| 228 | /** Creates a new plist XML document. | ||
| 229 | * | ||
| 230 | * @return The plist XML document. | ||
| 231 | */ | ||
| 232 | xmlDocPtr new_plist() | ||
| 233 | { | ||
| 234 | char *plist = strdup(plist_base); | ||
| 235 | xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); | ||
| 236 | |||
| 237 | if (!plist_xml) | ||
| 238 | return NULL; | ||
| 239 | |||
| 240 | free(plist); | ||
| 241 | |||
| 242 | return plist_xml; | ||
| 243 | } | ||
| 244 | |||
| 245 | /** Destroys a previously created XML document. | ||
| 246 | * | ||
| 247 | * @param plist The XML document to destroy. | ||
| 248 | */ | ||
| 249 | void free_plist(xmlDocPtr plist) | ||
| 250 | { | ||
| 251 | if (!plist) | ||
| 252 | return; | ||
| 253 | |||
| 254 | xmlFreeDoc(plist); | ||
| 255 | } | ||
| 256 | |||
| 257 | void node_to_xml(GNode * node, gpointer xml_struct) | ||
| 258 | { | ||
| 259 | if (!node) | ||
| 260 | return; | ||
| 261 | |||
| 262 | struct xml_node *xstruct = (struct xml_node *) xml_struct; | ||
| 263 | struct plist_data *node_data = (struct plist_data *) node->data; | ||
| 264 | |||
| 265 | xmlNodePtr child_node = NULL; | ||
| 266 | char isStruct = FALSE; | ||
| 267 | |||
| 268 | gchar *tag = NULL; | ||
| 269 | gchar *val = NULL; | ||
| 270 | |||
| 271 | switch (node_data->type) { | ||
| 272 | case PLIST_BOOLEAN: | ||
| 273 | { | ||
| 274 | if (node_data->boolval) | ||
| 275 | tag = "true"; | ||
| 276 | else | ||
| 277 | tag = "false"; | ||
| 278 | } | ||
| 279 | break; | ||
| 280 | |||
| 281 | case PLIST_UINT: | ||
| 282 | tag = "integer"; | ||
| 283 | val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); | ||
| 284 | break; | ||
| 285 | |||
| 286 | case PLIST_REAL: | ||
| 287 | tag = "real"; | ||
| 288 | val = g_strdup_printf("%Lf", (long double) node_data->realval); | ||
| 289 | break; | ||
| 290 | |||
| 291 | case PLIST_STRING: | ||
| 292 | tag = "string"; | ||
| 293 | val = g_strdup(node_data->strval); | ||
| 294 | break; | ||
| 295 | |||
| 296 | case PLIST_UNICODE: | ||
| 297 | tag = "string"; | ||
| 298 | val = g_strdup((gchar *) node_data->unicodeval); | ||
| 299 | break; | ||
| 300 | |||
| 301 | case PLIST_KEY: | ||
| 302 | tag = "key"; | ||
| 303 | val = g_strdup((gchar *) node_data->strval); | ||
| 304 | break; | ||
| 305 | |||
| 306 | case PLIST_DATA: | ||
| 307 | tag = "data"; | ||
| 308 | val = format_string(node_data->buff, 60, xstruct->depth); | ||
| 309 | break; | ||
| 310 | case PLIST_ARRAY: | ||
| 311 | tag = "array"; | ||
| 312 | isStruct = TRUE; | ||
| 313 | break; | ||
| 314 | case PLIST_DICT: | ||
| 315 | tag = "dict"; | ||
| 316 | isStruct = TRUE; | ||
| 317 | break; | ||
| 318 | case PLIST_DATE: //TODO : handle date tag | ||
| 319 | default: | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | |||
| 323 | int i = 0; | ||
| 324 | for (i = 0; i < xstruct->depth; i++) { | ||
| 325 | xmlNodeAddContent(xstruct->xml, "\t"); | ||
| 326 | } | ||
| 327 | child_node = xmlNewChild(xstruct->xml, NULL, tag, val); | ||
| 328 | xmlNodeAddContent(xstruct->xml, "\n"); | ||
| 329 | g_free(val); | ||
| 330 | |||
| 331 | //add return for structured types | ||
| 332 | if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) | ||
| 333 | xmlNodeAddContent(child_node, "\n"); | ||
| 334 | |||
| 335 | if (isStruct) { | ||
| 336 | struct xml_node child = { child_node, xstruct->depth + 1 }; | ||
| 337 | g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); | ||
| 338 | } | ||
| 339 | //fix indent for structured types | ||
| 340 | if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { | ||
| 341 | |||
| 342 | for (i = 0; i < xstruct->depth; i++) { | ||
| 343 | xmlNodeAddContent(child_node, "\t"); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | return; | ||
| 348 | } | ||
| 349 | |||
| 350 | void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) | ||
| 351 | { | ||
| 352 | xmlNodePtr node = NULL; | ||
| 353 | |||
| 354 | for (node = xml_node->children; node; node = node->next) { | ||
| 355 | |||
| 356 | while (node && !xmlStrcmp(node->name, "text")) | ||
| 357 | node = node->next; | ||
| 358 | if (!node) | ||
| 359 | break; | ||
| 360 | |||
| 361 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 362 | GNode *subnode = g_node_new(data); | ||
| 363 | g_node_append(plist_node, subnode); | ||
| 364 | |||
| 365 | if (!xmlStrcmp(node->name, "true")) { | ||
| 366 | data->boolval = 1; | ||
| 367 | data->type = PLIST_BOOLEAN; | ||
| 368 | continue; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (!xmlStrcmp(node->name, "false")) { | ||
| 372 | data->boolval = 0; | ||
| 373 | data->type = PLIST_BOOLEAN; | ||
| 374 | continue; | ||
| 375 | } | ||
| 376 | |||
| 377 | if (!xmlStrcmp(node->name, "integer")) { | ||
| 378 | char *strval = xmlNodeGetContent(node); | ||
| 379 | data->intval = atoi(strval); | ||
| 380 | data->type = PLIST_UINT; | ||
| 381 | continue; | ||
| 382 | } | ||
| 383 | |||
| 384 | if (!xmlStrcmp(node->name, "real")) { | ||
| 385 | char *strval = xmlNodeGetContent(node); | ||
| 386 | data->realval = atof(strval); | ||
| 387 | data->type = PLIST_REAL; | ||
| 388 | continue; | ||
| 389 | } | ||
| 390 | |||
| 391 | if (!xmlStrcmp(node->name, "date")) | ||
| 392 | continue; //TODO : handle date tag | ||
| 393 | |||
| 394 | if (!xmlStrcmp(node->name, "string")) { | ||
| 395 | data->strval = strdup(xmlNodeGetContent(node)); | ||
| 396 | data->type = PLIST_STRING; | ||
| 397 | continue; | ||
| 398 | } | ||
| 399 | |||
| 400 | if (!xmlStrcmp(node->name, "key")) { | ||
| 401 | data->strval = strdup(xmlNodeGetContent(node)); | ||
| 402 | data->type = PLIST_KEY; | ||
| 403 | continue; | ||
| 404 | } | ||
| 405 | |||
| 406 | if (!xmlStrcmp(node->name, "data")) { | ||
| 407 | data->buff = strdup(xmlNodeGetContent(node)); | ||
| 408 | data->type = PLIST_DATA; | ||
| 409 | continue; | ||
| 410 | } | ||
| 411 | |||
| 412 | if (!xmlStrcmp(node->name, "array")) { | ||
| 413 | data->type = PLIST_ARRAY; | ||
| 414 | xml_to_node(node, subnode); | ||
| 415 | continue; | ||
| 416 | } | ||
| 417 | |||
| 418 | if (!xmlStrcmp(node->name, "dict")) { | ||
| 419 | data->type = PLIST_DICT; | ||
| 420 | xml_to_node(node, subnode); | ||
| 421 | continue; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) | ||
| 427 | { | ||
| 428 | if (!plist || !plist_xml || *plist_xml) | ||
| 429 | return; | ||
| 430 | xmlDocPtr plist_doc = new_plist(); | ||
| 431 | xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); | ||
| 432 | struct xml_node root = { root_node, 0 }; | ||
| 433 | g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); | ||
| 434 | xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); | ||
| 435 | } | ||
| 436 | |||
| 437 | void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) | ||
| 438 | { | ||
| 439 | xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); | ||
| 440 | xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); | ||
| 441 | |||
| 442 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 443 | *plist = g_node_new(data); | ||
| 444 | data->type = PLIST_DICT; | ||
| 445 | xml_to_node(root_node, *plist); | ||
| 446 | } | ||
| 447 | |||
| 448 | |||
| 449 | |||
| 450 | /********************************************** | ||
| 451 | * * | ||
| 452 | * Binary Plist stuff * | ||
| 453 | * * | ||
| 454 | **********************************************/ | ||
| 455 | |||
| 456 | /* Magic marker and size. */ | ||
| 457 | #define BPLIST_MAGIC "bplist" | ||
| 458 | #define BPLIST_MAGIC_SIZE 6 | ||
| 459 | |||
| 460 | #define BPLIST_VERSION "00" | ||
| 461 | #define BPLIST_VERSION_SIZE 2 | ||
| 462 | |||
| 463 | |||
| 464 | #define BPLIST_TRL_SIZE 26 | ||
| 465 | #define BPLIST_TRL_OFFSIZE_IDX 0 | ||
| 466 | #define BPLIST_TRL_PARMSIZE_IDX 1 | ||
| 467 | #define BPLIST_TRL_NUMOBJ_IDX 2 | ||
| 468 | #define BPLIST_TRL_ROOTOBJ_IDX 10 | ||
| 469 | #define BPLIST_TRL_OFFTAB_IDX 18 | ||
| 470 | |||
| 471 | enum { | ||
| 472 | BPLIST_NULL = 0x00, | ||
| 473 | BPLIST_TRUE = 0x08, | ||
| 474 | BPLIST_FALSE = 0x09, | ||
| 475 | BPLIST_FILL = 0x0F, /* will be used for length grabbing */ | ||
| 476 | BPLIST_UINT = 0x10, | ||
| 477 | BPLIST_REAL = 0x20, | ||
| 478 | BPLIST_DATE = 0x30, | ||
| 479 | BPLIST_DATA = 0x40, | ||
| 480 | BPLIST_STRING = 0x50, | ||
| 481 | BPLIST_UNICODE = 0x60, | ||
| 482 | BPLIST_UID = 0x70, | ||
| 483 | BPLIST_ARRAY = 0xA0, | ||
| 484 | BPLIST_SET = 0xC0, | ||
| 485 | BPLIST_DICT = 0xD0, | ||
| 486 | BPLIST_MASK = 0xF0 | ||
| 487 | }; | ||
| 488 | |||
| 489 | void byte_convert(char *address, size_t size) | ||
| 490 | { | ||
| 491 | int i = 0, j = 0; | ||
| 492 | char tmp = '\0'; | ||
| 493 | |||
| 494 | for (i = 0; i < (size / 2); i++) { | ||
| 495 | tmp = address[i]; | ||
| 496 | j = ((size - 1) + 0) - i; | ||
| 497 | address[i] = address[j]; | ||
| 498 | address[j] = tmp; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | #include <byteswap.h> | ||
| 503 | #define swap_n_bytes(x, n) \ | ||
| 504 | n == 8 ? bswap_64(*(uint64_t *)(x)) : \ | ||
| 505 | (n == 4 ? bswap_32(*(uint32_t *)(x)) : \ | ||
| 506 | (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) )) | ||
| 507 | |||
| 508 | #define be64dec(x) bswap_64( *(uint64_t*)(x) ) | ||
| 509 | |||
| 510 | #define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8))) | ||
| 511 | #define get_real_bytes(x) (x >> 32 ? 4 : 8) | ||
| 512 | |||
| 513 | GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) | ||
| 514 | { | ||
| 515 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 516 | |||
| 517 | size = 1 << size; // make length less misleading | ||
| 518 | switch (size) { | ||
| 519 | case sizeof(uint8_t): | ||
| 520 | data->intval = bnode[0]; | ||
| 521 | break; | ||
| 522 | case sizeof(uint16_t): | ||
| 523 | memcpy(&data->intval, bnode, size); | ||
| 524 | data->intval = ntohs(data->intval); | ||
| 525 | break; | ||
| 526 | case sizeof(uint32_t): | ||
| 527 | memcpy(&data->intval, bnode, size); | ||
| 528 | data->intval = ntohl(data->intval); | ||
| 529 | break; | ||
| 530 | case sizeof(uint64_t): | ||
| 531 | memcpy(&data->intval, bnode, size); | ||
| 532 | byte_convert((char *) &data->intval, size); | ||
| 533 | break; | ||
| 534 | default: | ||
| 535 | free(data); | ||
| 536 | return NULL; | ||
| 537 | }; | ||
| 538 | |||
| 539 | *next_object = bnode + size; | ||
| 540 | data->type = PLIST_UINT; | ||
| 541 | return g_node_new(data); | ||
| 542 | } | ||
| 543 | |||
| 544 | GNode *parse_real_node(char *bnode, uint8_t size) | ||
| 545 | { | ||
| 546 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 547 | |||
| 548 | size = 1 << size; // make length less misleading | ||
| 549 | switch (size) { | ||
| 550 | case sizeof(float): | ||
| 551 | memcpy(&data->realval, bnode, size); | ||
| 552 | byte_convert((char *) &data->realval, size); | ||
| 553 | break; | ||
| 554 | case sizeof(double): | ||
| 555 | memcpy(&data->realval, bnode, size); | ||
| 556 | byte_convert((char *) &data->realval, size); | ||
| 557 | break; | ||
| 558 | default: | ||
| 559 | free(data); | ||
| 560 | return NULL; | ||
| 561 | } | ||
| 562 | data->type = PLIST_REAL; | ||
| 563 | return g_node_new(data); | ||
| 564 | } | ||
| 565 | |||
| 566 | GNode *parse_string_node(char *bnode, uint8_t size) | ||
| 567 | { | ||
| 568 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 569 | |||
| 570 | data->type = PLIST_STRING; | ||
| 571 | data->strval = (char *) malloc(sizeof(char) * (size + 1)); | ||
| 572 | memcpy(data->strval, bnode, size); | ||
| 573 | data->strval[size] = '\0'; | ||
| 574 | |||
| 575 | return g_node_new(data); | ||
| 576 | } | ||
| 577 | |||
| 578 | GNode *parse_unicode_node(char *bnode, uint8_t size) | ||
| 579 | { | ||
| 580 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 581 | |||
| 582 | data->type = PLIST_UNICODE; | ||
| 583 | data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1)); | ||
| 584 | memcpy(data->unicodeval, bnode, size); | ||
| 585 | data->unicodeval[size] = '\0'; | ||
| 586 | |||
| 587 | return g_node_new(data); | ||
| 588 | } | ||
| 589 | |||
| 590 | GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size) | ||
| 591 | { | ||
| 592 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 593 | |||
| 594 | data->type = PLIST_DATA; | ||
| 595 | data->length = size; | ||
| 596 | data->buff = (char *) malloc(sizeof(char) * size); | ||
| 597 | memcpy(data->buff, bnode, sizeof(char) * size); | ||
| 598 | |||
| 599 | return g_node_new(data); | ||
| 600 | } | ||
| 601 | |||
| 602 | GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) | ||
| 603 | { | ||
| 604 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 605 | |||
| 606 | data->type = PLIST_DICT; | ||
| 607 | data->length = size; | ||
| 608 | data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2); | ||
| 609 | memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2); | ||
| 610 | |||
| 611 | return g_node_new(data); | ||
| 612 | } | ||
| 613 | |||
| 614 | GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) | ||
| 615 | { | ||
| 616 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 617 | |||
| 618 | data->type = PLIST_ARRAY; | ||
| 619 | data->length = size; | ||
| 620 | data->buff = (char *) malloc(sizeof(char) * size * ref_size); | ||
| 621 | memcpy(data->buff, bnode, sizeof(char) * size * ref_size); | ||
| 622 | |||
| 623 | return g_node_new(data); | ||
| 624 | } | ||
| 625 | |||
| 626 | plist_type plist_get_node_type(plist_t node) | ||
| 627 | { | ||
| 628 | return ((struct plist_data *) node->data)->type; | ||
| 629 | } | ||
| 630 | |||
| 631 | uint64_t plist_get_node_uint_val(plist_t node) | ||
| 632 | { | ||
| 633 | if (PLIST_UINT == plist_get_node_type(node)) | ||
| 634 | return ((struct plist_data *) node->data)->intval; | ||
| 635 | else | ||
| 636 | return 0; | ||
| 637 | } | ||
| 638 | |||
| 639 | GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) | ||
| 640 | { | ||
| 641 | if (!object) | ||
| 642 | return NULL; | ||
| 643 | |||
| 644 | uint16_t type = *object & 0xF0; | ||
| 645 | uint64_t size = *object & 0x0F; | ||
| 646 | object++; | ||
| 647 | |||
| 648 | switch (type) { | ||
| 649 | |||
| 650 | case BPLIST_NULL: | ||
| 651 | switch (size) { | ||
| 652 | |||
| 653 | case BPLIST_TRUE: | ||
| 654 | { | ||
| 655 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 656 | data->type = PLIST_BOOLEAN; | ||
| 657 | data->boolval = TRUE; | ||
| 658 | return g_node_new(data); | ||
| 659 | } | ||
| 660 | |||
| 661 | case BPLIST_FALSE: | ||
| 662 | { | ||
| 663 | struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 664 | data->type = PLIST_BOOLEAN; | ||
| 665 | data->boolval = FALSE; | ||
| 666 | return g_node_new(data); | ||
| 667 | } | ||
| 668 | |||
| 669 | case BPLIST_NULL: | ||
| 670 | default: | ||
| 671 | return NULL; | ||
| 672 | } | ||
| 673 | |||
| 674 | case BPLIST_UINT: | ||
| 675 | return parse_uint_node(object, size, next_object); | ||
| 676 | |||
| 677 | case BPLIST_REAL: | ||
| 678 | return parse_real_node(object, size); | ||
| 679 | |||
| 680 | case BPLIST_DATE: | ||
| 681 | if (3 != size) | ||
| 682 | return NULL; | ||
| 683 | else | ||
| 684 | return parse_real_node(object, size); | ||
| 685 | |||
| 686 | case BPLIST_DATA: | ||
| 687 | if (0x0F == size) { | ||
| 688 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 689 | if (plist_get_node_type(size_node) != PLIST_UINT) | ||
| 690 | return NULL; | ||
| 691 | size = plist_get_node_uint_val(size_node); | ||
| 692 | } | ||
| 693 | return parse_data_node(object, size, dict_size); | ||
| 694 | |||
| 695 | case BPLIST_STRING: | ||
| 696 | if (0x0F == size) { | ||
| 697 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 698 | if (plist_get_node_type(size_node) != PLIST_UINT) | ||
| 699 | return NULL; | ||
| 700 | size = plist_get_node_uint_val(size_node); | ||
| 701 | } | ||
| 702 | return parse_string_node(object, size); | ||
| 703 | |||
| 704 | case BPLIST_UNICODE: | ||
| 705 | if (0x0F == size) { | ||
| 706 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 707 | if (plist_get_node_type(size_node) != PLIST_UINT) | ||
| 708 | return NULL; | ||
| 709 | size = plist_get_node_uint_val(size_node); | ||
| 710 | } | ||
| 711 | return parse_unicode_node(object, size); | ||
| 712 | |||
| 713 | case BPLIST_UID: | ||
| 714 | case BPLIST_ARRAY: | ||
| 715 | if (0x0F == size) { | ||
| 716 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 717 | if (plist_get_node_type(size_node) != PLIST_UINT) | ||
| 718 | return NULL; | ||
| 719 | size = plist_get_node_uint_val(size_node); | ||
| 720 | } | ||
| 721 | return parse_array_node(object, size, dict_size); | ||
| 722 | |||
| 723 | case BPLIST_SET: | ||
| 724 | case BPLIST_DICT: | ||
| 725 | if (0x0F == size) { | ||
| 726 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 727 | if (plist_get_node_type(size_node) != PLIST_UINT) | ||
| 728 | return NULL; | ||
| 729 | object++; | ||
| 730 | size = plist_get_node_uint_val(size_node); | ||
| 731 | } | ||
| 732 | return parse_dict_node(object, size, dict_size); | ||
| 733 | |||
| 734 | } | ||
| 735 | return NULL; | ||
| 736 | } | ||
| 737 | |||
| 738 | gpointer copy_plist_data(gconstpointer src, gpointer data) | ||
| 739 | { | ||
| 740 | struct plist_data *srcdata = (struct plist_data *) src; | ||
| 741 | struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1); | ||
| 742 | |||
| 743 | dstdata->type = srcdata->type; | ||
| 744 | dstdata->length = srcdata->length; | ||
| 745 | switch (dstdata->type) { | ||
| 746 | case PLIST_BOOLEAN: | ||
| 747 | dstdata->boolval = srcdata->boolval; | ||
| 748 | break; | ||
| 749 | case PLIST_UINT: | ||
| 750 | dstdata->intval = srcdata->intval; | ||
| 751 | break; | ||
| 752 | case PLIST_DATE: | ||
| 753 | case PLIST_REAL: | ||
| 754 | dstdata->realval = srcdata->realval; | ||
| 755 | break; | ||
| 756 | case PLIST_KEY: | ||
| 757 | case PLIST_STRING: | ||
| 758 | dstdata->strval = strdup(srcdata->strval); | ||
| 759 | break; | ||
| 760 | case PLIST_UNICODE: | ||
| 761 | dstdata->unicodeval = wcsdup(srcdata->unicodeval); | ||
| 762 | break; | ||
| 763 | case PLIST_DATA: | ||
| 764 | case PLIST_ARRAY: | ||
| 765 | case PLIST_DICT: | ||
| 766 | dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length); | ||
| 767 | memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length); | ||
| 768 | break; | ||
| 769 | |||
| 770 | default: | ||
| 771 | break; | ||
| 772 | } | ||
| 773 | |||
| 774 | return dstdata; | ||
| 775 | } | ||
| 776 | |||
| 777 | void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) | ||
| 778 | { | ||
| 779 | //first check we have enough data | ||
| 780 | if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) | ||
| 781 | return; | ||
| 782 | //check that plist_bin in actually a plist | ||
| 783 | if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) | ||
| 784 | return; | ||
| 785 | //check for known version | ||
| 786 | if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) | ||
| 787 | return; | ||
| 788 | |||
| 789 | //now parse trailer | ||
| 790 | const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); | ||
| 791 | |||
| 792 | uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; | ||
| 793 | uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; | ||
| 794 | uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); | ||
| 795 | uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); | ||
| 796 | uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); | ||
| 797 | |||
| 798 | log_debug_msg("Offset size: %i\n", offset_size); | ||
| 799 | log_debug_msg("Ref size: %i\n", dict_param_size); | ||
| 800 | log_debug_msg("Number of objects: %lli\n", num_objects); | ||
| 801 | log_debug_msg("Root object index: %lli\n", root_object); | ||
| 802 | log_debug_msg("Offset table index: %lli\n", offset_table_index); | ||
| 803 | |||
| 804 | if (num_objects == 0) | ||
| 805 | return; | ||
| 806 | |||
| 807 | //allocate serialized array of nodes | ||
| 808 | plist_t *nodeslist = NULL; | ||
| 809 | nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); | ||
| 810 | |||
| 811 | if (!nodeslist) | ||
| 812 | return; | ||
| 813 | |||
| 814 | //parse serialized nodes | ||
| 815 | uint64_t i = 0; | ||
| 816 | uint64_t current_offset = 0; | ||
| 817 | const char *offset_table = plist_bin + offset_table_index; | ||
| 818 | for (i = 0; i < num_objects; i++) { | ||
| 819 | current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size); | ||
| 820 | |||
| 821 | log_debug_msg("parse_nodes: current_offset = %i\n", current_offset); | ||
| 822 | char *obj = plist_bin + current_offset; | ||
| 823 | nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); | ||
| 824 | log_debug_msg("parse_nodes: parse_raw_node done\n"); | ||
| 825 | } | ||
| 826 | |||
| 827 | //setup children for structured types | ||
| 828 | int j = 0, str_i = 0, str_j = 0; | ||
| 829 | uint32_t index1 = 0, index2 = 0; | ||
| 830 | |||
| 831 | for (i = 0; i < num_objects; i++) { | ||
| 832 | |||
| 833 | log_debug_msg("parse_nodes: on node %i\n", i); | ||
| 834 | struct plist_data *data = (struct plist_data *) nodeslist[i]->data; | ||
| 835 | |||
| 836 | switch (data->type) { | ||
| 837 | case PLIST_DICT: | ||
| 838 | log_debug_msg("parse_nodes: dictionary found\n"); | ||
| 839 | for (j = 0; j < data->length; j++) { | ||
| 840 | str_i = j * dict_param_size; | ||
| 841 | str_j = (j + data->length) * dict_param_size; | ||
| 842 | |||
| 843 | index1 = swap_n_bytes(data->buff + str_i, dict_param_size); | ||
| 844 | index2 = swap_n_bytes(data->buff + str_j, dict_param_size); | ||
| 845 | |||
| 846 | //first one is actually a key | ||
| 847 | ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; | ||
| 848 | |||
| 849 | if (G_NODE_IS_ROOT(nodeslist[index1])) | ||
| 850 | g_node_append(nodeslist[i], nodeslist[index1]); | ||
| 851 | else | ||
| 852 | g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); | ||
| 853 | |||
| 854 | if (G_NODE_IS_ROOT(nodeslist[index2])) | ||
| 855 | g_node_append(nodeslist[i], nodeslist[index2]); | ||
| 856 | else | ||
| 857 | g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL)); | ||
| 858 | } | ||
| 859 | |||
| 860 | free(data->buff); | ||
| 861 | break; | ||
| 862 | |||
| 863 | case PLIST_ARRAY: | ||
| 864 | log_debug_msg("parse_nodes: array found\n"); | ||
| 865 | for (j = 0; j < data->length; j++) { | ||
| 866 | str_j = j * dict_param_size; | ||
| 867 | index1 = swap_n_bytes(data->buff + str_j, dict_param_size); | ||
| 868 | |||
| 869 | //g_node_append(nodeslist[i], nodeslist[index1]); | ||
| 870 | if (G_NODE_IS_ROOT(nodeslist[index1])) | ||
| 871 | g_node_append(nodeslist[i], nodeslist[index1]); | ||
| 872 | else | ||
| 873 | g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); | ||
| 874 | } | ||
| 875 | free(data->buff); | ||
| 876 | break; | ||
| 877 | default: | ||
| 878 | break; | ||
| 879 | } | ||
| 880 | } | ||
| 881 | |||
| 882 | *plist = nodeslist[root_object]; | ||
| 883 | } | ||
| 884 | |||
| 885 | GNode *find_query_node(plist_t plist, char *key, char *request) | 113 | GNode *find_query_node(plist_t plist, char *key, char *request) |
| 886 | { | 114 | { |
| 887 | if (!plist) | 115 | if (!plist) |
| @@ -998,347 +226,15 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) | |||
| 998 | } | 226 | } |
| 999 | } | 227 | } |
| 1000 | 228 | ||
| 1001 | guint plist_data_hash(gconstpointer key) | 229 | plist_type plist_get_node_type(plist_t node) |
| 1002 | { | ||
| 1003 | struct plist_data *data = (struct plist_data *) ((GNode *) key)->data; | ||
| 1004 | |||
| 1005 | guint hash = data->type; | ||
| 1006 | guint i = 0; | ||
| 1007 | |||
| 1008 | char *buff = NULL; | ||
| 1009 | guint size = 0; | ||
| 1010 | |||
| 1011 | switch (data->type) { | ||
| 1012 | case PLIST_BOOLEAN: | ||
| 1013 | case PLIST_UINT: | ||
| 1014 | case PLIST_REAL: | ||
| 1015 | buff = (char *) &data->intval; | ||
| 1016 | size = 8; | ||
| 1017 | break; | ||
| 1018 | case PLIST_KEY: | ||
| 1019 | case PLIST_STRING: | ||
| 1020 | buff = data->strval; | ||
| 1021 | size = strlen(buff); | ||
| 1022 | break; | ||
| 1023 | case PLIST_UNICODE: | ||
| 1024 | buff = data->unicodeval; | ||
| 1025 | size = strlen(buff) * sizeof(wchar_t); | ||
| 1026 | break; | ||
| 1027 | case PLIST_DATA: | ||
| 1028 | case PLIST_ARRAY: | ||
| 1029 | case PLIST_DICT: | ||
| 1030 | //for these types only hash pointer | ||
| 1031 | buff = &key; | ||
| 1032 | size = sizeof(gconstpointer); | ||
| 1033 | break; | ||
| 1034 | case PLIST_DATE: | ||
| 1035 | default: | ||
| 1036 | break; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | //now perform hash | ||
| 1040 | for (i = 0; i < size; buff++, i++) | ||
| 1041 | hash = hash << 7 ^ (*buff); | ||
| 1042 | |||
| 1043 | return hash; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | gboolean plist_data_compare(gconstpointer a, gconstpointer b) | ||
| 1047 | { | ||
| 1048 | if (!a || !b) | ||
| 1049 | return FALSE; | ||
| 1050 | |||
| 1051 | if (!((GNode *) a)->data || !((GNode *) b)->data) | ||
| 1052 | return FALSE; | ||
| 1053 | |||
| 1054 | struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data; | ||
| 1055 | struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data; | ||
| 1056 | |||
| 1057 | if (val_a->type != val_b->type) | ||
| 1058 | return FALSE; | ||
| 1059 | |||
| 1060 | switch (val_a->type) { | ||
| 1061 | case PLIST_BOOLEAN: | ||
| 1062 | case PLIST_UINT: | ||
| 1063 | case PLIST_REAL: | ||
| 1064 | if (val_a->intval == val_b->intval) //it is an union so this is sufficient | ||
| 1065 | return TRUE; | ||
| 1066 | else | ||
| 1067 | return FALSE; | ||
| 1068 | |||
| 1069 | case PLIST_KEY: | ||
| 1070 | case PLIST_STRING: | ||
| 1071 | if (!strcmp(val_a->strval, val_b->strval)) | ||
| 1072 | return TRUE; | ||
| 1073 | else | ||
| 1074 | return FALSE; | ||
| 1075 | case PLIST_UNICODE: | ||
| 1076 | if (!strcmp(val_a->unicodeval, val_b->unicodeval)) | ||
| 1077 | return TRUE; | ||
| 1078 | else | ||
| 1079 | return FALSE; | ||
| 1080 | |||
| 1081 | case PLIST_DATA: | ||
| 1082 | case PLIST_ARRAY: | ||
| 1083 | case PLIST_DICT: | ||
| 1084 | //compare pointer | ||
| 1085 | if (a == b) | ||
| 1086 | return TRUE; | ||
| 1087 | else | ||
| 1088 | return FALSE; | ||
| 1089 | break; | ||
| 1090 | case PLIST_DATE: | ||
| 1091 | default: | ||
| 1092 | break; | ||
| 1093 | } | ||
| 1094 | return FALSE; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | struct serialize_s { | ||
| 1098 | GPtrArray *objects; | ||
| 1099 | GHashTable *ref_table; | ||
| 1100 | }; | ||
| 1101 | |||
| 1102 | void serialize_plist(GNode * node, gpointer data) | ||
| 1103 | { | ||
| 1104 | struct serialize_s *ser = (struct serialize_s *) data; | ||
| 1105 | uint64_t current_index = ser->objects->len; | ||
| 1106 | |||
| 1107 | //first check that node is not yet in objects | ||
| 1108 | gpointer val = g_hash_table_lookup(ser->ref_table, node); | ||
| 1109 | if (val) { | ||
| 1110 | //data is already in table | ||
| 1111 | return; | ||
| 1112 | } | ||
| 1113 | //insert new ref | ||
| 1114 | g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index)); | ||
| 1115 | |||
| 1116 | //now append current node to object array | ||
| 1117 | g_ptr_array_add(ser->objects, node); | ||
| 1118 | |||
| 1119 | //now recurse on children | ||
| 1120 | g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data); | ||
| 1121 | return; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | |||
| 1125 | |||
| 1126 | void write_int(GByteArray * bplist, uint64_t val) | ||
| 1127 | { | ||
| 1128 | uint64_t size = get_needed_bytes(val); | ||
| 1129 | uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); | ||
| 1130 | buff[0] = BPLIST_UINT | size >> 1; | ||
| 1131 | memcpy(buff + 1, &val, size); | ||
| 1132 | swap_n_bytes(buff + 1, size); | ||
| 1133 | g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); | ||
| 1134 | free(buff); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | void write_real(GByteArray * bplist, double val) | ||
| 1138 | { | ||
| 1139 | uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space | ||
| 1140 | uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); | ||
| 1141 | buff[0] = BPLIST_REAL | size >> 1; | ||
| 1142 | memcpy(buff + 1, &val, size); | ||
| 1143 | swap_n_bytes(buff + 1, size); | ||
| 1144 | g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); | ||
| 1145 | free(buff); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) | ||
| 1149 | { | ||
| 1150 | uint8_t marker = mark | (size < 15 ? size : 0xf); | ||
| 1151 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | ||
| 1152 | if (size >= 15) { | ||
| 1153 | GByteArray *int_buff = g_byte_array_new(); | ||
| 1154 | write_int(int_buff, size); | ||
| 1155 | g_byte_array_append(bplist, int_buff->data, int_buff->len); | ||
| 1156 | g_byte_array_free(int_buff, TRUE); | ||
| 1157 | } | ||
| 1158 | uint8_t *buff = (uint8_t *) malloc(size); | ||
| 1159 | memcpy(buff, val, size); | ||
| 1160 | g_byte_array_append(bplist, buff, size); | ||
| 1161 | free(buff); | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | void write_data(GByteArray * bplist, uint8_t * val, uint64_t size) | ||
| 1165 | { | ||
| 1166 | write_raw_data(bplist, BPLIST_DATA, val, size); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | void write_string(GByteArray * bplist, char *val) | ||
| 1170 | { | ||
| 1171 | uint64_t size = strlen(val); | ||
| 1172 | write_raw_data(bplist, BPLIST_STRING, val, size); | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) | ||
| 1176 | { | ||
| 1177 | uint64_t size = g_node_n_children(node); | ||
| 1178 | uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); | ||
| 1179 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | ||
| 1180 | if (size >= 15) { | ||
| 1181 | GByteArray *int_buff = g_byte_array_new(); | ||
| 1182 | write_int(int_buff, size); | ||
| 1183 | g_byte_array_append(bplist, int_buff->data, int_buff->len); | ||
| 1184 | g_byte_array_free(int_buff, TRUE); | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | uint64_t idx = 0; | ||
| 1188 | uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); | ||
| 1189 | |||
| 1190 | GNode *cur = NULL; | ||
| 1191 | int i = 0; | ||
| 1192 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { | ||
| 1193 | idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); | ||
| 1194 | memcpy(buff + i * dict_param_size, &idx, dict_param_size); | ||
| 1195 | swap_n_bytes(buff + i * dict_param_size, dict_param_size); | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | //now append to bplist | ||
| 1199 | g_byte_array_append(bplist, buff, size * dict_param_size); | ||
| 1200 | free(buff); | ||
| 1201 | |||
| 1202 | } | ||
| 1203 | |||
| 1204 | void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) | ||
| 1205 | { | 230 | { |
| 1206 | uint64_t size = g_node_n_children(node) / 2; | 231 | return ((struct plist_data *) node->data)->type; |
| 1207 | uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); | ||
| 1208 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | ||
| 1209 | if (size >= 15) { | ||
| 1210 | GByteArray *int_buff = g_byte_array_new(); | ||
| 1211 | write_int(int_buff, size); | ||
| 1212 | g_byte_array_append(bplist, int_buff->data, int_buff->len); | ||
| 1213 | g_byte_array_free(int_buff, TRUE); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | uint64_t idx1 = 0; | ||
| 1217 | uint64_t idx2 = 0; | ||
| 1218 | uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); | ||
| 1219 | |||
| 1220 | GNode *cur = NULL; | ||
| 1221 | int i = 0; | ||
| 1222 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { | ||
| 1223 | idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); | ||
| 1224 | memcpy(buff + i * dict_param_size, &idx1, dict_param_size); | ||
| 1225 | swap_n_bytes(buff + i * dict_param_size, dict_param_size); | ||
| 1226 | |||
| 1227 | idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); | ||
| 1228 | memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); | ||
| 1229 | swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | //now append to bplist | ||
| 1233 | g_byte_array_append(bplist, buff, size * dict_param_size); | ||
| 1234 | free(buff); | ||
| 1235 | |||
| 1236 | } | 232 | } |
| 1237 | 233 | ||
| 1238 | void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | 234 | uint64_t plist_get_node_uint_val(plist_t node) |
| 1239 | { | 235 | { |
| 1240 | //first serialize tree | 236 | if (PLIST_UINT == plist_get_node_type(node)) |
| 1241 | 237 | return ((struct plist_data *) node->data)->intval; | |
| 1242 | //list of objects | 238 | else |
| 1243 | GPtrArray *objects = g_ptr_array_new(); | 239 | return 0; |
| 1244 | //hashtable to write only once same nodes | ||
| 1245 | GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); | ||
| 1246 | |||
| 1247 | //serialize plist | ||
| 1248 | struct serialize_s ser_s = { objects, ref_table }; | ||
| 1249 | g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s); | ||
| 1250 | |||
| 1251 | //now stream to output buffer | ||
| 1252 | uint8_t offset_size = 0; //unknown yet | ||
| 1253 | uint8_t dict_param_size = get_needed_bytes(objects->len); | ||
| 1254 | uint64_t num_objects = objects->len; | ||
| 1255 | uint64_t root_object = 0; //root is first in list | ||
| 1256 | uint64_t offset_table_index = 0; //unknown yet | ||
| 1257 | |||
| 1258 | //setup a dynamic bytes array to store bplist in | ||
| 1259 | GByteArray *bplist_buff = g_byte_array_new(); | ||
| 1260 | |||
| 1261 | //set magic number and version | ||
| 1262 | g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); | ||
| 1263 | g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); | ||
| 1264 | |||
| 1265 | //write objects and table | ||
| 1266 | int i = 0; | ||
| 1267 | uint8_t *buff = NULL; | ||
| 1268 | uint8_t size = 0; | ||
| 1269 | uint64_t offsets[num_objects]; | ||
| 1270 | for (i = 0; i < num_objects; i++) { | ||
| 1271 | |||
| 1272 | offsets[i] = bplist_buff->len; | ||
| 1273 | struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; | ||
| 1274 | |||
| 1275 | switch (data->type) { | ||
| 1276 | case PLIST_BOOLEAN: | ||
| 1277 | buff = (uint8_t *) malloc(sizeof(uint8_t)); | ||
| 1278 | buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE; | ||
| 1279 | g_byte_array_append(bplist_buff, buff, sizeof(uint8_t)); | ||
| 1280 | free(buff); | ||
| 1281 | break; | ||
| 1282 | |||
| 1283 | case PLIST_UINT: | ||
| 1284 | write_int(bplist_buff, data->intval); | ||
| 1285 | break; | ||
| 1286 | |||
| 1287 | case PLIST_REAL: | ||
| 1288 | write_real(bplist_buff, data->realval); | ||
| 1289 | break; | ||
| 1290 | |||
| 1291 | case PLIST_KEY: | ||
| 1292 | case PLIST_STRING: | ||
| 1293 | write_string(bplist_buff, data->strval); | ||
| 1294 | break; | ||
| 1295 | case PLIST_UNICODE: | ||
| 1296 | //TODO | ||
| 1297 | break; | ||
| 1298 | case PLIST_DATA: | ||
| 1299 | write_data(bplist_buff, data->strval, data->length); | ||
| 1300 | case PLIST_ARRAY: | ||
| 1301 | write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); | ||
| 1302 | break; | ||
| 1303 | case PLIST_DICT: | ||
| 1304 | write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); | ||
| 1305 | break; | ||
| 1306 | case PLIST_DATE: | ||
| 1307 | //TODO | ||
| 1308 | break; | ||
| 1309 | default: | ||
| 1310 | break; | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | //write offsets | ||
| 1315 | offset_size = get_needed_bytes(bplist_buff->len); | ||
| 1316 | for (i = 0; i <= num_objects; i++) { | ||
| 1317 | uint8_t *buff = (uint8_t *) malloc(offset_size); | ||
| 1318 | memcpy(buff, offsets + i, offset_size); | ||
| 1319 | swap_n_bytes(buff, offset_size); | ||
| 1320 | g_byte_array_append(bplist_buff, buff, offset_size); | ||
| 1321 | free(buff); | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | //setup trailer | ||
| 1325 | num_objects = bswap_64(num_objects); | ||
| 1326 | root_object = bswap_64(root_object); | ||
| 1327 | offset_table_index = bswap_64(offset_table_index); | ||
| 1328 | |||
| 1329 | char trailer[BPLIST_TRL_SIZE]; | ||
| 1330 | memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); | ||
| 1331 | memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); | ||
| 1332 | memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); | ||
| 1333 | memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t)); | ||
| 1334 | memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t)); | ||
| 1335 | |||
| 1336 | g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE); | ||
| 1337 | |||
| 1338 | //duplicate buffer | ||
| 1339 | *plist_bin = (char *) malloc(bplist_buff->len); | ||
| 1340 | memcpy(*plist_bin, bplist_buff->data, bplist_buff->len); | ||
| 1341 | *length = bplist_buff->len; | ||
| 1342 | |||
| 1343 | g_byte_array_free(bplist_buff, TRUE); | ||
| 1344 | } | 240 | } |
