summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--include/plist/plist.h183
-rw-r--r--src/plist.c231
3 files changed, 415 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 084095c..663aaef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,7 +54,7 @@ AC_TYPE_UINT32_T
54AC_TYPE_UINT8_T 54AC_TYPE_UINT8_T
55 55
56# Checks for library functions. 56# Checks for library functions.
57AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf gmtime_r localtime_r timegm strptime]) 57AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf gmtime_r localtime_r timegm strptime memmem])
58 58
59# Checking endianness 59# Checking endianness
60AC_C_BIGENDIAN([AC_DEFINE([__BIG_ENDIAN__], [1], [big endian])], 60AC_C_BIGENDIAN([AC_DEFINE([__BIG_ENDIAN__], [1], [big endian])],
diff --git a/include/plist/plist.h b/include/plist/plist.h
index 29b1fce..ab91612 100644
--- a/include/plist/plist.h
+++ b/include/plist/plist.h
@@ -762,6 +762,189 @@ extern "C"
762 #define PLIST_IS_KEY(__plist) _PLIST_IS_TYPE(__plist, KEY) 762 #define PLIST_IS_KEY(__plist) _PLIST_IS_TYPE(__plist, KEY)
763 #define PLIST_IS_UID(__plist) _PLIST_IS_TYPE(__plist, UID) 763 #define PLIST_IS_UID(__plist) _PLIST_IS_TYPE(__plist, UID)
764 764
765 /**
766 * Helper function to check the value of a PLIST_BOOL node.
767 *
768 * @param boolnode node of type PLIST_BOOL
769 * @return 1 if the boolean node has a value of TRUE, 0 if FALSE,
770 * or -1 if the node is not of type PLIST_BOOL
771 */
772 int plist_bool_val_is_true(plist_t boolnode);
773
774 /**
775 * Helper function to compare the value of a PLIST_UINT node against
776 * a given value.
777 *
778 * @param uintnode node of type PLIST_UINT
779 * @param cmpval value to compare against
780 * @return 0 if the node's value and cmpval are equal,
781 * 1 if the node's value is greater than cmpval,
782 * or -1 if the node's value is less than cmpval.
783 */
784 int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval);
785
786 /**
787 * Helper function to compare the value of a PLIST_UID node against
788 * a given value.
789 *
790 * @param uidnode node of type PLIST_UID
791 * @param cmpval value to compare against
792 * @return 0 if the node's value and cmpval are equal,
793 * 1 if the node's value is greater than cmpval,
794 * or -1 if the node's value is less than cmpval.
795 */
796 int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval);
797
798 /**
799 * Helper function to compare the value of a PLIST_REAL node against
800 * a given value.
801 *
802 * @note WARNING: Comparing floating point values can give inaccurate
803 * results because of the nature of floating point values on computer
804 * systems. While this function is designed to be as accurate as
805 * possible, please don't rely on it too much.
806 *
807 * @param realnode node of type PLIST_REAL
808 * @param cmpval value to compare against
809 * @return 0 if the node's value and cmpval are (almost) equal,
810 * 1 if the node's value is greater than cmpval,
811 * or -1 if the node's value is less than cmpval.
812 */
813 int plist_real_val_compare(plist_t realnode, double cmpval);
814
815 /**
816 * Helper function to compare the value of a PLIST_DATE node against
817 * a given set of seconds and fraction of a second since epoch.
818 *
819 * @param datenode node of type PLIST_DATE
820 * @param cmpsec number of seconds since epoch to compare against
821 * @param cmpusec fraction of a second in microseconds to compare against
822 * @return 0 if the node's date is equal to the supplied values,
823 * 1 if the node's date is greater than the supplied values,
824 * or -1 if the node's date is less than the supplied values.
825 */
826 int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec);
827
828 /**
829 * Helper function to compare the value of a PLIST_STRING node against
830 * a given value.
831 * This function basically behaves like strcmp.
832 *
833 * @param strnode node of type PLIST_STRING
834 * @param cmpval value to compare against
835 * @return 0 if the node's value and cmpval are equal,
836 * > 0 if the node's value is lexicographically greater than cmpval,
837 * or < 0 if the node's value is lexicographically less than cmpval.
838 */
839 int plist_string_val_compare(plist_t strnode, const char* cmpval);
840
841 /**
842 * Helper function to compare the value of a PLIST_STRING node against
843 * a given value, while not comparing more than n characters.
844 * This function basically behaves like strncmp.
845 *
846 * @param strnode node of type PLIST_STRING
847 * @param cmpval value to compare against
848 * @param n maximum number of characters to compare
849 * @return 0 if the node's value and cmpval are equal,
850 * > 0 if the node's value is lexicographically greater than cmpval,
851 * or < 0 if the node's value is lexicographically less than cmpval.
852 */
853 int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n);
854
855 /**
856 * Helper function to match a given substring in the value of a
857 * PLIST_STRING node.
858 *
859 * @param strnode node of type PLIST_STRING
860 * @param substr value to match
861 * @return 1 if the node's value contains the given substring,
862 * or 0 if not.
863 */
864 int plist_string_val_contains(plist_t strnode, const char* substr);
865
866 /**
867 * Helper function to compare the value of a PLIST_KEY node against
868 * a given value.
869 * This function basically behaves like strcmp.
870 *
871 * @param keynode node of type PLIST_KEY
872 * @param cmpval value to compare against
873 * @return 0 if the node's value and cmpval are equal,
874 * > 0 if the node's value is lexicographically greater than cmpval,
875 * or < 0 if the node's value is lexicographically less than cmpval.
876 */
877 int plist_key_val_compare(plist_t keynode, const char* cmpval);
878
879 /**
880 * Helper function to compare the value of a PLIST_KEY node against
881 * a given value, while not comparing more than n characters.
882 * This function basically behaves like strncmp.
883 *
884 * @param keynode node of type PLIST_KEY
885 * @param cmpval value to compare against
886 * @param n maximum number of characters to compare
887 * @return 0 if the node's value and cmpval are equal,
888 * > 0 if the node's value is lexicographically greater than cmpval,
889 * or < 0 if the node's value is lexicographically less than cmpval.
890 */
891 int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n);
892
893 /**
894 * Helper function to match a given substring in the value of a
895 * PLIST_KEY node.
896 *
897 * @param keynode node of type PLIST_KEY
898 * @param substr value to match
899 * @return 1 if the node's value contains the given substring,
900 * or 0 if not.
901 */
902 int plist_key_val_contains(plist_t keynode, const char* substr);
903
904 /**
905 * Helper function to compare the data of a PLIST_DATA node against
906 * a given blob and size.
907 * This function basically behaves like memcmp after making sure the
908 * size of the node's data value is equal to the size of cmpval (n),
909 * making this a "full match" comparison.
910 *
911 * @param datanode node of type PLIST_DATA
912 * @param cmpval data blob to compare against
913 * @param n size of data blob passed in cmpval
914 * @return 0 if the node's data blob and cmpval are equal,
915 * > 0 if the node's value is lexicographically greater than cmpval,
916 * or < 0 if the node's value is lexicographically less than cmpval.
917 */
918 int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n);
919
920 /**
921 * Helper function to compare the data of a PLIST_DATA node against
922 * a given blob and size, while no more than n bytes are compared.
923 * This function basically behaves like memcmp after making sure the
924 * size of the node's data value is at least n, making this a
925 * "starts with" comparison.
926 *
927 * @param datanode node of type PLIST_DATA
928 * @param cmpval data blob to compare against
929 * @param n size of data blob passed in cmpval
930 * @return 0 if the node's value and cmpval are equal,
931 * > 0 if the node's value is lexicographically greater than cmpval,
932 * or < 0 if the node's value is lexicographically less than cmpval.
933 */
934 int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n);
935
936 /**
937 * Helper function to match a given data blob within the value of a
938 * PLIST_DATA node.
939 *
940 * @param datanode node of type PLIST_KEY
941 * @param cmpval data blob to match
942 * @param n size of data blob passed in cmpval
943 * @return 1 if the node's value contains the given data blob
944 * or 0 if not.
945 */
946 int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n);
947
765 /*@}*/ 948 /*@}*/
766 949
767#ifdef __cplusplus 950#ifdef __cplusplus
diff --git a/src/plist.c b/src/plist.c
index 87be488..f58148b 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -21,6 +21,9 @@
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */ 22 */
23 23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
24 27
25#include <string.h> 28#include <string.h>
26#include "plist.h" 29#include "plist.h"
@@ -29,6 +32,7 @@
29#include <math.h> 32#include <math.h>
30#include <assert.h> 33#include <assert.h>
31#include <limits.h> 34#include <limits.h>
35#include <float.h>
32 36
33#ifdef WIN32 37#ifdef WIN32
34#include <windows.h> 38#include <windows.h>
@@ -111,6 +115,55 @@ static void __attribute__((destructor)) libplist_deinitialize(void)
111 115
112#endif 116#endif
113 117
118#ifndef HAVE_MEMMEM
119// see https://sourceware.org/legacy-ml/libc-alpha/2007-12/msg00000.html
120
121#ifndef _LIBC
122# define __builtin_expect(expr, val) (expr)
123#endif
124
125#undef memmem
126
127/* Return the first occurrence of NEEDLE in HAYSTACK. */
128void* memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len)
129{
130 /* not really Rabin-Karp, just using additive hashing */
131 char* haystack_ = (char*)haystack;
132 char* needle_ = (char*)needle;
133 int hash = 0; /* this is the static hash value of the needle */
134 int hay_hash = 0; /* rolling hash over the haystack */
135 char* last;
136 size_t i;
137
138 if (haystack_len < needle_len)
139 return NULL;
140
141 if (!needle_len)
142 return haystack_;
143
144 /* initialize hashes */
145 for (i = needle_len; i; --i) {
146 hash += *needle_++;
147 hay_hash += *haystack_++;
148 }
149
150 /* iterate over the haystack */
151 haystack_ = (char*)haystack;
152 needle_ = (char*)needle;
153 last = haystack_+(haystack_len - needle_len + 1);
154 for (; haystack_ < last; ++haystack_) {
155 if (__builtin_expect(hash == hay_hash, 0)
156 && *haystack_ == *needle_ /* prevent calling memcmp, was a optimization from existing glibc */
157 && !memcmp (haystack_, needle_, needle_len)) {
158 return haystack_;
159 }
160 /* roll the hash */
161 hay_hash -= *haystack_;
162 hay_hash += *(haystack_+needle_len);
163 }
164 return NULL;
165}
166#endif
114 167
115PLIST_API int plist_is_binary(const char *plist_data, uint32_t length) 168PLIST_API int plist_is_binary(const char *plist_data, uint32_t length)
116{ 169{
@@ -1132,3 +1185,181 @@ PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
1132 plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval)); 1185 plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval));
1133} 1186}
1134 1187
1188PLIST_API int plist_boolean_is_true(plist_t boolnode)
1189{
1190 if (!PLIST_IS_BOOLEAN(boolnode)) {
1191 return -1;
1192 }
1193 uint8_t bv = 0;
1194 plist_get_bool_val(boolnode, &bv);
1195 return (bv == 1);
1196}
1197
1198PLIST_API int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval)
1199{
1200 if (!PLIST_IS_UINT(uintnode)) {
1201 return -1;
1202 }
1203 uint64_t uintval = 0;
1204 plist_get_uint_val(uintnode, &uintval);
1205 if (uintval == cmpval) {
1206 return 0;
1207 } else if (uintval < cmpval) {
1208 return -1;
1209 } else {
1210 return 1;
1211 }
1212}
1213
1214PLIST_API int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval)
1215{
1216 if (!PLIST_IS_UID(uidnode)) {
1217 return -1;
1218 }
1219 uint64_t uidval = 0;
1220 plist_get_uid_val(uidnode, &uidval);
1221 if (uidval == cmpval) {
1222 return 0;
1223 } else if (uidval < cmpval) {
1224 return -1;
1225 } else {
1226 return 1;
1227 }
1228}
1229
1230PLIST_API int plist_real_val_compare(plist_t realnode, double cmpval)
1231{
1232 if (!PLIST_IS_REAL(realnode)) {
1233 return -1;
1234 }
1235 double a = 0;
1236 double b = cmpval;
1237 plist_get_real_val(realnode, &a);
1238 double abs_a = fabs(a);
1239 double abs_b = fabs(b);
1240 double diff = fabs(a - b);
1241 if (a == b) {
1242 return 0;
1243 } else if (a == 0 || b == 0 || (abs_a + abs_b < DBL_MIN)) {
1244 if (diff < (DBL_EPSILON * DBL_MIN)) {
1245 return 0;
1246 } else if (a < b) {
1247 return -1;
1248 }
1249 } else {
1250 if ((diff / fmin(abs_a + abs_b, DBL_MAX)) < DBL_EPSILON) {
1251 return 0;
1252 } else if (a < b) {
1253 return -1;
1254 }
1255 }
1256 return 1;
1257}
1258
1259PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec)
1260{
1261 if (!PLIST_IS_DATE(datenode)) {
1262 return -1;
1263 }
1264 int32_t sec = 0;
1265 int32_t usec = 0;
1266 plist_get_date_val(datenode, &sec, &usec);
1267 uint64_t dateval = ((int64_t)sec << 32) | usec;
1268 uint64_t cmpval = ((int64_t)cmpsec << 32) | cmpusec;
1269 if (dateval == cmpval) {
1270 return 0;
1271 } else if (dateval < cmpval) {
1272 return -1;
1273 } else {
1274 return 1;
1275 }
1276}
1277
1278PLIST_API int plist_string_val_compare(plist_t strnode, const char* cmpval)
1279{
1280 if (!PLIST_IS_STRING(strnode)) {
1281 return -1;
1282 }
1283 plist_data_t data = plist_get_data(strnode);
1284 return strcmp(data->strval, cmpval);
1285}
1286
1287PLIST_API int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n)
1288{
1289 if (!PLIST_IS_STRING(strnode)) {
1290 return -1;
1291 }
1292 plist_data_t data = plist_get_data(strnode);
1293 return strncmp(data->strval, cmpval, n);
1294}
1295
1296PLIST_API int plist_string_val_contains(plist_t strnode, const char* substr)
1297{
1298 if (!PLIST_IS_STRING(strnode)) {
1299 return 0;
1300 }
1301 plist_data_t data = plist_get_data(strnode);
1302 return (strstr(data->strval, substr) != NULL);
1303}
1304
1305PLIST_API int plist_key_val_compare(plist_t keynode, const char* cmpval)
1306{
1307 if (!PLIST_IS_KEY(keynode)) {
1308 return -1;
1309 }
1310 plist_data_t data = plist_get_data(keynode);
1311 return strcmp(data->strval, cmpval);
1312}
1313
1314PLIST_API int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n)
1315{
1316 if (!PLIST_IS_KEY(keynode)) {
1317 return -1;
1318 }
1319 plist_data_t data = plist_get_data(keynode);
1320 return strncmp(data->strval, cmpval, n);
1321}
1322
1323PLIST_API int plist_key_val_contains(plist_t keynode, const char* substr)
1324{
1325 if (!PLIST_IS_KEY(keynode)) {
1326 return 0;
1327 }
1328 plist_data_t data = plist_get_data(keynode);
1329 return (strstr(data->strval, substr) != NULL);
1330}
1331
1332PLIST_API int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n)
1333{
1334 if (!PLIST_IS_DATA(datanode)) {
1335 return -1;
1336 }
1337 plist_data_t data = plist_get_data(datanode);
1338 if (data->length < n) {
1339 return -1;
1340 } else if (data->length > n) {
1341 return 1;
1342 }
1343 return memcmp(data->buff, cmpval, n);
1344}
1345
1346PLIST_API int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n)
1347{
1348 if (!PLIST_IS_DATA(datanode)) {
1349 return -1;
1350 }
1351 plist_data_t data = plist_get_data(datanode);
1352 if (data->length < n) {
1353 return -1;
1354 }
1355 return memcmp(data->buff, cmpval, n);
1356}
1357
1358PLIST_API int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n)
1359{
1360 if (!PLIST_IS_DATA(datanode)) {
1361 return -1;
1362 }
1363 plist_data_t data = plist_get_data(datanode);
1364 return (memmem(data->buff, data->length, cmpval, n) != NULL);
1365}