summaryrefslogtreecommitdiffstats
path: root/src/plist.c
AgeCommit message (Collapse)AuthorFilesLines
4 daysplist: fix inverted strcmp in string to boolean conversionGravatar Arpit Jain1-2/+2
plist_dict_get_bool() compared the string value with strcmp() but treated a non-zero return as a match. strcmp() returns 0 on equality, so the conditions were inverted: "true" produced 0, "false" produced 1, and any other string also produced 1. The error branch could never be reached, since it required both comparisons to return 0 at once. The result is that the API returns the opposite of the stored value for both valid boolean strings, and returns true for strings that are not booleans at all, instead of reporting the conversion error. Compare == 0 in both conditions: input before after true 0 1 false 1 0 not-a-bool 1 error TRUE 1 error (empty) 1 error Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
6 daysptrarray: Handle realloc() failure in ptr_array_insert()Gravatar Comtea041-3/+13
ptr_array_insert() assigned the result of realloc() directly to pa->pdata and bumped the capacity without checking for failure, so on out-of-memory the old buffer was leaked and the following store or memmove() wrote through a NULL pointer. Keep the old buffer on failure and return -1 from ptr_array_insert() and ptr_array_add(). The callers now handle the error: - the array lookup cache (plist.c) is dropped instead of silently going out of sync with the node list; lookups then fall back to walking the children, as they do before the cache exists - bplist parsing (used_indexes) and serialization (objects) return PLIST_ERR_NO_MEM; ignoring the error in parse_bin_node_at_index() would otherwise loop forever since the array never grows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-05-22refactor: centralize formatting helpers and harden out-plutilGravatar Nikias Bassen1-1/+1
2026-04-27Add error handling to all modification functionsGravatar Nikias Bassen1-80/+94
Convert all array/dict modification functions from void to plist_err_t return type: - plist_array_set_item: replace at index n - plist_array_append_item: append to end - plist_array_insert_item: insert at position n - plist_array_remove_item: remove item at index n - plist_array_item_remove: remove item from its array parent - plist_dict_set_item: replace or insert key/value - plist_dict_remove_item: remove key/value pair - plist_dict_merge: merge source dict into target Returns: - PLIST_ERR_SUCCESS on success - PLIST_ERR_INVALID_ARG for invalid arguments (NULL, wrong type, out of range, etc.) - PLIST_ERR_NO_MEM on memory allocation failure - PLIST_ERR_UNKNOWN on unexpected internal errors Header documentation updated with full error code semantics for each function.
2026-03-22Add OpenStep coercion support for non-OpenStep plist typesGravatar Nikias Bassen1-2/+2
- Use PLIST_OPT_COERCE option to coerce PLIST_BOOLEAN, PLIST_DATE, PLIST_UID, and PLIST_NULL to OpenStep-compatible types (1 or 0, ISO 8601 strings, integers, and 'NULL' string) - Add plist_to_openstep_with_options() function to allow passing coercion option (and others) - Update plist_write_to_string() and plist_write_to_stream() accordingly
2026-03-20Add JSON coercion support for non-JSON plist typesGravatar Calil Khalil1-2/+2
- Add PLIST_OPT_COERCE option to coerce PLIST_DATE, PLIST_DATA, and PLIST_UID to JSON-compatible types (ISO 8601 strings, Base64 strings, and integers) - Add plist_to_json_with_options() function to allow passing coercion options (and others) - Update plist_write_to_string() and plist_write_to_stream() to support coercion option - Add --coerce flag to plistutil for JSON output - Create plist2json symlink that automatically enables coercion when invoked
2026-02-22xplist: Convert nested {CF$UID:<int>} dicts to PLIST_UID safelyGravatar Sami Kortelainen1-32/+80
Convert single-entry { "CF$UID" : <integer> } dictionaries to PLIST_UID nodes when closing a dict in the XML parser. Refactor node cleanup logic: - Split plist_free_data() into internal _plist_free_data() - Introduce plist_free_children() to release child nodes separately - Update plist_set_element_val() to free children before changing container node types - Ensure PLIST_DICT hashtables do not free values (assert + force free_func = NULL) This avoids in-place container mutation issues and ensures child nodes and container metadata are released correctly before changing node type. Co-authored-by: Sami Kortelainen <sami.kortelainen@piceasoft.com> Co-authored-by: Nikias Bassen <nikias@gmx.li>
2026-02-12plist: make array and dict iterators opaqueGravatar Nikias Bassen1-41/+68
Introduce private iterator structs for plist_array_iter and plist_dict_iter, and fix *_next_item() to properly advance iterator state and handle malformed containers safely.
2026-02-12Add NULL checks across codebaseGravatar Nikias Bassen1-13/+103
2026-02-10plist: Make plist copy and free implementations iterativeGravatar Nikias Bassen1-48/+205
Convert plist_free_node() and plist_copy_node() to iterative implementations. This avoids unbounded recursion and stack overflow when handling deeply nested plist data, while preserving existing semantics and caches.
2026-02-08plist: Handle node_attach/node_insert failuresGravatar Nikias Bassen1-43/+154
Update plist array and dict mutation helpers to check return values from node_attach() and node_insert(). This prevents cache corruption and allows new depth and cycle checks to be enforced correctly.
2026-01-23plist: Improve plist_dict_get_item() to safely iterate key/value pairsGravatar Nikias Bassen1-24/+32
Use explicit key/value stepping, zero-initialize hash lookup key, and perform length-checked comparisons on NUL-terminated key strings.
2026-01-22plist: Fix plist_is_binary() not checking for NULL inputGravatar Nikias Bassen1-1/+1
Fixes issue #300 Credit to @jasonmli8
2026-01-21plist: Fix incorrect size storage in plist_copy() for PLIST_STRING nodesGravatar Nikias Bassen1-3/+3
2026-01-20plist: Fix heap overflow caused by incorrect PLIST_STRING length during copyGravatar Nikias Bassen1-3/+18
Credit to @LkkkLxy. Addresses #277.
2026-01-20plist: Reject insertion of plist nodes that already have a parentGravatar Nikias Bassen1-57/+74
Credit to @LkkkLxy for reporting (#276). libplist nodes are owned by exactly one container. Inserting the same plist_t into multiple dicts or arrays corrupts the tree structure and leads to use-after-free crashes during traversal or plist_free(). Add explicit parent checks to dict and array insertion APIs to reject nodes that already belong to another container. In debug builds, this fails loudly via assert() and optional diagnostics; in release builds, the operation safely no-ops. Callers that need to reuse values must create a copy using plist_copy() or explicitly detach the node before reinserting it.
2026-01-12plist: make plist_data_compare NULL-safeGravatar Nikias Bassen1-10/+20
Ensure plist_data_compare safely handles NULL inputs by normalizing NULL data to empty values and avoiding invalid dereferences.
2025-09-12Fix proper use of callocGravatar Nikias Bassen1-1/+1
2025-05-14Silence deprecation warning by using underlying code directly2.7.0Gravatar Nikias Bassen1-3/+6
plist_date_val_compare calls plist_get_date_val which is now marked deprecated. To avoid compiler warnings during build, we use the underlying implementation directly instead of calling the function to work around it.
2025-05-13Add plist_new_unix_date, plist_get_unix_date_val, plist_set_unix_date_val ↵Gravatar Nikias Bassen1-0/+49
functions These functions work with int64_t values representing a UNIX timestamp instead of using the 'MAC epoch'. They should be used instead of plist_new_date, plist_get_date_val, and plist_set_date_val, which are now marked deprecated and might be removed in a future version of libplist.
2025-05-12Fix plist_set_date_val to use correct size for data storageGravatar Nikias Bassen1-1/+1
Otherwise the internal assertion will trigger since the incorrect size will be checked against. Thanks to @michaelwright235, @guyingzhao, and others for pointing this out!
2025-03-27Fix segmentation fault when calling plist_sort() on an empty dictionaryGravatar Nikias Bassen1-0/+3
Credit to @Anza2001
2024-12-03Remove pthread dependencyGravatar Nikias Bassen1-2/+0
2024-11-28Switch from detecting little endian (common) to detecting big endian (rare)Gravatar Duncan Ogilvie1-9/+9
This prevents a bug class where we bswap things when __LITTLE_ENDIAN__ is not defined. Almost all modern systems are little endian, so detecting __BIG_ENDIAN__ is a better strategy.
2024-11-28Switch to more generic global initializer methodGravatar Duncan Ogilvie1-74/+41
2024-05-13Revert "Change API around #PLIST_DATA to use uint8_t instead of char arrays"Gravatar Nikias Bassen1-5/+5
This reverts commit a91f5740d100414a76959714b819422ee5b2d8a8.
2024-04-18Add PLIST_DICT convenience functions for different queries/operationsGravatar Nikias Bassen1-0/+245
2024-04-14Change API around #PLIST_DATA to use uint8_t instead of char arraysGravatar Nikias Bassen1-5/+6
This makes it more obvious that it is arbitrary data and not necessarily a string value.
2024-02-05Add a libplist_version() function to the interfaceGravatar Nikias Bassen1-0/+8
2023-12-12Prevent OOB access in plist_from_memoryGravatar Nikias Bassen1-2/+14
Credit to OSS-Fuzz
2023-08-30Prevent adding NULL items to array/dictionary nodesGravatar Nikias Bassen1-0/+12
Thanks to @tihmstar for pointing this out!
2023-06-15Plug memory leak in plist_write_to_stream()Gravatar Nikias Bassen1-0/+1
Thanks @beyonik for pointing this out!
2023-05-21Add explicit casts and fix return type mismatchesGravatar Nikias Bassen1-43/+47
2023-05-20Add an explicit PLIST_FORMAT_NONE valueGravatar Nikias Bassen1-2/+2
2023-05-13Move PLIST_API to the headersGravatar Nikias Bassen1-83/+83
2023-05-05Silence compiler warning on 32bit systemsGravatar Nikias Bassen1-1/+1
2023-04-19Remove deprecated plist_dict_insert_item()Gravatar Nikias Bassen1-5/+0
2023-04-19Add plist_read_from_file() to interface, update plist_from_memory()Gravatar Nikias Bassen1-1/+51
plist_read_from_file() is a convenience function that will open a given file, checks its size, allocates a buffer large enough to hold the full contents, and reads from file to fill the buffer. Then, it calls plist_from_memory() to convert the data to plist format. A (breaking) change had to be made so that plist_from_memory() will also return the parsed format in its 4th argument (if non-NULL).
2023-04-16Add new output-only formats and Define constants for the different plist formatsGravatar Nikias Bassen1-0/+92
This commit introduces constants for the different plist formats, and adds 3 new human-readable output-only formats: - PLIST_FORMAT_PRINT: the default human-readable format - PLIST_FORMAT_LIMD: "libimobiledevice" format (used in ideviceinfo) - PLIST_FORMAT_PLUTIL: plutil-style format Also, a new set of write functions has been added: - plist_write_to_string - plist_write_to_stream - plist_write_to_file Plus a simple "dump" function: - plist_print See documentation for details.
2023-02-07Add function to interface to allow enabling/disabling error/debug output for ↵Gravatar Nikias Bassen1-0/+13
the format parses This makes the `-d` option work in plistutil that wasn't doing anything
2023-02-06libcnary: Updated typedefs of node_t and node_list_t to contain pointerGravatar Nikias Bassen1-41/+41
This makes the code more readable. Obviously all the code that uses it is also updated.
2023-02-05Fix plist_sort() by swapping the nodes in the tree instead of their dataGravatar Nikias Bassen1-29/+33
The problem was that we swapped potential child node data between nodes, but their parents would not be updated that way, leading to double frees or segmentation faults when freeing a plist. This commit instead fixes this by swapping the actual nodes in the tree.
2023-02-03Add new plist_sort() functionGravatar Nikias Bassen1-0/+61
2023-01-31bplist: Fix handling of PLIST_NULL node typeGravatar Nikias Bassen1-0/+1
2023-01-16Rename PLIST_UINT to PLIST_INT and add plist_new_int() and plist_get_int_val()Gravatar Nikias Bassen1-8/+60
This properly supports getting and setting signed or unsigned integer values. Also, a new helper function plist_int_val_is_negative() was added to determine if a given #PLIST_INT node has a negative value or not. The old type PLIST_UINT is defined as a macro with the value of PLIST_INT for backwards compatibility. This commit also adds int vs. uint support to the C++ interface, and the python bindings in a hopefully useful way.
2023-01-08Add support for OpenStep plist formatGravatar Nikias Bassen1-5/+49
2022-09-05Fix up warning with `-Wbad-function-cast`Gravatar Dave MacLachlan1-1/+4
2022-04-06Skip whitespace to properly detect format in plist_from_memory()Gravatar Nikias Bassen1-3/+8
2021-12-23Add support for JSON formatGravatar Nikias Bassen1-0/+6
2021-12-22Add a return value to plist_to_* and plist_from_* functionsGravatar Nikias Bassen1-7/+11
This way it can be easier determined why an import/export operation failed instead of just having a NULL result.