Add PLIST_DICT convenience functions for different queries/operations
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 @@
      */
     PLIST_API void plist_dict_merge(plist_t *target, plist_t source);
 
+    /**
+     * Get a boolean value from a given #PLIST_DICT entry.
+     *
+     * The value node can be of type #PLIST_BOOLEAN, but also
+     * #PLIST_STRING (either 'true' or 'false'),
+     * #PLIST_INT with a numerical value of 0 or >= 1,
+     * or #PLIST_DATA with a single byte with a value of 0 or >= 1.
+     *
+     * @note This function returns 0 if the dictionary does not contain an
+     * entry for the given key, if the value node is of any other than
+     * the above mentioned type, or has any mismatching value.
+     *
+     * @param dict A node of type #PLIST_DICT
+     * @param key The key to look for in dict
+     * @return 0 or 1 depending on the value of the node.
+     */
+    PLIST_API uint8_t plist_dict_get_bool(plist_t dict, const char *key);
+
+    /**
+     * Get a signed integer value from a given #PLIST_DICT entry.
+     * The value node can be of type #PLIST_INT, but also
+     * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
+     * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
+     *
+     * @note This function returns 0 if the dictionary does not contain an
+     * entry for the given key, if the value node is of any other than
+     * the above mentioned type, or has any mismatching value.
+     *
+     * @param dict A node of type #PLIST_DICT
+     * @param key The key to look for in dict
+     * @return Signed integer value depending on the value of the node.
+     */
+    PLIST_API int64_t plist_dict_get_int(plist_t dict, const char *key);
+
+    /**
+     * Get an unsigned integer value from a given #PLIST_DICT entry.
+     * The value node can be of type #PLIST_INT, but also
+     * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
+     * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
+     *
+     * @note This function returns 0 if the dictionary does not contain an
+     * entry for the given key, if the value node is of any other than
+     * the above mentioned type, or has any mismatching value.
+     *
+     * @param dict A node of type #PLIST_DICT
+     * @param key The key to look for in dict
+     * @return Signed integer value depending on the value of the node.
+     */
+    PLIST_API uint64_t plist_dict_get_uint(plist_t dict, const char *key);
+
+    /**
+     * Copy a node from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key.
+     */
+    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);
+
+    /**
+     * Copy a boolean value from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @note The boolean value from *source_dict* is retrieved with #plist_dict_get_bool,
+     *     but is **always** created as #PLIST_BOOLEAN in *target_dict*.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key.
+     */
+    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);
+
+    /**
+     * Copy a signed integer value from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @note The signed integer value from *source_dict* is retrieved with #plist_dict_get_int,
+     *     but is **always** created as #PLIST_INT.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node value to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key.
+     */
+    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);
+
+    /**
+     * Copy an unsigned integer value from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @note The unsigned integer value from *source_dict* is retrieved with #plist_dict_get_uint,
+     *     but is **always** created as #PLIST_INT.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node value to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key.
+     */
+    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);
+
+    /**
+     * Copy a #PLIST_DATA node from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @note This function is like #plist_dict_copy_item, except that it fails
+     *     if the source node is not of type #PLIST_DATA.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node value to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key, or if it is not of type #PLIST_DATA.
+     */
+    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);
+
+    /**
+     * Copy a #PLIST_STRING node from *source_dict* to *target_dict*.
+     * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+     * is non-NULL, in which case it is looked up with *alt_source_key*.
+     * The entry in *target_dict* is **always** created with *key*.
+     *
+     * @note This function is like #plist_dict_copy_item, except that it fails
+     *     if the source node is not of type #PLIST_STRING.
+     *
+     * @param target_dict The target dictionary to copy to.
+     * @param source_dict The source dictionary to copy from.
+     * @param key The key for the node value to copy.
+     * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+     *
+     * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+     *     any entry with given key or alt_source_key, or if it is not of type #PLIST_STRING.
+     */
+    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);
 
     /********************************************
      *                                          *
@@ -608,7 +768,7 @@
      *
      * @return Pointer to the buffer
      */
