summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/plist/plist.h162
-rw-r--r--src/plist.c245
2 files changed, 406 insertions, 1 deletions
diff --git a/include/plist/plist.h b/include/plist/plist.h
index dcc4a04..7d5b4cb 100644
--- a/include/plist/plist.h
+++ b/include/plist/plist.h
@@ -492,6 +492,166 @@ extern "C"
492 */ 492 */
493 PLIST_API void plist_dict_merge(plist_t *target, plist_t source); 493 PLIST_API void plist_dict_merge(plist_t *target, plist_t source);
494 494
495 /**
496 * Get a boolean value from a given #PLIST_DICT entry.
497 *
498 * The value node can be of type #PLIST_BOOLEAN, but also
499 * #PLIST_STRING (either 'true' or 'false'),
500 * #PLIST_INT with a numerical value of 0 or >= 1,
501 * or #PLIST_DATA with a single byte with a value of 0 or >= 1.
502 *
503 * @note This function returns 0 if the dictionary does not contain an
504 * entry for the given key, if the value node is of any other than
505 * the above mentioned type, or has any mismatching value.
506 *
507 * @param dict A node of type #PLIST_DICT
508 * @param key The key to look for in dict
509 * @return 0 or 1 depending on the value of the node.
510 */
511 PLIST_API uint8_t plist_dict_get_bool(plist_t dict, const char *key);
512
513 /**
514 * Get a signed integer value from a given #PLIST_DICT entry.
515 * The value node can be of type #PLIST_INT, but also
516 * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
517 * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
518 *
519 * @note This function returns 0 if the dictionary does not contain an
520 * entry for the given key, if the value node is of any other than
521 * the above mentioned type, or has any mismatching value.
522 *
523 * @param dict A node of type #PLIST_DICT
524 * @param key The key to look for in dict
525 * @return Signed integer value depending on the value of the node.
526 */
527 PLIST_API int64_t plist_dict_get_int(plist_t dict, const char *key);
528
529 /**
530 * Get an unsigned integer value from a given #PLIST_DICT entry.
531 * The value node can be of type #PLIST_INT, but also
532 * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
533 * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
534 *
535 * @note This function returns 0 if the dictionary does not contain an
536 * entry for the given key, if the value node is of any other than
537 * the above mentioned type, or has any mismatching value.
538 *
539 * @param dict A node of type #PLIST_DICT
540 * @param key The key to look for in dict
541 * @return Signed integer value depending on the value of the node.
542 */
543 PLIST_API uint64_t plist_dict_get_uint(plist_t dict, const char *key);
544
545 /**
546 * Copy a node from *source_dict* to *target_dict*.
547 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
548 * is non-NULL, in which case it is looked up with *alt_source_key*.
549 * The entry in *target_dict* is **always** created with *key*.
550 *
551 * @param target_dict The target dictionary to copy to.
552 * @param source_dict The source dictionary to copy from.
553 * @param key The key for the node to copy.
554 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
555 *
556 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
557 * any entry with given key or alt_source_key.
558 */
559 PLIST_API plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
560
561 /**
562 * Copy a boolean value from *source_dict* to *target_dict*.
563 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
564 * is non-NULL, in which case it is looked up with *alt_source_key*.
565 * The entry in *target_dict* is **always** created with *key*.
566 *
567 * @note The boolean value from *source_dict* is retrieved with #plist_dict_get_bool,
568 * but is **always** created as #PLIST_BOOLEAN in *target_dict*.
569 *
570 * @param target_dict The target dictionary to copy to.
571 * @param source_dict The source dictionary to copy from.
572 * @param key The key for the node to copy.
573 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
574 *
575 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
576 * any entry with given key or alt_source_key.
577 */
578 PLIST_API plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
579
580 /**
581 * Copy a signed integer value from *source_dict* to *target_dict*.
582 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
583 * is non-NULL, in which case it is looked up with *alt_source_key*.
584 * The entry in *target_dict* is **always** created with *key*.
585 *
586 * @note The signed integer value from *source_dict* is retrieved with #plist_dict_get_int,
587 * but is **always** created as #PLIST_INT.
588 *
589 * @param target_dict The target dictionary to copy to.
590 * @param source_dict The source dictionary to copy from.
591 * @param key The key for the node value to copy.
592 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
593 *
594 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
595 * any entry with given key or alt_source_key.
596 */
597 PLIST_API plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
598
599 /**
600 * Copy an unsigned integer value from *source_dict* to *target_dict*.
601 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
602 * is non-NULL, in which case it is looked up with *alt_source_key*.
603 * The entry in *target_dict* is **always** created with *key*.
604 *
605 * @note The unsigned integer value from *source_dict* is retrieved with #plist_dict_get_uint,
606 * but is **always** created as #PLIST_INT.
607 *
608 * @param target_dict The target dictionary to copy to.
609 * @param source_dict The source dictionary to copy from.
610 * @param key The key for the node value to copy.
611 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
612 *
613 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
614 * any entry with given key or alt_source_key.
615 */
616 PLIST_API plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
617
618 /**
619 * Copy a #PLIST_DATA node from *source_dict* to *target_dict*.
620 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
621 * is non-NULL, in which case it is looked up with *alt_source_key*.
622 * The entry in *target_dict* is **always** created with *key*.
623 *
624 * @note This function is like #plist_dict_copy_item, except that it fails
625 * if the source node is not of type #PLIST_DATA.
626 *
627 * @param target_dict The target dictionary to copy to.
628 * @param source_dict The source dictionary to copy from.
629 * @param key The key for the node value to copy.
630 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
631 *
632 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
633 * any entry with given key or alt_source_key, or if it is not of type #PLIST_DATA.
634 */
635 PLIST_API plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
636
637 /**
638 * Copy a #PLIST_STRING node from *source_dict* to *target_dict*.
639 * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
640 * is non-NULL, in which case it is looked up with *alt_source_key*.
641 * The entry in *target_dict* is **always** created with *key*.
642 *
643 * @note This function is like #plist_dict_copy_item, except that it fails
644 * if the source node is not of type #PLIST_STRING.
645 *
646 * @param target_dict The target dictionary to copy to.
647 * @param source_dict The source dictionary to copy from.
648 * @param key The key for the node value to copy.
649 * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
650 *
651 * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
652 * any entry with given key or alt_source_key, or if it is not of type #PLIST_STRING.
653 */
654 PLIST_API plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
495 655
496 /******************************************** 656 /********************************************
497 * * 657 * *
@@ -608,7 +768,7 @@ extern "C"
608 * 768 *
609 * @return Pointer to the buffer 769 * @return Pointer to the buffer
610 */ 770 */
611 PLIST_API const uint8_t* plist_get_data_ptr(plist_t node, uint64_t * length); 771 PLIST_API const uint8_t* plist_get_data_ptr(plist_t node, uint64_t* length);
612 772
613 /** 773 /**
614 * Get the value of a #PLIST_DATE node. 774 * Get the value of a #PLIST_DATE node.
diff --git a/src/plist.c b/src/plist.c
index 57f5ead..d1b0b5a 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -52,6 +52,13 @@
52typedef SSIZE_T ssize_t; 52typedef SSIZE_T ssize_t;
53#endif 53#endif
54 54
55#ifdef DEBUG
56static int plist_debug = 0;
57#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
58#else
59#define PLIST_ERR(...)
60#endif
61
55extern void plist_xml_init(void); 62extern void plist_xml_init(void);
56extern void plist_xml_deinit(void); 63extern void plist_xml_deinit(void);
57extern void plist_bin_init(void); 64extern void plist_bin_init(void);
@@ -61,6 +68,52 @@ extern void plist_json_deinit(void);
61extern void plist_ostep_init(void); 68extern void plist_ostep_init(void);
62extern void plist_ostep_deinit(void); 69extern void plist_ostep_deinit(void);
63 70
71#ifndef bswap16
72#define bswap16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
73#endif
74
75#ifndef bswap32
76#define bswap32(x) ((((x) & 0xFF000000) >> 24) \
77 | (((x) & 0x00FF0000) >> 8) \
78 | (((x) & 0x0000FF00) << 8) \
79 | (((x) & 0x000000FF) << 24))
80#endif
81
82#ifndef bswap64
83#define bswap64(x) ((((x) & 0xFF00000000000000ull) >> 56) \
84 | (((x) & 0x00FF000000000000ull) >> 40) \
85 | (((x) & 0x0000FF0000000000ull) >> 24) \
86 | (((x) & 0x000000FF00000000ull) >> 8) \
87 | (((x) & 0x00000000FF000000ull) << 8) \
88 | (((x) & 0x0000000000FF0000ull) << 24) \
89 | (((x) & 0x000000000000FF00ull) << 40) \
90 | (((x) & 0x00000000000000FFull) << 56))
91#endif
92
93#ifndef le16toh
94#ifdef __LITTLE_ENDIAN__
95#define le16toh(x) (x)
96#else
97#define le16toh(x) bswap16(x)
98#endif
99#endif
100
101#ifndef le32toh
102#ifdef __LITTLE_ENDIAN__
103#define le32toh(x) (x)
104#else
105#define le32toh(x) bswap32(x)
106#endif
107#endif
108
109#ifndef le64toh
110#ifdef __LITTLE_ENDIAN__
111#define le64toh(x) (x)
112#else
113#define le64toh(x) bswap64(x)
114#endif
115#endif
116
64static void internal_plist_init(void) 117static void internal_plist_init(void)
65{ 118{
66 plist_bin_init(); 119 plist_bin_init();
@@ -958,6 +1011,195 @@ void plist_dict_merge(plist_t *target, plist_t source)
958 free(it); 1011 free(it);
959} 1012}
960 1013
1014uint8_t plist_dict_get_bool(plist_t dict, const char *key)
1015{
1016 uint8_t bval = 0;
1017 uint64_t uintval = 0;
1018 const char *strval = NULL;
1019 uint64_t strsz = 0;
1020 plist_t node = plist_dict_get_item(dict, key);
1021 if (!node) {
1022 return 0;
1023 }
1024 switch (plist_get_node_type(node)) {
1025 case PLIST_BOOLEAN:
1026 plist_get_bool_val(node, &bval);
1027 break;
1028 case PLIST_INT:
1029 plist_get_uint_val(node, &uintval);
1030 bval = (uintval) ? 1 : 0;
1031 break;
1032 case PLIST_STRING:
1033 strval = plist_get_string_ptr(node, NULL);
1034 if (strval) {
1035 if (strcmp(strval, "true")) {
1036 bval = 1;
1037 } else if (strcmp(strval, "false")) {
1038 bval = 0;
1039 } else {
1040 PLIST_ERR("%s: invalid string '%s' for string to boolean conversion\n", __func__, strval);
1041 }
1042 }
1043 break;
1044 case PLIST_DATA:
1045 strval = (const char*)plist_get_data_ptr(node, &strsz);
1046 if (strval) {
1047 if (strsz == 1) {
1048 bval = (strval[0]) ? 1 : 0;
1049 } else {
1050 PLIST_ERR("%s: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
1051 }
1052 }
1053 break;
1054 default:
1055 break;
1056 }
1057 return bval;
1058}
1059
1060int64_t plist_dict_get_int(plist_t dict, const char *key)
1061{
1062 int64_t intval = 0;
1063 const char *strval = NULL;
1064 uint64_t strsz = 0;
1065 plist_t node = plist_dict_get_item(dict, key);
1066 if (!node) {
1067 return intval;
1068 }
1069 switch (plist_get_node_type(node)) {
1070 case PLIST_INT:
1071 plist_get_int_val(node, &intval);
1072 break;
1073 case PLIST_STRING:
1074 strval = plist_get_string_ptr(node, NULL);
1075 if (strval) {
1076 intval = strtoll(strval, NULL, 0);
1077 }
1078 break;
1079 case PLIST_DATA:
1080 strval = (const char*)plist_get_data_ptr(node, &strsz);
1081 if (strval) {
1082 if (strsz == 8) {
1083 intval = le64toh(*(int64_t*)strval);
1084 } else if (strsz == 4) {
1085 intval = le32toh(*(int32_t*)strval);
1086 } else if (strsz == 2) {
1087 intval = le16toh(*(int16_t*)strval);
1088 } else if (strsz == 1) {
1089 intval = strval[0];
1090 } else {
1091 PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
1092 }
1093 }
1094 break;
1095 default:
1096 break;
1097 }
1098 return intval;
1099}
1100
1101
1102uint64_t plist_dict_get_uint(plist_t dict, const char *key)
1103{
1104 uint64_t uintval = 0;
1105 const char *strval = NULL;
1106 uint64_t strsz = 0;
1107 plist_t node = plist_dict_get_item(dict, key);
1108 if (!node) {
1109 return uintval;
1110 }
1111 switch (plist_get_node_type(node)) {
1112 case PLIST_INT:
1113 plist_get_uint_val(node, &uintval);
1114 break;
1115 case PLIST_STRING:
1116 strval = plist_get_string_ptr(node, NULL);
1117 if (strval) {
1118 uintval = strtoull(strval, NULL, 0);
1119 }
1120 break;
1121 case PLIST_DATA:
1122 strval = (const char*)plist_get_data_ptr(node, &strsz);
1123 if (strval) {
1124 if (strsz == 8) {
1125 uintval = le64toh(*(uint64_t*)strval);
1126 } else if (strsz == 4) {
1127 uintval = le32toh(*(uint32_t*)strval);
1128 } else if (strsz == 2) {
1129 uintval = le16toh(*(uint16_t*)strval);
1130 } else if (strsz == 1) {
1131 uintval = strval[0];
1132 } else {
1133 PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
1134 }
1135 }
1136 break;
1137 default:
1138 break;
1139 }
1140 return uintval;
1141}
1142
1143plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1144{
1145 plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1146 if (!node) {
1147 return PLIST_ERR_INVALID_ARG;
1148 }
1149 plist_dict_set_item(target_dict, key, plist_copy(node));
1150 return PLIST_ERR_SUCCESS;
1151}
1152
1153plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1154{
1155 if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1156 return PLIST_ERR_INVALID_ARG;
1157 }
1158 uint8_t bval = plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key);
1159 plist_dict_set_item(target_dict, key, plist_new_bool(bval));
1160 return PLIST_ERR_SUCCESS;
1161}
1162
1163plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1164{
1165 if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1166 return PLIST_ERR_INVALID_ARG;
1167 }
1168 int64_t i64val = plist_dict_get_int(source_dict, (alt_source_key) ? alt_source_key : key);
1169 plist_dict_set_item(target_dict, key, plist_new_int(i64val));
1170 return PLIST_ERR_SUCCESS;
1171}
1172
1173plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1174{
1175 if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
1176 return PLIST_ERR_INVALID_ARG;
1177 }
1178 uint64_t u64val = plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key);
1179 plist_dict_set_item(target_dict, key, plist_new_uint(u64val));
1180 return PLIST_ERR_SUCCESS;
1181}
1182
1183plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1184{
1185 plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1186 if (!PLIST_IS_DATA(node)) {
1187 return PLIST_ERR_INVALID_ARG;
1188 }
1189 plist_dict_set_item(target_dict, key, plist_copy(node));
1190 return PLIST_ERR_SUCCESS;
1191}
1192
1193plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
1194{
1195 plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
1196 if (!PLIST_IS_STRING(node)) {
1197 return PLIST_ERR_INVALID_ARG;
1198 }
1199 plist_dict_set_item(target_dict, key, plist_copy(node));
1200 return PLIST_ERR_SUCCESS;
1201}
1202
961plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v) 1203plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
962{ 1204{
963 plist_t current = plist; 1205 plist_t current = plist;
@@ -1578,6 +1820,9 @@ extern void plist_ostep_set_debug(int debug);
1578 1820
1579void plist_set_debug(int debug) 1821void plist_set_debug(int debug)
1580{ 1822{
1823#if DEBUG
1824 plist_debug = debug;
1825#endif
1581 plist_xml_set_debug(debug); 1826 plist_xml_set_debug(debug);
1582 plist_bin_set_debug(debug); 1827 plist_bin_set_debug(debug);
1583 plist_json_set_debug(debug); 1828 plist_json_set_debug(debug);