diff options
| author | 2023-02-03 16:48:34 +0100 | |
|---|---|---|
| committer | 2023-02-03 16:48:34 +0100 | |
| commit | 706771e357570d1bee268fc7c2233506da967bcd (patch) | |
| tree | 4239e647149f94c5f6b5df998a88c8daf39a7b23 | |
| parent | c2f396a53745a74dd58de3b55092a77e0e9f639d (diff) | |
| download | libplist-706771e357570d1bee268fc7c2233506da967bcd.tar.gz libplist-706771e357570d1bee268fc7c2233506da967bcd.tar.bz2 | |
Add new plist_sort() function
| -rw-r--r-- | include/plist/plist.h | 8 | ||||
| -rw-r--r-- | src/plist.c | 61 |
2 files changed, 69 insertions, 0 deletions
diff --git a/include/plist/plist.h b/include/plist/plist.h index 2bb947f..0a21499 100644 --- a/include/plist/plist.h +++ b/include/plist/plist.h | |||
| @@ -1072,6 +1072,14 @@ extern "C" | |||
| 1072 | int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n); | 1072 | int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n); |
| 1073 | 1073 | ||
| 1074 | /** | 1074 | /** |
| 1075 | * Sort all PLIST_DICT key/value pairs in a property list lexicographically | ||
| 1076 | * by key. Recurses into the child nodes if necessary. | ||
| 1077 | * | ||
| 1078 | * @param plist The property list to perform the sorting operation on. | ||
| 1079 | */ | ||
| 1080 | void plist_sort(plist_t plist); | ||
| 1081 | |||
| 1082 | /** | ||
| 1075 | * Free memory allocated by relevant libplist API calls: | 1083 | * Free memory allocated by relevant libplist API calls: |
| 1076 | * - plist_to_xml() | 1084 | * - plist_to_xml() |
| 1077 | * - plist_to_bin() | 1085 | * - plist_to_bin() |
diff --git a/src/plist.c b/src/plist.c index b120046..72c3e98 100644 --- a/src/plist.c +++ b/src/plist.c | |||
| @@ -1495,3 +1495,64 @@ PLIST_API int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, s | |||
| 1495 | plist_data_t data = plist_get_data(datanode); | 1495 | plist_data_t data = plist_get_data(datanode); |
| 1496 | return (memmem(data->buff, data->length, cmpval, n) != NULL); | 1496 | return (memmem(data->buff, data->length, cmpval, n) != NULL); |
| 1497 | } | 1497 | } |
| 1498 | |||
| 1499 | PLIST_API void plist_sort(plist_t plist) | ||
| 1500 | { | ||
| 1501 | if (!plist) { | ||
| 1502 | return; | ||
| 1503 | } | ||
| 1504 | if (PLIST_IS_ARRAY(plist)) { | ||
| 1505 | uint32_t n = plist_array_get_size(plist); | ||
| 1506 | uint32_t i = 0; | ||
| 1507 | for (i = 0; i < n; i++) { | ||
| 1508 | plist_sort(plist_array_get_item(plist, i)); | ||
| 1509 | } | ||
| 1510 | } else if (PLIST_IS_DICT(plist)) { | ||
| 1511 | node_t *node = (node_t*)plist; | ||
| 1512 | node_t *ch; | ||
| 1513 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | ||
| 1514 | ch = node_next_sibling(ch); | ||
| 1515 | plist_sort((plist_t)ch); | ||
| 1516 | } | ||
| 1517 | #define KEY_DATA(x) (x->data) | ||
| 1518 | #define VAL_DATA(x) (x->next->data) | ||
| 1519 | #define VAL_COUNT(x) (x->next->count) | ||
| 1520 | #define VAL_CHDN(x) (x->next->children) | ||
| 1521 | #define NEXT_KEY(x) (x->next->next) | ||
| 1522 | #define NEXT_VAL(x) (NEXT_KEY(x)->next) | ||
| 1523 | #define NEXT_KEY_DATA(x) (NEXT_KEY(x)->data) | ||
| 1524 | #define NEXT_VAL_DATA(x) (NEXT_VAL(x)->data) | ||
| 1525 | #define NEXT_VAL_CHDN(x) (NEXT_VAL(x)->children) | ||
| 1526 | #define NEXT_VAL_COUNT(x) (NEXT_VAL(x)->count) | ||
| 1527 | #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval | ||
| 1528 | #define NEXT_KEY_STRVAL(x) ((plist_data_t)(NEXT_KEY_DATA(x)))->strval | ||
| 1529 | int swapped = 0; | ||
| 1530 | do { | ||
| 1531 | swapped = 0; | ||
| 1532 | node_t *lptr = NULL; | ||
| 1533 | node_t *ptr_key = node_first_child((node_t*)plist); | ||
| 1534 | while (NEXT_KEY(ptr_key) != lptr) { | ||
| 1535 | if (strcmp(KEY_STRVAL(ptr_key), NEXT_KEY_STRVAL(ptr_key)) > 0) { | ||
| 1536 | // backup old values | ||
| 1537 | void* key_data_tmp = KEY_DATA(ptr_key); | ||
| 1538 | void* val_data_tmp = VAL_DATA(ptr_key); | ||
| 1539 | struct node_list_t *val_chdn_tmp = VAL_CHDN(ptr_key); | ||
| 1540 | unsigned int val_count_tmp = VAL_COUNT(ptr_key); | ||
| 1541 | // replace current with next | ||
| 1542 | KEY_DATA(ptr_key) = NEXT_KEY_DATA(ptr_key); | ||
| 1543 | VAL_DATA(ptr_key) = NEXT_VAL_DATA(ptr_key); | ||
| 1544 | VAL_CHDN(ptr_key) = NEXT_VAL_CHDN(ptr_key); | ||
| 1545 | VAL_COUNT(ptr_key) = NEXT_VAL_COUNT(ptr_key); | ||
| 1546 | // replace next with old | ||
| 1547 | NEXT_KEY_DATA(ptr_key) = key_data_tmp; | ||
| 1548 | NEXT_VAL_DATA(ptr_key) = val_data_tmp; | ||
| 1549 | NEXT_VAL_CHDN(ptr_key) = val_chdn_tmp; | ||
| 1550 | NEXT_VAL_COUNT(ptr_key) = val_count_tmp; | ||
| 1551 | swapped = 1; | ||
| 1552 | } | ||
| 1553 | ptr_key = NEXT_KEY(ptr_key); | ||
| 1554 | } | ||
| 1555 | lptr = ptr_key; | ||
| 1556 | } while (swapped); | ||
| 1557 | } | ||
| 1558 | } | ||
