diff options
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | include/plist/plist.h | 183 | ||||
| -rw-r--r-- | src/plist.c | 231 |
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 | |||
| 54 | AC_TYPE_UINT8_T | 54 | AC_TYPE_UINT8_T |
| 55 | 55 | ||
| 56 | # Checks for library functions. | 56 | # Checks for library functions. |
| 57 | AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf gmtime_r localtime_r timegm strptime]) | 57 | AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf gmtime_r localtime_r timegm strptime memmem]) |
| 58 | 58 | ||
| 59 | # Checking endianness | 59 | # Checking endianness |
| 60 | AC_C_BIGENDIAN([AC_DEFINE([__BIG_ENDIAN__], [1], [big endian])], | 60 | AC_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. */ | ||
| 128 | void* 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 | ||
| 115 | PLIST_API int plist_is_binary(const char *plist_data, uint32_t length) | 168 | PLIST_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 | ||
| 1188 | PLIST_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 | |||
| 1198 | PLIST_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 | |||
| 1214 | PLIST_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 | |||
| 1230 | PLIST_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 | |||
| 1259 | PLIST_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 | |||
| 1278 | PLIST_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 | |||
| 1287 | PLIST_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 | |||
| 1296 | PLIST_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 | |||
| 1305 | PLIST_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 | |||
| 1314 | PLIST_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 | |||
| 1323 | PLIST_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 | |||
| 1332 | PLIST_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 | |||
| 1346 | PLIST_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 | |||
| 1358 | PLIST_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 | } | ||
