diff --git a/README.md b/README.md index 73922ec..e391c25 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,20 @@ make ``` mkdir workdir git clone https://github.com/lzfse/lzfse +mkdir -p lzfse/build +cd lzfse/build +cmake .. +msbuild lzfse.vcxproj /p:Configuration=release /p:Platform=x64 /p:PlatformToolset=v143 +cd ../.. +git clone https://github.com/libimobiledevice/libplist git clone https://github.com/jpaver/opengametools.git git clone https://github.com/oomer/vmax2bella.git +cp vmax2bella/patch_libplist/libplist.vcxproj ../libplist +cp vmax2bella/patch_libplist/cnary.c ../libplist/libcnary/cnary.c +cp vmax2bella/patch_libplist/plist.c ../libplist/libcnary/plist.c +cd libplist +msbuild libplist.vcxproj /p:Configuration=release /p:Platform=x64 /p:PlatformToolset=v143 +cd .. cd vmax2bella -msbuild vox2bella.vcxproj /p:Configuration=release /p:Platform=x64 /p:PlatformToolset=v143 +msbuild vmax2bella.vcxproj /p:Configuration=release /p:Platform=x64 /p:PlatformToolset=v143 ``` diff --git a/patch_libplist/cnary.c b/patch_libplist/cnary.c new file mode 100644 index 0000000..82c20bd --- /dev/null +++ b/patch_libplist/cnary.c @@ -0,0 +1,47 @@ +/* + * cnary.c + * + * Created on: Mar 9, 2011 + * Author: posixninja + * + * Copyright (c) 2011 Joshua Hill. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "node.h" + +int main(int argc, char* argv[]) { + puts("Creating root node"); + node_t root = node_create(NULL, NULL); + + puts("Creating child 1 node"); + node_t one = node_create(root, NULL); + puts("Creating child 2 node"); + node_t two = node_create(root, NULL); + + puts("Creating child 3 node"); + node_t three = node_create(one, NULL); + + puts("Debugging root node"); + node_debug(root); + + puts("Destroying root node"); + node_destroy(root); + return 0; +} + diff --git a/patch_libplist/libplist.vcxproj b/patch_libplist/libplist.vcxproj new file mode 100644 index 0000000..7a39570 --- /dev/null +++ b/patch_libplist/libplist.vcxproj @@ -0,0 +1,119 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + 16.0 + {A34F0D57-E086-45B3-9A7D-8A04CAD3AFEF} + Win32Proj + libplist + 10.0 + + + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + $(SolutionDir)bin\$(Platform)\$(Configuration)\ + $(SolutionDir)obj\$(Platform)\$(Configuration)\$(ProjectName)\ + + + + + WIN32;_WINDOWS;_USRDLL;LIBPLIST_EXPORTS;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;%(PreprocessorDefinitions) + $(ProjectDir)include;$(ProjectDir)src;$(ProjectDir)libcnary\include;$(ProjectDir);%(AdditionalIncludeDirectories) + Level3 + true + true + 4244;4267;4146 + + + Windows + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/patch_libplist/plist.c b/patch_libplist/plist.c new file mode 100644 index 0000000..03b1cae --- /dev/null +++ b/patch_libplist/plist.c @@ -0,0 +1,1969 @@ +/* + * plist.c + * Builds plist XML structures + * + * Copyright (c) 2009-2023 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2010-2015 Martin Szulecki, All Rights Reserved. + * Copyright (c) 2008 Zach C., All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE 1 +#include +#include "plist.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +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 + +#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 __BIG_ENDIAN__ +#define le16toh(x) bswap16(x) +#else +#define le16toh(x) (x) +#endif +#endif + +#ifndef le32toh +#ifdef __BIG_ENDIAN__ +#define le32toh(x) bswap32(x) +#else +#define le32toh(x) (x) +#endif +#endif + +#ifndef le64toh +#ifdef __BIG_ENDIAN__ +#define le64toh(x) bswap64(x) +#else +#define le64toh(x) (x) +#endif +#endif + +// Reference: https://stackoverflow.com/a/2390626/1806760 +// Initializer/finalizer sample for MSVC and GCC/Clang. +// 2010-2016 Joe Lowe. Released into the public domain. + +#ifdef __cplusplus + #define INITIALIZER(f) \ + static void f(void); \ + struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \ + static void f(void) +#elif defined(_MSC_VER) + #pragma section(".CRT$XCU",read) + #define INITIALIZER2_(f,p) \ + static void f(void); \ + __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ + __pragma(comment(linker,"/include:" p #f "_")) \ + static void f(void) + #ifdef _WIN64 + #define INITIALIZER(f) INITIALIZER2_(f,"") + #else + #define INITIALIZER(f) INITIALIZER2_(f,"_") + #endif +#else + #define INITIALIZER(f) \ + static void f(void) __attribute__((__constructor__)); \ + static void f(void) +#endif + +extern void plist_xml_init(void); +extern void plist_xml_deinit(void); +extern void plist_bin_init(void); +extern void plist_bin_deinit(void); +extern void plist_json_init(void); +extern void plist_json_deinit(void); +extern void plist_ostep_init(void); +extern void plist_ostep_deinit(void); + +static void internal_plist_deinit(void) +{ + plist_bin_deinit(); + plist_xml_deinit(); + plist_json_deinit(); + plist_ostep_deinit(); +} + +INITIALIZER(internal_plist_init) +{ + plist_bin_init(); + plist_xml_init(); + plist_json_init(); + plist_ostep_init(); + atexit(internal_plist_deinit); +} + +#ifndef HAVE_MEMMEM +// see https://sourceware.org/legacy-ml/libc-alpha/2007-12/msg00000.html + +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +#endif + +#undef memmem + +/* Return the first occurrence of NEEDLE in HAYSTACK. */ +void* memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len) +{ + /* not really Rabin-Karp, just using additive hashing */ + char* haystack_ = (char*)haystack; + char* needle_ = (char*)needle; + int hash = 0; /* this is the static hash value of the needle */ + int hay_hash = 0; /* rolling hash over the haystack */ + char* last; + size_t i; + + if (haystack_len < needle_len) + return NULL; + + if (!needle_len) + return haystack_; + + /* initialize hashes */ + for (i = needle_len; i; --i) { + hash += *needle_++; + hay_hash += *haystack_++; + } + + /* iterate over the haystack */ + haystack_ = (char*)haystack; + needle_ = (char*)needle; + last = haystack_+(haystack_len - needle_len + 1); + for (; haystack_ < last; ++haystack_) { + if (__builtin_expect(hash == hay_hash, 0) + && *haystack_ == *needle_ /* prevent calling memcmp, was a optimization from existing glibc */ + && !memcmp (haystack_, needle_, needle_len)) { + return haystack_; + } + /* roll the hash */ + hay_hash -= *haystack_; + hay_hash += *(haystack_+needle_len); + } + return NULL; +} +#endif + +int plist_is_binary(const char *plist_data, uint32_t length) +{ + if (length < 8) { + return 0; + } + + return (memcmp(plist_data, "bplist00", 8) == 0); +} + +#define SKIP_WS(blob, pos, len) \ + while (pos < len && ((blob[pos] == ' ') || (blob[pos] == '\t') || (blob[pos] == '\r') || (blob[pos] == '\n'))) pos++; +#define FIND_NEXT(blob, pos, len, chr) \ + while (pos < len && (blob[pos] != chr)) pos++; + +plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format) +{ + plist_err_t res = PLIST_ERR_UNKNOWN; + if (!plist) { + return PLIST_ERR_INVALID_ARG; + } + *plist = NULL; + if (!plist_data || length == 0) { + return PLIST_ERR_INVALID_ARG; + } + plist_format_t fmt = PLIST_FORMAT_NONE; + if (format) *format = PLIST_FORMAT_NONE; + if (plist_is_binary(plist_data, length)) { + res = plist_from_bin(plist_data, length, plist); + fmt = PLIST_FORMAT_BINARY; + } else { + uint32_t pos = 0; + int is_json = 0; + int is_xml = 0; + /* skip whitespace */ + SKIP_WS(plist_data, pos, length); + if (pos >= length) { + return PLIST_ERR_PARSE; + } + if (plist_data[pos] == '<' && (length-pos > 3) && !isxdigit(plist_data[pos+1]) && !isxdigit(plist_data[pos+2]) && !isxdigit(plist_data[pos+3])) { + is_xml = 1; + } else if (plist_data[pos] == '[') { + /* only valid for json */ + is_json = 1; + } else if (plist_data[pos] == '(') { + /* only valid for openstep */ + } else if (plist_data[pos] == '{') { + /* this could be json or openstep */ + pos++; + SKIP_WS(plist_data, pos, length); + if (pos >= length) { + return PLIST_ERR_PARSE; + } + if (plist_data[pos] == '"') { + /* still could be both */ + pos++; + while (pos < length) { + FIND_NEXT(plist_data, pos, length, '"'); + if (plist_data[pos-1] != '\\') { + break; + } + pos++; + } + if (pos >= length) { + return PLIST_ERR_PARSE; + } + if (plist_data[pos] == '"') { + pos++; + SKIP_WS(plist_data, pos, length); + if (pos >= length) { + return PLIST_ERR_PARSE; + } + if (plist_data[pos] == ':') { + /* this is definitely json */ + is_json = 1; + } + } + } + } + if (is_xml) { + res = plist_from_xml(plist_data, length, plist); + fmt = PLIST_FORMAT_XML; + } else if (is_json) { + res = plist_from_json(plist_data, length, plist); + fmt = PLIST_FORMAT_JSON; + } else { + res = plist_from_openstep(plist_data, length, plist); + fmt = PLIST_FORMAT_OSTEP; + } + } + if (format && res == PLIST_ERR_SUCCESS) { + *format = fmt; + } + return res; +} + +plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format) +{ + if (!filename || !plist) { + return PLIST_ERR_INVALID_ARG; + } + FILE *f = fopen(filename, "rb"); + if (!f) { + return PLIST_ERR_IO; + } + struct stat fst; + fstat(fileno(f), &fst); + if ((uint64_t)fst.st_size > UINT32_MAX) { + return PLIST_ERR_NO_MEM; + } + uint32_t total = (uint32_t)fst.st_size; + if (total == 0) { + return PLIST_ERR_PARSE; + } + char *buf = (char*)malloc(total); + if (!buf) { + fclose(f); + return PLIST_ERR_NO_MEM; + } + uint32_t done = 0; + while (done < total) { + ssize_t r = fread(buf + done, 1, total - done, f); + if (r <= 0) { + break; + } + done += r; + } + fclose(f); + if (done < total) { + free(buf); + return PLIST_ERR_IO; + } + plist_err_t res = plist_from_memory(buf, total, plist, format); + free(buf); + return res; +} + +plist_t plist_new_node(plist_data_t data) +{ + return (plist_t) node_create(NULL, data); +} + +plist_data_t plist_get_data(plist_t node) +{ + if (!node) + return NULL; + return (plist_data_t)((node_t)node)->data; +} + +plist_data_t plist_new_plist_data(void) +{ + plist_data_t data = (plist_data_t) calloc(sizeof(struct plist_data_s), 1); + return data; +} + +static unsigned int dict_key_hash(const void *data) +{ + plist_data_t keydata = (plist_data_t)data; + unsigned int hash = 5381; + size_t i; + char *str = keydata->strval; + for (i = 0; i < keydata->length; str++, i++) { + hash = ((hash << 5) + hash) + *str; + } + return hash; +} + +static int dict_key_compare(const void* a, const void* b) +{ + plist_data_t data_a = (plist_data_t)a; + plist_data_t data_b = (plist_data_t)b; + if (data_a->strval == NULL || data_b->strval == NULL) { + return FALSE; + } + if (data_a->length != data_b->length) { + return FALSE; + } + return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE; +} + +void plist_free_data(plist_data_t data) +{ + if (data) + { + switch (data->type) + { + case PLIST_KEY: + case PLIST_STRING: + free(data->strval); + break; + case PLIST_DATA: + free(data->buff); + break; + case PLIST_ARRAY: + ptr_array_free((ptrarray_t*)data->hashtable); + break; + case PLIST_DICT: + hash_table_destroy((hashtable_t*)data->hashtable); + break; + default: + break; + } + free(data); + } +} + +static int plist_free_node(node_t node) +{ + plist_data_t data = NULL; + int node_index = node_detach(node->parent, node); + data = plist_get_data(node); + plist_free_data(data); + node->data = NULL; + + node_t ch; + for (ch = node_first_child(node); ch; ) { + node_t next = node_next_sibling(ch); + plist_free_node(ch); + ch = next; + } + + node_destroy(node); + + return node_index; +} + +plist_t plist_new_dict(void) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_DICT; + return plist_new_node(data); +} + +plist_t plist_new_array(void) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_ARRAY; + return plist_new_node(data); +} + +//These nodes should not be handled by users +static plist_t plist_new_key(const char *val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_KEY; + data->strval = strdup(val); + data->length = strlen(val); + return plist_new_node(data); +} + +plist_t plist_new_string(const char *val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_STRING; + data->strval = strdup(val); + data->length = strlen(val); + return plist_new_node(data); +} + +plist_t plist_new_bool(uint8_t val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_BOOLEAN; + data->boolval = val; + data->length = sizeof(uint8_t); + return plist_new_node(data); +} + +plist_t plist_new_uint(uint64_t val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_INT; + data->intval = val; + data->length = (val > INT_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t); + return plist_new_node(data); +} + +plist_t plist_new_int(int64_t val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_INT; + data->intval = val; + data->length = sizeof(uint64_t); + return plist_new_node(data); +} + +plist_t plist_new_uid(uint64_t val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_UID; + data->intval = val; + data->length = sizeof(uint64_t); + return plist_new_node(data); +} + +plist_t plist_new_real(double val) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_REAL; + data->realval = val; + data->length = sizeof(double); + return plist_new_node(data); +} + +plist_t plist_new_data(const char *val, uint64_t length) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_DATA; + data->buff = (uint8_t *) malloc(length); + memcpy(data->buff, val, length); + data->length = length; + return plist_new_node(data); +} + +plist_t plist_new_date(int32_t sec, int32_t usec) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_DATE; + data->realval = (double)sec + (double)usec / 1000000; + data->length = sizeof(double); + return plist_new_node(data); +} + +plist_t plist_new_null(void) +{ + plist_data_t data = plist_new_plist_data(); + data->type = PLIST_NULL; + data->intval = 0; + data->length = 0; + return plist_new_node(data); +} + +void plist_free(plist_t plist) +{ + if (plist) + { + plist_free_node((node_t)plist); + } +} + +void plist_mem_free(void* ptr) +{ + if (ptr) + { + free(ptr); + } +} + +static plist_t plist_copy_node(node_t node) +{ + plist_type node_type = PLIST_NONE; + plist_t newnode = NULL; + plist_data_t data = plist_get_data(node); + plist_data_t newdata = plist_new_plist_data(); + + assert(data); // plist should always have data + assert(newdata); + + memcpy(newdata, data, sizeof(struct plist_data_s)); + + node_type = plist_get_node_type(node); + switch (node_type) { + case PLIST_DATA: + newdata->buff = (uint8_t *) malloc(data->length); + memcpy(newdata->buff, data->buff, data->length); + break; + case PLIST_KEY: + case PLIST_STRING: + newdata->strval = strdup(data->strval); + break; + case PLIST_ARRAY: + if (data->hashtable) { + ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity); + assert(pa); + newdata->hashtable = pa; + } + break; + case PLIST_DICT: + if (data->hashtable) { + hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL); + assert(ht); + newdata->hashtable = ht; + } + break; + default: + break; + } + newnode = plist_new_node(newdata); + + node_t ch; + unsigned int node_index = 0; + for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { + /* copy child node */ + plist_t newch = plist_copy_node(ch); + /* attach to new parent node */ + node_attach((node_t)newnode, (node_t)newch); + /* if needed, add child node to lookup table of parent node */ + switch (node_type) { + case PLIST_ARRAY: + if (newdata->hashtable) { + ptr_array_add((ptrarray_t*)newdata->hashtable, newch); + } + break; + case PLIST_DICT: + if (newdata->hashtable && (node_index % 2 != 0)) { + hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t)newch))->data, newch); + } + break; + default: + break; + } + node_index++; + } + return newnode; +} + +plist_t plist_copy(plist_t node) +{ + return node ? plist_copy_node((node_t)node) : NULL; +} + +uint32_t plist_array_get_size(plist_t node) +{ + uint32_t ret = 0; + if (node && PLIST_ARRAY == plist_get_node_type(node)) + { + ret = node_n_children((node_t)node); + } + return ret; +} + +plist_t plist_array_get_item(plist_t node, uint32_t n) +{ + plist_t ret = NULL; + if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) + { + ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (pa) { + ret = (plist_t)ptr_array_index(pa, n); + } else { + ret = (plist_t)node_nth_child((node_t)node, n); + } + } + return ret; +} + +uint32_t plist_array_get_item_index(plist_t node) +{ + plist_t father = plist_get_parent(node); + if (PLIST_ARRAY == plist_get_node_type(father)) + { + return node_child_position((node_t)father, (node_t)node); + } + return UINT_MAX; +} + +static void _plist_array_post_insert(plist_t node, plist_t item, long n) +{ + ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (pa) { + /* store pointer to item in array */ + ptr_array_insert(pa, item, n); + } else { + if (((node_t)node)->count > 100) { + /* make new lookup array */ + pa = ptr_array_new(128); + plist_t current = NULL; + for (current = (plist_t)node_first_child((node_t)node); + pa && current; + current = (plist_t)node_next_sibling((node_t)current)) + { + ptr_array_add(pa, current); + } + ((plist_data_t)((node_t)node)->data)->hashtable = pa; + } + } +} + +void plist_array_set_item(plist_t node, plist_t item, uint32_t n) +{ + if (!item) { + return; + } + if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) + { + plist_t old_item = plist_array_get_item(node, n); + if (old_item) + { + int idx = plist_free_node((node_t)old_item); + assert(idx >= 0); + if (idx < 0) { + return; + } + node_insert((node_t)node, idx, (node_t)item); + ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (pa) { + ptr_array_set(pa, item, idx); + } + } + } +} + +void plist_array_append_item(plist_t node, plist_t item) +{ + if (!item) { + return; + } + if (node && PLIST_ARRAY == plist_get_node_type(node)) + { + node_attach((node_t)node, (node_t)item); + _plist_array_post_insert(node, item, -1); + } +} + +void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) +{ + if (!item) { + return; + } + if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) + { + node_insert((node_t)node, n, (node_t)item); + _plist_array_post_insert(node, item, (long)n); + } +} + +void plist_array_remove_item(plist_t node, uint32_t n) +{ + if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) + { + plist_t old_item = plist_array_get_item(node, n); + if (old_item) + { + ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (pa) { + ptr_array_remove(pa, n); + } + plist_free(old_item); + } + } +} + +void plist_array_item_remove(plist_t node) +{ + plist_t father = plist_get_parent(node); + if (PLIST_ARRAY == plist_get_node_type(father)) + { + int n = node_child_position((node_t)father, (node_t)node); + if (n < 0) return; + ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)father)->data)->hashtable; + if (pa) { + ptr_array_remove(pa, n); + } + plist_free(node); + } +} + +void plist_array_new_iter(plist_t node, plist_array_iter *iter) +{ + if (iter) + { + *iter = malloc(sizeof(node_t)); + *((node_t*)(*iter)) = node_first_child((node_t)node); + } +} + +void plist_array_next_item(plist_t node, plist_array_iter iter, plist_t *item) +{ + node_t* iter_node = (node_t*)iter; + + if (item) + { + *item = NULL; + } + + if (node && PLIST_ARRAY == plist_get_node_type(node) && *iter_node) + { + if (item) + { + *item = (plist_t)(*iter_node); + } + *iter_node = node_next_sibling(*iter_node); + } +} + +uint32_t plist_dict_get_size(plist_t node) +{ + uint32_t ret = 0; + if (node && PLIST_DICT == plist_get_node_type(node)) + { + ret = node_n_children((node_t)node) / 2; + } + return ret; +} + +void plist_dict_new_iter(plist_t node, plist_dict_iter *iter) +{ + if (iter) + { + *iter = malloc(sizeof(node_t)); + *((node_t*)(*iter)) = node_first_child((node_t)node); + } +} + +void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val) +{ + node_t* iter_node = (node_t*)iter; + + if (key) + { + *key = NULL; + } + if (val) + { + *val = NULL; + } + + if (node && PLIST_DICT == plist_get_node_type(node) && *iter_node) + { + if (key) + { + plist_get_key_val((plist_t)(*iter_node), key); + } + *iter_node = node_next_sibling(*iter_node); + if (val) + { + *val = (plist_t)(*iter_node); + } + *iter_node = node_next_sibling(*iter_node); + } +} + +void plist_dict_get_item_key(plist_t node, char **key) +{ + plist_t father = plist_get_parent(node); + if (PLIST_DICT == plist_get_node_type(father)) + { + plist_get_key_val( (plist_t) node_prev_sibling((node_t)node), key); + } +} + +plist_t plist_dict_item_get_key(plist_t node) +{ + plist_t ret = NULL; + plist_t father = plist_get_parent(node); + if (PLIST_DICT == plist_get_node_type(father)) + { + ret = (plist_t)node_prev_sibling((node_t)node); + } + return ret; +} + +plist_t plist_dict_get_item(plist_t node, const char* key) +{ + plist_t ret = NULL; + + if (node && PLIST_DICT == plist_get_node_type(node)) + { + plist_data_t data = plist_get_data(node); + hashtable_t *ht = (hashtable_t*)data->hashtable; + if (ht) { + struct plist_data_s sdata; + sdata.strval = (char*)key; + sdata.length = strlen(key); + ret = (plist_t)hash_table_lookup(ht, &sdata); + } else { + plist_t current = NULL; + for (current = (plist_t)node_first_child((node_t)node); + current; + current = (plist_t)node_next_sibling(node_next_sibling((node_t)current))) + { + data = plist_get_data(current); + assert( PLIST_KEY == plist_get_node_type(current) ); + + if (data && !strcmp(key, data->strval)) + { + ret = (plist_t)node_next_sibling((node_t)current); + break; + } + } + } + } + return ret; +} + +void plist_dict_set_item(plist_t node, const char* key, plist_t item) +{ + if (!item) { + return; + } + if (node && PLIST_DICT == plist_get_node_type(node)) { + plist_t old_item = plist_dict_get_item(node, key); + plist_t key_node = NULL; + if (old_item) { + int idx = plist_free_node((node_t)old_item); + assert(idx >= 0); + if (idx < 0) { + return; + } + node_insert((node_t)node, idx, (node_t)item); + key_node = node_prev_sibling((node_t)item); + } else { + key_node = plist_new_key(key); + node_attach((node_t)node, (node_t)key_node); + node_attach((node_t)node, (node_t)item); + } + + hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (ht) { + /* store pointer to item in hash table */ + hash_table_insert(ht, (plist_data_t)((node_t)key_node)->data, item); + } else { + if (((node_t)node)->count > 500) { + /* make new hash table */ + ht = hash_table_new(dict_key_hash, dict_key_compare, NULL); + /* calculate the hashes for all entries we have so far */ + plist_t current = NULL; + for (current = (plist_t)node_first_child((node_t)node); + ht && current; + current = (plist_t)node_next_sibling(node_next_sibling((node_t)current))) + { + hash_table_insert(ht, ((node_t)current)->data, node_next_sibling((node_t)current)); + } + ((plist_data_t)((node_t)node)->data)->hashtable = ht; + } + } + } +} + +void plist_dict_remove_item(plist_t node, const char* key) +{ + if (node && PLIST_DICT == plist_get_node_type(node)) + { + plist_t old_item = plist_dict_get_item(node, key); + if (old_item) + { + plist_t key_node = node_prev_sibling((node_t)old_item); + hashtable_t* ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; + if (ht) { + hash_table_remove(ht, ((node_t)key_node)->data); + } + plist_free(key_node); + plist_free(old_item); + } + } +} + +void plist_dict_merge(plist_t *target, plist_t source) +{ + if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT)) + return; + + char* key = NULL; + plist_dict_iter it = NULL; + plist_t subnode = NULL; + plist_dict_new_iter(source, &it); + if (!it) + return; + + do { + plist_dict_next_item(source, it, &key, &subnode); + if (!key) + break; + + plist_dict_set_item(*target, key, plist_copy(subnode)); + free(key); + key = NULL; + } while (1); + free(it); +} + +static void plist_get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length) +{ + plist_data_t data = NULL; + + if (!node) + return; + + data = plist_get_data(node); + + *type = data->type; + *length = data->length; + + switch (*type) + { + case PLIST_BOOLEAN: + *((char *) value) = data->boolval; + break; + case PLIST_INT: + case PLIST_UID: + *((uint64_t *) value) = data->intval; + break; + case PLIST_REAL: + case PLIST_DATE: + *((double *) value) = data->realval; + break; + case PLIST_KEY: + case PLIST_STRING: + *((char **) value) = strdup(data->strval); + break; + case PLIST_DATA: + *((uint8_t **) value) = (uint8_t *) malloc(*length * sizeof(uint8_t)); + memcpy(*((uint8_t **) value), data->buff, *length * sizeof(uint8_t)); + break; + case PLIST_ARRAY: + case PLIST_DICT: + default: + break; + } +} + +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: + { + uint64_t temp = 0; + plist_get_type_and_value(node, NULL, &temp, NULL); + bval = (uint8_t)temp; + } + 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; + plist_type type = PLIST_NONE; + uint32_t i = 0; + + for (i = 0; i < length && current; i++) + { + type = plist_get_node_type(current); + + if (type == PLIST_ARRAY) + { + uint32_t n = va_arg(v, uint32_t); + current = plist_array_get_item(current, n); + } + else if (type == PLIST_DICT) + { + const char* key = va_arg(v, const char*); + current = plist_dict_get_item(current, key); + } + } + return current; +} + +plist_t plist_access_path(plist_t plist, uint32_t length, ...) +{ + plist_t ret = NULL; + va_list v; + + va_start(v, length); + ret = plist_access_pathv(plist, length, v); + va_end(v); + return ret; +} + +plist_t plist_get_parent(plist_t node) +{ + return node ? (plist_t) ((node_t) node)->parent : NULL; +} + +plist_type plist_get_node_type(plist_t node) +{ + if (node) + { + plist_data_t data = plist_get_data(node); + if (data) + return data->type; + } + return PLIST_NONE; +} + +void plist_get_key_val(plist_t node, char **val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_KEY != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + if (!*val) + return; + assert(length == strlen(*val)); +} + +void plist_get_string_val(plist_t node, char **val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_STRING != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + if (!*val) + return; + assert(length == strlen(*val)); +} + +const char* plist_get_string_ptr(plist_t node, uint64_t* length) +{ + if (!node) + return NULL; + plist_type type = plist_get_node_type(node); + if (PLIST_STRING != type) + return NULL; + plist_data_t data = plist_get_data(node); + if (length) + *length = data->length; + return (const char*)data->strval; +} + +void plist_get_bool_val(plist_t node, uint8_t * val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_BOOLEAN != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + assert(length == sizeof(uint8_t)); +} + +void plist_get_uint_val(plist_t node, uint64_t * val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_INT != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + assert(length == sizeof(uint64_t) || length == 16); +} + +void plist_get_int_val(plist_t node, int64_t * val) +{ + plist_get_uint_val(node, (uint64_t*)val); +} + +void plist_get_uid_val(plist_t node, uint64_t * val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_UID != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + assert(length == sizeof(uint64_t)); +} + +void plist_get_real_val(plist_t node, double *val) +{ + if (!node || !val) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + if (PLIST_REAL != type) + return; + plist_get_type_and_value(node, &type, (void *) val, &length); + assert(length == sizeof(double)); +} + +void plist_get_data_val(plist_t node, char **val, uint64_t * length) +{ + if (!node || !val || !length) + return; + plist_type type = plist_get_node_type(node); + if (PLIST_DATA != type) + return; + plist_get_type_and_value(node, &type, (void *) val, length); +} + +const char* plist_get_data_ptr(plist_t node, uint64_t* length) +{ + if (!node || !length) + return NULL; + plist_type type = plist_get_node_type(node); + if (PLIST_DATA != type) + return NULL; + plist_data_t data = plist_get_data(node); + *length = data->length; + return (const char*)data->buff; +} + +void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec) +{ + if (!node) + return; + plist_type type = plist_get_node_type(node); + uint64_t length = 0; + double val = 0; + if (PLIST_DATE != type) + return; + plist_get_type_and_value(node, &type, (void *) &val, &length); + assert(length == sizeof(double)); + if (sec) + *sec = (int32_t)val; + if (usec) + { + val = fabs((val - (int64_t)val) * 1000000); + *usec = (int32_t)val; + } +} + +int plist_data_compare(const void *a, const void *b) +{ + plist_data_t val_a = NULL; + plist_data_t val_b = NULL; + + if (!a || !b) + return FALSE; + + if (!((node_t) a)->data || !((node_t) b)->data) + return FALSE; + + val_a = plist_get_data((plist_t) a); + val_b = plist_get_data((plist_t) b); + + if (val_a->type != val_b->type) + return FALSE; + + switch (val_a->type) + { + case PLIST_BOOLEAN: + case PLIST_NULL: + case PLIST_INT: + case PLIST_REAL: + case PLIST_DATE: + case PLIST_UID: + if (val_a->length != val_b->length) + return FALSE; + return val_a->intval == val_b->intval; //it is an union so this is sufficient + + case PLIST_KEY: + case PLIST_STRING: + return strcmp(val_a->strval, val_b->strval) == 0; + + case PLIST_DATA: + if (val_a->length != val_b->length) + return FALSE; + return memcmp(val_a->buff, val_b->buff, val_a->length) == 0; + + case PLIST_ARRAY: + case PLIST_DICT: + //compare pointer + return a == b; + + default: + break; + } + return FALSE; +} + +char plist_compare_node_value(plist_t node_l, plist_t node_r) +{ + return plist_data_compare(node_l, node_r); +} + +static void plist_set_element_val(plist_t node, plist_type type, const void *value, uint64_t length) +{ + //free previous allocated buffer + plist_data_t data = plist_get_data(node); + assert(data); // a node should always have data attached + + switch (data->type) + { + case PLIST_KEY: + case PLIST_STRING: + free(data->strval); + data->strval = NULL; + break; + case PLIST_DATA: + free(data->buff); + data->buff = NULL; + break; + default: + break; + } + + //now handle value + + data->type = type; + data->length = length; + + switch (type) + { + case PLIST_BOOLEAN: + data->boolval = *((char *) value); + break; + case PLIST_INT: + case PLIST_UID: + data->intval = *((uint64_t *) value); + break; + case PLIST_REAL: + case PLIST_DATE: + data->realval = *((double *) value); + break; + case PLIST_KEY: + case PLIST_STRING: + data->strval = strdup((char *) value); + break; + case PLIST_DATA: + data->buff = (uint8_t *) malloc(length); + memcpy(data->buff, value, length); + break; + case PLIST_ARRAY: + case PLIST_DICT: + default: + break; + } +} + +void plist_set_key_val(plist_t node, const char *val) +{ + plist_t father = plist_get_parent(node); + plist_t item = plist_dict_get_item(father, val); + if (item) { + return; + } + plist_set_element_val(node, PLIST_KEY, val, strlen(val)); +} + +void plist_set_string_val(plist_t node, const char *val) +{ + plist_set_element_val(node, PLIST_STRING, val, strlen(val)); +} + +void plist_set_bool_val(plist_t node, uint8_t val) +{ + plist_set_element_val(node, PLIST_BOOLEAN, &val, sizeof(uint8_t)); +} + +void plist_set_uint_val(plist_t node, uint64_t val) +{ + plist_set_element_val(node, PLIST_INT, &val, (val > INT64_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t)); +} + +void plist_set_int_val(plist_t node, int64_t val) +{ + plist_set_element_val(node, PLIST_INT, &val, sizeof(uint64_t)); +} + +void plist_set_uid_val(plist_t node, uint64_t val) +{ + plist_set_element_val(node, PLIST_UID, &val, sizeof(uint64_t)); +} + +void plist_set_real_val(plist_t node, double val) +{ + plist_set_element_val(node, PLIST_REAL, &val, sizeof(double)); +} + +void plist_set_data_val(plist_t node, const char *val, uint64_t length) +{ + plist_set_element_val(node, PLIST_DATA, val, length); +} + +void plist_set_date_val(plist_t node, int32_t sec, int32_t usec) +{ + double val = (double)sec + (double)usec / 1000000; + plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval)); +} + +int plist_bool_val_is_true(plist_t boolnode) +{ + if (!PLIST_IS_BOOLEAN(boolnode)) { + return 0; + } + uint8_t bv = 0; + plist_get_bool_val(boolnode, &bv); + return (bv == 1); +} + +int plist_int_val_is_negative(plist_t intnode) +{ + if (!PLIST_IS_INT(intnode)) { + return 0; + } + plist_data_t data = plist_get_data(intnode); + if (data->length == 16) { + return 0; + } + if ((int64_t)data->intval < 0) { + return 1; + } + return 0; +} + +int plist_int_val_compare(plist_t uintnode, int64_t cmpval) +{ + if (!PLIST_IS_INT(uintnode)) { + return -1; + } + int64_t uintval = 0; + plist_get_int_val(uintnode, &uintval); + if (uintval == cmpval) { + return 0; + } + + if (uintval < cmpval) { + return -1; + } + + return 1; +} + +int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval) +{ + if (!PLIST_IS_INT(uintnode)) { + return -1; + } + uint64_t uintval = 0; + plist_get_uint_val(uintnode, &uintval); + if (uintval == cmpval) { + return 0; + } + + if (uintval < cmpval) { + return -1; + } + + return 1; +} + +int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval) +{ + if (!PLIST_IS_UID(uidnode)) { + return -1; + } + uint64_t uidval = 0; + plist_get_uid_val(uidnode, &uidval); + if (uidval == cmpval) { + return 0; + } + + if (uidval < cmpval) { + return -1; + } + + return 1; +} + +int plist_real_val_compare(plist_t realnode, double cmpval) +{ + if (!PLIST_IS_REAL(realnode)) { + return -1; + } + double a = 0; + double b = cmpval; + plist_get_real_val(realnode, &a); + double abs_a = fabs(a); + double abs_b = fabs(b); + double diff = fabs(a - b); + if (a == b) { + return 0; + } + + if (a == 0 || b == 0 || (abs_a + abs_b < DBL_MIN)) { + if (diff < (DBL_EPSILON * DBL_MIN)) { + return 0; + } + + if (a < b) { + return -1; + } + } else { + if ((diff / fmin(abs_a + abs_b, DBL_MAX)) < DBL_EPSILON) { + return 0; + } + + if (a < b) { + return -1; + } + } + return 1; +} + +int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec) +{ + if (!PLIST_IS_DATE(datenode)) { + return -1; + } + int32_t sec = 0; + int32_t usec = 0; + plist_get_date_val(datenode, &sec, &usec); + uint64_t dateval = ((int64_t)sec << 32) | usec; + uint64_t cmpval = ((int64_t)cmpsec << 32) | cmpusec; + if (dateval == cmpval) { + return 0; + } + + if (dateval < cmpval) { + return -1; + } + + return 1; +} + +int plist_string_val_compare(plist_t strnode, const char* cmpval) +{ + if (!PLIST_IS_STRING(strnode)) { + return -1; + } + plist_data_t data = plist_get_data(strnode); + return strcmp(data->strval, cmpval); +} + +int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n) +{ + if (!PLIST_IS_STRING(strnode)) { + return -1; + } + plist_data_t data = plist_get_data(strnode); + return strncmp(data->strval, cmpval, n); +} + +int plist_string_val_contains(plist_t strnode, const char* substr) +{ + if (!PLIST_IS_STRING(strnode)) { + return 0; + } + plist_data_t data = plist_get_data(strnode); + return (strstr(data->strval, substr) != NULL); +} + +int plist_key_val_compare(plist_t keynode, const char* cmpval) +{ + if (!PLIST_IS_KEY(keynode)) { + return -1; + } + plist_data_t data = plist_get_data(keynode); + return strcmp(data->strval, cmpval); +} + +int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n) +{ + if (!PLIST_IS_KEY(keynode)) { + return -1; + } + plist_data_t data = plist_get_data(keynode); + return strncmp(data->strval, cmpval, n); +} + +int plist_key_val_contains(plist_t keynode, const char* substr) +{ + if (!PLIST_IS_KEY(keynode)) { + return 0; + } + plist_data_t data = plist_get_data(keynode); + return (strstr(data->strval, substr) != NULL); +} + +int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n) +{ + if (!PLIST_IS_DATA(datanode)) { + return -1; + } + plist_data_t data = plist_get_data(datanode); + if (data->length < n) { + return -1; + } + + if (data->length > n) { + return 1; + } + + return memcmp(data->buff, cmpval, n); +} + +int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n) +{ + if (!PLIST_IS_DATA(datanode)) { + return -1; + } + plist_data_t data = plist_get_data(datanode); + if (data->length < n) { + return -1; + } + return memcmp(data->buff, cmpval, n); +} + +int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n) +{ + if (!PLIST_IS_DATA(datanode)) { + return -1; + } + plist_data_t data = plist_get_data(datanode); + return (memmem(data->buff, data->length, cmpval, n) != NULL); +} + +extern void plist_xml_set_debug(int debug); +extern void plist_bin_set_debug(int debug); +extern void plist_json_set_debug(int debug); +extern void plist_ostep_set_debug(int debug); + +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); + plist_ostep_set_debug(debug); +} + +void plist_sort(plist_t plist) +{ + if (!plist) { + return; + } + if (PLIST_IS_ARRAY(plist)) { + uint32_t n = plist_array_get_size(plist); + uint32_t i = 0; + for (i = 0; i < n; i++) { + plist_sort(plist_array_get_item(plist, i)); + } + } else if (PLIST_IS_DICT(plist)) { + node_t node = (node_t)plist; + node_t ch; + if (!node_first_child(node)) { + return; + } + for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { + ch = node_next_sibling(ch); + plist_sort((plist_t)ch); + } + #define KEY_DATA(x) (x->data) + #define NEXT_KEY(x) (x->next->next) + #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval + int swapped = 0; + do { + swapped = 0; + node_t lptr = NULL; + node_t cur_key = node_first_child((node_t)plist); + + while (NEXT_KEY(cur_key) != lptr) { + node_t next_key = NEXT_KEY(cur_key); + if (strcmp(KEY_STRVAL(cur_key), KEY_STRVAL(next_key)) > 0) { + node_t cur_val = cur_key->next; + node_t next_val = next_key->next; + // we need to swap 2 consecutive nodes with the 2 after them + // a -> b -> [c] -> [d] -> [e] -> [f] -> g -> h + // cur next + // swapped: + // a -> b -> [e] -> [f] -> [c] -> [d] -> g -> h + // next cur + node_t tmp_prev = cur_key->prev; + node_t tmp_next = next_val->next; + cur_key->prev = next_val; + cur_val->next = tmp_next; + next_val->next = cur_key; + next_key->prev = tmp_prev; + if (tmp_prev) { + tmp_prev->next = next_key; + } else { + ((node_t)plist)->children->begin = next_key; + } + if (tmp_next) { + tmp_next->prev = cur_val; + } else { + ((node_t)plist)->children->end = cur_val; + } + cur_key = next_key; + swapped = 1; + } + cur_key = NEXT_KEY(cur_key); + } + lptr = cur_key; + } while (swapped); + } +} + +plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length, plist_format_t format, plist_write_options_t options) +{ + plist_err_t err = PLIST_ERR_UNKNOWN; + switch (format) { + case PLIST_FORMAT_XML: + err = plist_to_xml(plist, output, length); + break; + case PLIST_FORMAT_JSON: + err = plist_to_json(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0)); + break; + case PLIST_FORMAT_OSTEP: + err = plist_to_openstep(plist, output, length, ((options & PLIST_OPT_COMPACT) == 0)); + break; + case PLIST_FORMAT_PRINT: + err = plist_write_to_string_default(plist, output, length, options); + break; + case PLIST_FORMAT_LIMD: + err = plist_write_to_string_limd(plist, output, length, options); + break; + case PLIST_FORMAT_PLUTIL: + err = plist_write_to_string_plutil(plist, output, length, options); + break; + default: + // unsupported output format + err = PLIST_ERR_FORMAT; + break; + } + return err; +} + +plist_err_t plist_write_to_stream(plist_t plist, FILE *stream, plist_format_t format, plist_write_options_t options) +{ + if (!plist || !stream) { + return PLIST_ERR_INVALID_ARG; + } + plist_err_t err = PLIST_ERR_UNKNOWN; + char *output = NULL; + uint32_t length = 0; + switch (format) { + case PLIST_FORMAT_BINARY: + err = plist_to_bin(plist, &output, &length); + break; + case PLIST_FORMAT_XML: + err = plist_to_xml(plist, &output, &length); + break; + case PLIST_FORMAT_JSON: + err = plist_to_json(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0)); + break; + case PLIST_FORMAT_OSTEP: + err = plist_to_openstep(plist, &output, &length, ((options & PLIST_OPT_COMPACT) == 0)); + break; + case PLIST_FORMAT_PRINT: + err = plist_write_to_stream_default(plist, stream, options); + break; + case PLIST_FORMAT_LIMD: + err = plist_write_to_stream_limd(plist, stream, options); + break; + case PLIST_FORMAT_PLUTIL: + err = plist_write_to_stream_plutil(plist, stream, options); + break; + default: + // unsupported output format + err = PLIST_ERR_FORMAT; + break; + } + if (output && err == PLIST_ERR_SUCCESS) { + if (fwrite(output, 1, length, stream) < length) { + err = PLIST_ERR_IO; + } + free(output); + } + return err; +} + +plist_err_t plist_write_to_file(plist_t plist, const char* filename, plist_format_t format, plist_write_options_t options) +{ + if (!plist || !filename) { + return PLIST_ERR_INVALID_ARG; + } + FILE* f = fopen(filename, "wb"); + if (!f) { + return PLIST_ERR_IO; + } + plist_err_t err = plist_write_to_stream(plist, f, format, options); + fclose(f); + return err; +} + +void plist_print(plist_t plist) +{ + plist_write_to_stream(plist, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_PARTIAL_DATA); +} + +const char* libplist_version() +{ +#ifndef PACKAGE_VERSION +#error PACKAGE_VERSION is not defined! +#endif + return PACKAGE_VERSION; +} + + diff --git a/vmax2bella.cpp b/vmax2bella.cpp index 8dc039a..4193744 100644 --- a/vmax2bella.cpp +++ b/vmax2bella.cpp @@ -591,6 +591,7 @@ dl::bella_sdk::Node addModelToScene(dl::Args& args, canonicalName + dl::String("vmaxMat") + dl::String(material) + dl::String("Color") + dl::String(color)); bool isMesh = false; bool isBox = true; + std::cout << vmaxMaterial[material].roughness << std::endl; if(material==7) { belMaterial["type"] = "liquid"; @@ -601,8 +602,8 @@ dl::bella_sdk::Node addModelToScene(dl::Args& args, isBox = false; } else if(material==6 || vmaxPalette[color-1].a < 255) { belMaterial["type"] = "glass"; - belMaterial["roughness"] = vmaxMaterial[material].roughness * 100.0f; - belMaterial["glassDepth"] = 500.0f; + belMaterial["roughness"] = vmaxMaterial[material].roughness/.9f * 100.0f; + belMaterial["glassDepth"] = 1500.0f; } else if(vmaxMaterial[material].metalness > 0.1f) { belMaterial["type"] = "metal"; belMaterial["roughness"] = vmaxMaterial[material].roughness * 100.0f; @@ -613,12 +614,14 @@ dl::bella_sdk::Node addModelToScene(dl::Args& args, belMaterial["type"] = "emitter"; belMaterial["emitterUnit"] = "radiance"; belMaterial["energy"] = vmaxMaterial[material].emission*1.0f; + } else if(vmaxMaterial[material].roughness > 0.8999f) { + belMaterial["type"] = "diffuse"; } else { belMaterial["type"] = "plastic"; belMaterial["roughness"] = vmaxMaterial[material].roughness * 100.0f; } - if (args.have("bevel")) { + if (args.have("bevel") && material != 7) { belMaterial["bevel"] = belBevel; } if (args.have("mode") && args.value("mode") == "mesh" || args.value("mode") == "both") {