summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Array.cpp51
-rw-r--r--src/Boolean.cpp2
-rw-r--r--src/Data.cpp13
-rw-r--r--src/Date.cpp24
-rw-r--r--src/Dictionary.cpp10
-rw-r--r--src/Integer.cpp5
-rw-r--r--src/Key.cpp4
-rw-r--r--src/Node.cpp2
-rw-r--r--src/Real.cpp2
-rw-r--r--src/String.cpp25
-rw-r--r--src/Structure.cpp27
-rw-r--r--src/Uid.cpp2
-rw-r--r--src/base64.c2
-rw-r--r--src/bplist.c195
-rw-r--r--src/hashtable.c10
-rw-r--r--src/hashtable.h2
-rw-r--r--src/jplist.c81
-rw-r--r--src/oplist.c98
-rw-r--r--src/out-default.c34
-rw-r--r--src/out-limd.c34
-rw-r--r--src/out-plutil.c34
-rw-r--r--src/plist.c442
-rw-r--r--src/plist.h17
-rw-r--r--src/time64.c1
-rw-r--r--src/xplist.c151
25 files changed, 986 insertions, 282 deletions
diff --git a/src/Array.cpp b/src/Array.cpp
index bc448d3..784df7c 100644
--- a/src/Array.cpp
+++ b/src/Array.cpp
@@ -40,7 +40,9 @@ static void array_fill(Array *_this, std::vector<Node*> &array, plist_t node)
do {
subnode = NULL;
plist_array_next_item(node, iter, &subnode);
- array.push_back( Node::FromPlist(subnode, _this) );
+ if (subnode) {
+ array.push_back( Node::FromPlist(subnode, _this) );
+ }
} while (subnode);
free(iter);
}
@@ -51,7 +53,7 @@ Array::Array(plist_t node, Node* parent) : Structure(parent)
array_fill(this, _array, _node);
}
-Array::Array(const PList::Array& a)
+Array::Array(const PList::Array& a) : Structure(a.GetParent())
{
_array.clear();
_node = plist_copy(a.GetPlist());
@@ -60,6 +62,8 @@ Array::Array(const PList::Array& a)
Array& Array::operator=(const PList::Array& a)
{
+ if (this == &a) return *this;
+
plist_free(_node);
for (size_t it = 0; it < _array.size(); it++) {
delete _array.at(it);
@@ -88,6 +92,26 @@ Node* Array::operator[](unsigned int array_index)
return _array.at(array_index);
}
+Node* Array::Back()
+{
+ return _array.back();
+}
+
+Node* Array::back()
+{
+ return _array.back();
+}
+
+Node* Array::Front()
+{
+ return _array.front();
+}
+
+Node* Array::front()
+{
+ return _array.front();
+}
+
Array::iterator Array::Begin()
{
return _array.begin();
@@ -132,7 +156,7 @@ size_t Array::size() const {
return _array.size();
}
-void Array::Append(Node* node)
+void Array::Append(const Node* node)
{
if (node)
{
@@ -143,7 +167,12 @@ void Array::Append(Node* node)
}
}
-void Array::Insert(Node* node, unsigned int pos)
+void Array::Append(const Node& node)
+{
+ Append(&node);
+}
+
+void Array::Insert(const Node* node, unsigned int pos)
{
if (node)
{
@@ -156,6 +185,11 @@ void Array::Insert(Node* node, unsigned int pos)
}
}
+void Array::Insert(const Node &node, unsigned int pos)
+{
+ Insert(&node, pos);
+}
+
void Array::Remove(Node* node)
{
if (node)
@@ -168,7 +202,7 @@ void Array::Remove(Node* node)
std::vector<Node*>::iterator it = _array.begin();
it += pos;
_array.erase(it);
- delete node;
+ free(node);
}
}
@@ -181,10 +215,15 @@ void Array::Remove(unsigned int pos)
_array.erase(it);
}
-unsigned int Array::GetNodeIndex(Node* node) const
+unsigned int Array::GetNodeIndex(const Node* node) const
{
std::vector<Node*>::const_iterator it = std::find(_array.begin(), _array.end(), node);
return std::distance (_array.begin(), it);
}
+unsigned int Array::GetNodeIndex(const Node& node) const
+{
+ return GetNodeIndex(&node);
+}
+
} // namespace PList
diff --git a/src/Boolean.cpp b/src/Boolean.cpp
index 9ec1a63..2a5e303 100644
--- a/src/Boolean.cpp
+++ b/src/Boolean.cpp
@@ -40,6 +40,8 @@ Boolean::Boolean(const PList::Boolean& b) : Node(PLIST_BOOLEAN)
Boolean& Boolean::operator=(const PList::Boolean& b)
{
+ if (this == &b) return *this;
+
plist_free(_node);
_node = plist_copy(b.GetPlist());
return *this;
diff --git a/src/Data.cpp b/src/Data.cpp
index a96fc50..94767c9 100644
--- a/src/Data.cpp
+++ b/src/Data.cpp
@@ -40,6 +40,8 @@ Data::Data(const PList::Data& d) : Node(PLIST_DATA)
Data& Data::operator=(const PList::Data& b)
{
+ if (this == &b) return *this;
+
plist_free(_node);
_node = plist_copy(b.GetPlist());
return *this;
@@ -50,6 +52,11 @@ Data::Data(const std::vector<char>& buff) : Node(PLIST_DATA)
plist_set_data_val(_node, &buff[0], buff.size());
}
+Data::Data(const char* buff, uint64_t size) : Node(PLIST_DATA)
+{
+ plist_set_data_val(_node, buff, size);
+}
+
Data::~Data()
{
}
@@ -66,14 +73,10 @@ void Data::SetValue(const std::vector<char>& buff)
std::vector<char> Data::GetValue() const
{
- char* buff = NULL;
uint64_t length = 0;
- plist_get_data_val(_node, &buff, &length);
+ const char* buff = plist_get_data_ptr(_node, &length);
std::vector<char> ret(buff, buff + length);
- delete buff;
return ret;
}
-
-
} // namespace PList
diff --git a/src/Date.cpp b/src/Date.cpp
index 8b8e650..214220b 100644
--- a/src/Date.cpp
+++ b/src/Date.cpp
@@ -34,20 +34,22 @@ Date::Date(plist_t node, Node* parent) : Node(node, parent)
Date::Date(const PList::Date& d) : Node(PLIST_DATE)
{
- timeval t = d.GetValue();
- plist_set_date_val(_node, t.tv_sec, t.tv_usec);
+ int64_t t = d.GetValue();
+ plist_set_unix_date_val(_node, t);
}
Date& Date::operator=(const PList::Date& d)
{
+ if (this == &d) return *this;
+
plist_free(_node);
_node = plist_copy(d.GetPlist());
return *this;
}
-Date::Date(timeval t) : Node(PLIST_DATE)
+Date::Date(int64_t t) : Node(PLIST_DATE)
{
- plist_set_date_val(_node, t.tv_sec, t.tv_usec);
+ plist_set_unix_date_val(_node, t);
}
Date::~Date()
@@ -59,18 +61,16 @@ Node* Date::Clone() const
return new Date(*this);
}
-void Date::SetValue(timeval t)
+void Date::SetValue(int64_t t)
{
- plist_set_date_val(_node, t.tv_sec, t.tv_usec);
+ plist_set_unix_date_val(_node, t);
}
-timeval Date::GetValue() const
+int64_t Date::GetValue() const
{
- int32_t tv_sec = 0;
- int32_t tv_usec = 0;
- plist_get_date_val(_node, &tv_sec, &tv_usec);
- timeval t = {tv_sec, tv_usec};
- return t;
+ int64_t sec = 0;
+ plist_get_unix_date_val(_node, &sec);
+ return sec;
}
} // namespace PList
diff --git a/src/Dictionary.cpp b/src/Dictionary.cpp
index 30c20b6..b354945 100644
--- a/src/Dictionary.cpp
+++ b/src/Dictionary.cpp
@@ -40,7 +40,7 @@ static void dictionary_fill(Dictionary *_this, std::map<std::string,Node*> &map,
plist_dict_next_item(node, it, &key, &subnode);
if (key && subnode)
map[std::string(key)] = Node::FromPlist(subnode, _this);
- delete key;
+ free(key);
} while (subnode);
free(it);
}
@@ -51,7 +51,7 @@ Dictionary::Dictionary(plist_t node, Node* parent) : Structure(parent)
dictionary_fill(this, _map, _node);
}
-Dictionary::Dictionary(const PList::Dictionary& d)
+Dictionary::Dictionary(const PList::Dictionary& d) : Structure(d.GetParent())
{
for (Dictionary::iterator it = _map.begin(); it != _map.end(); it++)
{
@@ -65,6 +65,8 @@ Dictionary::Dictionary(const PList::Dictionary& d)
Dictionary& Dictionary::operator=(const PList::Dictionary& d)
{
+ if (this == &d) return *this;
+
for (Dictionary::iterator it = _map.begin(); it != _map.end(); it++)
{
plist_free(it->second->GetPlist());
@@ -176,9 +178,9 @@ void Dictionary::Remove(Node* node)
plist_dict_get_item_key(node->GetPlist(), &key);
plist_dict_remove_item(_node, key);
std::string skey = key;
- delete key;
+ free(key);
_map.erase(skey);
- delete node;
+ free(node);
}
}
diff --git a/src/Integer.cpp b/src/Integer.cpp
index 30a5405..26e7ccf 100644
--- a/src/Integer.cpp
+++ b/src/Integer.cpp
@@ -35,11 +35,14 @@ Integer::Integer(plist_t node, Node* parent) : Node(node, parent)
Integer::Integer(const PList::Integer& i) : Node(PLIST_INT)
{
- plist_set_uint_val(_node, i.GetValue());
+ plist_free(_node);
+ _node = plist_copy(i.GetPlist());
}
Integer& Integer::operator=(const PList::Integer& i)
{
+ if (this == &i) return *this;
+
plist_free(_node);
_node = plist_copy(i.GetPlist());
return *this;
diff --git a/src/Key.cpp b/src/Key.cpp
index 79265d5..459227a 100644
--- a/src/Key.cpp
+++ b/src/Key.cpp
@@ -40,6 +40,8 @@ Key::Key(const PList::Key& k) : Node(PLIST_INT)
Key& Key::operator=(const PList::Key& k)
{
+ if (this == &k) return *this;
+
plist_free(_node);
_node = plist_copy(k.GetPlist());
return *this;
@@ -69,7 +71,7 @@ std::string Key::GetValue() const
char* s = NULL;
plist_get_key_val(_node, &s);
std::string ret = s ? s : "";
- delete s;
+ free(s);
return ret;
}
diff --git a/src/Node.cpp b/src/Node.cpp
index 0bd428a..1043b31 100644
--- a/src/Node.cpp
+++ b/src/Node.cpp
@@ -73,7 +73,7 @@ Node::Node(plist_type type, Node* parent) : _parent(parent)
_node = plist_new_data(NULL,0);
break;
case PLIST_DATE:
- _node = plist_new_date(0,0);
+ _node = plist_new_unix_date(0);
break;
case PLIST_ARRAY:
_node = plist_new_array();
diff --git a/src/Real.cpp b/src/Real.cpp
index 02d1d9b..b743ab5 100644
--- a/src/Real.cpp
+++ b/src/Real.cpp
@@ -39,6 +39,8 @@ Real::Real(const PList::Real& d) : Node(PLIST_INT)
Real& Real::operator=(const PList::Real& d)
{
+ if (this == &d) return *this;
+
plist_free(_node);
_node = plist_copy(d.GetPlist());
return *this;
diff --git a/src/String.cpp b/src/String.cpp
index 2ddc28b..bcd5e2e 100644
--- a/src/String.cpp
+++ b/src/String.cpp
@@ -40,16 +40,37 @@ String::String(const PList::String& s) : Node(PLIST_INT)
String& String::operator=(const PList::String& s)
{
+ if (this == &s) return *this;
+
plist_free(_node);
_node = plist_copy(s.GetPlist());
return *this;
}
+String& String::operator=(const std::string& s)
+{
+ plist_free(_node);
+ _node = plist_new_string(s.c_str());
+ return *this;
+}
+
+String& String::operator=(const char* s)
+{
+ plist_free(_node);
+ _node = plist_new_string(s);
+ return *this;
+}
+
String::String(const std::string& s) : Node(PLIST_STRING)
{
plist_set_string_val(_node, s.c_str());
}
+String::String(const char *s) : Node(PLIST_STRING)
+{
+ plist_set_string_val(_node, s);
+}
+
String::~String()
{
}
@@ -66,10 +87,8 @@ void String::SetValue(const std::string& s)
std::string String::GetValue() const
{
- char* s = NULL;
- plist_get_string_val(_node, &s);
+ const char* s = plist_get_string_ptr(_node, NULL);
std::string ret = s ? s : "";
- delete s;
return ret;
}
diff --git a/src/Structure.cpp b/src/Structure.cpp
index 670cce6..65e5ca8 100644
--- a/src/Structure.cpp
+++ b/src/Structure.cpp
@@ -57,7 +57,7 @@ std::string Structure::ToXml() const
uint32_t length = 0;
plist_to_xml(_node, &xml, &length);
std::string ret(xml, xml+length);
- delete xml;
+ free(xml);
return ret;
}
@@ -67,7 +67,7 @@ std::vector<char> Structure::ToBin() const
uint32_t length = 0;
plist_to_bin(_node, &bin, &length);
std::vector<char> ret(bin, bin+length);
- delete bin;
+ free(bin);
return ret;
}
@@ -77,7 +77,7 @@ void Structure::UpdateNodeParent(Node* node)
if ( NULL != node->_parent )
{
plist_type type = plist_get_node_type(node->_parent);
- if (PLIST_ARRAY ==type || PLIST_DICT == type )
+ if (PLIST_ARRAY == type || PLIST_DICT == type)
{
Structure* s = static_cast<Structure*>(node->_parent);
s->Remove(node);
@@ -117,8 +117,27 @@ Structure* Structure::FromBin(const std::vector<char>& bin)
plist_from_bin(&bin[0], bin.size(), &root);
return ImportStruct(root);
+}
+
+Structure* Structure::FromBin(const char* bin, uint64_t size)
+{
+ plist_t root = NULL;
+ plist_from_bin(bin, size, &root);
+ return ImportStruct(root);
}
-} // namespace PList
+Structure* Structure::FromMemory(const std::vector<char>& buf, plist_format_t *format)
+{
+ return Structure::FromMemory(&buf[0], buf.size(), format);
+}
+Structure* Structure::FromMemory(const char* buf, uint64_t size, plist_format_t *format)
+{
+ plist_t root = NULL;
+ plist_from_memory(buf, size, &root, format);
+ return ImportStruct(root);
+}
+
+
+} // namespace PList
diff --git a/src/Uid.cpp b/src/Uid.cpp
index 8c73c80..d73f777 100644
--- a/src/Uid.cpp
+++ b/src/Uid.cpp
@@ -40,6 +40,8 @@ Uid::Uid(const PList::Uid& i) : Node(PLIST_UID)
Uid& Uid::operator=(const PList::Uid& i)
{
+ if (this == &i) return *this;
+
plist_free(_node);
_node = plist_copy(i.GetPlist());
return *this;
diff --git a/src/base64.c b/src/base64.c
index ee02356..76990b9 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -78,7 +78,7 @@ unsigned char *base64decode(const char *buf, size_t *size)
if (len <= 0) return NULL;
unsigned char *outbuf = (unsigned char*)malloc((len/4)*3+3);
const char *ptr = buf;
- int p = 0;
+ size_t p = 0;
int wv, w1, w2, w3, w4;
int tmpval[4];
int tmpcnt = 0;
diff --git a/src/bplist.c b/src/bplist.c
index 93f0bc6..8d50f2e 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -87,6 +87,28 @@ union plist_uint_ptr
uint64_t *u64ptr;
};
+#ifdef _MSC_VER
+uint64_t get_unaligned_64(uint64_t *ptr)
+{
+ uint64_t temp;
+ memcpy(&temp, ptr, sizeof(temp));
+ return temp;
+}
+
+uint32_t get_unaligned_32(uint32_t *ptr)
+{
+ uint32_t temp;
+ memcpy(&temp, ptr, sizeof(temp));
+ return temp;
+}
+
+uint16_t get_unaligned_16(uint16_t *ptr)
+{
+ uint16_t temp;
+ memcpy(&temp, ptr, sizeof(temp));
+ return temp;
+}
+#else
#define get_unaligned(ptr) \
({ \
struct __attribute__((packed)) { \
@@ -94,6 +116,7 @@ union plist_uint_ptr
} *__p = (void *) (ptr); \
__p->__v; \
})
+#endif
#ifndef bswap16
@@ -148,17 +171,31 @@ union plist_uint_ptr
#define beNtoh(x,n) be64toh((x) << ((8-(n)) << 3))
#endif
+#ifdef _MSC_VER
+static uint64_t UINT_TO_HOST(const void* x, uint8_t n)
+{
+ union plist_uint_ptr __up;
+ __up.src = (n > 8) ? (const char*)x + (n - 8) : (const char*)x;
+ return (n >= 8 ? be64toh( get_unaligned_64(__up.u64ptr) ) :
+ (n == 4 ? be32toh( get_unaligned_32(__up.u32ptr) ) :
+ (n == 2 ? be16toh( get_unaligned_16(__up.u16ptr) ) :
+ (n == 1 ? *__up.u8ptr :
+ beNtoh( get_unaligned_64(__up.u64ptr), n)
+ ))));
+}
+#else
#define UINT_TO_HOST(x, n) \
({ \
union plist_uint_ptr __up; \
- __up.src = ((n) > 8) ? (x) + ((n) - 8) : (x); \
+ __up.src = ((n) > 8) ? (const char*)(x) + ((n) - 8) : (const char*)(x); \
((n) >= 8 ? be64toh( get_unaligned(__up.u64ptr) ) : \
((n) == 4 ? be32toh( get_unaligned(__up.u32ptr) ) : \
((n) == 2 ? be16toh( get_unaligned(__up.u16ptr) ) : \
- ((n) == 1 ? *__up.u8ptr : \
+ ((n) == 1 ? *__up.u8ptr : \
beNtoh( get_unaligned(__up.u64ptr), n) \
)))); \
})
+#endif
#define get_needed_bytes(x) \
( ((uint64_t)(x)) < (1ULL << 8) ? 1 : \
@@ -168,15 +205,13 @@ union plist_uint_ptr
#define get_real_bytes(x) ((x) == (float) (x) ? sizeof(float) : sizeof(double))
-#if (defined(__LITTLE_ENDIAN__) \
- && !defined(__FLOAT_WORD_ORDER__)) \
- || (defined(__FLOAT_WORD_ORDER__) \
- && __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#define float_bswap64(x) bswap64(x)
-#define float_bswap32(x) bswap32(x)
-#else
+#if (defined(__BIG_ENDIAN__) && !defined(__FLOAT_WORD_ORDER__)) \
+ || (defined(__FLOAT_WORD_ORDER__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
#define float_bswap64(x) (x)
#define float_bswap32(x) (x)
+#else
+#define float_bswap64(x) bswap64(x)
+#define float_bswap32(x) bswap32(x)
#endif
#ifndef __has_builtin
@@ -204,13 +239,16 @@ struct bplist_data {
const char* offset_table;
uint32_t level;
ptrarray_t* used_indexes;
+ plist_err_t err;
};
#ifdef DEBUG
static int plist_bin_debug = 0;
#define PLIST_BIN_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binparser] ERROR: " __VA_ARGS__); }
+#define PLIST_BIN_WRITE_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binwriter] ERROR: " __VA_ARGS__); }
#else
#define PLIST_BIN_ERR(...)
+#define PLIST_BIN_WRITE_ERR(...)
#endif
void plist_bin_init(void)
@@ -271,19 +309,30 @@ static plist_t parse_int_node(const char **bnode, uint8_t size)
static plist_t parse_real_node(const char **bnode, uint8_t size)
{
plist_data_t data = plist_new_plist_data();
- uint8_t buf[8];
size = 1 << size; // make length less misleading
switch (size)
{
case sizeof(uint32_t):
- *(uint32_t*)buf = float_bswap32(get_unaligned((uint32_t*)*bnode));
- data->realval = *(float *) buf;
- break;
+ {
+ uint32_t ival;
+ memcpy(&ival, *bnode, sizeof(uint32_t));
+ ival = float_bswap32(ival);
+ float fval;
+ memcpy(&fval, &ival, sizeof(float));
+ data->realval = fval;
+ }
+ break;
+
case sizeof(uint64_t):
- *(uint64_t*)buf = float_bswap64(get_unaligned((uint64_t*)*bnode));
- data->realval = *(double *) buf;
+ {
+ uint64_t ival;
+ memcpy(&ival, *bnode, sizeof(uint64_t));
+ ival = float_bswap64(ival);
+ memcpy(&data->realval, &ival, sizeof(double));
break;
+ }
+
default:
free(data);
PLIST_BIN_ERR("%s: Invalid byte size for real node\n", __func__);
@@ -323,13 +372,13 @@ static plist_t parse_string_node(const char **bnode, uint64_t size)
return node_create(NULL, data);
}
-static char *plist_utf16be_to_utf8(uint16_t *unistr, long len, long *items_read, long *items_written)
+static char *plist_utf16be_to_utf8(uint16_t *unistr, size_t len, size_t *items_read, size_t *items_written)
{
if (!unistr || (len <= 0)) return NULL;
char* outbuf;
char* outbuf_new;
- int p = 0;
- long i = 0;
+ size_t p = 0;
+ size_t i = 0;
uint16_t wc;
uint32_t w;
@@ -343,7 +392,7 @@ static char *plist_utf16be_to_utf8(uint16_t *unistr, long len, long *items_read,
}
while (i < len) {
- wc = be16toh(get_unaligned(unistr + i));
+ wc = UINT_TO_HOST(unistr + i, sizeof(wc));
i++;
if (wc >= 0xD800 && wc <= 0xDBFF) {
if (!read_lead_surrogate) {
@@ -397,8 +446,8 @@ static char *plist_utf16be_to_utf8(uint16_t *unistr, long len, long *items_read,
static plist_t parse_unicode_node(const char **bnode, uint64_t size)
{
plist_data_t data = plist_new_plist_data();
- long items_read = 0;
- long items_written = 0;
+ size_t items_read = 0;
+ size_t items_written = 0;
data->type = PLIST_STRING;
data->strval = plist_utf16be_to_utf8((uint16_t*)(*bnode), size, &items_read, &items_written);
@@ -739,6 +788,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
if (node_index >= bplist->num_objects) {
PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%" PRIu64 ")\n", node_index, bplist->num_objects);
+ bplist->err = PLIST_ERR_PARSE;
return NULL;
}
@@ -746,6 +796,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
if (idx_ptr < bplist->offset_table ||
idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) {
PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index);
+ bplist->err = PLIST_ERR_PARSE;
return NULL;
}
@@ -753,6 +804,14 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
/* make sure the node offset is in a sane range */
if ((ptr < bplist->data+BPLIST_MAGIC_SIZE+BPLIST_VERSION_SIZE) || (ptr >= bplist->offset_table)) {
PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index);
+ bplist->err = PLIST_ERR_PARSE;
+ return NULL;
+ }
+
+ /* check nesting depth */
+ if (bplist->level > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_BIN_ERR("maximum nesting depth (%u) exceeded\n",(unsigned)PLIST_MAX_NESTING_DEPTH);
+ bplist->err = PLIST_ERR_MAX_NESTING;
return NULL;
}
@@ -772,6 +831,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
void *node_level = ptr_array_index(bplist->used_indexes, bplist->level);
if (node_i == node_level) {
PLIST_BIN_ERR("recursion detected in binary plist\n");
+ bplist->err = PLIST_ERR_CIRCULAR_REF;
return NULL;
}
}
@@ -830,7 +890,14 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
ref_size = trailer->ref_size;
num_objects = be64toh(trailer->num_objects);
root_object = be64toh(trailer->root_object_index);
- offset_table = (char *)(plist_bin + be64toh(trailer->offset_table_offset));
+
+ uint64_t offset_table_offset = be64toh(trailer->offset_table_offset);
+ uint64_t max_valid_offset = (uint64_t)length - sizeof(bplist_trailer_t);
+ if (offset_table_offset > max_valid_offset) {
+ PLIST_BIN_ERR("offset table offset outside of valid range\n");
+ return PLIST_ERR_PARSE;
+ }
+ offset_table = (char *)(plist_bin + offset_table_offset);
if (num_objects == 0) {
PLIST_BIN_ERR("number of objects must be larger than 0\n");
@@ -876,6 +943,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
bplist.offset_table = offset_table;
bplist.level = 0;
bplist.used_indexes = ptr_array_new(16);
+ bplist.err = PLIST_ERR_SUCCESS;
if (!bplist.used_indexes) {
PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n");
@@ -887,7 +955,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
ptr_array_free(bplist.used_indexes);
if (!*plist) {
- return PLIST_ERR_PARSE;
+ return (bplist.err != PLIST_ERR_SUCCESS) ? bplist.err : PLIST_ERR_PARSE;
}
return PLIST_ERR_SUCCESS;
@@ -944,35 +1012,58 @@ struct serialize_s
{
ptrarray_t* objects;
hashtable_t* ref_table;
+ hashtable_t* in_stack;
};
-static void serialize_plist(node_t node, void* data)
+static plist_err_t serialize_plist(node_t node, void* data, uint32_t depth)
{
uint64_t *index_val = NULL;
struct serialize_s *ser = (struct serialize_s *) data;
- uint64_t current_index = ser->objects->len;
- //first check that node is not yet in objects
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_BIN_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ // circular reference check: is node on current recursion stack?
+ if (hash_table_lookup(ser->in_stack, node)) {
+ PLIST_BIN_WRITE_ERR("circular reference detected\n");
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // first check that node is not yet in objects
void* val = hash_table_lookup(ser->ref_table, node);
- if (val)
- {
- //data is already in table
- return;
+ if (val) {
+ // data is already in table
+ return PLIST_ERR_SUCCESS;
}
- //insert new ref
+
+ // mark as active
+ hash_table_insert(ser->in_stack, node, (void*)1);
+
+ // insert new ref
index_val = (uint64_t *) malloc(sizeof(uint64_t));
assert(index_val != NULL);
- *index_val = current_index;
+ *index_val = ser->objects->len;
hash_table_insert(ser->ref_table, node, index_val);
- //now append current node to object array
+ // now append current node to object array
ptr_array_add(ser->objects, node);
- //now recurse on children
+ // now recurse on children
node_t ch;
+ plist_err_t err = PLIST_ERR_SUCCESS;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- serialize_plist(ch, data);
+ err = serialize_plist(ch, data, depth+1);
+ if (err != PLIST_ERR_SUCCESS) {
+ break;
+ }
}
+
+ // leave recursion stack
+ hash_table_remove(ser->in_stack, node);
+
+ return err;
}
#define Log2(x) ((x) == 8 ? 3 : ((x) == 4 ? 2 : ((x) == 2 ? 1 : 0)))
@@ -1051,11 +1142,11 @@ static void write_string(bytearray_t * bplist, char *val, uint64_t size)
write_raw_data(bplist, BPLIST_STRING, (uint8_t *) val, size);
}
-static uint16_t *plist_utf8_to_utf16be(char *unistr, long size, long *items_read, long *items_written)
+static uint16_t *plist_utf8_to_utf16be(char *unistr, size_t size, size_t *items_read, size_t *items_written)
{
uint16_t *outbuf;
- int p = 0;
- long i = 0;
+ size_t p = 0;
+ size_t i = 0;
unsigned char c0;
unsigned char c1;
@@ -1095,7 +1186,7 @@ static uint16_t *plist_utf8_to_utf16be(char *unistr, long size, long *items_read
i+=1;
} else {
// invalid character
- PLIST_BIN_ERR("%s: invalid utf8 sequence in string at index %lu\n", __func__, i);
+ PLIST_BIN_ERR("%s: invalid utf8 sequence in string at index %zu\n", __func__, i);
break;
}
}
@@ -1110,10 +1201,10 @@ static uint16_t *plist_utf8_to_utf16be(char *unistr, long size, long *items_read
return outbuf;
}
-static void write_unicode(bytearray_t * bplist, char *val, uint64_t size)
+static void write_unicode(bytearray_t * bplist, char *val, size_t size)
{
- long items_read = 0;
- long items_written = 0;
+ size_t items_read = 0;
+ size_t items_written = 0;
uint16_t *unicodestr = NULL;
unicodestr = plist_utf8_to_utf16be(val, size, &items_read, &items_written);
@@ -1198,6 +1289,7 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
{
ptrarray_t* objects = NULL;
hashtable_t* ref_table = NULL;
+ hashtable_t* in_stack = NULL;
struct serialize_s ser_s;
uint8_t offset_size = 0;
uint8_t ref_size = 0;
@@ -1227,11 +1319,28 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
ptr_array_free(objects);
return PLIST_ERR_NO_MEM;
}
+ //hashtable for circular reference detection
+ in_stack = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!in_stack) {
+ ptr_array_free(objects);
+ hash_table_destroy(ref_table);
+ return PLIST_ERR_NO_MEM;
+ }
//serialize plist
ser_s.objects = objects;
ser_s.ref_table = ref_table;
- serialize_plist((node_t)plist, &ser_s);
+ ser_s.in_stack = in_stack;
+ plist_err_t err = serialize_plist((node_t)plist, &ser_s, 0);
+ if (err != PLIST_ERR_SUCCESS) {
+ ptr_array_free(objects);
+ hash_table_destroy(ref_table);
+ hash_table_destroy(in_stack);
+ return err;
+ }
+ //no longer needed
+ hash_table_destroy(in_stack);
+ ser_s.in_stack = NULL;
//now stream to output buffer
offset_size = 0; //unknown yet
diff --git a/src/hashtable.c b/src/hashtable.c
index 86dae82..dd6dbfc 100644
--- a/src/hashtable.c
+++ b/src/hashtable.c
@@ -47,7 +47,7 @@ void hash_table_destroy(hashtable_t *ht)
ht->free_func(e->value);
}
hashentry_t* old = e;
- e = (hashentry_t*)e->next;
+ e = e->next;
free(old);
}
}
@@ -71,7 +71,7 @@ void hash_table_insert(hashtable_t* ht, void *key, void *value)
e->value = value;
return;
}
- e = (hashentry_t*)e->next;
+ e = e->next;
}
// if we get here, the element is not yet in the list.
@@ -103,7 +103,7 @@ void* hash_table_lookup(hashtable_t* ht, void *key)
if (ht->compare_func(e->key, key)) {
return e->value;
}
- e = (hashentry_t*)e->next;
+ e = e->next;
}
return NULL;
}
@@ -124,7 +124,7 @@ void hash_table_remove(hashtable_t* ht, void *key)
// found element, remove it from the list
hashentry_t* old = e;
if (e == ht->entries[idx0]) {
- ht->entries[idx0] = (hashentry_t*)e->next;
+ ht->entries[idx0] = e->next;
} else {
last->next = e->next;
}
@@ -135,6 +135,6 @@ void hash_table_remove(hashtable_t* ht, void *key)
return;
}
last = e;
- e = (hashentry_t*)e->next;
+ e = e->next;
}
}
diff --git a/src/hashtable.h b/src/hashtable.h
index 42d7b93..514cfec 100644
--- a/src/hashtable.h
+++ b/src/hashtable.h
@@ -25,7 +25,7 @@
typedef struct hashentry_t {
void *key;
void *value;
- void *next;
+ struct hashentry_t *next;
} hashentry_t;
typedef unsigned int(*hash_func_t)(const void* key);
diff --git a/src/jplist.c b/src/jplist.c
index 782d2b3..9a40844 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -38,6 +38,7 @@
#include "plist.h"
#include "strbuf.h"
#include "jsmn.h"
+#include "hashtable.h"
#ifdef DEBUG
static int plist_json_debug = 0;
@@ -72,8 +73,10 @@ void plist_json_set_debug(int debug)
}
#ifndef HAVE_STRNDUP
+#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
+#endif
static char* strndup(const char* str, size_t len)
{
char *newstr = (char *)malloc(len+1);
@@ -83,8 +86,10 @@ static char* strndup(const char* str, size_t len)
}
return newstr;
}
+#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
+#endif
static size_t dtostr(char *buf, size_t bufsize, double realval)
{
@@ -311,18 +316,32 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_JSON_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+ PLIST_JSON_WRITE_ERR("circular reference detected\n");
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
unsigned int n_children = node_n_children(node);
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- plist_err_t res = node_estimate_size(ch, size, depth + 1, prettify);
+ plist_err_t res = _node_estimate_size(ch, size, depth + 1, prettify, visited);
if (res < 0) {
return res;
}
@@ -398,6 +417,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, prettify, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, int prettify)
{
uint64_t size = 0;
@@ -448,6 +476,7 @@ plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, in
typedef struct {
jsmntok_t* tokens;
int count;
+ plist_err_t err;
} jsmntok_info_t;
static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
@@ -460,6 +489,8 @@ static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
if (str[0] == '-') {
is_neg = 1;
(*endp)++;
+ } else if (str[0] == '+') {
+ (*endp)++;
}
if (is_neg) {
MAX++;
@@ -522,7 +553,7 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index)
} else {
val = plist_new_uint((uint64_t)intpart);
}
- } else if ((*endp == '.' && endp+1 < str_end && isdigit(*(endp+1))) || ((*endp == 'e' || *endp == 'E') && endp+1 < str_end && (isdigit(*(endp+1)) || ((*(endp+1) == '-') && endp+2 < str_end && isdigit(*(endp+2)))))) {
+ } else if ((*endp == '.' && endp+1 < str_end && isdigit(*(endp+1))) || ((*endp == 'e' || *endp == 'E') && endp+1 < str_end && (isdigit(*(endp+1)) || (((*(endp+1) == '-') || (*(endp+1) == '+')) && endp+2 < str_end && isdigit(*(endp+2)))))) {
/* floating point */
double dval = (double)intpart;
char* fendp = endp;
@@ -546,7 +577,7 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index)
if (fendp >= str_end) {
break;
}
- if (fendp+1 < str_end && (*fendp == 'e' || *fendp == 'E') && (isdigit(*(fendp+1)) || ((*(fendp+1) == '-') && fendp+2 < str_end && isdigit(*(fendp+2))))) {
+ if (fendp+1 < str_end && (*fendp == 'e' || *fendp == 'E') && (isdigit(*(fendp+1)) || (((*(fendp+1) == '-') || (*(fendp+1) == '+')) && fendp+2 < str_end && isdigit(*(fendp+2))))) {
int64_t exp = parse_decimal(fendp+1, str_end, &fendp);
dval = dval * pow(10, (double)exp);
} else {
@@ -673,12 +704,18 @@ static plist_t parse_string(const char* js, jsmntok_info_t* ti, int* index)
return node;
}
-static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index);
+static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth);
-static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
+static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth)
{
if (ti->tokens[*index].type != JSMN_ARRAY) {
PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__);
+ ti->err = PLIST_ERR_PARSE;
+ return NULL;
+ }
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH);
+ ti->err = PLIST_ERR_MAX_NESTING;
return NULL;
}
plist_t arr = plist_new_array();
@@ -689,15 +726,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
if (j >= ti->count) {
PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
plist_free(arr);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
plist_t val = NULL;
switch (ti->tokens[j].type) {
case JSMN_OBJECT:
- val = parse_object(js, ti, &j);
+ val = parse_object(js, ti, &j, depth+1);
break;
case JSMN_ARRAY:
- val = parse_array(js, ti, &j);
+ val = parse_array(js, ti, &j, depth+1);
break;
case JSMN_STRING:
val = parse_string(js, ti, &j);
@@ -712,6 +750,7 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
plist_array_append_item(arr, val);
} else {
plist_free(arr);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
}
@@ -719,10 +758,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
return arr;
}
-static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
+static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth)
{
if (ti->tokens[*index].type != JSMN_OBJECT) {
PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__);
+ ti->err = PLIST_ERR_PARSE;
+ return NULL;
+ }
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH);
+ ti->err = PLIST_ERR_MAX_NESTING;
return NULL;
}
int num_tokens = ti->tokens[*index].size;
@@ -730,6 +775,7 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
int j = (*index)+1;
if (num_tokens % 2 != 0) {
PLIST_JSON_ERR("%s: number of children must be even\n", __func__);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
plist_t obj = plist_new_dict();
@@ -737,12 +783,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
if (j+1 >= ti->count) {
PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
plist_free(obj);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
if (ti->tokens[j].type == JSMN_STRING) {
char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL);
if (!key) {
plist_free(obj);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
plist_t val = NULL;
@@ -750,10 +798,10 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
num++;
switch (ti->tokens[j].type) {
case JSMN_OBJECT:
- val = parse_object(js, ti, &j);
+ val = parse_object(js, ti, &j, depth+1);
break;
case JSMN_ARRAY:
- val = parse_array(js, ti, &j);
+ val = parse_array(js, ti, &j, depth+1);
break;
case JSMN_STRING:
val = parse_string(js, ti, &j);
@@ -769,12 +817,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
} else {
free(key);
plist_free(obj);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
free(key);
} else {
PLIST_JSON_ERR("%s: keys must be of type STRING\n", __func__);
plist_free(obj);
+ ti->err = PLIST_ERR_PARSE;
return NULL;
}
}
@@ -834,7 +884,7 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist)
}
int startindex = 0;
- jsmntok_info_t ti = { tokens, parser.toknext };
+ jsmntok_info_t ti = { tokens, parser.toknext, PLIST_ERR_SUCCESS };
switch (tokens[startindex].type) {
case JSMN_PRIMITIVE:
*plist = parse_primitive(json, &ti, &startindex);
@@ -843,14 +893,17 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist)
*plist = parse_string(json, &ti, &startindex);
break;
case JSMN_ARRAY:
- *plist = parse_array(json, &ti, &startindex);
+ *plist = parse_array(json, &ti, &startindex, 0);
break;
case JSMN_OBJECT:
- *plist = parse_object(json, &ti, &startindex);
+ *plist = parse_object(json, &ti, &startindex, 0);
break;
default:
break;
}
free(tokens);
+ if (!*plist) {
+ return (ti.err != PLIST_ERR_SUCCESS) ? ti.err : PLIST_ERR_PARSE;
+ }
return PLIST_ERR_SUCCESS;
}
diff --git a/src/oplist.c b/src/oplist.c
index 6ab6603..0eea27a 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -37,6 +37,7 @@
#include "plist.h"
#include "strbuf.h"
+#include "hashtable.h"
#ifdef DEBUG
static int plist_ostep_debug = 0;
@@ -71,8 +72,10 @@ void plist_ostep_set_debug(int debug)
}
#ifndef HAVE_STRNDUP
+#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
+#endif
static char* strndup(const char* str, size_t len)
{
char *newstr = (char *)malloc(len+1);
@@ -82,8 +85,10 @@ static char* strndup(const char* str, size_t len)
}
return newstr;
}
+#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
+#endif
static size_t dtostr(char *buf, size_t bufsize, double realval)
{
@@ -355,18 +360,32 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_OSTEP_WRITE_ERR("node tree is nested too deeply\n");
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+ PLIST_OSTEP_WRITE_ERR("circular reference detected\n");
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
unsigned int n_children = node_n_children(node);
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- plist_err_t res = node_estimate_size(ch, size, depth + 1, prettify);
+ plist_err_t res = _node_estimate_size(ch, size, depth + 1, prettify, visited);
if (res < 0) {
return res;
}
@@ -442,6 +461,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, prettify, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
plist_err_t plist_to_openstep(plist_t plist, char **openstep, uint32_t* length, int prettify)
{
uint64_t size = 0;
@@ -488,7 +516,7 @@ struct _parse_ctx {
const char *start;
const char *pos;
const char *end;
- int err;
+ plist_err_t err;
uint32_t depth;
};
typedef struct _parse_ctx* parse_ctx;
@@ -545,50 +573,50 @@ static void parse_dict_data(parse_ctx ctx, plist_t dict)
}
key = NULL;
ctx->err = node_from_openstep(ctx, &key);
- if (ctx->err != 0) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
break;
}
if (!PLIST_IS_STRING(key)) {
PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
parse_skip_ws(ctx);
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos != '=') {
PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
ctx->pos++;
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
val = NULL;
ctx->err = node_from_openstep(ctx, &val);
- if (ctx->err != 0) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
break;
}
if (!val) {
PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
parse_skip_ws(ctx);
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos != ';') {
PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
@@ -608,10 +636,10 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
plist_t subnode = NULL;
const char *p = NULL;
ctx->depth++;
- if (ctx->depth > 1000) {
+ if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
- ctx->err++;
- return PLIST_ERR_PARSE;
+ ctx->err = PLIST_ERR_MAX_NESTING;
+ return ctx->err;
}
while (ctx->pos < ctx->end && !ctx->err) {
parse_skip_ws(ctx);
@@ -629,12 +657,12 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
}
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos != '}') {
PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos++;
@@ -652,11 +680,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
break;
}
ctx->err = node_from_openstep(ctx, &tmp);
- if (ctx->err != 0) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
break;
}
if (!tmp) {
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
plist_array_append_item(subnode, tmp);
@@ -664,7 +692,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
parse_skip_ws(ctx);
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos != ',') {
@@ -674,17 +702,17 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
}
plist_free(tmp);
tmp = NULL;
- if (ctx->err) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
goto err_out;
}
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos != ')') {
PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos++;
@@ -699,7 +727,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
parse_skip_ws(ctx);
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (*ctx->pos == '>') {
@@ -707,19 +735,19 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
}
if (!isxdigit(*ctx->pos)) {
PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
uint8_t b = HEX_DIGIT(*ctx->pos);
ctx->pos++;
if (ctx->pos >= ctx->end) {
PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
if (!isxdigit(*ctx->pos)) {
PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
b = (b << 4) + HEX_DIGIT(*ctx->pos);
@@ -735,14 +763,14 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
byte_array_free(bytes);
plist_free_data(data);
PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (*ctx->pos != '>') {
byte_array_free(bytes);
plist_free_data(data);
PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos++;
@@ -757,7 +785,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
char c = *ctx->pos;
ctx->pos++;
p = ctx->pos;
- int num_escapes = 0;
+ size_t num_escapes = 0;
while (ctx->pos < ctx->end) {
if (*ctx->pos == '\\') {
num_escapes++;
@@ -770,13 +798,13 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
if (ctx->pos >= ctx->end) {
plist_free_data(data);
PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (*ctx->pos != c) {
plist_free_data(data);
PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
size_t slen = ctx->pos - p;
@@ -877,7 +905,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
} else {
plist_free_data(data);
PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
break;
}
}
@@ -886,11 +914,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
ctx->depth--;
err_out:
- if (ctx->err) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
plist_free(subnode);
plist_free(*plist);
*plist = NULL;
- return PLIST_ERR_PARSE;
+ return ctx->err;
}
return PLIST_ERR_SUCCESS;
}
diff --git a/src/out-default.c b/src/out-default.c
index 266070b..fb57bcf 100644
--- a/src/out-default.c
+++ b/src/out-default.c
@@ -38,6 +38,7 @@
#include "plist.h"
#include "strbuf.h"
#include "time64.h"
+#include "hashtable.h"
#define MAC_EPOCH 978307200
@@ -310,19 +311,37 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+#endif
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: circular reference detected\n");
+#endif
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
unsigned int n_children = node_n_children(node);
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- plist_err_t res = node_estimate_size(ch, size, depth + 1, indent, partial_data);
- if (res < 0) {
+ plist_err_t res = _node_estimate_size(ch, size, depth + 1, indent, partial_data, visited);
+ if (res != PLIST_ERR_SUCCESS) {
return res;
}
}
@@ -401,6 +420,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, indent, partial_data, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options)
{
uint8_t indent = 0;
diff --git a/src/out-limd.c b/src/out-limd.c
index 7d861f8..35247fb 100644
--- a/src/out-limd.c
+++ b/src/out-limd.c
@@ -40,6 +40,7 @@
#include "strbuf.h"
#include "time64.h"
#include "base64.h"
+#include "hashtable.h"
#define MAC_EPOCH 978307200
@@ -278,19 +279,37 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+#endif
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: circular reference detected\n");
+#endif
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
unsigned int n_children = node_n_children(node);
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- plist_err_t res = node_estimate_size(ch, size, depth + 1, indent);
- if (res < 0) {
+ plist_err_t res = _node_estimate_size(ch, size, depth + 1, indent, visited);
+ if (res != PLIST_ERR_SUCCESS) {
return res;
}
}
@@ -359,6 +378,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, indent, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options)
{
uint8_t indent = 0;
diff --git a/src/out-plutil.c b/src/out-plutil.c
index d85f22c..bf9e72e 100644
--- a/src/out-plutil.c
+++ b/src/out-plutil.c
@@ -38,6 +38,7 @@
#include "plist.h"
#include "strbuf.h"
#include "time64.h"
+#include "hashtable.h"
#define MAC_EPOCH 978307200
@@ -304,19 +305,37 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+#endif
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+#if DEBUG
+ fprintf(stderr, "libplist: ERROR: circular reference detected\n");
+#endif
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
unsigned int n_children = node_n_children(node);
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- plist_err_t res = node_estimate_size(ch, size, depth + 1);
- if (res < 0) {
+ plist_err_t res = _node_estimate_size(ch, size, depth + 1, visited);
+ if (res != PLIST_ERR_SUCCESS) {
return res;
}
}
@@ -388,6 +407,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options)
{
plist_err_t res = node_to_string((node_t)plist, &outbuf, 0);
diff --git a/src/plist.c b/src/plist.c
index 2078520..17b8419 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -35,11 +35,10 @@
#include <limits.h>
#include <float.h>
#include <ctype.h>
+#include <inttypes.h>
#ifdef WIN32
#include <windows.h>
-#else
-#include <pthread.h>
#endif
#include <node.h>
@@ -47,10 +46,92 @@
#include <hashtable.h>
#include <ptrarray.h>
+#define MAC_EPOCH 978307200
+
#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);
@@ -60,14 +141,6 @@ extern void plist_json_deinit(void);
extern void plist_ostep_init(void);
extern void plist_ostep_deinit(void);
-static void internal_plist_init(void)
-{
- plist_bin_init();
- plist_xml_init();
- plist_json_init();
- plist_ostep_init();
-}
-
static void internal_plist_deinit(void)
{
plist_bin_deinit();
@@ -76,66 +149,14 @@ static void internal_plist_deinit(void)
plist_ostep_deinit();
}
-#ifdef WIN32
-typedef volatile struct {
- LONG lock;
- int state;
-} thread_once_t;
-
-static thread_once_t init_once = {0, 0};
-static thread_once_t deinit_once = {0, 0};
-
-static void thread_once(thread_once_t *once_control, void (*init_routine)(void))
+INITIALIZER(internal_plist_init)
{
- while (InterlockedExchange(&(once_control->lock), 1) != 0) {
- Sleep(1);
- }
- if (!once_control->state) {
- once_control->state = 1;
- init_routine();
- }
- InterlockedExchange(&(once_control->lock), 0);
-}
-#else
-static pthread_once_t init_once = PTHREAD_ONCE_INIT;
-static pthread_once_t deinit_once = PTHREAD_ONCE_INIT;
-#define thread_once pthread_once
-#endif
-
-#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
- #if defined(__llvm__) || defined(__GNUC__)
- #define HAVE_ATTRIBUTE_CONSTRUCTOR
- #endif
-#endif
-
-#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
-static void __attribute__((constructor)) libplist_initialize(void)
-{
- thread_once(&init_once, internal_plist_init);
-}
-
-static void __attribute__((destructor)) libplist_deinitialize(void)
-{
- thread_once(&deinit_once, internal_plist_deinit);
-}
-#elif defined(WIN32)
-BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
-{
- switch (dwReason) {
- case DLL_PROCESS_ATTACH:
- thread_once(&init_once, internal_plist_init);
- break;
- case DLL_PROCESS_DETACH:
- thread_once(&deinit_once, internal_plist_deinit);
- break;
- default:
- break;
- }
- return 1;
+ plist_bin_init();
+ plist_xml_init();
+ plist_json_init();
+ plist_ostep_init();
+ atexit(internal_plist_deinit);
}
-#else
-#warning No compiler support for constructor/destructor attributes, some features might not be available.
-#endif
#ifndef HAVE_MEMMEM
// see https://sourceware.org/legacy-ml/libc-alpha/2007-12/msg00000.html
@@ -337,7 +358,7 @@ plist_data_t plist_get_data(plist_t node)
plist_data_t plist_new_plist_data(void)
{
- plist_data_t data = (plist_data_t) calloc(sizeof(struct plist_data_s), 1);
+ plist_data_t data = (plist_data_t) calloc(1, sizeof(struct plist_data_s));
return data;
}
@@ -494,8 +515,10 @@ plist_t plist_new_data(const char *val, uint64_t length)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATA;
+if (val && length) {
data->buff = (uint8_t *) malloc(length);
memcpy(data->buff, val, length);
+}
data->length = length;
return plist_new_node(data);
}
@@ -509,6 +532,15 @@ plist_t plist_new_date(int32_t sec, int32_t usec)
return plist_new_node(data);
}
+plist_t plist_new_unix_date(int64_t sec)
+{
+ plist_data_t data = plist_new_plist_data();
+ data->type = PLIST_DATE;
+ data->realval = (double)sec - MAC_EPOCH;
+ data->length = sizeof(double);
+ return plist_new_node(data);
+}
+
plist_t plist_new_null(void)
{
plist_data_t data = plist_new_plist_data();
@@ -957,6 +989,195 @@ void plist_dict_merge(plist_t *target, plist_t source)
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;
@@ -1184,20 +1405,40 @@ void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
}
}
+void plist_get_unix_date_val(plist_t node, int64_t *sec)
+{
+ if (!node || !sec)
+ 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));
+ *sec = (int64_t)val + MAC_EPOCH;
+}
+
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 (a == b)
+ return TRUE;
- if (!((node_t) a)->data || !((node_t) b)->data)
+ if (!a || !b)
return FALSE;
val_a = plist_get_data((plist_t) a);
val_b = plist_get_data((plist_t) b);
+ if (val_a == NULL && val_b == NULL)
+ return TRUE;
+
+ if (val_a == NULL || val_b == NULL)
+ return FALSE;
+
if (val_a->type != val_b->type)
return FALSE;
@@ -1209,28 +1450,30 @@ int plist_data_compare(const void *a, const void *b)
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
+ return val_a->length == val_b->length
+ && val_a->intval == val_b->intval; // it is a union so this is sufficient
case PLIST_KEY:
case PLIST_STRING:
+ if (!val_a->strval || !val_b->strval)
+ return val_a->strval == val_b->strval;
return strcmp(val_a->strval, val_b->strval) == 0;
- case PLIST_DATA:
+ case PLIST_DATA: {
if (val_a->length != val_b->length)
return FALSE;
+ if (val_a->length == 0)
+ return TRUE;
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;
}
- return FALSE;
}
char plist_compare_node_value(plist_t node_l, plist_t node_r)
@@ -1340,7 +1583,13 @@ void plist_set_data_val(plist_t node, const char *val, uint64_t 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));
+ plist_set_element_val(node, PLIST_DATE, &val, sizeof(double));
+}
+
+void plist_set_unix_date_val(plist_t node, int64_t sec)
+{
+ double val = (double)(sec - MAC_EPOCH);
+ plist_set_element_val(node, PLIST_DATE, &val, sizeof(double));
}
int plist_bool_val_is_true(plist_t boolnode)
@@ -1462,9 +1711,12 @@ 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);
+ plist_data_t data = plist_get_data(datenode);
+ assert(data->length == sizeof(double));
+ double val = data->realval;
+ int32_t sec = (int32_t)val;
+ val = fabs((val - (int64_t)val) * 1000000);
+ int32_t usec = (int32_t)val;
uint64_t dateval = ((int64_t)sec << 32) | usec;
uint64_t cmpval = ((int64_t)cmpsec << 32) | cmpusec;
if (dateval == cmpval) {
@@ -1478,6 +1730,24 @@ int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec)
return 1;
}
+int plist_unix_date_val_compare(plist_t datenode, int64_t cmpval)
+{
+ if (!PLIST_IS_DATE(datenode)) {
+ return -1;
+ }
+ int64_t dateval = 0;
+ plist_get_unix_date_val(datenode, &dateval);
+ 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)) {
@@ -1577,6 +1847,9 @@ 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);
@@ -1597,6 +1870,9 @@ void plist_sort(plist_t plist)
} 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);
diff --git a/src/plist.h b/src/plist.h
index a993e3a..e310bcc 100644
--- a/src/plist.h
+++ b/src/plist.h
@@ -49,6 +49,10 @@
#endif
#endif
+#ifndef PLIST_MAX_NESTING_DEPTH
+#define PLIST_MAX_NESTING_DEPTH 512
+#endif
+
#include "plist/plist.h"
struct plist_data_s
@@ -81,4 +85,17 @@ extern plist_err_t plist_write_to_stream_default(plist_t plist, FILE *stream, pl
extern plist_err_t plist_write_to_stream_limd(plist_t plist, FILE *stream, plist_write_options_t options);
extern plist_err_t plist_write_to_stream_plutil(plist_t plist, FILE *stream, plist_write_options_t options);
+static inline unsigned int plist_node_ptr_hash(const void *ptr)
+{
+ uintptr_t h = (uintptr_t)ptr;
+ h ^= (h >> 16);
+ h *= 0x85ebca6b;
+ return (unsigned int)h;
+}
+
+static inline int plist_node_ptr_compare(const void *a, const void *b)
+{
+ return a == b;
+}
+
#endif
diff --git a/src/time64.c b/src/time64.c
index 07639df..cfbe7ac 100644
--- a/src/time64.c
+++ b/src/time64.c
@@ -224,6 +224,7 @@ Time64_T timegm64(const struct TM *date) {
Time64_T days = 0;
Time64_T seconds = 0;
Year year;
+ assert(date != NULL);
Year orig_year = (Year)date->tm_year;
int cycles = 0;
diff --git a/src/xplist.c b/src/xplist.c
index 66e1dba..9870104 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -46,6 +46,7 @@
#include "base64.h"
#include "strbuf.h"
#include "time64.h"
+#include "hashtable.h"
#define XPLIST_KEY "key"
#define XPLIST_KEY_LEN 3
@@ -256,7 +257,7 @@ static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth
/* append tag */
str_buf_append(*outbuf, "<", 1);
str_buf_append(*outbuf, tag, tag_len);
- if (node_data->type == PLIST_STRING || node_data->type == PLIST_KEY) {
+ if ((node_data->type == PLIST_STRING || node_data->type == PLIST_KEY) && node_data->length > 0) {
size_t j;
size_t len;
off_t start = 0;
@@ -444,17 +445,34 @@ static int num_digits_u(uint64_t i)
return n;
}
-static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth)
+static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited)
{
plist_data_t data;
if (!node) {
return PLIST_ERR_INVALID_ARG;
}
+
+ if (depth > PLIST_MAX_NESTING_DEPTH) {
+ PLIST_XML_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+ return PLIST_ERR_MAX_NESTING;
+ }
+
+ if (hash_table_lookup(visited, node)) {
+ PLIST_XML_WRITE_ERR("circular reference detected\n");
+ return PLIST_ERR_CIRCULAR_REF;
+ }
+
+ // mark as visited
+ hash_table_insert(visited, node, (void*)1);
+
data = plist_get_data(node);
if (node->children) {
node_t ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
- node_estimate_size(ch, size, depth + 1);
+ plist_err_t err = _node_estimate_size(ch, size, depth + 1, visited);
+ if (err != PLIST_ERR_SUCCESS) {
+ return err;
+ }
}
switch (data->type) {
case PLIST_DICT:
@@ -529,6 +547,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept
return PLIST_ERR_SUCCESS;
}
+static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth)
+{
+ hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL);
+ if (!visited) return PLIST_ERR_NO_MEM;
+ plist_err_t err = _node_estimate_size(node, size, depth, visited);
+ hash_table_destroy(visited);
+ return err;
+}
+
plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)
{
uint64_t size = 0;
@@ -574,7 +601,7 @@ plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)
struct _parse_ctx {
const char *pos;
const char *end;
- int err;
+ plist_err_t err;
};
typedef struct _parse_ctx* parse_ctx;
@@ -698,21 +725,21 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
find_char(ctx, '<', 0);
if (ctx->pos >= ctx->end || *ctx->pos != '<') {
PLIST_XML_ERR("EOF while looking for closing tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
q = ctx->pos;
ctx->pos++;
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("EOF while parsing '%s'\n", p);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
if (*ctx->pos == '!') {
ctx->pos++;
if (ctx->pos >= ctx->end-1) {
PLIST_XML_ERR("EOF while parsing <! special tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
if (*ctx->pos == '-' && *(ctx->pos+1) == '-') {
@@ -725,7 +752,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
find_str(ctx, "-->", 3, 0);
if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {
PLIST_XML_ERR("EOF while looking for end of comment\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
ctx->pos += 3;
@@ -733,7 +760,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
ctx->pos++;
if (ctx->pos >= ctx->end - 8) {
PLIST_XML_ERR("EOF while parsing <[ tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
if (strncmp(ctx->pos, "CDATA[", 6) == 0) {
@@ -749,7 +776,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
find_str(ctx, "]]>", 3, 0);
if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "]]>", 3) != 0) {
PLIST_XML_ERR("EOF while looking for end of CDATA block\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
q = ctx->pos;
@@ -763,14 +790,14 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
p = ctx->pos;
find_next(ctx, " \r\n\t>", 5, 1);
PLIST_XML_ERR("Invalid special tag <[%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
} else {
p = ctx->pos;
find_next(ctx, " \r\n\t>", 5, 1);
PLIST_XML_ERR("Invalid special tag <!%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
} else if (*ctx->pos == '/') {
@@ -779,25 +806,25 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
p = ctx->pos;
find_next(ctx, " \r\n\t>", 5, 1);
PLIST_XML_ERR("Invalid tag <%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
} while (1);
ctx->pos++;
if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) {
PLIST_XML_ERR("EOF or end tag mismatch\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
ctx->pos+=tag_len;
parse_skip_ws(ctx);
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("EOF while parsing closing tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
} else if (*ctx->pos != '>') {
PLIST_XML_ERR("Invalid closing tag; expected '>', found '%c'\n", *ctx->pos);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
return NULL;
}
ctx->pos++;
@@ -973,6 +1000,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
void *prev;
};
struct node_path_item* node_path = NULL;
+ int depth = 0;
while (ctx->pos < ctx->end && !ctx->err) {
parse_skip_ws(ctx);
@@ -983,13 +1011,13 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
p = ctx->pos;
find_next(ctx, " \t\r\n", 4, 0);
PLIST_XML_ERR("Expected: opening tag, found: %.*s\n", (int)(ctx->pos - p), p);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos++;
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("EOF while parsing tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
@@ -997,12 +1025,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
find_str(ctx, "?>", 2, 1);
if (ctx->pos > ctx->end-2) {
PLIST_XML_ERR("EOF while looking for <? tag closing marker\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (strncmp(ctx->pos, "?>", 2) != 0) {
PLIST_XML_ERR("Couldn't find <? tag closing marker\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos += 2;
@@ -1014,7 +1042,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
find_str(ctx,"-->", 3, 0);
if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {
PLIST_XML_ERR("Couldn't find end of comment\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos+=3;
@@ -1025,7 +1053,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
find_next(ctx, " \t\r\n[>", 6, 1);
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("EOF while parsing !DOCTYPE\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (*ctx->pos == '[') {
@@ -1043,7 +1071,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
find_str(ctx, "]>", 2, 1);
if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) {
PLIST_XML_ERR("Couldn't find end of DOCTYPE\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
ctx->pos += 2;
@@ -1052,7 +1080,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
p = ctx->pos;
find_next(ctx, " \r\n\t>", 5, 1);
PLIST_XML_ERR("Invalid or incomplete special tag <%.*s> encountered\n", (int)(ctx->pos - p), p);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
continue;
@@ -1063,10 +1091,10 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
find_next(ctx," \r\n\t<>", 6, 0);
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("Unexpected EOF while parsing XML\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
- int taglen = ctx->pos - p;
+ size_t taglen = ctx->pos - p;
tag = (char*)malloc(taglen + 1);
strncpy(tag, p, taglen);
tag[taglen] = '\0';
@@ -1075,16 +1103,16 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
}
if (ctx->pos >= ctx->end) {
PLIST_XML_ERR("Unexpected EOF while parsing XML\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (*ctx->pos != '>') {
PLIST_XML_ERR("Missing '>' for tag <%s\n", tag);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (*(ctx->pos-1) == '/') {
- int idx = ctx->pos - p - 1;
+ size_t idx = ctx->pos - p - 1;
if (idx < taglen)
tag[idx] = '\0';
is_empty = 1;
@@ -1101,14 +1129,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
}
if (is_empty) {
PLIST_XML_ERR("Empty plist tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));
if (!path_item) {
PLIST_XML_ERR("out of memory when allocating node path item\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
path_item->type = "plist";
@@ -1119,17 +1147,17 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
} else if (!strcmp(tag, "/plist")) {
if (!has_content) {
PLIST_XML_ERR("encountered empty plist tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (!node_path) {
PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (strcmp(node_path->type, tag+1) != 0) {
PLIST_XML_ERR("mismatching closing tag <%s> found for opening tag <%s>\n", tag, node_path->type);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
struct node_path_item *path_item = node_path;
@@ -1157,7 +1185,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!tp) {
PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (tp->begin) {
@@ -1166,7 +1194,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!str_content) {
PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
char *str = str_content;
@@ -1208,7 +1236,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!tp) {
PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (tp->begin) {
@@ -1217,7 +1245,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!str_content) {
PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
data->realval = atof(str_content);
@@ -1252,14 +1280,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!tp) {
PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
str = text_parts_get_content(tp, 1, &length, NULL);
text_parts_free((text_part_t*)first_part.next);
if (!str) {
PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) {
@@ -1274,6 +1302,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
data->length = length;
}
} else {
+ if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) {
+ keyname = strdup("");
+ free(tag);
+ tag = NULL;
+ plist_free(subnode);
+ subnode = NULL;
+ continue;
+ }
data->strval = strdup("");
data->length = 0;
}
@@ -1285,7 +1321,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!tp) {
PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (tp->begin) {
@@ -1294,7 +1330,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!str_content) {
PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
size_t size = tp->length;
@@ -1317,7 +1353,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!tp) {
PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
Time64_T timev = 0;
@@ -1328,7 +1364,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (!str_content) {
PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
text_parts_free((text_part_t*)first_part.next);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
@@ -1357,7 +1393,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
} else {
PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : "");
ctx->pos = ctx->end;
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (subnode && !closing_tag) {
@@ -1375,7 +1411,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
case PLIST_DICT:
if (!keyname) {
PLIST_XML_ERR("missing key name while adding dict item\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
plist_dict_set_item(parent, keyname, subnode);
@@ -1386,35 +1422,42 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
default:
/* should not happen */
PLIST_XML_ERR("parent is not a structured node\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
}
if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) {
+ if (depth >= PLIST_MAX_NESTING_DEPTH) {
+ PLIST_XML_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
+ ctx->err = PLIST_ERR_MAX_NESTING;
+ goto err_out;
+ }
struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));
if (!path_item) {
PLIST_XML_ERR("out of memory when allocating node path item\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
path_item->type = (data->type == PLIST_DICT) ? XPLIST_DICT : XPLIST_ARRAY;
path_item->prev = node_path;
node_path = path_item;
+ depth++;
parent = subnode;
}
subnode = NULL;
} else if (closing_tag) {
if (!node_path) {
PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n");
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
if (strcmp(node_path->type, tag+1) != 0) {
PLIST_XML_ERR("unexpected %s found (for opening %s)\n", tag, node_path->type);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
goto err_out;
}
+ if (depth > 0) depth--;
struct node_path_item *path_item = node_path;
node_path = (struct node_path_item*)node_path->prev;
free(path_item);
@@ -1436,7 +1479,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
if (node_path) {
PLIST_XML_ERR("EOF encountered while </%s> was expected\n", node_path->type);
- ctx->err++;
+ ctx->err = PLIST_ERR_PARSE;
}
err_out:
@@ -1451,10 +1494,10 @@ err_out:
free(path_item);
}
- if (ctx->err) {
+ if (ctx->err != PLIST_ERR_SUCCESS) {
plist_free(*plist);
*plist = NULL;
- return PLIST_ERR_PARSE;
+ return ctx->err;
}
/* check if we have a UID "dict" so we can replace it with a proper UID node */
@@ -1481,7 +1524,7 @@ plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * pli
return PLIST_ERR_INVALID_ARG;
}
- struct _parse_ctx ctx = { plist_xml, plist_xml + length, 0 };
+ struct _parse_ctx ctx = { plist_xml, plist_xml + length, PLIST_ERR_SUCCESS };
return node_from_xml(&ctx, plist);
}