3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
15 #include "libxml/parser.h"
21 #define BUF_SZ (128*1024)
23 static char *preamble
=
24 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
25 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
26 "<plist version=\"1.0\">\n";
27 static char *postfix
=
30 typedef struct queue_item_s queue_item_t
;
44 return calloc(1, sizeof(queue_t
));
47 void queue_free(queue_t
**_q
)
53 queue_item_t
*n
, *i
= q
->head
;
64 void queue_push_head(queue_t
*q
, void *v
)
66 queue_item_t
*i
= calloc(1, sizeof(queue_item_t
));
72 void * queue_peek_head(queue_t
*q
)
75 return q
->head
->value
;
79 void * queue_pop_head(queue_t
*q
)
95 int queue_is_empty(queue_t
*q
)
97 return q
->head
== NULL
;
100 char * markup_escape_text(const char *str
)
103 int len
= strlen(str
);
105 int alloc
= len
+ step
;
106 char *markup
= malloc(alloc
);
108 for (ii
= 0, jj
= 0; ii
< len
; ii
++)
113 char *tmp
= realloc(markup
, alloc
);
159 markup
[jj
++] = str
[ii
];
189 static tag_map_t tag_map
[] =
195 {"integer", P_INTEGER
},
197 {"string", P_STRING
},
203 #define TAG_MAP_SZ (sizeof(tag_map)/sizeof(tag_map_t))
218 const xmlChar
*xname
,
219 const xmlChar
**attr_names
)
221 char *name
= (char*)xname
;
222 parse_data_t
*pd
= (parse_data_t
*)ud
;
230 // Check to see if the first element found has been closed
231 // If so, ignore any junk following it.
235 for (ii
= 0; ii
< TAG_MAP_SZ
; ii
++)
237 if (strcmp(name
, tag_map
[ii
].tag
) == 0)
239 id
.id
= tag_map
[ii
].id
;
243 if (ii
== TAG_MAP_SZ
)
245 hb_error("Unrecognized start tag (%s)", name
);
253 queue_push_head(pd
->tag_stack
, id
.pid
);
254 hb_value_type_t gtype
= 0;
255 hb_value_t
*gval
= NULL
;
256 hb_value_t
*current
= queue_peek_head(pd
->stack
);
264 if (pd
->key
) free(pd
->key
);
269 gval
= hb_dict_init();
270 queue_push_head(pd
->stack
, gval
);
274 gval
= hb_value_array_init();
275 queue_push_head(pd
->stack
, gval
);
299 // Add the element to the current container
301 { // There's an element to add
307 gtype
= hb_value_type(current
);
308 if (gtype
== HB_VALUE_TYPE_ARRAY
)
310 hb_value_array_append(current
, gval
);
312 else if (gtype
== HB_VALUE_TYPE_DICT
)
316 hb_error("No key for dictionary item");
317 hb_value_free(&gval
);
321 hb_dict_set(current
, pd
->key
, gval
);
326 hb_error("Invalid container type. This shouldn't happen");
334 const xmlChar
*xname
)
336 char *name
= (char*)xname
;
337 parse_data_t
*pd
= (parse_data_t
*)ud
;
346 // Check to see if the first element found has been closed
347 // If so, ignore any junk following it.
351 for (ii
= 0; ii
< TAG_MAP_SZ
; ii
++)
353 if (strcmp(name
, tag_map
[ii
].tag
) == 0)
359 if (ii
== TAG_MAP_SZ
)
361 hb_error("Unrecognized start tag (%s)", name
);
364 start_id
.pid
= queue_pop_head(pd
->tag_stack
);
365 if (start_id
.id
!= id
)
366 hb_error("start tag != end tag: (%s %d) %d", name
, id
, id
);
368 hb_value_t
*gval
= NULL
;
369 hb_value_t
*current
= queue_peek_head(pd
->stack
);
370 hb_value_type_t gtype
= 0;
372 if (pd
->value
!= NULL
)
383 if (pd
->key
) free(pd
->key
);
384 pd
->key
= strdup(value
);
389 queue_pop_head(pd
->stack
);
393 queue_pop_head(pd
->stack
);
397 uint64_t val
= strtoll(value
, NULL
, 0);
398 gval
= hb_value_int(val
);
402 double val
= strtod(value
, NULL
);
403 gval
= hb_value_double(val
);
407 gval
= hb_value_string(value
);
411 gval
= hb_value_bool(1);
415 gval
= hb_value_bool(0);
419 hb_error("Unhandled plist type %d", id
);
424 // Get the top of the data structure stack and if it's an array
425 // or dict, add the current element
432 gtype
= hb_value_type(current
);
433 if (gtype
== HB_VALUE_TYPE_ARRAY
)
435 hb_value_array_append(current
, gval
);
437 else if (gtype
== HB_VALUE_TYPE_DICT
)
441 hb_error("No key for dictionary item");
442 hb_value_free(&gval
);
446 hb_dict_set(current
, pd
->key
, gval
);
451 hb_error("Invalid container type. This shouldn't happen");
454 if (queue_is_empty(pd
->stack
))
461 const xmlChar
*xtext
,
464 char *text
= (char*)xtext
;
465 parse_data_t
*pd
= (parse_data_t
*)ud
;
468 if (pd
->value
!= NULL
)
470 pos
= strlen(pd
->value
);
472 char *tmp
= realloc(pd
->value
, pos
+ len
+ 1);
476 strncpy(pd
->value
+ pos
, text
, len
);
477 pd
->value
[pos
+ len
] = 0;
481 parse_warning(void *ud
, const char *msg
, ...)
486 hb_valog(0, "Plist parse warning: ", msg
, args
);
491 parse_error(void *ud
, const char *msg
, ...)
496 hb_valog(0, "Plist parse error: ", msg
, args
);
501 hb_plist_parse(const char *buf
, size_t len
)
503 xmlSAXHandler parser
;
506 pd
.stack
= queue_new();
507 pd
.tag_stack
= queue_new();
513 memset(&parser
, 0, sizeof(parser
));
514 parser
.initialized
= XML_SAX2_MAGIC
;
515 parser
.startElement
= start_element
;
516 parser
.endElement
= end_element
;
517 parser
.characters
= text_data
;
518 parser
.warning
= parse_warning
;
519 parser
.error
= parse_error
;
520 int result
= xmlSAXUserParseMemory(&parser
, &pd
, buf
, len
);
523 hb_error("Plist parse failed");
528 if (pd
.key
) free(pd
.key
);
529 if (pd
.value
) free(pd
.value
);
530 queue_free(&pd
.stack
);
531 queue_free(&pd
.tag_stack
);
537 hb_plist_parse_file(const char *filename
)
544 fd
= fopen(filename
, "r");
547 // File doesn't exist
550 fseek(fd
, 0, SEEK_END
);
552 fseek(fd
, 0, SEEK_SET
);
553 buffer
= malloc(size
+1);
554 size
= fread(buffer
, 1, size
, fd
);
556 gval
= hb_plist_parse(buffer
, size
);
563 indent_fprintf(FILE *file
, int indent
, const char *fmt
, ...)
567 for (; indent
; indent
--)
570 vfprintf(file
, fmt
, ap
);
575 gval_write(FILE *file
, hb_value_t
*gval
)
577 static int indent
= 0;
579 hb_value_type_t gtype
;
581 if (gval
== NULL
) return;
582 gtype
= hb_value_type(gval
);
583 if (gtype
== HB_VALUE_TYPE_ARRAY
)
588 indent_fprintf(file
, indent
, "<array>\n");
590 count
= hb_value_array_len(gval
);
591 for (ii
= 0; ii
< count
; ii
++)
593 val
= hb_value_array_get(gval
, ii
);
594 gval_write(file
, val
);
597 indent_fprintf(file
, indent
, "</array>\n");
599 else if (gtype
== HB_VALUE_TYPE_DICT
)
605 indent_fprintf(file
, indent
, "<dict>\n");
608 for (iter
= hb_dict_iter_init(gval
);
609 iter
!= HB_DICT_ITER_DONE
;
610 iter
= hb_dict_iter_next(gval
, iter
))
612 key
= hb_dict_iter_key(iter
);
613 val
= hb_dict_iter_value(iter
);
614 indent_fprintf(file
, indent
, "<key>%s</key>\n", key
);
615 gval_write(file
, val
);
619 indent_fprintf(file
, indent
, "</dict>\n");
621 else if (gtype
== HB_VALUE_TYPE_BOOL
)
624 if (hb_value_get_bool(gval
))
632 indent_fprintf(file
, indent
, "<%s />\n", tag
);
634 else if (gtype
== HB_VALUE_TYPE_DOUBLE
)
636 double val
= hb_value_get_double(gval
);
637 indent_fprintf(file
, indent
, "<real>%.17g</real>\n", val
);
639 else if (gtype
== HB_VALUE_TYPE_INT
)
641 int64_t val
= hb_value_get_int(gval
);
642 indent_fprintf(file
, indent
, "<integer>%"PRId64
"</integer>\n", val
);
644 else if (gtype
== HB_VALUE_TYPE_STRING
)
646 const char *str
= hb_value_get_string(gval
);
647 char *esc
= markup_escape_text(str
);
648 indent_fprintf(file
, indent
, "<string>%s</string>\n", esc
);
653 // Try to make anything thats unrecognized into a string
654 hb_error("Unhandled data type %d", gtype
);
659 hb_plist_write(FILE *file
, hb_value_t
*gval
)
661 fprintf(file
, "%s", preamble
);
662 gval_write(file
, gval
);
663 fprintf(file
, "%s", postfix
);
667 hb_plist_write_file(const char *filename
, hb_value_t
*gval
)
671 file
= fopen(filename
, "w");
675 hb_plist_write(file
, gval
);
682 main(int argc
, char *argv
[])
686 file
= fopen(argv
[1], "r");
687 gval
= hb_plist_parse_file(file
);
689 hb_plist_write_file(argv
[2], gval
);
691 hb_plist_write(stdout
, gval
);
692 if (file
) fclose (file
);