summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml3
-rw-r--r--.github/workflows/build.yml8
-rw-r--r--.github/workflows/cifuzz.yml2
-rw-r--r--.github/workflows/codeql-analysis.yml6
-rw-r--r--Makefile.am1
-rw-r--r--NEWS35
-rw-r--r--README.md6
-rw-r--r--configure.ac55
-rw-r--r--cython/plist.pyx50
-rw-r--r--cython/plist_util.c31
-rw-r--r--cython/plist_util.h4
-rw-r--r--include/plist/Array.h19
-rw-r--r--include/plist/Data.h1
-rw-r--r--include/plist/Date.h6
-rw-r--r--include/plist/Dictionary.h5
-rw-r--r--include/plist/String.h3
-rw-r--r--include/plist/Structure.h3
-rw-r--r--include/plist/plist.h244
-rw-r--r--m4/ax_python_devel.m4361
-rw-r--r--src/Array.cpp49
-rw-r--r--src/Data.cpp11
-rw-r--r--src/Date.cpp22
-rw-r--r--src/Dictionary.cpp8
-rw-r--r--src/Integer.cpp3
-rw-r--r--src/Key.cpp2
-rw-r--r--src/Node.cpp2
-rw-r--r--src/String.cpp23
-rw-r--r--src/Structure.cpp27
-rw-r--r--src/bplist.c78
-rw-r--r--src/jplist.c10
-rw-r--r--src/oplist.c4
-rw-r--r--src/plist.c412
-rw-r--r--tools/Makefile.am4
-rw-r--r--tools/plistutil.c5
34 files changed, 1155 insertions, 348 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..e995b30
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+github: nikias
+patreon: nikias
+custom: ["https://www.paypal.me/NikiasBassen"]
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 68948af..233a584 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,6 +2,7 @@ name: build
on:
push:
+ pull_request:
schedule:
- cron: '0 0 1 * *'
@@ -50,7 +51,7 @@ jobs:
else
brew install libtool autoconf automake
fi
- pip3 install cython
+ pip3 install --break-system-packages cython
shell: bash
- uses: actions/checkout@v4
with:
@@ -74,6 +75,7 @@ jobs:
PYTHON_EXEC_PREFIX=`$PYTHON3_BIN -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('exec_prefix'))"`
PYTHON_LIBS_PATH=$PYTHON_EXEC_PREFIX/lib
PYTHON_FRAMEWORK_PATH=$PYTHON_EXEC_PREFIX/Python3
+ export PYTHON_CPPFLAGS="-I$PYTHON_EXEC_PREFIX/Headers"
export PYTHON_LIBS="-L$PYTHON_LIBS_PATH -lpython$PYTHON_VER"
export PYTHON_EXTRA_LDFLAGS="-Wl,-stack_size,1000000 -framework CoreFoundation $PYTHON_FRAMEWORK_PATH"
fi
@@ -95,7 +97,7 @@ jobs:
name: libplist-latest_macOS
path: libplist.tar
build-windows:
- runs-on: windows-2019
+ runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
@@ -116,6 +118,8 @@ jobs:
base-devel
git
mingw-w64-${{ matrix.arch }}-gcc
+ mingw-w64-${{ matrix.arch }}-pkg-config
+ mingw-w64-${{ matrix.arch }}-python
make
libtool
autoconf
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index 1a69794..c5d6ec0 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -19,7 +19,7 @@ jobs:
dry-run: false
language: c++
- name: Upload Crash
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 9e02074..8f2384a 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -28,7 +28,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -36,7 +36,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,4 +50,4 @@ jobs:
make
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/Makefile.am b/Makefile.am
index f44a6bc..e6923a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,7 @@ EXTRA_DIST = \
git-version-gen
dist-hook:
+ @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi
echo $(VERSION) > $(distdir)/.tarball-version
docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/include/plist/*.h
diff --git a/NEWS b/NEWS
index 760f4e4..2627893 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,38 @@
+Version 2.7.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * Add plist_new_unix_date, plist_get_unix_date_val, plist_set_unix_date_val functions
+ that work with int64_t values representing a UNIX timestamp instead of
+ using the 'MAC epoch'.
+ These new functions should be used instead of plist_new_date,
+ plist_get_date_val, and plist_set_date_val, which are now marked deprecated
+ and might be removed in a future version of libplist.
+ * Allow building the library without tool(s)
+ * Switch to more generic global initializer method
+ * json: Allow e+/E+ in exponent as per RFC 8259
+ * C++: Add more convenience functions to the interface
+ * C++: Add more type variants to different constructors and operators
+- Bugfixes:
+ * Fix segmentation fault when calling plist_sort() on an empty dictionary
+ * Fix compilation on MSVC
+ * C++: Fix bug in internal helper function of Array class
+ * C++: Fix String::GetValue memory leaking and support assignment of const char*
+
+Version 2.6.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * Revert back API change around PLIST_DATA to use char* again
+
+Version 2.5.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * Change API around PLIST_DATA to use uint8_t* instead of char*
+ * Add PLIST_DICT helper functions for different operations
+ * Require Cython 3.0 for python bindings
+
Version 2.4.0
~~~~~~~~~~~~~
diff --git a/README.md b/README.md
index 3d36250..ad36634 100644
--- a/README.md
+++ b/README.md
@@ -260,8 +260,8 @@ Please make sure your contribution adheres to:
## Links
* Homepage: https://libimobiledevice.org/
-* Repository: https://git.libimobiledevice.org/libplist.git
-* Repository (Mirror): https://github.com/libimobiledevice/libplist.git
+* Repository: https://github.com/libimobiledevice/libplist.git
+* Repository (Mirror): https://git.libimobiledevice.org/libplist.git
* Issue Tracker: https://github.com/libimobiledevice/libplist/issues
* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
* Twitter: https://twitter.com/libimobiledev
@@ -279,5 +279,5 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
This project is an independent software library and has not been authorized,
sponsored, or otherwise approved by Apple Inc.
-README Updated on: 2024-02-21
+README Updated on: 2024-10-22
diff --git a/configure.ac b/configure.ac
index 757ea95..6f574d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@ dnl libtool versioning
# changes to the signature and the semantic)
# ? :+1 : ? == just internal changes
# CURRENT : REVISION : AGE
-LIBPLIST_SO_VERSION=8:0:4
+LIBPLIST_SO_VERSION=11:0:7
AC_SUBST(LIBPLIST_SO_VERSION)
@@ -71,41 +71,12 @@ case ${host_os} in
;;
*)
AC_MSG_RESULT([${host_os}])
- AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build libplist])])
- AC_CHECK_LIB(pthread, [pthread_once], [], [AC_MSG_ERROR([pthread with pthread_once required to build libplist])])
;;
esac
AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
AC_SEARCH_LIBS([fmin],[m])
-# Check if the C compiler supports __attribute__((constructor))
-AC_CACHE_CHECK([wether the C compiler supports constructor/destructor attributes],
- ac_cv_attribute_constructor, [
- ac_cv_attribute_constructor=no
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
- [[
- #ifndef __has_attribute
- #define __has_attribute(x) 0
- #endif
- #if !__has_attribute(constructor)
- #error No constructor attribute
- #endif
- #if !__has_attribute(destructor)
- #error No destructor attribute
- #endif
- static void __attribute__((constructor)) test_constructor(void) {
- }
- static void __attribute__((destructor)) test_destructor(void) {
- }
- ]], [])],
- [ac_cv_attribute_constructor=yes]
- )]
-)
-if test "$ac_cv_attribute_constructor" = "yes"; then
- AC_DEFINE(HAVE_ATTRIBUTE_CONSTRUCTOR, 1, [Define if the C compiler supports constructor/destructor attributes])
-fi
-
# Check if struct tm has a tm_gmtoff member
AC_CACHE_CHECK(for tm_gmtoff in struct tm, ac_cv_struct_tm_gmtoff,
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
@@ -147,9 +118,9 @@ AC_ARG_WITH([cython],
[build_cython=false],
[build_cython=true])
if test "$build_cython" = "true"; then
- AC_PROG_CYTHON([0.17.0])
+ AC_PROG_CYTHON([3.0.0])
if [test "x$CYTHON" != "xfalse"]; then
- AM_PATH_PYTHON([2.3], [CYTHON_PYTHON])
+ AM_PATH_PYTHON([3.0], [CYTHON_PYTHON])
fi
else
CYTHON=false
@@ -174,8 +145,16 @@ else
fi
AM_CONDITIONAL([HAVE_CYTHON],[test "x$cython_python_bindings" = "xyes"])
-AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -Wno-strict-aliasing $PTHREAD_CFLAGS")
-GLOBAL_LDFLAGS="$PTHREAD_LIBS"
+AC_ARG_WITH([tools],
+ [AS_HELP_STRING([--with-tools], [Build libplist tools. [default=yes]])],
+ [build_tools=${withval}],
+ [build_tools=yes]
+)
+AS_IF([test "x$build_tools" = "xyes"], [AC_DEFINE(BUILD_TOOLS, 1, [Define if we are building plist tools])])
+AM_CONDITIONAL(BUILD_TOOLS, test "x$build_tools" = "xyes")
+
+AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -Wno-strict-aliasing")
+GLOBAL_LDFLAGS=""
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],
@@ -226,7 +205,11 @@ AC_ARG_WITH([tests],
[AS_HELP_STRING([--without-tests],
[Do not build libplist test suite (default is yes)])],
[build_tests=${withval}],
- [build_tests=yes])
+ [build_tests=${build_tools}])
+
+if test "x$build_tests" = "xyes" -a "x$build_tools" != "xyes"; then
+ AC_MSG_ERROR([Building the test suite requires plistutil. Reconfigure with --with-tools=yes to enable.])
+fi
if test "x$build_fuzzers" = "xyes"; then
if test "x$build_sanitizers" = "xno"; then
@@ -345,6 +328,8 @@ Configuration for $PACKAGE $VERSION:
Install prefix ..........: $prefix
Debug code ..............: $debug
Python bindings .........: $cython_python_bindings
+ Build tools .............: $build_tools
+ Build test suite ........: $build_tests
$EXTRA_CONF
Now type 'make' to build $PACKAGE $VERSION,
and then 'make install' for installation.
diff --git a/cython/plist.pyx b/cython/plist.pyx
index b5f4ef6..29c1181 100644
--- a/cython/plist.pyx
+++ b/cython/plist.pyx
@@ -33,9 +33,9 @@ cdef extern from *:
void plist_get_real_val(plist_t node, double *val)
void plist_set_real_val(plist_t node, double val)
- plist_t plist_new_date(int32_t sec, int32_t usec)
- void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
- void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
+ plist_t plist_new_unix_date(int64_t sec)
+ void plist_get_unix_date_val(plist_t node, int64_t *sec)
+ void plist_set_unix_date_val(plist_t node, int64_t sec)
void plist_get_key_val(plist_t node, char **val)
void plist_set_key_val(plist_t node, char *val)
@@ -488,23 +488,21 @@ cdef String String_factory(plist_t c_node, bint managed=True):
instance._c_node = c_node
return instance
-MAC_EPOCH = 978307200
-
cdef extern from "plist_util.h":
- void datetime_to_ints(object obj, int32_t* sec, int32_t* usec)
- object ints_to_datetime(int32_t sec, int32_t usec)
+ int64_t datetime_to_timestamp(object obj)
+ object timestamp_to_datetime(int64_t sec)
int check_datetime(object obj)
cdef plist_t create_date_plist(value=None):
cdef plist_t node = NULL
- cdef int32_t secs
- cdef int32_t usecs
if value is None:
- node = plist_new_date(0, 0)
+ node = plist_new_unix_date(0)
+ elif isinstance(value, int):
+ node = plist_new_unix_date(value)
+ elif isinstance(value, float):
+ node = plist_new_unix_date(int(value))
elif check_datetime(value):
- datetime_to_ints(value, &secs, &usecs)
- secs -= MAC_EPOCH
- node = plist_new_date(secs, usecs)
+ node = plist_new_unix_date(datetime_to_timestamp(value))
return node
cdef class Date(Node):
@@ -531,19 +529,21 @@ cdef class Date(Node):
return d >= other
cpdef object get_value(self):
- cdef int32_t secs = 0
- cdef int32_t usecs = 0
- plist_get_date_val(self._c_node, &secs, &usecs)
- secs += MAC_EPOCH
- return ints_to_datetime(secs, usecs)
+ cdef int64_t secs = 0
+ plist_get_unix_date_val(self._c_node, &secs)
+ return timestamp_to_datetime(secs)
cpdef set_value(self, object value):
- cdef int32_t secs
- cdef int32_t usecs
- if not check_datetime(value):
- raise ValueError("Expected a datetime")
- datetime_to_ints(value, &secs, &usecs)
- plist_set_date_val(self._c_node, secs, usecs)
+ cdef int64_t secs = 0
+ if isinstance(value, int):
+ secs = value
+ elif isinstance(value, float):
+ secs = int(value)
+ elif check_datetime(value):
+ secs = datetime_to_timestamp(value)
+ else:
+ raise ValueError("Expected int or datetime")
+ plist_set_unix_date_val(self._c_node, secs)
cdef Date Date_factory(plist_t c_node, bint managed=True):
cdef Date instance = Date.__new__(Date)
@@ -851,7 +851,7 @@ cdef plist_t native_to_plist_t(object native):
return plist_new_string(native)
if isinstance(native, bool):
return plist_new_bool(<bint>native)
- if isinstance(native, int) or isinstance(native, long):
+ if isinstance(native, int):
return plist_new_uint(native)
if isinstance(native, float):
return plist_new_real(native)
diff --git a/cython/plist_util.c b/cython/plist_util.c
index 4f922e5..27084fa 100644
--- a/cython/plist_util.c
+++ b/cython/plist_util.c
@@ -3,13 +3,11 @@
#include <time.h>
#include <datetime.h>
-void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec) {
+int64_t datetime_to_timestamp(PyObject* obj) {
PyDateTime_IMPORT;
if (!PyDateTime_Check(obj)) {
- PyErr_SetString(PyExc_ValueError,"Expected a datetime");
- sec = NULL;
- usec = NULL;
- return;
+ PyErr_SetString(PyExc_ValueError,"Expected a datetime");
+ return 0;
}
struct tm t;
memset(&t, 0, sizeof(t));
@@ -19,22 +17,21 @@ void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec) {
t.tm_mday = PyDateTime_GET_DAY(obj);
t.tm_mon = PyDateTime_GET_MONTH(obj)-1;
t.tm_year = PyDateTime_GET_YEAR(obj)-1900;
- *sec = (int32_t)mktime(&t);
- *usec = PyDateTime_DATE_GET_MICROSECOND(obj);
+ return mktime(&t);
}
-PyObject* ints_to_datetime(int32_t sec, int32_t usec) {
- time_t sec_tt = sec;
+PyObject* timestamp_to_datetime(int64_t sec) {
+ time_t sec_tt = sec;
struct tm* t = gmtime(&sec_tt);
if(t){
- PyDateTime_IMPORT;
- return PyDateTime_FromDateAndTime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, usec);
+ PyDateTime_IMPORT;
+ return PyDateTime_FromDateAndTime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, 0);
}
- return NULL;
+ return NULL;
}
int check_datetime(PyObject* ob) {
- if(ob){
- PyDateTime_IMPORT;
- return PyDateTime_Check(ob);
- }
- return 0;
+ if(ob){
+ PyDateTime_IMPORT;
+ return PyDateTime_Check(ob);
+ }
+ return 0;
}
diff --git a/cython/plist_util.h b/cython/plist_util.h
index fbf56b6..e0a84b5 100644
--- a/cython/plist_util.h
+++ b/cython/plist_util.h
@@ -1,5 +1,5 @@
#include <Python.h>
-void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec);
-PyObject* ints_to_datetime(int32_t sec, int32_t usec);
+int64_t datetime_to_timestamp(PyObject* obj);
+PyObject* timestamp_to_datetime(int64_t sec);
int check_datetime(PyObject* obj);
diff --git a/include/plist/Array.h b/include/plist/Array.h
index 0239c78..f4360c5 100644
--- a/include/plist/Array.h
+++ b/include/plist/Array.h
@@ -43,6 +43,10 @@ public :
typedef std::vector<Node*>::const_iterator const_iterator;
Node* operator[](unsigned int index);
+ Node* Back();
+ Node* back();
+ Node* Front();
+ Node* front();
iterator Begin();
iterator begin();
iterator End();
@@ -52,11 +56,20 @@ public :
const_iterator End() const;
const_iterator end() const;
size_t size() const;
- void Append(Node* node);
- void Insert(Node* node, unsigned int pos);
+ void Append(const Node& node);
+ void Append(const Node* node);
+ void Insert(const Node& node, unsigned int pos);
+ void Insert(const Node* node, unsigned int pos);
void Remove(Node* node);
void Remove(unsigned int pos);
- unsigned int GetNodeIndex(Node* node) const;
+ unsigned int GetNodeIndex(const Node& node) const;
+ unsigned int GetNodeIndex(const Node* node) const;
+ template <typename T> T* at(unsigned int index) {
+ return (T*)(_array.at(index));
+ }
+ template <typename T> T* At(unsigned int index) {
+ return (T*)(_array.at(index));
+ }
private :
std::vector<Node*> _array;
diff --git a/include/plist/Data.h b/include/plist/Data.h
index b566a6c..1de88aa 100644
--- a/include/plist/Data.h
+++ b/include/plist/Data.h
@@ -36,6 +36,7 @@ public :
Data(const Data& d);
Data& operator=(const Data& b);
Data(const std::vector<char>& buff);
+ Data(const char* buff, uint64_t size);
virtual ~Data();
Node* Clone() const;
diff --git a/include/plist/Date.h b/include/plist/Date.h
index 5113cf3..7026699 100644
--- a/include/plist/Date.h
+++ b/include/plist/Date.h
@@ -40,13 +40,13 @@ public :
Date(plist_t node, Node* parent = NULL);
Date(const Date& d);
Date& operator=(const Date& d);
- Date(timeval t);
+ Date(int64_t t);
virtual ~Date();
Node* Clone() const;
- void SetValue(timeval t);
- timeval GetValue() const;
+ void SetValue(int64_t t);
+ int64_t GetValue() const;
};
};
diff --git a/include/plist/Dictionary.h b/include/plist/Dictionary.h
index 583a430..37ff1c9 100644
--- a/include/plist/Dictionary.h
+++ b/include/plist/Dictionary.h
@@ -60,11 +60,12 @@ public :
void Remove(Node* node);
void Remove(const std::string& key);
std::string GetNodeKey(Node* node);
+ template <typename T> T* Get(const std::string& key) {
+ return (T*)(_map[key]);
+ }
private :
std::map<std::string,Node*> _map;
-
-
};
};
diff --git a/include/plist/String.h b/include/plist/String.h
index 9aba16b..95f8dd1 100644
--- a/include/plist/String.h
+++ b/include/plist/String.h
@@ -35,7 +35,10 @@ public :
String(plist_t node, Node* parent = NULL);
String(const String& s);
String& operator=(const String& s);
+ String& operator=(const std::string& s);
+ String& operator=(const char* s);
String(const std::string& s);
+ String(const char *s);
virtual ~String();
Node* Clone() const;
diff --git a/include/plist/Structure.h b/include/plist/Structure.h
index eded8b2..b7fbdb5 100644
--- a/include/plist/Structure.h
+++ b/include/plist/Structure.h
@@ -43,6 +43,9 @@ public :
static Structure* FromXml(const std::string& xml);
static Structure* FromBin(const std::vector<char>& bin);
+ static Structure* FromBin(const char* bin, uint64_t size);
+ static Structure* FromMemory(const std::vector<char>& buf, plist_format_t* format = NULL);
+ static Structure* FromMemory(const char* buf, uint64_t size, plist_format_t* format = NULL);
protected:
Structure(Node* parent = NULL);
diff --git a/include/plist/plist.h b/include/plist/plist.h
index 46aca16..41af8ce 100644
--- a/include/plist/plist.h
+++ b/include/plist/plist.h
@@ -263,12 +263,11 @@ extern "C"
/**
* Create a new plist_t type #PLIST_DATE
*
- * @param sec the number of seconds since 01/01/2001
- * @param usec the number of microseconds
+ * @param sec The number of seconds since 01/01/1970 (UNIX timestamp)
* @return the created item
* @sa #plist_type
*/
- PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec);
+ PLIST_API plist_t plist_new_unix_date(int64_t sec);
/**
* Create a new plist_t type #PLIST_UID
@@ -492,6 +491,166 @@ extern "C"
*/
PLIST_API void plist_dict_merge(plist_t *target, plist_t source);
+ /**
+ * Get a boolean value from a given #PLIST_DICT entry.
+ *
+ * The value node can be of type #PLIST_BOOLEAN, but also
+ * #PLIST_STRING (either 'true' or 'false'),
+ * #PLIST_INT with a numerical value of 0 or >= 1,
+ * or #PLIST_DATA with a single byte with a value of 0 or >= 1.
+ *
+ * @note This function returns 0 if the dictionary does not contain an
+ * entry for the given key, if the value node is of any other than
+ * the above mentioned type, or has any mismatching value.
+ *
+ * @param dict A node of type #PLIST_DICT
+ * @param key The key to look for in dict
+ * @return 0 or 1 depending on the value of the node.
+ */
+ PLIST_API uint8_t plist_dict_get_bool(plist_t dict, const char *key);
+
+ /**
+ * Get a signed integer value from a given #PLIST_DICT entry.
+ * The value node can be of type #PLIST_INT, but also
+ * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
+ * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
+ *
+ * @note This function returns 0 if the dictionary does not contain an
+ * entry for the given key, if the value node is of any other than
+ * the above mentioned type, or has any mismatching value.
+ *
+ * @param dict A node of type #PLIST_DICT
+ * @param key The key to look for in dict
+ * @return Signed integer value depending on the value of the node.
+ */
+ PLIST_API int64_t plist_dict_get_int(plist_t dict, const char *key);
+
+ /**
+ * Get an unsigned integer value from a given #PLIST_DICT entry.
+ * The value node can be of type #PLIST_INT, but also
+ * #PLIST_STRING with a numerical value as string (decimal or hexadecimal),
+ * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order.
+ *
+ * @note This function returns 0 if the dictionary does not contain an
+ * entry for the given key, if the value node is of any other than
+ * the above mentioned type, or has any mismatching value.
+ *
+ * @param dict A node of type #PLIST_DICT
+ * @param key The key to look for in dict
+ * @return Signed integer value depending on the value of the node.
+ */
+ PLIST_API uint64_t plist_dict_get_uint(plist_t dict, const char *key);
+
+ /**
+ * Copy a node from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key.
+ */
+ PLIST_API plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+
+ /**
+ * Copy a boolean value from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @note The boolean value from *source_dict* is retrieved with #plist_dict_get_bool,
+ * but is **always** created as #PLIST_BOOLEAN in *target_dict*.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key.
+ */
+ PLIST_API plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+
+ /**
+ * Copy a signed integer value from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @note The signed integer value from *source_dict* is retrieved with #plist_dict_get_int,
+ * but is **always** created as #PLIST_INT.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node value to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key.
+ */
+ PLIST_API plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+
+ /**
+ * Copy an unsigned integer value from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @note The unsigned integer value from *source_dict* is retrieved with #plist_dict_get_uint,
+ * but is **always** created as #PLIST_INT.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node value to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key.
+ */
+ PLIST_API plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+
+ /**
+ * Copy a #PLIST_DATA node from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @note This function is like #plist_dict_copy_item, except that it fails
+ * if the source node is not of type #PLIST_DATA.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node value to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key, or if it is not of type #PLIST_DATA.
+ */
+ PLIST_API plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+
+ /**
+ * Copy a #PLIST_STRING node from *source_dict* to *target_dict*.
+ * The node is looked up in *source_dict* with given *key*, unless *alt_source_key*
+ * is non-NULL, in which case it is looked up with *alt_source_key*.
+ * The entry in *target_dict* is **always** created with *key*.
+ *
+ * @note This function is like #plist_dict_copy_item, except that it fails
+ * if the source node is not of type #PLIST_STRING.
+ *
+ * @param target_dict The target dictionary to copy to.
+ * @param source_dict The source dictionary to copy from.
+ * @param key The key for the node value to copy.
+ * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL.
+ *
+ * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain
+ * any entry with given key or alt_source_key, or if it is not of type #PLIST_STRING.
+ */
+ PLIST_API plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
/********************************************
* *
@@ -615,10 +774,9 @@ extern "C"
* This function does nothing if node is not of type #PLIST_DATE
*
* @param node the node
- * @param sec a pointer to an int32_t variable. Represents the number of seconds since 01/01/2001.
- * @param usec a pointer to an int32_t variable. Represents the number of microseconds
+ * @param sec a pointer to an int64_t variable. Represents the number of seconds since 01/01/1970 (UNIX timestamp).
*/
- PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec);
+ PLIST_API void plist_get_unix_date_val(plist_t node, int64_t *sec);
/**
* Get the value of a #PLIST_UID node.
@@ -707,10 +865,9 @@ extern "C"
* Forces type of node to #PLIST_DATE
*
* @param node the node
- * @param sec the number of seconds since 01/01/2001
- * @param usec the number of microseconds
+ * @param sec the number of seconds since 01/01/1970 (UNIX timestamp)
*/
- PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec);
+ PLIST_API void plist_set_unix_date_val(plist_t node, int64_t sec);
/**
* Set the value of a node.
@@ -1053,16 +1210,15 @@ extern "C"
/**
* Helper function to compare the value of a PLIST_DATE node against
- * a given set of seconds and fraction of a second since epoch.
+ * a given number of seconds since epoch (UNIX timestamp).
*
* @param datenode node of type PLIST_DATE
- * @param cmpsec number of seconds since epoch to compare against
- * @param cmpusec fraction of a second in microseconds to compare against
+ * @param cmpval Number of seconds to compare against (UNIX timestamp)
* @return 0 if the node's date is equal to the supplied values,
* 1 if the node's date is greater than the supplied values,
* or -1 if the node's date is less than the supplied values.
*/
- PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec);
+ PLIST_API int plist_unix_date_val_compare(plist_t datenode, int64_t cmpval);
/**
* Helper function to compare the value of a PLIST_STRING node against
@@ -1222,6 +1378,68 @@ extern "C"
*/
PLIST_API const char* libplist_version();
+
+ /********************************************
+ * *
+ * Deprecated API *
+ * *
+ ********************************************/
+
+ /**
+ * Create a new plist_t type #PLIST_DATE
+ *
+ * @deprecated Deprecated. Use plist_new_unix_date instead.
+ *
+ * @param sec the number of seconds since 01/01/2001
+ * @param usec the number of microseconds
+ * @return the created item
+ * @sa #plist_type
+ */
+ PLIST_WARN_DEPRECATED("use plist_new_unix_date instead")
+ PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec);
+
+ /**
+ * Get the value of a #PLIST_DATE node.
+ * This function does nothing if node is not of type #PLIST_DATE
+ *
+ * @deprecated Deprecated. Use plist_get_unix_date_val instead.
+ *
+ * @param node the node
+ * @param sec a pointer to an int32_t variable. Represents the number of seconds since 01/01/2001.
+ * @param usec a pointer to an int32_t variable. Represents the number of microseconds
+ */
+ PLIST_WARN_DEPRECATED("use plist_get_unix_date_val instead")
+ PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec);
+
+ /**
+ * Set the value of a node.
+ * Forces type of node to #PLIST_DATE
+ *
+ * @deprecated Deprecated. Use plist_set_unix_date_val instead.
+ *
+ * @param node the node
+ * @param sec the number of seconds since 01/01/2001
+ * @param usec the number of microseconds
+ */
+ PLIST_WARN_DEPRECATED("use plist_set_unix_date_val instead")
+ PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec);
+
+ /**
+ * Helper function to compare the value of a PLIST_DATE node against
+ * a given set of seconds and fraction of a second since epoch.
+ *
+ * @deprecated Deprecated. Use plist_unix_date_val_compare instead.
+ *
+ * @param datenode node of type PLIST_DATE
+ * @param cmpsec number of seconds since epoch to compare against
+ * @param cmpusec fraction of a second in microseconds to compare against
+ * @return 0 if the node's date is equal to the supplied values,
+ * 1 if the node's date is greater than the supplied values,
+ * or -1 if the node's date is less than the supplied values.
+ */
+ PLIST_WARN_DEPRECATED("use plist_unix_date_val_compare instead")
+ PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec);
+
/*@}*/
#ifdef __cplusplus
diff --git a/m4/ax_python_devel.m4 b/m4/ax_python_devel.m4
index 44dbd83..935056c 100644
--- a/m4/ax_python_devel.m4
+++ b/m4/ax_python_devel.m4
@@ -4,7 +4,7 @@
#
# SYNOPSIS
#
-# AX_PYTHON_DEVEL([version])
+# AX_PYTHON_DEVEL([version[,optional]])
#
# DESCRIPTION
#
@@ -23,6 +23,11 @@
# version number. Don't use "PYTHON_VERSION" for this: that environment
# variable is declared as precious and thus reserved for the end-user.
#
+# By default this will fail if it does not detect a development version of
+# python. If you want it to continue, set optional to true, like
+# AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be
+# "no" if it fails.
+#
# This macro should work for all versions of Python >= 2.1.0. As an end
# user, you can disable the check for the python version by setting the
# PYTHON_NOVERSIONCHECK environment variable to something else than the
@@ -67,10 +72,18 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 21
+#serial 37
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
AC_DEFUN([AX_PYTHON_DEVEL],[
+ # Get whether it's optional
+ if test -z "$2"; then
+ ax_python_devel_optional=false
+ else
+ ax_python_devel_optional=$2
+ fi
+ ax_python_devel_found=yes
+
#
# Allow the use of a (user set) custom python version
#
@@ -81,21 +94,26 @@ AC_DEFUN([AX_PYTHON_DEVEL],[
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
- AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
+ AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up, python development not available])
+ fi
+ ax_python_devel_found=no
PYTHON_VERSION=""
fi
- #
- # Check for a version of Python >= 2.1.0
- #
- AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check for a version of Python >= 2.1.0
+ #
+ AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
+ ac_supports_python_ver=`$PYTHON -c "import sys; \
ver = sys.version.split ()[[0]]; \
print (ver >= '2.1.0')"`
- if test "$ac_supports_python_ver" != "True"; then
+ if test "$ac_supports_python_ver" != "True"; then
if test -z "$PYTHON_NOVERSIONCHECK"; then
AC_MSG_RESULT([no])
- AC_MSG_FAILURE([
+ AC_MSG_WARN([
This version of the AC@&t@_PYTHON_DEVEL macro
doesn't work properly with versions of Python before
2.1.0. You may need to re-run configure, setting the
@@ -104,58 +122,119 @@ PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
to something else than an empty string.
])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_FAILURE([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
else
AC_MSG_RESULT([skip at user request])
fi
- else
+ else
AC_MSG_RESULT([yes])
+ fi
fi
- #
- # if the macro parameter ``version'' is set, honour it
- #
- if test -n "$1"; then
+ if test $ax_python_devel_found = yes; then
+ #
+ # If the macro parameter ``version'' is set, honour it.
+ # A Python shim class, VPy, is used to implement correct version comparisons via
+ # string expressions, since e.g. a naive textual ">= 2.7.3" won't work for
+ # Python 2.7.10 (the ".1" being evaluated as less than ".3").
+ #
+ if test -n "$1"; then
AC_MSG_CHECKING([for a version of Python $1])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
- ver = sys.version.split ()[[0]]; \
+ cat << EOF > ax_python_devel_vpy.py
+class VPy:
+ def vtup(self, s):
+ return tuple(map(int, s.strip().replace("rc", ".").split(".")))
+ def __init__(self):
+ import sys
+ self.vpy = tuple(sys.version_info)[[:3]]
+ def __eq__(self, s):
+ return self.vpy == self.vtup(s)
+ def __ne__(self, s):
+ return self.vpy != self.vtup(s)
+ def __lt__(self, s):
+ return self.vpy < self.vtup(s)
+ def __gt__(self, s):
+ return self.vpy > self.vtup(s)
+ def __le__(self, s):
+ return self.vpy <= self.vtup(s)
+ def __ge__(self, s):
+ return self.vpy >= self.vtup(s)
+EOF
+ ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \
+ ver = ax_python_devel_vpy.VPy(); \
print (ver $1)"`
+ rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py*
if test "$ac_supports_python_ver" = "True"; then
- AC_MSG_RESULT([yes])
+ AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
- AC_MSG_ERROR([this package requires Python $1.
+ AC_MSG_WARN([this package requires Python $1.
If you have it installed, but it isn't the default Python
interpreter in your system path, please pass the PYTHON_VERSION
variable to configure. See ``configure --help'' for reference.
])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
PYTHON_VERSION=""
fi
+ fi
fi
- #
- # Check if you have distutils, else fail
- #
- AC_MSG_CHECKING([for the distutils Python package])
- ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
- if test $? -eq 0; then
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check if you have distutils, else fail
+ #
+ AC_MSG_CHECKING([for the sysconfig Python package])
+ ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
+ if test $? -eq 0; then
AC_MSG_RESULT([yes])
- else
+ IMPORT_SYSCONFIG="import sysconfig"
+ else
AC_MSG_RESULT([no])
- AC_MSG_ERROR([cannot import Python module "distutils".
+
+ AC_MSG_CHECKING([for the distutils Python package])
+ ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
+ if test $? -eq 0; then
+ AC_MSG_RESULT([yes])
+ IMPORT_SYSCONFIG="from distutils import sysconfig"
+ else
+ AC_MSG_WARN([cannot import Python module "distutils".
Please check your Python installation. The error was:
-$ac_distutils_result])
- PYTHON_VERSION=""
+$ac_sysconfig_result])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
+ fi
+ fi
fi
- #
- # Check for Python include path
- #
- AC_MSG_CHECKING([for Python include path])
- if test -z "$PYTHON_CPPFLAGS"; then
- python_path=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_inc ());"`
- plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check for Python include path
+ #
+ AC_MSG_CHECKING([for Python include path])
+ if test -z "$PYTHON_CPPFLAGS"; then
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
+ # sysconfig module has different functions
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_path ('include'));"`
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_path ('platinclude'));"`
+ else
+ # old distutils way
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_inc ());"`
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_inc (plat_specific=1));"`
+ fi
if test -n "${python_path}"; then
if test "${plat_python_path}" != "${python_path}"; then
python_path="-I$python_path -I$plat_python_path"
@@ -164,22 +243,22 @@ $ac_distutils_result])
fi
fi
PYTHON_CPPFLAGS=$python_path
- fi
- AC_MSG_RESULT([$PYTHON_CPPFLAGS])
- AC_SUBST([PYTHON_CPPFLAGS])
+ fi
+ AC_MSG_RESULT([$PYTHON_CPPFLAGS])
+ AC_SUBST([PYTHON_CPPFLAGS])
- #
- # Check for Python library path
- #
- AC_MSG_CHECKING([for Python library path])
- if test -z "$PYTHON_LIBS"; then
+ #
+ # Check for Python library path
+ #
+ AC_MSG_CHECKING([for Python library path])
+ if test -z "$PYTHON_LIBS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
ac_python_version=`cat<<EOD | $PYTHON -
# join all versioning strings, on some systems
# major/minor numbers could be in different list elements
-from distutils.sysconfig import *
+from sysconfig import *
e = get_config_var('VERSION')
if e is not None:
print(e)
@@ -190,7 +269,7 @@ EOD`
ac_python_version=$PYTHON_VERSION
else
ac_python_version=`$PYTHON -c "import sys; \
- print (sys.version[[:3]])"`
+ print ("%d.%d" % sys.version_info[[:2]])"`
fi
fi
@@ -202,8 +281,8 @@ EOD`
ac_python_libdir=`cat<<EOD | $PYTHON -
# There should be only one
-import distutils.sysconfig
-e = distutils.sysconfig.get_config_var('LIBDIR')
+$IMPORT_SYSCONFIG
+e = sysconfig.get_config_var('LIBDIR')
if e is not None:
print (e)
EOD`
@@ -211,8 +290,8 @@ EOD`
# Now, for the library:
ac_python_library=`cat<<EOD | $PYTHON -
-import distutils.sysconfig
-c = distutils.sysconfig.get_config_vars()
+$IMPORT_SYSCONFIG
+c = sysconfig.get_config_vars()
if 'LDVERSION' in c:
print ('python'+c[['LDVERSION']])
else:
@@ -231,83 +310,140 @@ EOD`
else
# old way: use libpython from python_configdir
ac_python_libdir=`$PYTHON -c \
- "from distutils.sysconfig import get_python_lib as f; \
+ "from sysconfig import get_python_lib as f; \
import os; \
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
fi
- if test -z "PYTHON_LIBS"; then
- AC_MSG_ERROR([
+ if test -z "$PYTHON_LIBS"; then
+ AC_MSG_WARN([
Cannot determine location of your Python DSO. Please check it was installed with
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
fi
+ fi
fi
- AC_MSG_RESULT([$PYTHON_LIBS])
- AC_SUBST([PYTHON_LIBS])
- #
- # Check for site packages
- #
- AC_MSG_CHECKING([for Python site-packages path])
- if test -z "$PYTHON_SITE_PKG"; then
- PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_lib(0,0));"`
- fi
- AC_MSG_RESULT([$PYTHON_SITE_PKG])
- AC_SUBST([PYTHON_SITE_PKG])
+ if test $ax_python_devel_found = yes; then
+ AC_MSG_RESULT([$PYTHON_LIBS])
+ AC_SUBST([PYTHON_LIBS])
- #
- # libraries which must be linked in when embedding
- #
- AC_MSG_CHECKING(python extra libraries)
- if test -z "$PYTHON_EXTRA_LIBS"; then
- PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
- conf = distutils.sysconfig.get_config_var; \
+ #
+ # Check for site packages
+ #
+ AC_MSG_CHECKING([for Python site-packages path])
+ if test -z "$PYTHON_SITE_PKG"; then
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
+ PYTHON_SITE_PKG=`$PYTHON -c "
+$IMPORT_SYSCONFIG;
+if hasattr(sysconfig, 'get_default_scheme'):
+ scheme = sysconfig.get_default_scheme()
+else:
+ scheme = sysconfig._get_default_scheme()
+if scheme == 'posix_local':
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
+ scheme = 'posix_prefix'
+prefix = '$prefix'
+if prefix == 'NONE':
+ prefix = '$ac_default_prefix'
+sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix})
+print(sitedir)"`
+ else
+ # distutils.sysconfig way
+ PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_lib(0,0));"`
+ fi
+ fi
+ AC_MSG_RESULT([$PYTHON_SITE_PKG])
+ AC_SUBST([PYTHON_SITE_PKG])
+
+ #
+ # Check for platform-specific site packages
+ #
+ AC_MSG_CHECKING([for Python platform specific site-packages path])
+ if test -z "$PYTHON_PLATFORM_SITE_PKG"; then
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
+ PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "
+$IMPORT_SYSCONFIG;
+if hasattr(sysconfig, 'get_default_scheme'):
+ scheme = sysconfig.get_default_scheme()
+else:
+ scheme = sysconfig._get_default_scheme()
+if scheme == 'posix_local':
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
+ scheme = 'posix_prefix'
+prefix = '$prefix'
+if prefix == 'NONE':
+ prefix = '$ac_default_prefix'
+sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase': prefix})
+print(sitedir)"`
+ else
+ # distutils.sysconfig way
+ PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_lib(1,0));"`
+ fi
+ fi
+ AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
+ AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
+
+ #
+ # libraries which must be linked in when embedding
+ #
+ AC_MSG_CHECKING(python extra libraries)
+ if test -z "$PYTHON_EXTRA_LIBS"; then
+ PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ conf = sysconfig.get_config_var; \
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
- fi
- AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
- AC_SUBST(PYTHON_EXTRA_LIBS)
+ fi
+ AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
+ AC_SUBST(PYTHON_EXTRA_LIBS)
- #
- # linking flags needed when embedding
- #
- AC_MSG_CHECKING(python extra linking flags)
- if test -z "$PYTHON_EXTRA_LDFLAGS"; then
- PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
- conf = distutils.sysconfig.get_config_var; \
+ #
+ # linking flags needed when embedding
+ #
+ AC_MSG_CHECKING(python extra linking flags)
+ if test -z "$PYTHON_EXTRA_LDFLAGS"; then
+ PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ conf = sysconfig.get_config_var; \
print (conf('LINKFORSHARED'))"`
- fi
- AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
- AC_SUBST(PYTHON_EXTRA_LDFLAGS)
+ # Hack for macos, it sticks this in here.
+ PYTHON_EXTRA_LDFLAGS=`echo $PYTHON_EXTRA_LDFLAGS | sed 's/CoreFoundation.*$/CoreFoundation/'`
+ fi
+ AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
+ AC_SUBST(PYTHON_EXTRA_LDFLAGS)
- #
- # final check to see if everything compiles alright
- #
- AC_MSG_CHECKING([consistency of all components of python development environment])
- # save current global flags
- ac_save_LIBS="$LIBS"
- ac_save_LDFLAGS="$LDFLAGS"
- ac_save_CPPFLAGS="$CPPFLAGS"
- LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS"
- LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
- CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
- AC_LANG_PUSH([C])
- AC_LINK_IFELSE([
+ #
+ # final check to see if everything compiles alright
+ #
+ AC_MSG_CHECKING([consistency of all components of python development environment])
+ # save current global flags
+ ac_save_LIBS="$LIBS"
+ ac_save_LDFLAGS="$LDFLAGS"
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS"
+ LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
+ CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
+ AC_LANG_PUSH([C])
+ AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <Python.h>]],
[[Py_Initialize();]])
],[pythonexists=yes],[pythonexists=no])
- AC_LANG_POP([C])
- # turn back to default flags
- CPPFLAGS="$ac_save_CPPFLAGS"
- LIBS="$ac_save_LIBS"
- LDFLAGS="$ac_save_LDFLAGS"
+ AC_LANG_POP([C])
+ # turn back to default flags
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ LDFLAGS="$ac_save_LDFLAGS"
- AC_MSG_RESULT([$pythonexists])
+ AC_MSG_RESULT([$pythonexists])
- if test ! "x$pythonexists" = "xyes"; then
- AC_MSG_FAILURE([
+ if test ! "x$pythonexists" = "xyes"; then
+ AC_MSG_WARN([
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LIBS environment variable.
@@ -317,8 +453,13 @@ EOD`
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================
- ])
- PYTHON_VERSION=""
+ ])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
+ fi
fi
#
diff --git a/src/Array.cpp b/src/Array.cpp
index bc448d3..49b8924 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());
@@ -88,6 +90,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 +154,7 @@ size_t Array::size() const {
return _array.size();
}
-void Array::Append(Node* node)
+void Array::Append(const Node* node)
{
if (node)
{
@@ -143,7 +165,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 +183,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 +200,7 @@ void Array::Remove(Node* node)
std::vector<Node*>::iterator it = _array.begin();
it += pos;
_array.erase(it);
- delete node;
+ free(node);
}
}
@@ -181,10 +213,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/Data.cpp b/src/Data.cpp
index a96fc50..56b2d6b 100644
--- a/src/Data.cpp
+++ b/src/Data.cpp
@@ -50,6 +50,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 +71,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..cbfa123 100644
--- a/src/Date.cpp
+++ b/src/Date.cpp
@@ -34,8 +34,8 @@ 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)
@@ -45,9 +45,9 @@ Date& Date::operator=(const PList::Date& d)
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 +59,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..0a909e5 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++)
{
@@ -176,9 +176,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..653455d 100644
--- a/src/Integer.cpp
+++ b/src/Integer.cpp
@@ -35,7 +35,8 @@ 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)
diff --git a/src/Key.cpp b/src/Key.cpp
index 79265d5..86a0bf8 100644
--- a/src/Key.cpp
+++ b/src/Key.cpp
@@ -69,7 +69,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/String.cpp b/src/String.cpp
index 2ddc28b..8daec0f 100644
--- a/src/String.cpp
+++ b/src/String.cpp
@@ -45,11 +45,30 @@ String& String::operator=(const PList::String& s)
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 +85,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/bplist.c b/src/bplist.c
index 93f0bc6..85e55e2 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
@@ -271,19 +306,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__);
@@ -343,7 +389,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) {
diff --git a/src/jplist.c b/src/jplist.c
index 782d2b3..1c7a932 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -72,8 +72,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 +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)
{
@@ -460,6 +464,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 +528,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 +552,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 {
diff --git a/src/oplist.c b/src/oplist.c
index 6ab6603..33896f9 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -71,8 +71,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 +84,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)
{
diff --git a/src/plist.c b/src/plist.c
index 2078520..fe98f34 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;
}
@@ -509,6 +530,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 +987,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,6 +1403,20 @@ 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;
@@ -1340,7 +1573,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 +1701,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 +1720,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 +1837,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 +1860,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/tools/Makefile.am b/tools/Makefile.am
index 9f3214d..5883286 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,3 +1,5 @@
+if BUILD_TOOLS
+
AM_CFLAGS = \
$(GLOBAL_CFLAGS) \
-I$(top_srcdir)/include
@@ -8,3 +10,5 @@ bin_PROGRAMS = plistutil
plistutil_SOURCES = plistutil.c
plistutil_LDADD = $(top_builddir)/src/libplist-2.0.la
+
+endif
diff --git a/tools/plistutil.c b/tools/plistutil.c
index 8121a7d..b6b64d3 100644
--- a/tools/plistutil.c
+++ b/tools/plistutil.c
@@ -32,10 +32,13 @@
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
+#ifndef _MSC_VER
#include <unistd.h>
+#endif
#ifdef _MSC_VER
#pragma warning(disable:4996)
+#define STDIN_FILENO _fileno(stdin)
#endif
typedef struct _options
@@ -170,7 +173,7 @@ static options_t *parse_arguments(int argc, char *argv[])
}
else if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v"))
{
- printf("plistutil %s\n", PACKAGE_VERSION);
+ printf("plistutil %s\n", libplist_version());
exit(EXIT_SUCCESS);
}
else