-    PLIST_API const uint8_t* plist_get_data_ptr(plist_t node, uint64_t * length);
+    PLIST_API const uint8_t* plist_get_data_ptr(plist_t node, uint64_t* length);
 
     /**
      * 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 @@
 typedef SSIZE_T ssize_t;
 #endif
 
+#ifdef DEBUG
+static int plist_debug = 0;
+#define PLIST_ERR(...) if (plist_debug > 0) { fprintf(stderr, "libplist ERROR: " __VA_ARGS__); }
+#else
+#define PLIST_ERR(...)
+#endif
+
 extern void plist_xml_init(void);
 extern void plist_xml_deinit(void);
 extern void plist_bin_init(void);
@@ -61,6 +68,52 @@
 extern void plist_ostep_init(void);
 extern void plist_ostep_deinit(void);
 
+#ifndef bswap16
+#define bswap16(x)   ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#endif
+
+#ifndef bswap32
+#define bswap32(x)   ((((x) & 0xFF000000) >> 24) \
+                    | (((x) & 0x00FF0000) >>  8) \
+                    | (((x) & 0x0000FF00) <<  8) \
+                    | (((x) & 0x000000FF) << 24))
+#endif
+
+#ifndef bswap64
+#define bswap64(x)   ((((x) & 0xFF00000000000000ull) >> 56) \
+                    | (((x) & 0x00FF000000000000ull) >> 40) \
+                    | (((x) & 0x0000FF0000000000ull) >> 24) \
+                    | (((x) & 0x000000FF00000000ull) >>  8) \
+                    | (((x) & 0x00000000FF000000ull) <<  8) \
+                    | (((x) & 0x0000000000FF0000ull) << 24) \
+                    | (((x) & 0x000000000000FF00ull) << 40) \
+                    | (((x) & 0x00000000000000FFull) << 56))
+#endif
+
+#ifndef le16toh
+#ifdef __LITTLE_ENDIAN__
+#define le16toh(x) (x)
+#else
+#define le16toh(x) bswap16(x)
+#endif
+#endif
+
+#ifndef le32toh
+#ifdef __LITTLE_ENDIAN__
+#define le32toh(x) (x)
+#else
+#define le32toh(x) bswap32(x)
+#endif
+#endif
+
+#ifndef le64toh
+#ifdef __LITTLE_ENDIAN__
+#define le64toh(x) (x)
+#else
+#define le64toh(x) bswap64(x)
+#endif
+#endif
+
 static void internal_plist_init(void)
 {
     plist_bin_init();
@@ -958,6 +1011,195 @@
 	free(it);
 }
 
+uint8_t plist_dict_get_bool(plist_t dict, const char *key)
+{
+	uint8_t bval = 0;
+	uint64_t uintval = 0;
+	const char *strval = NULL;
+	uint64_t strsz = 0;
+	plist_t node = plist_dict_get_item(dict, key);
+	if (!node) {
+		return 0;
+	}
+	switch (plist_get_node_type(node)) {
+	case PLIST_BOOLEAN:
+		plist_get_bool_val(node, &bval);
+		break;
+	case PLIST_INT:
+		plist_get_uint_val(node, &uintval);
+		bval = (uintval) ? 1 : 0;
+		break;
+	case PLIST_STRING:
+		strval = plist_get_string_ptr(node, NULL);
+		if (strval) {
+			if (strcmp(strval, "true")) {
+				bval = 1;
+			} else if (strcmp(strval, "false")) {
+				bval = 0;
+			} else {
+				PLIST_ERR("%s: invalid string '%s' for string to boolean conversion\n", __func__, strval);
+			}
+		}
+		break;
+	case PLIST_DATA:
+		strval = (const char*)plist_get_data_ptr(node, &strsz);
+		if (strval) {
+			if (strsz == 1) {
+				bval = (strval[0]) ? 1 : 0;
+			} else {
+				PLIST_ERR("%s: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return bval;
+}
+
+int64_t plist_dict_get_int(plist_t dict, const char *key)
+{
+	int64_t intval = 0;
+	const char *strval = NULL;
+	uint64_t strsz = 0;
+	plist_t node = plist_dict_get_item(dict, key);
+	if (!node) {
+		return intval;
+	}
+	switch (plist_get_node_type(node)) {
+	case PLIST_INT:
+		plist_get_int_val(node, &intval);
+		break;
+	case PLIST_STRING:
+		strval = plist_get_string_ptr(node, NULL);
+		if (strval) {
+			intval = strtoll(strval, NULL, 0);
+		}
+		break;
+	case PLIST_DATA:
+		strval = (const char*)plist_get_data_ptr(node, &strsz);
+		if (strval) {
+			if (strsz == 8) {
+				intval = le64toh(*(int64_t*)strval);
+			} else if (strsz == 4) {
+				intval = le32toh(*(int32_t*)strval);
+			} else if (strsz == 2) {
+				intval = le16toh(*(int16_t*)strval);
+			} else if (strsz == 1) {
+				intval = strval[0];
+			} else {
+				PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return intval;
+}
+
+
+uint64_t plist_dict_get_uint(plist_t dict, const char *key)
+{
+	uint64_t uintval = 0;
+	const char *strval = NULL;
+	uint64_t strsz = 0;
+	plist_t node = plist_dict_get_item(dict, key);
+	if (!node) {
+		return uintval;
+	}
+	switch (plist_get_node_type(node)) {
+	case PLIST_INT:
+		plist_get_uint_val(node, &uintval);
+		break;
+	case PLIST_STRING:
+		strval = plist_get_string_ptr(node, NULL);
+		if (strval) {
+			uintval = strtoull(strval, NULL, 0);
+		}
+		break;
+	case PLIST_DATA:
+		strval = (const char*)plist_get_data_ptr(node, &strsz);
+		if (strval) {
+			if (strsz == 8) {
+				uintval = le64toh(*(uint64_t*)strval);
+			} else if (strsz == 4) {
+				uintval = le32toh(*(uint32_t*)strval);
+			} else if (strsz == 2) {
+				uintval = le16toh(*(uint16_t*)strval);
+			} else if (strsz == 1) {
+				uintval = strval[0];
+			} else {
+				PLIST_ERR("%s: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return uintval;
+}
+
+plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
+	if (!node) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	plist_dict_set_item(target_dict, key, plist_copy(node));
+	return PLIST_ERR_SUCCESS;
+}
+
+plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	uint8_t bval = plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key);
+	plist_dict_set_item(target_dict, key, plist_new_bool(bval));
+	return PLIST_ERR_SUCCESS;
+}
+
+plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	int64_t i64val = plist_dict_get_int(source_dict, (alt_source_key) ? alt_source_key : key);
+	plist_dict_set_item(target_dict, key, plist_new_int(i64val));
+	return PLIST_ERR_SUCCESS;
+}
+
+plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	uint64_t u64val = plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key);
+	plist_dict_set_item(target_dict, key, plist_new_uint(u64val));
+	return PLIST_ERR_SUCCESS;
+}
+
+plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
+	if (!PLIST_IS_DATA(node)) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	plist_dict_set_item(target_dict, key, plist_copy(node));
+	return PLIST_ERR_SUCCESS;
+}
+
+plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key)
+{
+	plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key);
+	if (!PLIST_IS_STRING(node)) {
+		return PLIST_ERR_INVALID_ARG;
+	}
+	plist_dict_set_item(target_dict, key, plist_copy(node));
+	return PLIST_ERR_SUCCESS;
+}
+
 plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
 {
     plist_t current = plist;
@@ -1578,6 +1820,9 @@
 
 void plist_set_debug(int debug)
 {
+#if DEBUG
+    plist_debug = debug;
+#endif
     plist_xml_set_debug(debug);
     plist_bin_set_debug(debug);
     plist_json_set_debug(debug);