1 /* WEED is free software; you can redistribute it and/or
2    modify it under the terms of the GNU Lesser General Public
3    License as published by the Free Software Foundation; either
4    version 3 of the License, or (at your option) any later version.
5 
6    Weed is distributed in the hope that it will be useful,
7    but WITHOUT ANY WARRANTY; without even the implied warranty of
8    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9    Lesser General Public License for more details.
10 
11    You should have received a copy of the GNU Lesser General Public
12    License along with this source code; if not, write to the Free Software
13    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 
15    Weed is developed by:
16    Gabriel "Salsaman" Finch - http://lives-video.com
17 
18    partly based on LiViDO, which is developed by:
19 
20    Niels Elburg - http://veejay.sf.net
21    Denis "Jaromil" Rojo - http://freej.dyne.org
22    Tom Schouten - http://zwizwa.fartit.com
23    Andraz Tori - http://cvs.cinelerra.org
24 
25    reviewed with suggestions and contributions from:
26    Silvano "Kysucix" Galliani - http://freej.dyne.org
27    Kentaro Fukuchi - http://megaui.net/fukuchi
28    Jun Iio - http://www.malib.net
29    Carlo Prelz - http://www2.fluido.as:8080/
30 */
31 
32 /* (C) G. Finch, 2005 - 2020 */
33 
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 
38 #define __LIBWEED__
39 #define __WEED__HOST__
40 
41 #ifndef NEED_LOCAL_WEED
42 #include <weed/weed.h>
43 #include <weed/weed-effects.h>
44 #include <weed/weed-utils.h>
45 #else
46 #include "weed.h"
47 #include "weed-effects.h"
48 #include "weed-utils.h"
49 #endif
50 
51 /////////////////////////////////////////////////////////////////
52 
53 #define weed_get_value(plant, key, value) weed_leaf_get(plant, key, 0, value)
54 #define weed_check_leaf(plant, key) weed_get_value(plant, key, NULL)
55 
56 static weed_malloc_f _malloc_func = malloc;
57 static weed_calloc_f _calloc_func = calloc;
58 static weed_memcpy_f _memcpy_func = memcpy;
59 static weed_memcmp_f _memcmp_func = memcmp;
60 static weed_free_f _free_func = free;
61 
62 
weed_utils_set_custom_memfuncs(weed_malloc_f malloc_func,weed_calloc_f calloc_func,weed_memcpy_f memcpy_func,weed_memcmp_f memcmp_func,weed_free_f free_func)63 void weed_utils_set_custom_memfuncs(weed_malloc_f malloc_func, weed_calloc_f calloc_func, weed_memcpy_f memcpy_func,
64                                     weed_memcmp_f memcmp_func, weed_free_f free_func) {
65   if (malloc_func) _malloc_func = malloc_func;
66   if (calloc_func) _calloc_func = calloc_func;
67   if (memcpy_func) _memcpy_func = memcpy_func;
68   if (memcmp_func) _memcmp_func = memcmp_func;
69   if (free_func) _free_func = free_func;
70 }
71 
72 
weed_plant_has_leaf(weed_plant_t * plant,const char * key)73 int weed_plant_has_leaf(weed_plant_t *plant, const char *key) {
74   // check for existence of a leaf, must have a value and not just a seed_type
75   if (weed_check_leaf(plant, key) == WEED_SUCCESS) return WEED_TRUE;
76   return WEED_FALSE;
77 }
78 
79 
weed_leaf_exists(weed_plant_t * plant,const char * key)80 int weed_leaf_exists(weed_plant_t *plant, const char *key) {
81   // check for existence of a leaf, may have only a seed_type but no value set
82   if (weed_leaf_seed_type(plant, key) == WEED_SEED_INVALID) return WEED_FALSE;
83   return WEED_TRUE;
84 }
85 
86 
87 /////////////////////////////////////////////////////////////////
88 // leaf setters
89 
weed_set_int_value(weed_plant_t * plant,const char * key,int32_t value)90 weed_error_t weed_set_int_value(weed_plant_t *plant, const char *key, int32_t value) {
91   return weed_leaf_set(plant, key, WEED_SEED_INT, 1, (weed_voidptr_t)&value);
92 }
93 
94 
weed_set_double_value(weed_plant_t * plant,const char * key,double value)95 weed_error_t weed_set_double_value(weed_plant_t *plant, const char *key, double value) {
96   return weed_leaf_set(plant, key, WEED_SEED_DOUBLE, 1, (weed_voidptr_t)&value);
97 }
98 
99 
weed_set_boolean_value(weed_plant_t * plant,const char * key,int32_t value)100 weed_error_t weed_set_boolean_value(weed_plant_t *plant, const char *key, int32_t value) {
101   return weed_leaf_set(plant, key, WEED_SEED_BOOLEAN, 1, (weed_voidptr_t)&value);
102 }
103 
104 
weed_set_int64_value(weed_plant_t * plant,const char * key,int64_t value)105 weed_error_t weed_set_int64_value(weed_plant_t *plant, const char *key, int64_t value) {
106   return weed_leaf_set(plant, key, WEED_SEED_INT64, 1, (weed_voidptr_t)&value);
107 }
108 
109 
weed_set_string_value(weed_plant_t * plant,const char * key,const char * value)110 weed_error_t weed_set_string_value(weed_plant_t *plant, const char *key, const char *value) {
111   return weed_leaf_set(plant, key, WEED_SEED_STRING, 1, (weed_voidptr_t)&value);
112 }
113 
114 
weed_set_funcptr_value(weed_plant_t * plant,const char * key,weed_voidptr_t value)115 weed_error_t weed_set_funcptr_value(weed_plant_t *plant, const char *key, weed_voidptr_t value) {
116   return weed_leaf_set(plant, key, WEED_SEED_FUNCPTR, 1, (weed_voidptr_t)&value);
117 }
118 
119 
weed_set_voidptr_value(weed_plant_t * plant,const char * key,weed_voidptr_t value)120 weed_error_t weed_set_voidptr_value(weed_plant_t *plant, const char *key, weed_voidptr_t value) {
121   return weed_leaf_set(plant, key, WEED_SEED_VOIDPTR, 1, (weed_voidptr_t)&value);
122 }
123 
124 
weed_set_plantptr_value(weed_plant_t * plant,const char * key,weed_plant_t * value)125 weed_error_t weed_set_plantptr_value(weed_plant_t *plant, const char *key, weed_plant_t *value) {
126   return weed_leaf_set(plant, key, WEED_SEED_PLANTPTR, 1, (weed_voidptr_t)&value);
127 }
128 
129 
weed_set_custom_value(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_voidptr_t value)130 weed_error_t weed_set_custom_value(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_voidptr_t value) {
131   return weed_leaf_set(plant, key, seed_type, 1, (weed_voidptr_t)&value);
132 }
133 
134 
135 //////////////////////////////////////////////////////////////////////////////////////////////////
136 
weed_leaf_check(weed_plant_t * plant,const char * key,uint32_t seed_type)137 static inline weed_error_t weed_leaf_check(weed_plant_t *plant, const char *key, uint32_t seed_type) {
138   weed_error_t err;
139   if ((err = weed_check_leaf(plant, key)) != WEED_SUCCESS) return err;
140   if (weed_leaf_seed_type(plant, key) != seed_type) return WEED_ERROR_WRONG_SEED_TYPE;
141   return WEED_SUCCESS;
142 }
143 
144 
weed_value_get(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_voidptr_t retval)145 static inline weed_error_t weed_value_get(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_voidptr_t retval) {
146   weed_error_t err;
147   if ((err = weed_leaf_check(plant, key, seed_type)) != WEED_SUCCESS) return err;
148   return weed_get_value(plant, key, retval);
149 }
150 
151 
152 ////////////////////////////////////////////////////////////
153 
weed_get_int_value(weed_plant_t * plant,const char * key,weed_error_t * error)154 int32_t weed_get_int_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
155   int32_t retval = 0;
156   weed_error_t err = weed_value_get(plant, key, WEED_SEED_INT, &retval);
157   if (error) *error = err;
158   return retval;
159 }
160 
161 
weed_get_double_value(weed_plant_t * plant,const char * key,weed_error_t * error)162 double weed_get_double_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
163   double retval = 0.;
164   weed_error_t err = weed_value_get(plant, key, WEED_SEED_DOUBLE, &retval);
165   if (error) *error = err;
166   return retval;
167 }
168 
169 
weed_get_boolean_value(weed_plant_t * plant,const char * key,weed_error_t * error)170 int32_t weed_get_boolean_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
171   int32_t retval = WEED_FALSE;
172   weed_error_t err = weed_value_get(plant, key, WEED_SEED_BOOLEAN, &retval);
173   if (error) *error = err;
174   return retval;
175 }
176 
177 
weed_get_int64_value(weed_plant_t * plant,const char * key,weed_error_t * error)178 int64_t weed_get_int64_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
179   int64_t retval = 0;
180   weed_error_t err = weed_value_get(plant, key, WEED_SEED_INT64, &retval);
181   if (error) *error = err;
182   return retval;
183 }
184 
185 
weed_get_string_value(weed_plant_t * plant,const char * key,weed_error_t * error)186 char *weed_get_string_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
187   char *retval = NULL;
188   weed_error_t err = weed_check_leaf(plant, key);
189   if (err != WEED_SUCCESS) {
190     if (error) *error = err;
191     return NULL;
192   }
193   if (weed_leaf_seed_type(plant, key) != WEED_SEED_STRING) {
194     if (error) *error = WEED_ERROR_WRONG_SEED_TYPE;
195     return NULL;
196   }
197   if ((retval = (char *)(*_malloc_func)(weed_leaf_element_size(plant, key, 0) + 1)) == NULL) {
198     if (error) *error = WEED_ERROR_MEMORY_ALLOCATION;
199     return NULL;
200   }
201   if ((err = weed_value_get(plant, key, WEED_SEED_STRING, &retval)) != WEED_SUCCESS) {
202     if (retval) {
203       (*_free_func)(retval);
204       retval = NULL;
205     }
206   }
207   if (error) *error = err;
208   return retval;
209 }
210 
211 
weed_get_voidptr_value(weed_plant_t * plant,const char * key,weed_error_t * error)212 weed_voidptr_t weed_get_voidptr_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
213   weed_voidptr_t retval = NULL;
214   weed_error_t err = weed_value_get(plant, key, WEED_SEED_VOIDPTR, &retval);
215   if (error) *error = err;
216   return retval;
217 }
218 
219 
weed_get_funcptr_value(weed_plant_t * plant,const char * key,weed_error_t * error)220 weed_funcptr_t weed_get_funcptr_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
221   weed_funcptr_t retval = NULL;
222   weed_error_t err = weed_value_get(plant, key, WEED_SEED_FUNCPTR, &retval);
223   if (error) *error = err;
224   return retval;
225 }
226 
227 
weed_get_plantptr_value(weed_plant_t * plant,const char * key,weed_error_t * error)228 weed_plant_t *weed_get_plantptr_value(weed_plant_t *plant, const char *key, weed_error_t *error) {
229   weed_plant_t *retval = NULL;
230   weed_error_t err = weed_value_get(plant, key, WEED_SEED_PLANTPTR, &retval);
231   if (error) *error = err;
232   return retval;
233 }
234 
235 
weed_get_custom_value(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_error_t * error)236 weed_voidptr_t weed_get_custom_value(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_error_t *error) {
237   weed_voidptr_t retval = NULL;
238   weed_error_t err = weed_value_get(plant, key, seed_type, &retval);
239   if (error) *error = err;
240   return retval;
241 }
242 
243 
244 ////////////////////////////////////////////////////////////
245 
weed_get_values(weed_plant_t * plant,const char * key,size_t dsize,char ** retval,int * elems)246 static inline weed_error_t weed_get_values(weed_plant_t *plant, const char *key, size_t dsize, char **retval, int *elems) {
247   weed_error_t err;
248   weed_size_t num_elems = weed_leaf_num_elements(plant, key);
249 
250   if (num_elems * dsize > 0) {
251     if ((*retval = (char *)(*_calloc_func)(num_elems, dsize)) == NULL) {
252       return WEED_ERROR_MEMORY_ALLOCATION;
253     }
254   }
255 
256   for (int i = 0; i < num_elems; i++) {
257     if ((err = weed_leaf_get(plant, key, i, (weed_voidptr_t) & (*retval)[i * dsize])) != WEED_SUCCESS) {
258       (*_free_func)(*retval);
259       *retval = NULL;
260       return err;
261     }
262   }
263   if (elems) *elems = (int)num_elems;
264   return WEED_SUCCESS;
265 }
266 
267 
weed_get_arrayx(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_size_t typelen,weed_error_t * error,int * elems)268 static inline weed_voidptr_t weed_get_arrayx(weed_plant_t *plant, const char *key,
269     uint32_t seed_type, weed_size_t typelen, weed_error_t *error, int *elems) {
270   char *retvals = NULL;
271   weed_error_t err = weed_leaf_check(plant, key, seed_type);
272   if (err != WEED_SUCCESS) {
273     if (elems) *elems = 0;
274     if (error) *error = err;
275     return NULL;
276   }
277   err = weed_get_values(plant, key, typelen, &retvals, elems);
278   if (error) *error = err;
279   return retvals;
280 }
281 
282 
weed_get_int_array_counted(weed_plant_t * plant,const char * key,int * count)283 int32_t *weed_get_int_array_counted(weed_plant_t *plant, const char *key, int *count) {
284   return (int32_t *)(weed_get_arrayx(plant, key, WEED_SEED_INT, 4, NULL, count));
285 }
weed_get_int_array(weed_plant_t * plant,const char * key,weed_error_t * error)286 int32_t *weed_get_int_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
287   return (int32_t *)(weed_get_arrayx(plant, key, WEED_SEED_INT, 4, error, NULL));
288 }
289 
weed_get_double_array_counted(weed_plant_t * plant,const char * key,int * count)290 double *weed_get_double_array_counted(weed_plant_t *plant, const char *key, int *count) {
291   return (double *)(weed_get_arrayx(plant, key, WEED_SEED_DOUBLE, 8, NULL, count));
292 }
weed_get_double_array(weed_plant_t * plant,const char * key,weed_error_t * error)293 double *weed_get_double_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
294   return (double *)(weed_get_arrayx(plant, key, WEED_SEED_DOUBLE, 8, error, NULL));
295 }
296 
weed_get_boolean_array_counted(weed_plant_t * plant,const char * key,int * count)297 int32_t *weed_get_boolean_array_counted(weed_plant_t *plant, const char *key, int *count) {
298   return (int32_t *)(weed_get_arrayx(plant, key, WEED_SEED_BOOLEAN, 4, NULL, count));
299 }
weed_get_boolean_array(weed_plant_t * plant,const char * key,weed_error_t * error)300 int32_t *weed_get_boolean_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
301   return (int32_t *)(weed_get_arrayx(plant, key, WEED_SEED_BOOLEAN, 4, error, NULL));
302 }
303 
weed_get_int64_array_counted(weed_plant_t * plant,const char * key,int * count)304 int64_t *weed_get_int64_array_counted(weed_plant_t *plant, const char *key, int *count) {
305   return (int64_t *)(weed_get_arrayx(plant, key, WEED_SEED_INT64, 8, NULL, count));
306 }
weed_get_int64_array(weed_plant_t * plant,const char * key,weed_error_t * error)307 int64_t *weed_get_int64_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
308   return (int64_t *)(weed_get_arrayx(plant, key, WEED_SEED_INT64, 8, error, NULL));
309 }
310 
311 
__weed_get_string_array__(weed_plant_t * plant,const char * key,weed_error_t * error,int * count)312 char **__weed_get_string_array__(weed_plant_t *plant, const char *key, weed_error_t *error, int *count) {
313   weed_size_t num_elems;
314   char **retvals = NULL;
315 
316   weed_error_t err = weed_leaf_check(plant, key, WEED_SEED_STRING);
317 
318   if (err != WEED_SUCCESS) {
319     if (error) *error = err;
320     return NULL;
321   }
322 
323   if ((num_elems = weed_leaf_num_elements(plant, key)) == 0) return NULL;
324 
325   if ((retvals = (char **)(*_malloc_func)(num_elems * sizeof(char *))) == NULL) {
326     if (error) *error = WEED_ERROR_MEMORY_ALLOCATION;
327     return NULL;
328   }
329 
330   for (int i = 0; i < num_elems; i++) {
331     if ((retvals[i] = (char *)(*_malloc_func)(weed_leaf_element_size(plant, key, i) + 1)) == NULL) {
332       for (--i; i >= 0; i--)(*_free_func)(retvals[i]);
333       if (error) *error = WEED_ERROR_MEMORY_ALLOCATION;
334       (*_free_func)(retvals);
335       return NULL;
336     }
337     if ((err = weed_leaf_get(plant, key, i, &retvals[i])) != WEED_SUCCESS) {
338       for (--i; i >= 0; i--)(*_free_func)(retvals[i]);
339       if (error) *error = err;
340       (*_free_func)(retvals);
341       return NULL;
342     }
343   }
344   if (error) *error = WEED_SUCCESS;
345   if (count) *count = num_elems;
346   return retvals;
347 }
348 
349 
weed_get_string_array_counted(weed_plant_t * plant,const char * key,int * count)350 char **weed_get_string_array_counted(weed_plant_t *plant, const char *key, int *count) {
351   return __weed_get_string_array__(plant, key, NULL, count);
352 }
weed_get_string_array(weed_plant_t * plant,const char * key,weed_error_t * error)353 char **weed_get_string_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
354   return __weed_get_string_array__(plant, key, error, NULL);
355 }
356 
weed_get_funcptr_array_counted(weed_plant_t * plant,const char * key,int * count)357 weed_funcptr_t *weed_get_funcptr_array_counted(weed_plant_t *plant, const char *key, int *count) {
358   return (weed_funcptr_t *)(weed_get_arrayx(plant, key, WEED_SEED_FUNCPTR, WEED_FUNCPTR_SIZE, NULL, count));
359 }
weed_get_funcptr_array(weed_plant_t * plant,const char * key,weed_error_t * error)360 weed_funcptr_t *weed_get_funcptr_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
361   return (weed_funcptr_t *)(weed_get_arrayx(plant, key, WEED_SEED_FUNCPTR, WEED_FUNCPTR_SIZE, error, NULL));
362 }
363 
weed_get_voidptr_array_counted(weed_plant_t * plant,const char * key,int * count)364 weed_voidptr_t *weed_get_voidptr_array_counted(weed_plant_t *plant, const char *key, int *count) {
365   return (weed_voidptr_t *)(weed_get_arrayx(plant, key, WEED_SEED_VOIDPTR, WEED_VOIDPTR_SIZE, NULL, count));
366 }
weed_get_voidptr_array(weed_plant_t * plant,const char * key,weed_error_t * error)367 weed_voidptr_t *weed_get_voidptr_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
368   return (weed_voidptr_t *)(weed_get_arrayx(plant, key, WEED_SEED_VOIDPTR, WEED_VOIDPTR_SIZE, error, NULL));
369 }
370 
weed_get_plantptr_array_counted(weed_plant_t * plant,const char * key,int * count)371 weed_plant_t **weed_get_plantptr_array_counted(weed_plant_t *plant, const char *key, int *count) {
372   return (weed_plant_t **)(weed_get_arrayx(plant, key, WEED_SEED_PLANTPTR, WEED_VOIDPTR_SIZE, NULL, count));
373 }
weed_get_plantptr_array(weed_plant_t * plant,const char * key,weed_error_t * error)374 weed_plant_t **weed_get_plantptr_array(weed_plant_t *plant, const char *key, weed_error_t *error) {
375   return (weed_plant_t **)(weed_get_arrayx(plant, key, WEED_SEED_PLANTPTR, WEED_VOIDPTR_SIZE, error, NULL));
376 }
377 
weed_get_custom_array_counted(weed_plant_t * plant,const char * key,uint32_t seed_type,int * count)378 weed_voidptr_t *weed_get_custom_array_counted(weed_plant_t *plant, const char *key, uint32_t seed_type, int *count) {
379   return (weed_voidptr_t *)(weed_get_arrayx(plant, key, seed_type, WEED_VOIDPTR_SIZE, NULL, count));
380 }
weed_get_custom_array(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_error_t * error)381 weed_voidptr_t *weed_get_custom_array(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_error_t *error) {
382   return (weed_voidptr_t *)(weed_get_arrayx(plant, key, seed_type, WEED_VOIDPTR_SIZE, error, NULL));
383 }
384 
385 /////////////////////////////////////////////////////
386 
weed_set_int_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,int32_t * values)387 weed_error_t weed_set_int_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, int32_t *values) {
388   return weed_leaf_set(plant, key, WEED_SEED_INT, num_elems, (weed_voidptr_t)values);
389 }
390 
weed_set_double_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,double * values)391 weed_error_t weed_set_double_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, double *values) {
392   return weed_leaf_set(plant, key, WEED_SEED_DOUBLE, num_elems, (weed_voidptr_t)values);
393 }
394 
weed_set_boolean_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,int32_t * values)395 weed_error_t weed_set_boolean_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, int32_t *values) {
396   return weed_leaf_set(plant, key, WEED_SEED_BOOLEAN, num_elems, (weed_voidptr_t)values);
397 }
398 
weed_set_int64_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,int64_t * values)399 weed_error_t weed_set_int64_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, int64_t *values) {
400   return weed_leaf_set(plant, key, WEED_SEED_INT64, num_elems, (weed_voidptr_t)values);
401 }
402 
weed_set_string_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,char ** values)403 weed_error_t weed_set_string_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, char **values) {
404   return weed_leaf_set(plant, key, WEED_SEED_STRING, num_elems, (weed_voidptr_t)values);
405 }
406 
weed_set_funcptr_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,weed_funcptr_t * values)407 weed_error_t weed_set_funcptr_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, weed_funcptr_t *values) {
408   return weed_leaf_set(plant, key, WEED_SEED_FUNCPTR, num_elems, (weed_voidptr_t)values);
409 }
410 
weed_set_voidptr_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,weed_voidptr_t * values)411 weed_error_t weed_set_voidptr_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, weed_voidptr_t *values) {
412   return weed_leaf_set(plant, key, WEED_SEED_VOIDPTR, num_elems, (weed_voidptr_t)values);
413 }
414 
weed_set_plantptr_array(weed_plant_t * plant,const char * key,weed_size_t num_elems,weed_plant_t ** values)415 weed_error_t weed_set_plantptr_array(weed_plant_t *plant, const char *key, weed_size_t num_elems, weed_plant_t **values) {
416   return weed_leaf_set(plant, key, WEED_SEED_PLANTPTR, num_elems, (weed_voidptr_t)values);
417 }
418 
weed_set_custom_array(weed_plant_t * plant,const char * key,uint32_t seed_type,weed_size_t num_elems,weed_voidptr_t * values)419 weed_error_t weed_set_custom_array(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems,
420                                    weed_voidptr_t *values) {
421   return weed_leaf_set(plant, key, seed_type, num_elems, (weed_voidptr_t)values);
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
425 
weed_get_plant_type(weed_plant_t * plant)426 int32_t weed_get_plant_type(weed_plant_t *plant) {
427   if (!plant) return WEED_PLANT_UNKNOWN;
428   return weed_get_int_value(plant, WEED_LEAF_TYPE, NULL);
429 }
430 
431 
weed_leaf_copy_nth(weed_plant_t * dst,const char * keyt,weed_plant_t * src,const char * keyf,int n)432 weed_error_t weed_leaf_copy_nth(weed_plant_t *dst, const char *keyt, weed_plant_t *src, const char *keyf, int n) {
433   // copy a leaf from src to dest
434   // pointers are copied by reference only
435   // strings are duplicated
436 
437   // if src or dst are NULL, nothing is copied and WEED_SUCCESS is returned
438 
439   // may return the standard errors:
440   // WEED_SUCCESS, WEED_ERROR_MEMORY_ALLOCATION, WEED_ERROR_IMMUTABLE, WEED_ERROR_WRONG_SEED_TYPE
441   weed_error_t err;
442   uint32_t seed_type;
443   int num, count;
444 
445   if (!dst || !src) return WEED_SUCCESS;
446 
447   if ((err = weed_check_leaf(src, keyf)) == WEED_ERROR_NOSUCH_LEAF) return WEED_ERROR_NOSUCH_LEAF;
448 
449   seed_type = weed_leaf_seed_type(src, keyf);
450 
451   if (err == WEED_ERROR_NOSUCH_ELEMENT) {
452     err = weed_leaf_set(dst, keyt, seed_type, 0, NULL);
453   } else {
454     switch (seed_type) {
455     case WEED_SEED_INT: {
456       int32_t *datai = weed_get_arrayx(src, keyf, WEED_SEED_INT, 4, &err, &num);
457       if (err == WEED_SUCCESS) {
458         if (n >= 0) {
459           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
460           else {
461             int32_t *datai2 = weed_get_arrayx(dst, keyt, WEED_SEED_INT, 4, &err, &count);
462             if (err == WEED_SUCCESS) {
463               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
464               else {
465                 datai2[n] = datai[n];
466                 (*_free_func)(datai);
467                 datai = datai2;
468                   num = count;
469 		// *INDENT-OFF*
470  }}}}
471 	// *INDENT-ON*
472         if (err == WEED_SUCCESS)
473           err = weed_set_int_array(dst, keyt, num, datai);
474       }
475       if (datai)(*_free_func)(datai);
476     }
477     break;
478     case WEED_SEED_INT64: {
479       int64_t *datai64 = weed_get_arrayx(src, keyf, WEED_SEED_INT64, 8, &err, &num);
480       if (err == WEED_SUCCESS) {
481         if (n >= 0) {
482           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
483           else {
484             int64_t *datai642 = weed_get_arrayx(dst, keyt, WEED_SEED_INT64, 8, &err, &count);
485             if (err == WEED_SUCCESS) {
486               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
487               else {
488                 datai642[n] = datai64[n];
489                 (*_free_func)(datai64);
490                 datai64 = datai642;
491                   num = count;
492 		// *INDENT-OFF*
493  }}}}
494 	// *INDENT-ON*
495         if (err == WEED_SUCCESS)
496           err = weed_set_int64_array(dst, keyt, num, datai64);
497       }
498       if (datai64)(*_free_func)(datai64);
499     }
500     break;
501     case WEED_SEED_BOOLEAN: {
502       int32_t *datai = weed_get_arrayx(src, keyf, WEED_SEED_BOOLEAN, 4, &err, &num);
503       if (err == WEED_SUCCESS) {
504         if (n >= 0) {
505           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
506           else {
507             int32_t *datai2 = weed_get_arrayx(dst, keyt, WEED_SEED_BOOLEAN, 4, &err, &count);
508             if (err == WEED_SUCCESS) {
509               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
510               else {
511                 datai2[n] = datai[n];
512                 (*_free_func)(datai);
513                 datai = datai2;
514                   num = count;
515 		// *INDENT-OFF*
516  }}}}
517 	// *INDENT-ON*
518         if (err == WEED_SUCCESS)
519           err = weed_set_boolean_array(dst, keyt, num, datai);
520       }
521       if (datai)(*_free_func)(datai);
522     }
523     break;
524     case WEED_SEED_DOUBLE: {
525       double *datad = weed_get_arrayx(src, keyf, WEED_SEED_DOUBLE, 8, &err, &num);
526       if (err == WEED_SUCCESS) {
527         if (n >= 0) {
528           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
529           else {
530             double *datad2 = weed_get_arrayx(dst, keyt, WEED_SEED_DOUBLE, 8, &err, &count);
531             if (err == WEED_SUCCESS) {
532               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
533               else {
534                 datad2[n] = datad[n];
535                 (*_free_func)(datad);
536                 datad = datad2;
537                   num = count;
538 		// *INDENT-OFF*
539  }}}}
540 	// *INDENT-ON*
541         if (err == WEED_SUCCESS)
542           err = weed_set_double_array(dst, keyt, num, datad);
543       }
544       if (datad)(*_free_func)(datad);
545     }
546     break;
547     case WEED_SEED_FUNCPTR: {
548       weed_funcptr_t *dataf = weed_get_arrayx(src, keyf, WEED_SEED_FUNCPTR, WEED_FUNCPTR_SIZE, &err, &num);
549       if (err == WEED_SUCCESS) {
550         if (n >= 0) {
551           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
552           else {
553             weed_funcptr_t *dataf2 = NULL;
554             dataf2 = weed_get_arrayx(dst, keyt, WEED_SEED_FUNCPTR, WEED_FUNCPTR_SIZE, &err, &count);
555             if (err == WEED_SUCCESS) {
556               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
557               else {
558                 dataf2[n] = dataf[n];
559                 (*_free_func)(dataf);
560                 dataf = dataf2;
561                   num = count;
562 		// *INDENT-OFF*
563  }}}}
564 	// *INDENT-ON*
565         if (err == WEED_SUCCESS)
566           err = weed_set_funcptr_array(dst, keyt, num, dataf);
567       }
568       if (dataf)(*_free_func)(dataf);
569     }
570     break;
571     case WEED_SEED_VOIDPTR: {
572       weed_voidptr_t *datav = weed_get_arrayx(src, keyf, WEED_SEED_VOIDPTR, WEED_VOIDPTR_SIZE, &err, &num);
573       if (err == WEED_SUCCESS) {
574         if (n >= 0) {
575           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
576           else {
577             weed_voidptr_t *datav2 = weed_get_arrayx(dst, keyt, WEED_SEED_VOIDPTR, WEED_VOIDPTR_SIZE, &err, &count);
578             if (err == WEED_SUCCESS) {
579               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
580               else {
581                 datav2[n] = datav[n];
582                 (*_free_func)(datav);
583                 datav = datav2;
584                   num = count;
585 		// *INDENT-OFF*
586  }}}}
587 	// *INDENT-ON*
588         if (err == WEED_SUCCESS)
589           err = weed_set_voidptr_array(dst, keyt, num, datav);
590       }
591       if (datav)(*_free_func)(datav);
592     }
593     break;
594     case WEED_SEED_PLANTPTR: {
595       weed_plant_t **datap = weed_get_arrayx(src, keyf, WEED_SEED_PLANTPTR, WEED_VOIDPTR_SIZE, &err, &num);
596       if (err == WEED_SUCCESS) {
597         if (n >= 0) {
598           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
599           else {
600             weed_plant_t **datap2 = weed_get_arrayx(dst, keyt, WEED_SEED_PLANTPTR, WEED_VOIDPTR_SIZE, &err, &count);
601             if (err == WEED_SUCCESS) {
602               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
603               else {
604                 datap2[n] = datap[n];
605                 (*_free_func)(datap);
606                 datap = datap2;
607                   num = count;
608 		// *INDENT-OFF*
609  }}}}
610 	// *INDENT-ON*
611         if (err == WEED_SUCCESS)
612           err = weed_set_plantptr_array(dst, keyt, num, datap);
613       }
614       if (datap)(*_free_func)(datap);
615     }
616     break;
617     case WEED_SEED_STRING: {
618       char **datac = __weed_get_string_array__(src, keyf, &err, &num);
619       if (err == WEED_SUCCESS) {
620         if (n >= 0) {
621           if (n >= num) err = WEED_ERROR_NOSUCH_ELEMENT;
622           else {
623             char **datac2 = __weed_get_string_array__(dst, keyt, &err, &count);
624             if (err == WEED_SUCCESS) {
625               if (n >= count) err = WEED_ERROR_NOSUCH_ELEMENT;
626               else {
627                 (*_free_func)(datac2[n]);
628                 datac2[n] = datac[n];
629                 for (int i = 0; i < num; i++) if (i != n)(*_free_func)(datac[n]);
630                 (*_free_func)(datac);
631                 datac = datac2;
632                   num = count;
633 		// *INDENT-OFF*
634  }}}}
635 	// *INDENT-ON*
636         if (err == WEED_SUCCESS)
637           err = weed_set_string_array(dst, keyt, num, datac);
638       }
639       for (int i = 0; i < num; i++)(*_free_func)(datac[i]);
640       (*_free_func)(datac);
641     }
642     break;
643     }
644   }
645   return err;
646 }
647 
weed_leaf_copy(weed_plant_t * dst,const char * keyt,weed_plant_t * src,const char * keyf)648 weed_error_t weed_leaf_copy(weed_plant_t *dst, const char *keyt, weed_plant_t *src, const char *keyf) {
649   return weed_leaf_copy_nth(dst, keyt, src, keyf, -1);
650 }
651 
weed_leaf_dup(weed_plant_t * dst,weed_plant_t * src,const char * key)652 weed_error_t weed_leaf_dup(weed_plant_t *dst, weed_plant_t *src, const char *key) {
653   return weed_leaf_copy_nth(dst, key, src, key, -1);
654 }
655 
weed_leaf_dup_nth(weed_plant_t * dst,weed_plant_t * src,const char * key,int n)656 weed_error_t weed_leaf_dup_nth(weed_plant_t *dst, weed_plant_t *src, const char *key, int n) {
657   return weed_leaf_copy_nth(dst, key, src, key, n);
658 }
659 
weed_leaf_elements_equate(weed_plant_t * p0,const char * k0,weed_plant_t * p1,const char * k1,int elem)660 int weed_leaf_elements_equate(weed_plant_t *p0, const char *k0, weed_plant_t *p1, const char *k1, int elem) {
661   int c0, c1;
662   int32_t st;
663   weed_error_t err;
664   int ret = WEED_FALSE, i;
665   if (!p0 || !p1) return WEED_FALSE;
666   st = weed_leaf_seed_type(p0, k0);
667   if (st == WEED_SEED_INVALID || st != weed_leaf_seed_type(p1, k1)) return WEED_FALSE;
668   if (st != WEED_SEED_STRING) {
669     weed_size_t sz = weed_leaf_element_size(p0, k0, 0);
670     char *m0 = weed_get_arrayx(p0, k0, st, sz, &err, &c0);
671     if (err == WEED_SUCCESS) {
672       char *m1 = weed_get_arrayx(p1, k1, st, sz, &err, &c1);
673       if (err == WEED_SUCCESS) {
674         if (elem < 0) {
675           if (c0 == c1 && !(*_memcmp_func)(m0, m1, c0 * sz)) ret = WEED_TRUE;
676         } else if (c0 > elem && c1 > elem && !(*_memcmp_func)(m0 + elem * sz, m1 + elem * sz, sz)) ret = WEED_TRUE;
677       }
678       if (m1)(*_free_func)(m1);
679     }
680     if (m0)(*_free_func)(m0);
681   } else {
682     char **s0 = __weed_get_string_array__(p0, k0, &err, &c0);
683     if (err == WEED_SUCCESS) {
684       char **s1 = __weed_get_string_array__(p1, k1, &err, &c1);
685       if (err == WEED_SUCCESS) {
686         if (elem < 0) {
687           if (c0 == c1) {
688             for (i = 0; i < c0; i++) if (strcmp(s0[i], s1[i])) break;
689             if (i == c0) ret = WEED_TRUE;
690           }
691         } else if (c0 > elem && c1 > elem && !strcmp(s0[elem], s1[elem])) ret = WEED_TRUE;
692       }
693       if (s1) {
694         for (i = 0; i < c1; i++)(*_free_func)(s1[i]);
695         (*_free_func)(s1);
696       }
697     }
698     if (s0) {
699       for (i = 0; i < c0; i++)(*_free_func)(s0[i]);
700       (*_free_func)(s0);
701     }
702   }
703   return ret;
704 }
705 
706 
weed_plant_copy(weed_plant_t * src)707 weed_plant_t *weed_plant_copy(weed_plant_t *src) {
708   weed_plant_t *plant;
709   weed_error_t err;
710   char **proplist;
711   char *prop;
712   int i = 0;
713 
714   if (!src) return NULL;
715 
716   plant = weed_plant_new(weed_get_int_value(src, WEED_LEAF_TYPE, &err));
717   if (!plant) return NULL;
718 
719   proplist = weed_plant_list_leaves(src, NULL);
720   for (prop = proplist[0]; (prop = proplist[i]) != NULL && err == WEED_SUCCESS; i++) {
721     if (err == WEED_SUCCESS) {
722       if (strcmp(prop, WEED_LEAF_TYPE)) {
723         err = weed_leaf_copy(plant, prop, src, prop);
724         if (err == WEED_ERROR_IMMUTABLE || err == WEED_ERROR_WRONG_SEED_TYPE) err = WEED_SUCCESS; // ignore these errors
725       }
726     }(*_free_func)(prop);
727   }(*_free_func)(proplist);
728 
729   if (err == WEED_ERROR_MEMORY_ALLOCATION) {
730     //if (plant!=NULL) weed_plant_free(plant); // well, we should free the plant, but the plugins don't have this function...
731     return NULL;
732   }
733 
734   return plant;
735 }
736 
737 //////////////////////////////////////////////////////////////////////////////////////////////////////////
738 
739 #define weed_seed_is_ptr(seed_type) (seed_type >= 64 ? WEED_TRUE : WEED_FALSE)
740 
741 #define weed_seed_get_size(seed_type, size) (weed_seed_is_ptr(seed_type) ? WEED_VOIDPTR_SIZE : \
742 					      (seed_type == WEED_SEED_BOOLEAN || seed_type == WEED_SEED_INT) ? 4 : \
743 					      seed_type == WEED_SEED_DOUBLE ? 8 : \
744 					      seed_type == WEED_SEED_INT64 ? 8 : \
745 					      seed_type == WEED_SEED_STRING ? size : 0)
746 
747 
weed_find_leaf(weed_plant_t * leaf,const char * key)748 static inline weed_leaf_t *weed_find_leaf(weed_plant_t *leaf, const char *key) {
749   for (; leaf; leaf = leaf->next) {
750     if (!strcmp((char *)leaf->key, (char *)key)) return leaf;
751   }
752   return NULL;
753 }
754 
755 
_weed_default_get(weed_plant_t * plant,const char * key,void * value)756 static weed_error_t _weed_default_get(weed_plant_t *plant, const char *key, void *value) {
757   // we pass a pointer to this function back to the plugin so that it can bootstrap its real functions
758 
759   // here we must assume that the plugin does not yet have its (static) memory functions, so we can only
760   // use the standard ones
761 
762   weed_leaf_t *leaf = weed_find_leaf(plant, key);
763   if (!leaf) return WEED_ERROR_NOSUCH_LEAF;
764   if (!leaf->num_elements) return WEED_ERROR_NOSUCH_ELEMENT;
765   if (!value) return WEED_SUCCESS; // value can be NULL to check if leaf exists
766 
767   if (leaf->seed_type == WEED_SEED_FUNCPTR) {
768     if (leaf->data[0]->value.funcptr == NULL) {
769       // because this is a special function, we return an error if the value is NULL, even though the value exists
770       *((weed_funcptr_t **)value) = NULL;
771       return WEED_ERROR_NOSUCH_ELEMENT;
772     }
773     (*_memcpy_func)(value, &(((weed_data_t *)(leaf->data[0]))->value.funcptr), WEED_FUNCPTR_SIZE);
774     return WEED_SUCCESS;
775   }
776   if (weed_seed_is_ptr(leaf->seed_type)) {
777     if (leaf->data[0]->value.voidptr == NULL) *((void **)value) = NULL;
778     else (*_memcpy_func)(value, &(((weed_data_t *)(leaf->data[0]))->value.voidptr), WEED_VOIDPTR_SIZE);
779     return WEED_SUCCESS;
780   } else {
781     if (leaf->seed_type == WEED_SEED_STRING) {
782       weed_size_t size = leaf->data[0]->size;
783       char **valuecharptrptr = (char **)value;
784       if (size > 0)(*_memcpy_func)(*valuecharptrptr, leaf->data[0]->value.voidptr, size);
785       (*valuecharptrptr)[size] = 0;
786     } else (*_memcpy_func)(value, leaf->data[0]->value.voidptr,
787                              weed_seed_get_size(leaf->seed_type, leaf->data[0]->size));
788   }
789   return WEED_SUCCESS;
790 }
791 
792 
793 static weed_host_info_callback_f host_info_callback = NULL;
794 static void *host_info_callback_data = NULL;
795 
weed_set_host_info_callback(weed_host_info_callback_f cb,void * user_data)796 void weed_set_host_info_callback(weed_host_info_callback_f cb, void *user_data) {
797   host_info_callback = cb;
798   host_info_callback_data = user_data;
799 }
800 
801 
check_weed_abi_compat(int32_t higher,int32_t lower)802 int check_weed_abi_compat(int32_t higher, int32_t lower) {
803   if (lower == higher) return WEED_TRUE; // equal versions are always compatible
804   if (lower > higher) {
805     int32_t tmp = lower;
806     lower = higher;
807     higher = tmp;
808   }
809   if (higher > WEED_ABI_VERSION) return WEED_FALSE; // we cant possibly know about future versions
810   if (lower < 200 && higher >= 200) return WEED_FALSE; // ABI 200 made breaking changes
811   if (higher < 100) return WEED_FALSE;
812   return WEED_TRUE;
813 }
814 
815 
check_filter_api_compat(int32_t higher,int32_t lower)816 int check_filter_api_compat(int32_t higher, int32_t lower) {
817   if (lower == higher) return WEED_TRUE; // equal versions are always compatible
818   if (lower > higher) {
819     int32_t tmp = lower;
820     lower = higher;
821     higher = tmp;
822   }
823   if (higher > WEED_FILTER_API_VERSION) return WEED_FALSE; // we cant possibly know about future versions
824   if (higher < 100) return WEED_FALSE;
825   return WEED_TRUE;
826 }
827 
828 
check_version_compat(int host_weed_api_version,int plugin_weed_api_min_version,int plugin_weed_api_max_version,int host_filter_api_version,int plugin_filter_api_min_version,int plugin_filter_api_max_version)829 static int check_version_compat(int host_weed_api_version,
830                                 int plugin_weed_api_min_version,
831                                 int plugin_weed_api_max_version,
832                                 int host_filter_api_version,
833                                 int plugin_filter_api_min_version,
834                                 int plugin_filter_api_max_version) {
835   if (plugin_weed_api_min_version > host_weed_api_version || plugin_filter_api_min_version > host_filter_api_version)
836     return WEED_FALSE;
837 
838   if (host_weed_api_version > plugin_weed_api_max_version) {
839     if (check_weed_abi_compat(host_weed_api_version, plugin_weed_api_max_version) == 0) return 0;
840   }
841 
842   if (host_filter_api_version > plugin_filter_api_max_version) {
843     return check_filter_api_compat(host_filter_api_version, plugin_filter_api_max_version);
844   }
845   return WEED_TRUE;
846 }
847 
848 
weed_bootstrap(weed_default_getter_f * value,int32_t plugin_min_weed_abi_version,int32_t plugin_max_weed_abi_version,int32_t plugin_min_filter_api_version,int32_t plugin_max_filter_api_version)849 weed_plant_t *weed_bootstrap(weed_default_getter_f * value,
850                              int32_t plugin_min_weed_abi_version,
851                              int32_t plugin_max_weed_abi_version,
852                              int32_t plugin_min_filter_api_version,
853                              int32_t plugin_max_filter_api_version) {
854   // function is called from weed_setup() in the plugin, using the fn ptr passed by the host
855 
856   // here is where we define the functions for the plugin to use
857   // the host is free to implement its own version and then pass a pointer to that function in weed_setup() for the plugin
858 
859   static weed_leaf_get_f wlg;
860   static weed_plant_new_f wpn;
861   static weed_plant_list_leaves_f wpll;
862   static weed_leaf_num_elements_f wlne;
863   static weed_leaf_element_size_f wles;
864   static weed_leaf_seed_type_f wlst;
865   static weed_leaf_get_flags_f wlgf;
866   static weed_leaf_set_f wls;
867   static weed_malloc_f weedmalloc;
868 #if WEED_ABI_CHECK_VERSION(200)
869   static weed_realloc_f weedrealloc;
870   static weed_calloc_f weedcalloc;
871   static weed_memmove_f weedmemmove;
872 #endif
873   static weed_free_f weedfree;
874   static weed_memcpy_f weedmemcpy;
875   static weed_memset_f weedmemset;
876   static weed_plant_free_f wpf;
877   static weed_leaf_delete_f wld;
878 
879   int host_set_host_info = WEED_FALSE;
880 
881 #if WEED_ABI_CHECK_VERSION(200)
882   int32_t host_weed_abi_version = weed_get_abi_version();
883 #else
884   /* versions here are just default values, we will set them again later, after possibly calling the host_info_callback function */
885   int32_t host_weed_abi_version = WEED_ABI_VERSION;
886 #endif
887   int32_t host_filter_api_version = WEED_FILTER_API_VERSION;
888 
889   int32_t plugin_weed_abi_version = plugin_min_weed_abi_version;
890   int32_t plugin_filter_api_version = plugin_min_filter_api_version;
891 
892   weed_plant_t *host_info = NULL;
893   weed_plant_t *plugin_info = NULL;
894 
895   weed_error_t err;
896 
897   if (host_weed_abi_version > WEED_ABI_VERSION) return NULL;
898 
899   *value = _weed_default_get; // value is a pointer to fn. ptr
900   if (*value == NULL) return NULL;
901 
902   if (plugin_min_weed_abi_version > plugin_max_weed_abi_version) {
903     // plugin author may be confused
904     int32_t tmp = plugin_min_weed_abi_version;
905     plugin_min_weed_abi_version = plugin_max_weed_abi_version;
906     plugin_max_weed_abi_version = tmp;
907   }
908   if (plugin_min_filter_api_version > plugin_max_filter_api_version) {
909     int32_t tmp = plugin_min_weed_abi_version;
910     plugin_min_weed_abi_version = plugin_max_weed_abi_version;
911     plugin_max_weed_abi_version = tmp;
912   }
913 
914   // set pointers to the functions the plugin will use
915 
916   wpn = weed_plant_new;
917   wpll = weed_plant_list_leaves;
918   wlne = weed_leaf_num_elements;
919   wles = weed_leaf_element_size;
920   wlst = weed_leaf_seed_type;
921   wlgf = weed_leaf_get_flags;
922   wls  = weed_leaf_set;
923   wlg  = weed_leaf_get;
924 
925   // added for plugins in Filter API 200
926   wpf = weed_plant_free;
927   wld = weed_leaf_delete;
928 
929   weedmalloc = malloc;
930   weedfree = free;
931   weedmemcpy = memcpy;
932   weedmemset = memset;
933 
934 #if WEED_ABI_CHECK_VERSION(200)
935   // added for plugins in Weed ABI 200
936   weedrealloc = realloc;
937   weedmemmove = memmove;
938   weedcalloc = calloc;
939 #endif
940 
941   host_info = weed_plant_new(WEED_PLANT_HOST_INFO);
942   if (!host_info) return NULL;
943 
944   if (weed_set_int_value(host_info, WEED_LEAF_WEED_ABI_VERSION, host_weed_abi_version) != WEED_SUCCESS) {
945     if (host_info) weed_plant_free(host_info);
946     return NULL;
947   }
948   if (weed_set_int_value(host_info, WEED_LEAF_FILTER_API_VERSION, host_filter_api_version) != WEED_SUCCESS) {
949     if (host_info) weed_plant_free(host_info);
950     return NULL;
951   }
952 
953   if (weedmalloc) {
954     if (weed_set_funcptr_value(host_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)weedmalloc) != WEED_SUCCESS) {
955       if (host_info) weed_plant_free(host_info);
956       return NULL;
957     }
958   }
959   if (weedfree) {
960     if (weed_set_funcptr_value(host_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)weedfree) != WEED_SUCCESS) {
961       if (host_info) weed_plant_free(host_info);
962       return NULL;
963     }
964   }
965   if (weedmemset) {
966     if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMSET_FUNC, (weed_funcptr_t)weedmemset) != WEED_SUCCESS) {
967       if (host_info) weed_plant_free(host_info);
968       return NULL;
969     }
970   }
971   if (weedmemcpy) {
972     if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)weedmemcpy) != WEED_SUCCESS) {
973       if (host_info) weed_plant_free(host_info);
974       return NULL;
975     }
976   }
977 
978 #if WEED_ABI_CHECK_VERSION(200)
979   if (plugin_max_weed_abi_version >= 200) {
980     if (weedmemmove) {
981       if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMMOVE_FUNC, (weed_funcptr_t)weedmemmove) != WEED_SUCCESS) {
982         if (host_info) weed_plant_free(host_info);
983         return NULL;
984       }
985     }
986     if (weedrealloc) {
987       if (weed_set_funcptr_value(host_info, WEED_LEAF_REALLOC_FUNC, (weed_funcptr_t)weedrealloc) != WEED_SUCCESS) {
988         if (host_info) weed_plant_free(host_info);
989         return NULL;
990       }
991     }
992     if (weedcalloc) {
993       if (weed_set_funcptr_value(host_info, WEED_LEAF_CALLOC_FUNC, (weed_funcptr_t)weedcalloc) != WEED_SUCCESS) {
994         if (host_info) weed_plant_free(host_info);
995         return NULL;
996       }
997     }
998   }
999 
1000 #endif
1001 
1002   if (wpn) {
1003     if (weed_set_funcptr_value(host_info, WEED_PLANT_NEW_FUNC, (weed_funcptr_t)wpn) != WEED_SUCCESS) {
1004       if (host_info) weed_plant_free(host_info);
1005       return NULL;
1006     }
1007   }
1008   if (wlg) {
1009     if (weed_set_funcptr_value(host_info, WEED_LEAF_GET_FUNC, (weed_funcptr_t)wlg) != WEED_SUCCESS) {
1010       if (host_info) weed_plant_free(host_info);
1011       return NULL;
1012     }
1013   }
1014   if (wls) {
1015     if (weed_set_funcptr_value(host_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)wls) != WEED_SUCCESS) {
1016       if (host_info) weed_plant_free(host_info);
1017       return NULL;
1018     }
1019   }
1020   if (wlst) {
1021     if (weed_set_funcptr_value(host_info, WEED_LEAF_SEED_TYPE_FUNC, (weed_funcptr_t)wlst) != WEED_SUCCESS) {
1022       if (host_info) weed_plant_free(host_info);
1023       return NULL;
1024     }
1025   }
1026   if (wlne) {
1027     if (weed_set_funcptr_value(host_info, WEED_LEAF_NUM_ELEMENTS_FUNC, (weed_funcptr_t)wlne) != WEED_SUCCESS) {
1028       if (host_info) weed_plant_free(host_info);
1029       return NULL;
1030     }
1031   }
1032   if (wles) {
1033     if (weed_set_funcptr_value(host_info, WEED_LEAF_ELEMENT_SIZE_FUNC, (weed_funcptr_t)wles) != WEED_SUCCESS) {
1034       if (host_info) weed_plant_free(host_info);
1035       return NULL;
1036     }
1037   }
1038   if (wpll) {
1039     if (weed_set_funcptr_value(host_info, WEED_PLANT_LIST_LEAVES_FUNC, (weed_funcptr_t)wpll) != WEED_SUCCESS) {
1040       if (host_info) weed_plant_free(host_info);
1041       return NULL;
1042     }
1043   }
1044   if (wlgf) {
1045     if (weed_set_funcptr_value(host_info, WEED_LEAF_GET_FLAGS_FUNC, (weed_funcptr_t)wlgf) != WEED_SUCCESS) {
1046       if (host_info) weed_plant_free(host_info);
1047       return NULL;
1048     }
1049   }
1050   if (plugin_max_filter_api_version >= 200) {
1051     if (wpf) {
1052       if (weed_set_funcptr_value(host_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)wpf) != WEED_SUCCESS) {
1053         if (host_info) weed_plant_free(host_info);
1054         return NULL;
1055       }
1056     }
1057     if (wld) {
1058       if (weed_set_funcptr_value(host_info, WEED_LEAF_DELETE_FUNC, (weed_funcptr_t)wld) != WEED_SUCCESS) {
1059         if (host_info) weed_plant_free(host_info);
1060         return NULL;
1061       }
1062     }
1063   }
1064 
1065   plugin_info = weed_plant_new(WEED_PLANT_PLUGIN_INFO);
1066   if (!plugin_info) {
1067     if (host_info) weed_plant_free(host_info);
1068     return NULL;
1069   }
1070 
1071   if (weed_set_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, plugin_info) != WEED_SUCCESS) {
1072     if (plugin_info) weed_plant_free(plugin_info);
1073     if (host_info) weed_plant_free(host_info);
1074     return NULL;
1075   }
1076 
1077   if (weed_set_int_value(plugin_info, WEED_LEAF_MIN_WEED_ABI_VERSION, plugin_min_weed_abi_version) != WEED_SUCCESS) {
1078     if (plugin_info) weed_plant_free(plugin_info);
1079     if (host_info) weed_plant_free(host_info);
1080     return NULL;
1081   }
1082   if (weed_set_int_value(plugin_info, WEED_LEAF_MAX_WEED_ABI_VERSION, plugin_max_weed_abi_version) != WEED_SUCCESS) {
1083     if (plugin_info) weed_plant_free(plugin_info);
1084     if (host_info) weed_plant_free(host_info);
1085     return NULL;
1086   }
1087   if (weed_set_int_value(plugin_info, WEED_LEAF_MIN_FILTER_API_VERSION, plugin_min_filter_api_version) != WEED_SUCCESS) {
1088     if (plugin_info) weed_plant_free(plugin_info);
1089     if (host_info) weed_plant_free(host_info);
1090     return NULL;
1091   }
1092   if (weed_set_int_value(plugin_info, WEED_LEAF_MAX_FILTER_API_VERSION, plugin_max_filter_api_version) != WEED_SUCCESS) {
1093     if (plugin_info) weed_plant_free(plugin_info);
1094     if (host_info) weed_plant_free(host_info);
1095     return NULL;
1096   }
1097 
1098   if (host_info_callback) {
1099     // if host set a callback function, we call it so it can examine and adjust the host_info plant
1100     // including setting memory functions and checking the weed and filter api values if it wishes
1101     // host can also substitute its own host_info
1102     // the host is also free to adjust or replace plant_info
1103 
1104     weed_plant_t *host_host_info = host_info_callback(host_info, host_info_callback_data);
1105     if (!host_host_info) {
1106       if (plugin_info) weed_plant_free(plugin_info);
1107       return NULL;
1108     }
1109 
1110     if (host_host_info != host_info) {
1111       if (host_info) weed_plant_free(host_info);
1112       host_info = host_host_info;
1113       host_set_host_info = WEED_TRUE;
1114     }
1115 
1116     if (weed_plant_has_leaf(host_info, WEED_LEAF_WEED_ABI_VERSION)) {
1117       host_weed_abi_version = weed_get_int_value(host_host_info, WEED_LEAF_WEED_ABI_VERSION, &err);
1118       if (err != WEED_SUCCESS) {
1119         if (plugin_info) weed_plant_free(plugin_info);
1120         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1121         return NULL;
1122       }
1123     }
1124     if (weed_plant_has_leaf(host_info, WEED_LEAF_FILTER_API_VERSION)) {
1125       host_filter_api_version = weed_get_int_value(host_host_info, WEED_LEAF_FILTER_API_VERSION, &err);
1126       if (err != WEED_SUCCESS) {
1127         if (plugin_info) weed_plant_free(plugin_info);
1128         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1129         return NULL;
1130       }
1131     }
1132   }
1133 
1134   if (!check_version_compat(host_weed_abi_version, plugin_min_weed_abi_version, plugin_max_weed_abi_version,
1135                             host_filter_api_version, plugin_min_filter_api_version, plugin_max_filter_api_version)) {
1136     if (plugin_info) weed_plant_free(plugin_info);
1137     if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1138     return NULL;
1139   }
1140 
1141   plugin_weed_abi_version = host_weed_abi_version;
1142   plugin_filter_api_version = host_filter_api_version;
1143 
1144   if (host_set_host_info) {
1145     if (weed_plant_has_leaf(host_info, WEED_LEAF_PLUGIN_INFO)) {
1146       weed_plant_t *host_plugin_info = weed_get_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, &err);
1147       if (err != WEED_SUCCESS) {
1148         if (plugin_info) weed_plant_free(plugin_info);
1149         return NULL;
1150       }
1151 
1152       if (host_plugin_info != plugin_info) {
1153         if (plugin_info) weed_plant_free(plugin_info);
1154         plugin_info = NULL;
1155       }
1156     }
1157 
1158     // host replaced the host_info with one of its own, check that all of the functions are present
1159     if (!weed_plant_has_leaf(host_info, WEED_LEAF_MALLOC_FUNC)) {
1160       if (weedmalloc == NULL) {
1161         if (plugin_info) weed_plant_free(plugin_info);
1162         return NULL;
1163       }
1164       if (weed_set_funcptr_value(host_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)weedmalloc) != WEED_SUCCESS) {
1165         if (plugin_info) weed_plant_free(plugin_info);
1166         return NULL;
1167       }
1168     }
1169     if (!weed_plant_has_leaf(host_info, WEED_LEAF_FREE_FUNC)) {
1170       if (weedfree == NULL) {
1171         if (plugin_info) weed_plant_free(plugin_info);
1172         return NULL;
1173       }
1174       if (weed_set_funcptr_value(host_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)weedfree) != WEED_SUCCESS) {
1175         if (plugin_info) weed_plant_free(plugin_info);
1176         return NULL;
1177       }
1178     }
1179     if (!weed_plant_has_leaf(host_info, WEED_LEAF_MEMSET_FUNC)) {
1180       if (weedmemset == NULL) {
1181         if (plugin_info) weed_plant_free(plugin_info);
1182         return NULL;
1183       }
1184       if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMSET_FUNC, (weed_funcptr_t)weedmemset) != WEED_SUCCESS) {
1185         if (plugin_info) weed_plant_free(plugin_info);
1186         return NULL;
1187       }
1188     }
1189     if (!weed_plant_has_leaf(host_info, WEED_LEAF_MEMCPY_FUNC)) {
1190       if (weedmemcpy == NULL) {
1191         if (plugin_info) weed_plant_free(plugin_info);
1192         return NULL;
1193       }
1194       if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)weedmemcpy) != WEED_SUCCESS) {
1195         if (plugin_info) weed_plant_free(plugin_info);
1196         return NULL;
1197       }
1198     }
1199 
1200 #if WEED_ABI_CHECK_VERSION(200)
1201     if (plugin_weed_abi_version >= 200) {
1202       if (!weed_plant_has_leaf(host_info, WEED_LEAF_MEMMOVE_FUNC)) {
1203         if (weedmemmove == NULL) {
1204           if (plugin_info) weed_plant_free(plugin_info);
1205           return NULL;
1206         }
1207         if (weed_set_funcptr_value(host_info, WEED_LEAF_MEMMOVE_FUNC, (weed_funcptr_t)weedmemmove) != WEED_SUCCESS) {
1208           if (plugin_info) weed_plant_free(plugin_info);
1209           return NULL;
1210         }
1211       }
1212       if (!weed_plant_has_leaf(host_info, WEED_LEAF_REALLOC_FUNC)) {
1213         if (weedrealloc == NULL) {
1214           if (plugin_info) weed_plant_free(plugin_info);
1215           return NULL;
1216         }
1217         if (weed_set_funcptr_value(host_info, WEED_LEAF_REALLOC_FUNC, (weed_funcptr_t)weedrealloc) != WEED_SUCCESS) {
1218           if (plugin_info) weed_plant_free(plugin_info);
1219           return NULL;
1220         }
1221       }
1222       if (!weed_plant_has_leaf(host_info, WEED_LEAF_CALLOC_FUNC)) {
1223         if (weedcalloc == NULL) {
1224           if (plugin_info) weed_plant_free(plugin_info);
1225           return NULL;
1226         }
1227         if (weed_set_funcptr_value(host_info, WEED_LEAF_CALLOC_FUNC, (weed_funcptr_t)weedcalloc) != WEED_SUCCESS) {
1228           if (plugin_info) weed_plant_free(plugin_info);
1229           return NULL;
1230         }
1231       }
1232     }
1233 
1234 #endif
1235 
1236     if (!weed_plant_has_leaf(host_info, WEED_PLANT_NEW_FUNC)) {
1237       if (wpn == NULL) {
1238         if (plugin_info) weed_plant_free(plugin_info);
1239         return NULL;
1240       }
1241       if (weed_set_funcptr_value(host_info, WEED_PLANT_NEW_FUNC, (weed_funcptr_t)wpn) != WEED_SUCCESS) {
1242         if (plugin_info) weed_plant_free(plugin_info);
1243         return NULL;
1244       }
1245     }
1246     if (!weed_plant_has_leaf(host_info, WEED_LEAF_GET_FUNC)) {
1247       if (wlg == NULL) {
1248         if (plugin_info) weed_plant_free(plugin_info);
1249         return NULL;
1250       }
1251       if (weed_set_funcptr_value(host_info, WEED_LEAF_GET_FUNC, (weed_funcptr_t)wlg) != WEED_SUCCESS) {
1252         if (plugin_info) weed_plant_free(plugin_info);
1253         return NULL;
1254       }
1255     }
1256     if (!weed_plant_has_leaf(host_info, WEED_LEAF_SET_FUNC)) {
1257       if (wls == NULL) {
1258         if (plugin_info) weed_plant_free(plugin_info);
1259         return NULL;
1260       }
1261       if (weed_set_funcptr_value(host_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)wls) != WEED_SUCCESS) {
1262         if (plugin_info) weed_plant_free(plugin_info);
1263         return NULL;
1264       }
1265     }
1266     if (!weed_plant_has_leaf(host_info, WEED_LEAF_SEED_TYPE_FUNC)) {
1267       if (wlst == NULL) {
1268         if (plugin_info) weed_plant_free(plugin_info);
1269         return NULL;
1270       }
1271       if (weed_set_funcptr_value(host_info, WEED_LEAF_SEED_TYPE_FUNC, (weed_funcptr_t)wlst) != WEED_SUCCESS) {
1272         if (plugin_info) weed_plant_free(plugin_info);
1273         return NULL;
1274       }
1275     }
1276     if (!weed_plant_has_leaf(host_info, WEED_LEAF_NUM_ELEMENTS_FUNC)) {
1277       if (wlne == NULL) {
1278         if (plugin_info) weed_plant_free(plugin_info);
1279         return NULL;
1280       }
1281       if (weed_set_funcptr_value(host_info, WEED_LEAF_NUM_ELEMENTS_FUNC, (weed_funcptr_t)wlne) != WEED_SUCCESS) {
1282         if (plugin_info) weed_plant_free(plugin_info);
1283         return NULL;
1284       }
1285     }
1286     if (!weed_plant_has_leaf(host_info, WEED_LEAF_ELEMENT_SIZE_FUNC)) {
1287       if (wles == NULL) {
1288         if (plugin_info) weed_plant_free(plugin_info);
1289         return NULL;
1290       }
1291       if (weed_set_funcptr_value(host_info, WEED_LEAF_ELEMENT_SIZE_FUNC, (weed_funcptr_t)wles) != WEED_SUCCESS) {
1292         if (plugin_info) weed_plant_free(plugin_info);
1293         return NULL;
1294       }
1295     }
1296     if (!weed_plant_has_leaf(host_info, WEED_PLANT_LIST_LEAVES_FUNC)) {
1297       if (wpll == NULL) {
1298         if (plugin_info) weed_plant_free(plugin_info);
1299         return NULL;
1300       }
1301       if (weed_set_funcptr_value(host_info, WEED_PLANT_LIST_LEAVES_FUNC, (weed_funcptr_t)wpll) != WEED_SUCCESS) {
1302         if (plugin_info) weed_plant_free(plugin_info);
1303         return NULL;
1304       }
1305     }
1306     if (!weed_plant_has_leaf(host_info, WEED_LEAF_GET_FLAGS_FUNC)) {
1307       if (wlgf == NULL) {
1308         if (plugin_info) weed_plant_free(plugin_info);
1309         return NULL;
1310       }
1311       if (weed_set_funcptr_value(host_info, WEED_LEAF_GET_FLAGS_FUNC, (weed_funcptr_t)wlgf) != WEED_SUCCESS) {
1312         if (plugin_info) weed_plant_free(plugin_info);
1313         return NULL;
1314       }
1315     }
1316   }
1317 
1318   if (plugin_filter_api_version >= 200) {
1319     if (!weed_plant_has_leaf(host_info, WEED_PLANT_FREE_FUNC)) {
1320       if (wpf == NULL) {
1321         if (plugin_info) weed_plant_free(plugin_info);
1322         return NULL;
1323       }
1324       if (weed_set_funcptr_value(host_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)wpf) != WEED_SUCCESS) {
1325         if (plugin_info) weed_plant_free(plugin_info);
1326         return NULL;
1327       }
1328     }
1329     if (!weed_plant_has_leaf(host_info, WEED_LEAF_DELETE_FUNC)) {
1330       if (wld == NULL) {
1331         if (plugin_info) weed_plant_free(plugin_info);
1332         return NULL;
1333       }
1334       if (weed_set_funcptr_value(host_info, WEED_LEAF_DELETE_FUNC, (weed_funcptr_t)wld) != WEED_SUCCESS) {
1335         if (plugin_info) weed_plant_free(plugin_info);
1336         return NULL;
1337       }
1338     }
1339   }
1340 
1341 #if WEED_ABI_CHECK_VERSION(200)
1342   // readjust the ABI depending on the weed_abi_version selected by the host
1343 
1344   if (plugin_weed_abi_version < 200) {
1345     // added in ABI 200, so remove them for lower versions
1346     if (weed_plant_has_leaf(host_info, WEED_LEAF_REALLOC_FUNC)) {
1347       err = weed_leaf_delete(host_info, WEED_LEAF_REALLOC_FUNC);
1348       if (err != WEED_SUCCESS && err != WEED_ERROR_UNDELETABLE) {
1349         if (plugin_info) weed_plant_free(plugin_info);
1350         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1351         return NULL;
1352       }
1353     }
1354     weedrealloc = NULL;
1355     if (weed_plant_has_leaf(host_info, WEED_LEAF_CALLOC_FUNC)) {
1356       err = weed_leaf_delete(host_info, WEED_LEAF_CALLOC_FUNC);
1357       if (err != WEED_SUCCESS && err != WEED_ERROR_UNDELETABLE) {
1358         if (plugin_info) weed_plant_free(plugin_info);
1359         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1360         return NULL;
1361       }
1362     }
1363     weedcalloc = NULL;
1364     if (weed_plant_has_leaf(host_info, WEED_LEAF_MEMMOVE_FUNC)) {
1365       err = weed_leaf_delete(host_info, WEED_LEAF_MEMMOVE_FUNC);
1366       if (err != WEED_SUCCESS && err != WEED_ERROR_UNDELETABLE) {
1367         if (plugin_info) weed_plant_free(plugin_info);
1368         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1369         return NULL;
1370       }
1371     }
1372     weedmemmove = NULL;
1373   }
1374 #endif
1375 
1376   if (plugin_filter_api_version < 200) {
1377     if (weed_plant_has_leaf(host_info, WEED_PLANT_FREE_FUNC)) {
1378       err = weed_leaf_delete(host_info, WEED_PLANT_FREE_FUNC);
1379       if (err != WEED_SUCCESS && err != WEED_ERROR_UNDELETABLE) {
1380         if (plugin_info) weed_plant_free(plugin_info);
1381         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1382         return NULL;
1383       }
1384     }
1385     wpf = NULL;
1386     if (weed_plant_has_leaf(host_info, WEED_LEAF_DELETE_FUNC)) {
1387       err = weed_leaf_delete(host_info, WEED_LEAF_DELETE_FUNC);
1388       if (err != WEED_SUCCESS && err != WEED_ERROR_UNDELETABLE) {
1389         if (plugin_info) weed_plant_free(plugin_info);
1390         if (host_set_host_info == WEED_FALSE) if (host_info) weed_plant_free(host_info);
1391         return NULL;
1392       }
1393     }
1394     wld = NULL;
1395   }
1396   return host_info;
1397 }
1398 
1399 
1400 
1401