1 /*
2   Copyright 2007-2019 David Robillard <d@drobilla.net>
3 
4   Permission to use, copy, modify, and/or distribute this software for any
5   purpose with or without fee is hereby granted, provided that the above
6   copyright notice and this permission notice appear in all copies.
7 
8   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 #include "filesystem.h"
18 #include "lilv_internal.h"
19 
20 #include "lilv/lilv.h"
21 #include "serd/serd.h"
22 #include "sord/sord.h"
23 #include "sratom/sratom.h"
24 #include "zix/tree.h"
25 
26 #include "lv2/atom/atom.h"
27 #include "lv2/atom/forge.h"
28 #include "lv2/core/lv2.h"
29 #include "lv2/presets/presets.h"
30 #include "lv2/state/state.h"
31 #include "lv2/urid/urid.h"
32 
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdbool.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #define USTR(s) ((const uint8_t*)(s))
42 
43 typedef struct {
44   void*    value; ///< Value/Object
45   size_t   size;  ///< Size of value
46   uint32_t key;   ///< Key/Predicate (URID)
47   uint32_t type;  ///< Type of value (URID)
48   uint32_t flags; ///< State flags (POD, etc)
49 } Property;
50 
51 typedef struct {
52   char*     symbol; ///< Symbol of port
53   LV2_Atom* atom;   ///< Value in port
54 } PortValue;
55 
56 typedef struct {
57   char* abs; ///< Absolute path of actual file
58   char* rel; ///< Abstract path (relative path in state dir)
59 } PathMap;
60 
61 typedef struct {
62   size_t    n;
63   Property* props;
64 } PropertyArray;
65 
66 struct LilvStateImpl {
67   LilvNode*     plugin_uri;  ///< Plugin URI
68   LilvNode*     uri;         ///< State/preset URI
69   char*         dir;         ///< Save directory (if saved)
70   char*         scratch_dir; ///< Directory for files created by plugin
71   char*         copy_dir;    ///< Directory for snapshots of external files
72   char*         link_dir;    ///< Directory for links to external files
73   char*         label;       ///< State/Preset label
74   ZixTree*      abs2rel;     ///< PathMap sorted by abs
75   ZixTree*      rel2abs;     ///< PathMap sorted by rel
76   PropertyArray props;       ///< State properties
77   PropertyArray metadata;    ///< State metadata
78   PortValue*    values;      ///< Port values
79   uint32_t      atom_Path;   ///< atom:Path URID
80   uint32_t      n_values;    ///< Number of port values
81 };
82 
83 static int
abs_cmp(const void * a,const void * b,void * user_data)84 abs_cmp(const void* a, const void* b, void* user_data)
85 {
86   return strcmp(((const PathMap*)a)->abs, ((const PathMap*)b)->abs);
87 }
88 
89 static int
rel_cmp(const void * a,const void * b,void * user_data)90 rel_cmp(const void* a, const void* b, void* user_data)
91 {
92   return strcmp(((const PathMap*)a)->rel, ((const PathMap*)b)->rel);
93 }
94 
95 static int
property_cmp(const void * a,const void * b)96 property_cmp(const void* a, const void* b)
97 {
98   const uint32_t a_key = ((const Property*)a)->key;
99   const uint32_t b_key = ((const Property*)b)->key;
100 
101   if (a_key < b_key) {
102     return -1;
103   }
104 
105   if (b_key < a_key) {
106     return 1;
107   }
108 
109   return 0;
110 }
111 
112 static int
value_cmp(const void * a,const void * b)113 value_cmp(const void* a, const void* b)
114 {
115   return strcmp(((const PortValue*)a)->symbol, ((const PortValue*)b)->symbol);
116 }
117 
118 static void
path_rel_free(void * ptr)119 path_rel_free(void* ptr)
120 {
121   free(((PathMap*)ptr)->abs);
122   free(((PathMap*)ptr)->rel);
123   free(ptr);
124 }
125 
126 static PortValue*
append_port_value(LilvState * state,const char * port_symbol,const void * value,uint32_t size,uint32_t type)127 append_port_value(LilvState*  state,
128                   const char* port_symbol,
129                   const void* value,
130                   uint32_t    size,
131                   uint32_t    type)
132 {
133   PortValue* pv = NULL;
134   if (value) {
135     state->values = (PortValue*)realloc(
136       state->values, (++state->n_values) * sizeof(PortValue));
137 
138     pv             = &state->values[state->n_values - 1];
139     pv->symbol     = lilv_strdup(port_symbol);
140     pv->atom       = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size);
141     pv->atom->size = size;
142     pv->atom->type = type;
143     memcpy(pv->atom + 1, value, size);
144   }
145   return pv;
146 }
147 
148 static const char*
lilv_state_rel2abs(const LilvState * state,const char * path)149 lilv_state_rel2abs(const LilvState* state, const char* path)
150 {
151   ZixTreeIter*  iter = NULL;
152   const PathMap key  = {NULL, (char*)path};
153   if (state->rel2abs && !zix_tree_find(state->rel2abs, &key, &iter)) {
154     return ((const PathMap*)zix_tree_get(iter))->abs;
155   }
156   return path;
157 }
158 
159 static void
append_property(LilvState * state,PropertyArray * array,uint32_t key,const void * value,size_t size,uint32_t type,uint32_t flags)160 append_property(LilvState*     state,
161                 PropertyArray* array,
162                 uint32_t       key,
163                 const void*    value,
164                 size_t         size,
165                 uint32_t       type,
166                 uint32_t       flags)
167 {
168   array->props =
169     (Property*)realloc(array->props, (++array->n) * sizeof(Property));
170 
171   Property* const prop = &array->props[array->n - 1];
172   if ((flags & LV2_STATE_IS_POD) || type == state->atom_Path) {
173     prop->value = malloc(size);
174     memcpy(prop->value, value, size);
175   } else {
176     prop->value = (void*)value;
177   }
178 
179   prop->size  = size;
180   prop->key   = key;
181   prop->type  = type;
182   prop->flags = flags;
183 }
184 
185 static const Property*
find_property(const LilvState * const state,const uint32_t key)186 find_property(const LilvState* const state, const uint32_t key)
187 {
188   if (!state->props.props) {
189     return NULL;
190   }
191 
192   const Property search_key = {NULL, 0, key, 0, 0};
193 
194   return (const Property*)bsearch(&search_key,
195                                   state->props.props,
196                                   state->props.n,
197                                   sizeof(Property),
198                                   property_cmp);
199 }
200 
201 static LV2_State_Status
store_callback(LV2_State_Handle handle,uint32_t key,const void * value,size_t size,uint32_t type,uint32_t flags)202 store_callback(LV2_State_Handle handle,
203                uint32_t         key,
204                const void*      value,
205                size_t           size,
206                uint32_t         type,
207                uint32_t         flags)
208 {
209   LilvState* const state = (LilvState*)handle;
210 
211   if (!key) {
212     return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for bad arguments
213   }
214 
215   if (find_property((const LilvState*)handle, key)) {
216     return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for duplicate keys
217   }
218 
219   append_property(state, &state->props, key, value, size, type, flags);
220   return LV2_STATE_SUCCESS;
221 }
222 
223 static const void*
retrieve_callback(LV2_State_Handle handle,uint32_t key,size_t * size,uint32_t * type,uint32_t * flags)224 retrieve_callback(LV2_State_Handle handle,
225                   uint32_t         key,
226                   size_t*          size,
227                   uint32_t*        type,
228                   uint32_t*        flags)
229 {
230   const Property* const prop = find_property((const LilvState*)handle, key);
231 
232   if (prop) {
233     *size  = prop->size;
234     *type  = prop->type;
235     *flags = prop->flags;
236     return prop->value;
237   }
238   return NULL;
239 }
240 
241 static bool
path_exists(const char * path,const void * ignored)242 path_exists(const char* path, const void* ignored)
243 {
244   return lilv_path_exists(path);
245 }
246 
247 static bool
lilv_state_has_path(const char * path,const void * state)248 lilv_state_has_path(const char* path, const void* state)
249 {
250   return lilv_state_rel2abs((const LilvState*)state, path) != path;
251 }
252 
253 static char*
make_path(LV2_State_Make_Path_Handle handle,const char * path)254 make_path(LV2_State_Make_Path_Handle handle, const char* path)
255 {
256   LilvState* state = (LilvState*)handle;
257   lilv_create_directories(state->dir);
258 
259   return lilv_path_join(state->dir, path);
260 }
261 
262 static char*
abstract_path(LV2_State_Map_Path_Handle handle,const char * abs_path)263 abstract_path(LV2_State_Map_Path_Handle handle, const char* abs_path)
264 {
265   LilvState*    state     = (LilvState*)handle;
266   char*         path      = NULL;
267   char*         real_path = lilv_path_canonical(abs_path);
268   const PathMap key       = {real_path, NULL};
269   ZixTreeIter*  iter      = NULL;
270 
271   if (abs_path[0] == '\0') {
272     return lilv_strdup(abs_path);
273   }
274 
275   if (!zix_tree_find(state->abs2rel, &key, &iter)) {
276     // Already mapped path in a previous call
277     PathMap* pm = (PathMap*)zix_tree_get(iter);
278     free(real_path);
279     return lilv_strdup(pm->rel);
280   }
281 
282   if (lilv_path_is_child(real_path, state->dir)) {
283     // File in state directory (loaded, or created by plugin during save)
284     path = lilv_path_relative_to(real_path, state->dir);
285   } else if (lilv_path_is_child(real_path, state->scratch_dir)) {
286     // File created by plugin earlier
287     path = lilv_path_relative_to(real_path, state->scratch_dir);
288     if (state->copy_dir) {
289       int st = lilv_create_directories(state->copy_dir);
290       if (st) {
291         LILV_ERRORF(
292           "Error creating directory %s (%s)\n", state->copy_dir, strerror(st));
293       }
294 
295       char* cpath = lilv_path_join(state->copy_dir, path);
296       char* copy  = lilv_get_latest_copy(real_path, cpath);
297       if (!copy || !lilv_file_equals(real_path, copy)) {
298         // No recent enough copy, make a new one
299         free(copy);
300         copy = lilv_find_free_path(cpath, path_exists, NULL);
301         if ((st = lilv_copy_file(real_path, copy))) {
302           LILV_ERRORF("Error copying state file %s (%s)\n", copy, strerror(st));
303         }
304       }
305       free(real_path);
306       free(cpath);
307 
308       // Refer to the latest copy in plugin state
309       real_path = copy;
310     }
311   } else if (state->link_dir) {
312     // New path outside state directory, make a link
313     char* const name = lilv_path_filename(real_path);
314 
315     // Find a free name in the (virtual) state directory
316     path = lilv_find_free_path(name, lilv_state_has_path, state);
317 
318     free(name);
319   } else {
320     // No link directory, preserve absolute path
321     path = lilv_strdup(abs_path);
322   }
323 
324   // Add record to path mapping
325   PathMap* pm = (PathMap*)malloc(sizeof(PathMap));
326   pm->abs     = real_path;
327   pm->rel     = lilv_strdup(path);
328   zix_tree_insert(state->abs2rel, pm, NULL);
329   zix_tree_insert(state->rel2abs, pm, NULL);
330 
331   return path;
332 }
333 
334 static char*
absolute_path(LV2_State_Map_Path_Handle handle,const char * state_path)335 absolute_path(LV2_State_Map_Path_Handle handle, const char* state_path)
336 {
337   LilvState* state = (LilvState*)handle;
338   char*      path  = NULL;
339   if (lilv_path_is_absolute(state_path)) {
340     // Absolute path, return identical path
341     path = lilv_strdup(state_path);
342   } else if (state->dir) {
343     // Relative path inside state directory
344     path = lilv_path_join(state->dir, state_path);
345   } else {
346     // State has not been saved, unmap
347     path = lilv_strdup(lilv_state_rel2abs(state, state_path));
348   }
349 
350   return path;
351 }
352 
353 /** Return a new features array with built-in features added to `features`. */
354 static const LV2_Feature**
add_features(const LV2_Feature * const * features,const LV2_Feature * map,const LV2_Feature * make,const LV2_Feature * free)355 add_features(const LV2_Feature* const* features,
356              const LV2_Feature*        map,
357              const LV2_Feature*        make,
358              const LV2_Feature*        free)
359 {
360   size_t n_features = 0;
361   for (; features && features[n_features]; ++n_features) {
362   }
363 
364   const LV2_Feature** ret =
365     (const LV2_Feature**)calloc(n_features + 4, sizeof(LV2_Feature*));
366 
367   if (features) {
368     memcpy(ret, features, n_features * sizeof(LV2_Feature*));
369   }
370 
371   size_t i = n_features;
372   if (map) {
373     ret[i++] = map;
374   }
375   if (make) {
376     ret[i++] = make;
377   }
378   if (free) {
379     ret[i++] = free;
380   }
381 
382   return ret;
383 }
384 
385 /// Return the canonical path for a directory with a trailing separator
386 static char*
real_dir(const char * path)387 real_dir(const char* path)
388 {
389   char* abs_path = lilv_path_canonical(path);
390   char* base     = lilv_path_join(abs_path, NULL);
391   free(abs_path);
392   return base;
393 }
394 
395 static const char*
state_strerror(LV2_State_Status st)396 state_strerror(LV2_State_Status st)
397 {
398   switch (st) {
399   case LV2_STATE_SUCCESS:
400     return "Completed successfully";
401   case LV2_STATE_ERR_BAD_TYPE:
402     return "Unsupported type";
403   case LV2_STATE_ERR_BAD_FLAGS:
404     return "Unsupported flags";
405   case LV2_STATE_ERR_NO_FEATURE:
406     return "Missing features";
407   case LV2_STATE_ERR_NO_PROPERTY:
408     return "Missing property";
409   default:
410     return "Unknown error";
411   }
412 }
413 
414 static void
lilv_free_path(LV2_State_Free_Path_Handle handle,char * path)415 lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
416 {
417   lilv_free(path);
418 }
419 
420 LilvState*
lilv_state_new_from_instance(const LilvPlugin * plugin,LilvInstance * instance,LV2_URID_Map * map,const char * scratch_dir,const char * copy_dir,const char * link_dir,const char * save_dir,LilvGetPortValueFunc get_value,void * user_data,uint32_t flags,const LV2_Feature * const * features)421 lilv_state_new_from_instance(const LilvPlugin*         plugin,
422                              LilvInstance*             instance,
423                              LV2_URID_Map*             map,
424                              const char*               scratch_dir,
425                              const char*               copy_dir,
426                              const char*               link_dir,
427                              const char*               save_dir,
428                              LilvGetPortValueFunc      get_value,
429                              void*                     user_data,
430                              uint32_t                  flags,
431                              const LV2_Feature* const* features)
432 {
433   const LV2_Feature** sfeatures = NULL;
434   LilvWorld* const    world     = plugin->world;
435   LilvState* const    state     = (LilvState*)calloc(1, sizeof(LilvState));
436   state->plugin_uri  = lilv_node_duplicate(lilv_plugin_get_uri(plugin));
437   state->abs2rel     = zix_tree_new(false, abs_cmp, NULL, path_rel_free);
438   state->rel2abs     = zix_tree_new(false, rel_cmp, NULL, NULL);
439   state->scratch_dir = scratch_dir ? real_dir(scratch_dir) : NULL;
440   state->copy_dir    = copy_dir ? real_dir(copy_dir) : NULL;
441   state->link_dir    = link_dir ? real_dir(link_dir) : NULL;
442   state->dir         = save_dir ? real_dir(save_dir) : NULL;
443   state->atom_Path   = map->map(map->handle, LV2_ATOM__Path);
444 
445   LV2_State_Map_Path  pmap          = {state, abstract_path, absolute_path};
446   LV2_Feature         pmap_feature  = {LV2_STATE__mapPath, &pmap};
447   LV2_State_Make_Path pmake         = {state, make_path};
448   LV2_Feature         pmake_feature = {LV2_STATE__makePath, &pmake};
449   LV2_State_Free_Path pfree         = {NULL, lilv_free_path};
450   LV2_Feature         pfree_feature = {LV2_STATE__freePath, &pfree};
451   features = sfeatures = add_features(
452     features, &pmap_feature, save_dir ? &pmake_feature : NULL, &pfree_feature);
453 
454   // Store port values
455   if (get_value) {
456     LilvNode* lv2_ControlPort = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
457     LilvNode* lv2_InputPort   = lilv_new_uri(world, LILV_URI_INPUT_PORT);
458     for (uint32_t i = 0; i < plugin->num_ports; ++i) {
459       const LilvPort* const port = plugin->ports[i];
460       if (lilv_port_is_a(plugin, port, lv2_ControlPort) &&
461           lilv_port_is_a(plugin, port, lv2_InputPort)) {
462         uint32_t    size  = 0;
463         uint32_t    type  = 0;
464         const char* sym   = lilv_node_as_string(port->symbol);
465         const void* value = get_value(sym, user_data, &size, &type);
466         append_port_value(state, sym, value, size, type);
467       }
468     }
469     lilv_node_free(lv2_ControlPort);
470     lilv_node_free(lv2_InputPort);
471   }
472 
473   // Store properties
474   const LV2_Descriptor*      desc = instance->lv2_descriptor;
475   const LV2_State_Interface* iface =
476     (desc->extension_data)
477       ? (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface)
478       : NULL;
479 
480   if (iface) {
481     LV2_State_Status st =
482       iface->save(instance->lv2_handle, store_callback, state, flags, features);
483     if (st) {
484       LILV_ERRORF("Error saving plugin state: %s\n", state_strerror(st));
485       free(state->props.props);
486       state->props.props = NULL;
487       state->props.n     = 0;
488     } else {
489       qsort(state->props.props, state->props.n, sizeof(Property), property_cmp);
490     }
491   }
492 
493   if (state->values) {
494     qsort(state->values, state->n_values, sizeof(PortValue), value_cmp);
495   }
496 
497   free(sfeatures);
498   return state;
499 }
500 
501 void
lilv_state_emit_port_values(const LilvState * state,LilvSetPortValueFunc set_value,void * user_data)502 lilv_state_emit_port_values(const LilvState*     state,
503                             LilvSetPortValueFunc set_value,
504                             void*                user_data)
505 {
506   for (uint32_t i = 0; i < state->n_values; ++i) {
507     const PortValue* value = &state->values[i];
508     const LV2_Atom*  atom  = value->atom;
509     set_value(value->symbol, user_data, atom + 1, atom->size, atom->type);
510   }
511 }
512 
513 void
lilv_state_restore(const LilvState * state,LilvInstance * instance,LilvSetPortValueFunc set_value,void * user_data,uint32_t flags,const LV2_Feature * const * features)514 lilv_state_restore(const LilvState*          state,
515                    LilvInstance*             instance,
516                    LilvSetPortValueFunc      set_value,
517                    void*                     user_data,
518                    uint32_t                  flags,
519                    const LV2_Feature* const* features)
520 {
521   if (!state) {
522     LILV_ERROR("lilv_state_restore() called on NULL state\n");
523     return;
524   }
525 
526   LV2_State_Map_Path map_path = {
527     (LilvState*)state, abstract_path, absolute_path};
528   LV2_Feature map_feature = {LV2_STATE__mapPath, &map_path};
529 
530   LV2_State_Free_Path free_path    = {NULL, lilv_free_path};
531   LV2_Feature         free_feature = {LV2_STATE__freePath, &free_path};
532 
533   if (instance) {
534     const LV2_Descriptor* desc = instance->lv2_descriptor;
535     if (desc->extension_data) {
536       const LV2_State_Interface* iface =
537         (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface);
538 
539       if (iface && iface->restore) {
540         const LV2_Feature** sfeatures =
541           add_features(features, &map_feature, NULL, &free_feature);
542 
543         iface->restore(instance->lv2_handle,
544                        retrieve_callback,
545                        (LV2_State_Handle)state,
546                        flags,
547                        sfeatures);
548 
549         free(sfeatures);
550       }
551     }
552   }
553 
554   if (set_value) {
555     lilv_state_emit_port_values(state, set_value, user_data);
556   }
557 }
558 
559 static void
set_state_dir_from_model(LilvState * state,const SordNode * graph)560 set_state_dir_from_model(LilvState* state, const SordNode* graph)
561 {
562   if (!state->dir && graph) {
563     const char* uri  = (const char*)sord_node_get_string(graph);
564     char*       path = lilv_file_uri_parse(uri, NULL);
565 
566     state->dir = lilv_path_join(path, NULL);
567     free(path);
568   }
569   assert(!state->dir || lilv_path_is_absolute(state->dir));
570 }
571 
572 static LilvState*
new_state_from_model(LilvWorld * world,LV2_URID_Map * map,SordModel * model,const SordNode * node,const char * dir)573 new_state_from_model(LilvWorld*      world,
574                      LV2_URID_Map*   map,
575                      SordModel*      model,
576                      const SordNode* node,
577                      const char*     dir)
578 {
579   // Check that we know at least something about this state subject
580   if (!sord_ask(model, node, 0, 0, 0)) {
581     return NULL;
582   }
583 
584   // Allocate state
585   LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState));
586   state->dir             = lilv_path_join(dir, NULL);
587   state->atom_Path       = map->map(map->handle, LV2_ATOM__Path);
588   state->uri             = lilv_node_new_from_node(world, node);
589 
590   // Get the plugin URI this state applies to
591   SordIter* i = sord_search(model, node, world->uris.lv2_appliesTo, 0, 0);
592   if (i) {
593     const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
594     const SordNode* graph  = sord_iter_get_node(i, SORD_GRAPH);
595     state->plugin_uri      = lilv_node_new_from_node(world, object);
596     set_state_dir_from_model(state, graph);
597     sord_iter_free(i);
598   } else if (sord_ask(
599                model, node, world->uris.rdf_a, world->uris.lv2_Plugin, 0)) {
600     // Loading plugin description as state (default state)
601     state->plugin_uri = lilv_node_new_from_node(world, node);
602   } else {
603     LILV_ERRORF("State %s missing lv2:appliesTo property\n",
604                 sord_node_get_string(node));
605   }
606 
607   // Get the state label
608   i = sord_search(model, node, world->uris.rdfs_label, NULL, NULL);
609   if (i) {
610     const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
611     const SordNode* graph  = sord_iter_get_node(i, SORD_GRAPH);
612     state->label = lilv_strdup((const char*)sord_node_get_string(object));
613     set_state_dir_from_model(state, graph);
614     sord_iter_free(i);
615   }
616 
617   Sratom*        sratom = sratom_new(map);
618   SerdChunk      chunk  = {NULL, 0};
619   LV2_Atom_Forge forge;
620   lv2_atom_forge_init(&forge, map);
621   lv2_atom_forge_set_sink(
622     &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
623 
624   // Get port values
625   SordIter* ports = sord_search(model, node, world->uris.lv2_port, 0, 0);
626   FOREACH_MATCH (ports) {
627     const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
628 
629     SordNode* label  = sord_get(model, port, world->uris.rdfs_label, 0, 0);
630     SordNode* symbol = sord_get(model, port, world->uris.lv2_symbol, 0, 0);
631     SordNode* value  = sord_get(model, port, world->uris.pset_value, 0, 0);
632     if (!value) {
633       value = sord_get(model, port, world->uris.lv2_default, 0, 0);
634     }
635     if (!symbol) {
636       LILV_ERRORF("State `%s' port missing symbol.\n",
637                   sord_node_get_string(node));
638     } else if (value) {
639       chunk.len = 0;
640       sratom_read(sratom, &forge, world->world, model, value);
641       const LV2_Atom* atom = (const LV2_Atom*)chunk.buf;
642 
643       append_port_value(state,
644                         (const char*)sord_node_get_string(symbol),
645                         LV2_ATOM_BODY_CONST(atom),
646                         atom->size,
647                         atom->type);
648 
649       if (label) {
650         lilv_state_set_label(state, (const char*)sord_node_get_string(label));
651       }
652     }
653     sord_node_free(world->world, value);
654     sord_node_free(world->world, symbol);
655     sord_node_free(world->world, label);
656   }
657   sord_iter_free(ports);
658 
659   // Get properties
660   SordNode* statep     = sord_new_uri(world->world, USTR(LV2_STATE__state));
661   SordNode* state_node = sord_get(model, node, statep, NULL, NULL);
662   if (state_node) {
663     SordIter* props = sord_search(model, state_node, 0, 0, 0);
664     FOREACH_MATCH (props) {
665       const SordNode* p   = sord_iter_get_node(props, SORD_PREDICATE);
666       const SordNode* o   = sord_iter_get_node(props, SORD_OBJECT);
667       const char*     key = (const char*)sord_node_get_string(p);
668 
669       chunk.len = 0;
670       lv2_atom_forge_set_sink(
671         &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
672 
673       sratom_read(sratom, &forge, world->world, model, o);
674       const LV2_Atom* atom  = (const LV2_Atom*)chunk.buf;
675       uint32_t        flags = LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE;
676       Property        prop  = {NULL, 0, 0, 0, flags};
677 
678       prop.key   = map->map(map->handle, key);
679       prop.type  = atom->type;
680       prop.size  = atom->size;
681       prop.value = malloc(atom->size);
682       memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size);
683       if (atom->type == forge.Path) {
684         prop.flags = LV2_STATE_IS_POD;
685       }
686 
687       if (prop.value) {
688         state->props.props = (Property*)realloc(
689           state->props.props, (++state->props.n) * sizeof(Property));
690         state->props.props[state->props.n - 1] = prop;
691       }
692     }
693     sord_iter_free(props);
694   }
695   sord_node_free(world->world, state_node);
696   sord_node_free(world->world, statep);
697 
698   serd_free((void*)chunk.buf);
699   sratom_free(sratom);
700 
701   if (state->props.props) {
702     qsort(state->props.props, state->props.n, sizeof(Property), property_cmp);
703   }
704   if (state->values) {
705     qsort(state->values, state->n_values, sizeof(PortValue), value_cmp);
706   }
707 
708   return state;
709 }
710 
711 LilvState*
lilv_state_new_from_world(LilvWorld * world,LV2_URID_Map * map,const LilvNode * node)712 lilv_state_new_from_world(LilvWorld*      world,
713                           LV2_URID_Map*   map,
714                           const LilvNode* node)
715 {
716   if (!lilv_node_is_uri(node) && !lilv_node_is_blank(node)) {
717     LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
718                 lilv_node_as_string(node));
719     return NULL;
720   }
721 
722   return new_state_from_model(world, map, world->model, node->node, NULL);
723 }
724 
725 LilvState*
lilv_state_new_from_file(LilvWorld * world,LV2_URID_Map * map,const LilvNode * subject,const char * path)726 lilv_state_new_from_file(LilvWorld*      world,
727                          LV2_URID_Map*   map,
728                          const LilvNode* subject,
729                          const char*     path)
730 {
731   if (subject && !lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) {
732     LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
733                 lilv_node_as_string(subject));
734     return NULL;
735   }
736 
737   uint8_t*    abs_path = (uint8_t*)lilv_path_absolute(path);
738   SerdNode    node     = serd_node_new_file_uri(abs_path, NULL, NULL, true);
739   SerdEnv*    env      = serd_env_new(&node);
740   SordModel*  model    = sord_new(world->world, SORD_SPO, false);
741   SerdReader* reader   = sord_new_reader(model, env, SERD_TURTLE, NULL);
742 
743   serd_reader_read_file(reader, node.buf);
744 
745   SordNode* subject_node =
746     (subject) ? subject->node
747               : sord_node_from_serd_node(world->world, env, &node, NULL, NULL);
748 
749   char*      dirname   = lilv_path_parent(path);
750   char*      real_path = lilv_path_canonical(dirname);
751   char*      dir_path  = lilv_path_join(real_path, NULL);
752   LilvState* state =
753     new_state_from_model(world, map, model, subject_node, dir_path);
754   free(dir_path);
755   free(real_path);
756   free(dirname);
757 
758   serd_node_free(&node);
759   free(abs_path);
760   serd_reader_free(reader);
761   sord_free(model);
762   serd_env_free(env);
763   return state;
764 }
765 
766 static void
set_prefixes(SerdEnv * env)767 set_prefixes(SerdEnv* env)
768 {
769 #define SET_PSET(e, p, u) serd_env_set_prefix_from_strings(e, p, u)
770   SET_PSET(env, USTR("atom"), USTR(LV2_ATOM_PREFIX));
771   SET_PSET(env, USTR("lv2"), USTR(LV2_CORE_PREFIX));
772   SET_PSET(env, USTR("pset"), USTR(LV2_PRESETS_PREFIX));
773   SET_PSET(env, USTR("rdf"), USTR(LILV_NS_RDF));
774   SET_PSET(env, USTR("rdfs"), USTR(LILV_NS_RDFS));
775   SET_PSET(env, USTR("state"), USTR(LV2_STATE_PREFIX));
776   SET_PSET(env, USTR("xsd"), USTR(LILV_NS_XSD));
777 }
778 
779 LilvState*
lilv_state_new_from_string(LilvWorld * world,LV2_URID_Map * map,const char * str)780 lilv_state_new_from_string(LilvWorld* world, LV2_URID_Map* map, const char* str)
781 {
782   if (!str) {
783     return NULL;
784   }
785 
786   SerdNode    base   = SERD_NODE_NULL;
787   SerdEnv*    env    = serd_env_new(&base);
788   SordModel*  model  = sord_new(world->world, SORD_SPO | SORD_OPS, false);
789   SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
790 
791   set_prefixes(env);
792   serd_reader_read_string(reader, USTR(str));
793 
794   SordNode* o = sord_new_uri(world->world, USTR(LV2_PRESETS__Preset));
795   SordNode* s = sord_get(model, NULL, world->uris.rdf_a, o, NULL);
796 
797   LilvState* state = new_state_from_model(world, map, model, s, NULL);
798 
799   sord_node_free(world->world, s);
800   sord_node_free(world->world, o);
801   serd_reader_free(reader);
802   sord_free(model);
803   serd_env_free(env);
804 
805   return state;
806 }
807 
808 static SerdWriter*
ttl_writer(SerdSink sink,void * stream,const SerdNode * base,SerdEnv ** new_env)809 ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env)
810 {
811   SerdURI base_uri = SERD_URI_NULL;
812   if (base && base->buf) {
813     serd_uri_parse(base->buf, &base_uri);
814   }
815 
816   SerdEnv* env = *new_env ? *new_env : serd_env_new(base);
817   set_prefixes(env);
818 
819   SerdWriter* writer =
820     serd_writer_new(SERD_TURTLE,
821                     (SerdStyle)(SERD_STYLE_RESOLVED | SERD_STYLE_ABBREVIATED |
822                                 SERD_STYLE_CURIED),
823                     env,
824                     &base_uri,
825                     sink,
826                     stream);
827 
828   if (!*new_env) {
829     *new_env = env;
830   }
831 
832   return writer;
833 }
834 
835 static SerdWriter*
ttl_file_writer(FILE * fd,const SerdNode * node,SerdEnv ** env)836 ttl_file_writer(FILE* fd, const SerdNode* node, SerdEnv** env)
837 {
838   SerdWriter* writer = ttl_writer(serd_file_sink, fd, node, env);
839 
840   fseek(fd, 0, SEEK_END);
841   if (ftell(fd) == 0) {
842     serd_env_foreach(*env, (SerdPrefixSink)serd_writer_set_prefix, writer);
843   } else {
844     fprintf(fd, "\n");
845   }
846 
847   return writer;
848 }
849 
850 static void
add_to_model(SordWorld * world,SerdEnv * env,SordModel * model,const SerdNode s,const SerdNode p,const SerdNode o)851 add_to_model(SordWorld*     world,
852              SerdEnv*       env,
853              SordModel*     model,
854              const SerdNode s,
855              const SerdNode p,
856              const SerdNode o)
857 {
858   SordNode* ss = sord_node_from_serd_node(world, env, &s, NULL, NULL);
859   SordNode* sp = sord_node_from_serd_node(world, env, &p, NULL, NULL);
860   SordNode* so = sord_node_from_serd_node(world, env, &o, NULL, NULL);
861 
862   SordQuad quad = {ss, sp, so, NULL};
863   sord_add(model, quad);
864 
865   sord_node_free(world, ss);
866   sord_node_free(world, sp);
867   sord_node_free(world, so);
868 }
869 
870 static void
remove_manifest_entry(SordWorld * world,SordModel * model,const char * subject)871 remove_manifest_entry(SordWorld* world, SordModel* model, const char* subject)
872 {
873   SordNode* s = sord_new_uri(world, USTR(subject));
874   SordIter* i = sord_search(model, s, NULL, NULL, NULL);
875   while (!sord_iter_end(i)) {
876     sord_erase(model, i);
877   }
878   sord_iter_free(i);
879   sord_node_free(world, s);
880 }
881 
882 static int
write_manifest(LilvWorld * world,SerdEnv * env,SordModel * model,const SerdNode * file_uri)883 write_manifest(LilvWorld*      world,
884                SerdEnv*        env,
885                SordModel*      model,
886                const SerdNode* file_uri)
887 {
888   char* const path = (char*)serd_file_uri_parse(file_uri->buf, NULL);
889   FILE* const wfd  = fopen(path, "w");
890   if (!wfd) {
891     LILV_ERRORF("Failed to open %s for writing (%s)\n", path, strerror(errno));
892 
893     serd_free(path);
894     return 1;
895   }
896 
897   SerdWriter* writer = ttl_file_writer(wfd, file_uri, &env);
898   sord_write(model, writer, NULL);
899   serd_writer_free(writer);
900   fclose(wfd);
901   serd_free(path);
902   return 0;
903 }
904 
905 static int
add_state_to_manifest(LilvWorld * lworld,const LilvNode * plugin_uri,const char * manifest_path,const char * state_uri,const char * state_path)906 add_state_to_manifest(LilvWorld*      lworld,
907                       const LilvNode* plugin_uri,
908                       const char*     manifest_path,
909                       const char*     state_uri,
910                       const char*     state_path)
911 {
912   SordWorld* world    = lworld->world;
913   SerdNode   manifest = serd_node_new_file_uri(USTR(manifest_path), 0, 0, 1);
914   SerdNode   file     = serd_node_new_file_uri(USTR(state_path), 0, 0, 1);
915   SerdEnv*   env      = serd_env_new(&manifest);
916   SordModel* model    = sord_new(world, SORD_SPO, false);
917 
918   if (lilv_path_exists(manifest_path)) {
919     // Read manifest into model
920     SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
921     SerdStatus  st     = serd_reader_read_file(reader, manifest.buf);
922     if (st) {
923       LILV_WARNF("Failed to read manifest (%s)\n", serd_strerror(st));
924     }
925     serd_reader_free(reader);
926   }
927 
928   // Choose state URI (use file URI if not given)
929   if (!state_uri) {
930     state_uri = (const char*)file.buf;
931   }
932 
933   // Remove any existing manifest entries for this state
934   remove_manifest_entry(world, model, state_uri);
935 
936   // Add manifest entry for this state to model
937   SerdNode s = serd_node_from_string(SERD_URI, USTR(state_uri));
938 
939   // <state> a pset:Preset
940   add_to_model(world,
941                env,
942                model,
943                s,
944                serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
945                serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
946 
947   // <state> a pset:Preset
948   add_to_model(world,
949                env,
950                model,
951                s,
952                serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
953                serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
954 
955   // <state> rdfs:seeAlso <file>
956   add_to_model(world,
957                env,
958                model,
959                s,
960                serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "seeAlso")),
961                file);
962 
963   // <state> lv2:appliesTo <plugin>
964   add_to_model(
965     world,
966     env,
967     model,
968     s,
969     serd_node_from_string(SERD_URI, USTR(LV2_CORE__appliesTo)),
970     serd_node_from_string(SERD_URI, USTR(lilv_node_as_string(plugin_uri))));
971 
972   /* Re-open manifest for locked writing.  We need to do this because it may
973      need to be truncated, and the file can only be open once on Windows. */
974 
975   FILE* wfd = fopen(manifest_path, "wb");
976   int   r   = 0;
977   if (!wfd) {
978     LILV_ERRORF(
979       "Failed to open %s for writing (%s)\n", manifest_path, strerror(errno));
980     r = 1;
981   }
982 
983   SerdWriter* writer = ttl_file_writer(wfd, &manifest, &env);
984   lilv_flock(wfd, true, true);
985   sord_write(model, writer, NULL);
986   lilv_flock(wfd, false, true);
987   serd_writer_free(writer);
988   fclose(wfd);
989 
990   sord_free(model);
991   serd_node_free(&file);
992   serd_node_free(&manifest);
993   serd_env_free(env);
994 
995   return r;
996 }
997 
998 static bool
link_exists(const char * path,const void * data)999 link_exists(const char* path, const void* data)
1000 {
1001   const char* target = (const char*)data;
1002   if (!lilv_path_exists(path)) {
1003     return false;
1004   }
1005   char* real_path = lilv_path_canonical(path);
1006   bool  matches   = !strcmp(real_path, target);
1007   free(real_path);
1008   return !matches;
1009 }
1010 
1011 static int
maybe_symlink(const char * oldpath,const char * newpath)1012 maybe_symlink(const char* oldpath, const char* newpath)
1013 {
1014   if (link_exists(newpath, oldpath)) {
1015     return 0;
1016   }
1017 
1018   const int st = lilv_symlink(oldpath, newpath);
1019   if (st) {
1020     LILV_ERRORF(
1021       "Failed to link %s => %s (%s)\n", newpath, oldpath, strerror(errno));
1022   }
1023 
1024   return st;
1025 }
1026 
1027 static void
write_property_array(const LilvState * state,const PropertyArray * array,Sratom * sratom,uint32_t flags,const SerdNode * subject,LV2_URID_Unmap * unmap,const char * dir)1028 write_property_array(const LilvState*     state,
1029                      const PropertyArray* array,
1030                      Sratom*              sratom,
1031                      uint32_t             flags,
1032                      const SerdNode*      subject,
1033                      LV2_URID_Unmap*      unmap,
1034                      const char*          dir)
1035 {
1036   for (uint32_t i = 0; i < array->n; ++i) {
1037     Property*   prop = &array->props[i];
1038     const char* key  = unmap->unmap(unmap->handle, prop->key);
1039 
1040     const SerdNode p = serd_node_from_string(SERD_URI, USTR(key));
1041     if (prop->type == state->atom_Path && !dir) {
1042       const char* path     = (const char*)prop->value;
1043       const char* abs_path = lilv_state_rel2abs(state, path);
1044       LILV_WARNF("Writing absolute path %s\n", abs_path);
1045       sratom_write(sratom,
1046                    unmap,
1047                    flags,
1048                    subject,
1049                    &p,
1050                    prop->type,
1051                    strlen(abs_path) + 1,
1052                    abs_path);
1053     } else if (prop->flags & LV2_STATE_IS_POD ||
1054                prop->type == state->atom_Path) {
1055       sratom_write(
1056         sratom, unmap, flags, subject, &p, prop->type, prop->size, prop->value);
1057     } else {
1058       LILV_WARNF("Lost non-POD property <%s> on save\n", key);
1059     }
1060   }
1061 }
1062 
1063 static int
lilv_state_write(LilvWorld * world,LV2_URID_Map * map,LV2_URID_Unmap * unmap,const LilvState * state,SerdWriter * writer,const char * uri,const char * dir)1064 lilv_state_write(LilvWorld*       world,
1065                  LV2_URID_Map*    map,
1066                  LV2_URID_Unmap*  unmap,
1067                  const LilvState* state,
1068                  SerdWriter*      writer,
1069                  const char*      uri,
1070                  const char*      dir)
1071 {
1072   SerdNode lv2_appliesTo =
1073     serd_node_from_string(SERD_CURIE, USTR("lv2:appliesTo"));
1074 
1075   const SerdNode* plugin_uri = sord_node_to_serd_node(state->plugin_uri->node);
1076 
1077   SerdNode subject = serd_node_from_string(SERD_URI, USTR(uri ? uri : ""));
1078 
1079   // <subject> a pset:Preset
1080   SerdNode p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type"));
1081   SerdNode o = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset));
1082   serd_writer_write_statement(writer, 0, NULL, &subject, &p, &o, NULL, NULL);
1083 
1084   // <subject> lv2:appliesTo <http://example.org/plugin>
1085   serd_writer_write_statement(
1086     writer, 0, NULL, &subject, &lv2_appliesTo, plugin_uri, NULL, NULL);
1087 
1088   // <subject> rdfs:label label
1089   if (state->label) {
1090     p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "label"));
1091     o = serd_node_from_string(SERD_LITERAL, USTR(state->label));
1092     serd_writer_write_statement(writer, 0, NULL, &subject, &p, &o, NULL, NULL);
1093   }
1094 
1095   SerdEnv*        env  = serd_writer_get_env(writer);
1096   const SerdNode* base = serd_env_get_base_uri(env, NULL);
1097 
1098   Sratom* sratom = sratom_new(map);
1099   sratom_set_sink(sratom,
1100                   (const char*)base->buf,
1101                   (SerdStatementSink)serd_writer_write_statement,
1102                   (SerdEndSink)serd_writer_end_anon,
1103                   writer);
1104 
1105   // Write metadata
1106   sratom_set_pretty_numbers(sratom, false); // Use precise types
1107   write_property_array(
1108     state, &state->metadata, sratom, 0, &subject, unmap, dir);
1109 
1110   // Write port values
1111   sratom_set_pretty_numbers(sratom, true); // Use pretty numbers
1112   for (uint32_t i = 0; i < state->n_values; ++i) {
1113     PortValue* const value = &state->values[i];
1114 
1115     const SerdNode port =
1116       serd_node_from_string(SERD_BLANK, USTR(value->symbol));
1117 
1118     // <> lv2:port _:symbol
1119     p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__port));
1120     serd_writer_write_statement(
1121       writer, SERD_ANON_O_BEGIN, NULL, &subject, &p, &port, NULL, NULL);
1122 
1123     // _:symbol lv2:symbol "symbol"
1124     p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__symbol));
1125     o = serd_node_from_string(SERD_LITERAL, USTR(value->symbol));
1126     serd_writer_write_statement(
1127       writer, SERD_ANON_CONT, NULL, &port, &p, &o, NULL, NULL);
1128 
1129     // _:symbol pset:value value
1130     p = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__value));
1131     sratom_write(sratom,
1132                  unmap,
1133                  SERD_ANON_CONT,
1134                  &port,
1135                  &p,
1136                  value->atom->type,
1137                  value->atom->size,
1138                  value->atom + 1);
1139 
1140     serd_writer_end_anon(writer, &port);
1141   }
1142 
1143   // Write properties
1144   const SerdNode body = serd_node_from_string(SERD_BLANK, USTR("body"));
1145   if (state->props.n > 0) {
1146     p = serd_node_from_string(SERD_URI, USTR(LV2_STATE__state));
1147     serd_writer_write_statement(
1148       writer, SERD_ANON_O_BEGIN, NULL, &subject, &p, &body, NULL, NULL);
1149   }
1150   sratom_set_pretty_numbers(sratom, false); // Use precise types
1151   write_property_array(
1152     state, &state->props, sratom, SERD_ANON_CONT, &body, unmap, dir);
1153 
1154   if (state->props.n > 0) {
1155     serd_writer_end_anon(writer, &body);
1156   }
1157 
1158   sratom_free(sratom);
1159   return 0;
1160 }
1161 
1162 static void
lilv_state_make_links(const LilvState * state,const char * dir)1163 lilv_state_make_links(const LilvState* state, const char* dir)
1164 {
1165   // Create symlinks to files
1166   for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
1167        i != zix_tree_end(state->abs2rel);
1168        i = zix_tree_iter_next(i)) {
1169     const PathMap* pm = (const PathMap*)zix_tree_get(i);
1170 
1171     char* path = lilv_path_absolute_child(pm->rel, dir);
1172     if (lilv_path_is_child(pm->abs, state->copy_dir) &&
1173         strcmp(state->copy_dir, dir)) {
1174       // Link directly to snapshot in the copy directory
1175       maybe_symlink(pm->abs, path);
1176     } else if (!lilv_path_is_child(pm->abs, dir)) {
1177       const char* link_dir = state->link_dir ? state->link_dir : dir;
1178       char*       pat      = lilv_path_absolute_child(pm->rel, link_dir);
1179       if (!strcmp(dir, link_dir)) {
1180         // Link directory is save directory, make link at exact path
1181         remove(pat);
1182         maybe_symlink(pm->abs, pat);
1183       } else {
1184         // Make a link in the link directory to external file
1185         char* lpath = lilv_find_free_path(pat, link_exists, pm->abs);
1186         if (!lilv_path_exists(lpath)) {
1187           if (lilv_symlink(pm->abs, lpath)) {
1188             LILV_ERRORF("Failed to link %s => %s (%s)\n",
1189                         pm->abs,
1190                         lpath,
1191                         strerror(errno));
1192           }
1193         }
1194 
1195         // Make a link in the save directory to the external link
1196         char* target = lilv_path_relative_to(lpath, dir);
1197         maybe_symlink(lpath, path);
1198         free(target);
1199         free(lpath);
1200       }
1201       free(pat);
1202     }
1203     free(path);
1204   }
1205 }
1206 
1207 int
lilv_state_save(LilvWorld * world,LV2_URID_Map * map,LV2_URID_Unmap * unmap,const LilvState * state,const char * uri,const char * dir,const char * filename)1208 lilv_state_save(LilvWorld*       world,
1209                 LV2_URID_Map*    map,
1210                 LV2_URID_Unmap*  unmap,
1211                 const LilvState* state,
1212                 const char*      uri,
1213                 const char*      dir,
1214                 const char*      filename)
1215 {
1216   if (!filename || !dir || lilv_create_directories(dir)) {
1217     return 1;
1218   }
1219 
1220   char*       abs_dir = real_dir(dir);
1221   char* const path    = lilv_path_join(abs_dir, filename);
1222   FILE*       fd      = fopen(path, "w");
1223   if (!fd) {
1224     LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno));
1225     free(abs_dir);
1226     free(path);
1227     return 4;
1228   }
1229 
1230   // Create symlinks to files if necessary
1231   lilv_state_make_links(state, abs_dir);
1232 
1233   // Write state to Turtle file
1234   SerdNode    file = serd_node_new_file_uri(USTR(path), NULL, NULL, true);
1235   SerdNode    node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file;
1236   SerdEnv*    env  = NULL;
1237   SerdWriter* ttl  = ttl_file_writer(fd, &file, &env);
1238   int         ret =
1239     lilv_state_write(world, map, unmap, state, ttl, (const char*)node.buf, dir);
1240 
1241   // Set saved dir and uri (FIXME: const violation)
1242   free(state->dir);
1243   lilv_node_free(state->uri);
1244   ((LilvState*)state)->dir = lilv_strdup(abs_dir);
1245   ((LilvState*)state)->uri = lilv_new_uri(world, (const char*)node.buf);
1246 
1247   serd_node_free(&file);
1248   serd_writer_free(ttl);
1249   serd_env_free(env);
1250   fclose(fd);
1251 
1252   // Add entry to manifest
1253   if (!ret) {
1254     char* const manifest = lilv_path_join(abs_dir, "manifest.ttl");
1255 
1256     ret = add_state_to_manifest(world, state->plugin_uri, manifest, uri, path);
1257 
1258     free(manifest);
1259   }
1260 
1261   free(abs_dir);
1262   free(path);
1263   return ret;
1264 }
1265 
1266 char*
lilv_state_to_string(LilvWorld * world,LV2_URID_Map * map,LV2_URID_Unmap * unmap,const LilvState * state,const char * uri,const char * base_uri)1267 lilv_state_to_string(LilvWorld*       world,
1268                      LV2_URID_Map*    map,
1269                      LV2_URID_Unmap*  unmap,
1270                      const LilvState* state,
1271                      const char*      uri,
1272                      const char*      base_uri)
1273 {
1274   if (!uri) {
1275     LILV_ERROR("Attempt to serialise state with no URI\n");
1276     return NULL;
1277   }
1278 
1279   SerdChunk   chunk  = {NULL, 0};
1280   SerdEnv*    env    = NULL;
1281   SerdNode    base   = serd_node_from_string(SERD_URI, USTR(base_uri));
1282   SerdWriter* writer = ttl_writer(serd_chunk_sink, &chunk, &base, &env);
1283 
1284   lilv_state_write(world, map, unmap, state, writer, uri, NULL);
1285 
1286   serd_writer_free(writer);
1287   serd_env_free(env);
1288   char* str    = (char*)serd_chunk_sink_finish(&chunk);
1289   char* result = lilv_strdup(str);
1290   serd_free(str);
1291   return result;
1292 }
1293 
1294 static void
try_unlink(const char * state_dir,const char * path)1295 try_unlink(const char* state_dir, const char* path)
1296 {
1297   if (!strncmp(state_dir, path, strlen(state_dir))) {
1298     if (lilv_path_exists(path) && lilv_remove(path)) {
1299       LILV_ERRORF("Failed to remove %s (%s)\n", path, strerror(errno));
1300     }
1301   }
1302 }
1303 
1304 static char*
get_canonical_path(const LilvNode * const node)1305 get_canonical_path(const LilvNode* const node)
1306 {
1307   char* const path      = lilv_node_get_path(node, NULL);
1308   char* const real_path = lilv_path_canonical(path);
1309 
1310   free(path);
1311   return real_path;
1312 }
1313 
1314 int
lilv_state_delete(LilvWorld * world,const LilvState * state)1315 lilv_state_delete(LilvWorld* world, const LilvState* state)
1316 {
1317   if (!state->dir) {
1318     LILV_ERROR("Attempt to delete unsaved state\n");
1319     return -1;
1320   }
1321 
1322   LilvNode*  bundle        = lilv_new_file_uri(world, NULL, state->dir);
1323   LilvNode*  manifest      = lilv_world_get_manifest_uri(world, bundle);
1324   char*      manifest_path = get_canonical_path(manifest);
1325   const bool has_manifest  = lilv_path_exists(manifest_path);
1326   SordModel* model         = sord_new(world->world, SORD_SPO, false);
1327 
1328   if (has_manifest) {
1329     // Read manifest into temporary local model
1330     SerdEnv*    env = serd_env_new(sord_node_to_serd_node(manifest->node));
1331     SerdReader* ttl = sord_new_reader(model, env, SERD_TURTLE, NULL);
1332     serd_reader_read_file(ttl, USTR(manifest_path));
1333     serd_reader_free(ttl);
1334     serd_env_free(env);
1335   }
1336 
1337   if (state->uri) {
1338     SordNode* file =
1339       sord_get(model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL);
1340     if (file) {
1341       // Remove state file
1342       const uint8_t* uri       = sord_node_get_string(file);
1343       char*          path      = (char*)serd_file_uri_parse(uri, NULL);
1344       char*          real_path = lilv_path_canonical(path);
1345       if (path) {
1346         try_unlink(state->dir, real_path);
1347       }
1348       serd_free(real_path);
1349       serd_free(path);
1350     }
1351 
1352     // Remove any existing manifest entries for this state
1353     const char* state_uri_str = lilv_node_as_string(state->uri);
1354     remove_manifest_entry(world->world, model, state_uri_str);
1355     remove_manifest_entry(world->world, world->model, state_uri_str);
1356   }
1357 
1358   // Drop bundle from model
1359   lilv_world_unload_bundle(world, bundle);
1360 
1361   if (sord_num_quads(model) == 0) {
1362     // Manifest is empty, attempt to remove bundle entirely
1363     if (has_manifest) {
1364       try_unlink(state->dir, manifest_path);
1365     }
1366 
1367     // Remove all known files from state bundle
1368     if (state->abs2rel) {
1369       // State created from instance, get paths from map
1370       for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
1371            i != zix_tree_end(state->abs2rel);
1372            i = zix_tree_iter_next(i)) {
1373         const PathMap* pm   = (const PathMap*)zix_tree_get(i);
1374         char*          path = lilv_path_join(state->dir, pm->rel);
1375         try_unlink(state->dir, path);
1376         free(path);
1377       }
1378     } else {
1379       // State loaded from model, get paths from loaded properties
1380       for (uint32_t i = 0; i < state->props.n; ++i) {
1381         const Property* const p = &state->props.props[i];
1382         if (p->type == state->atom_Path) {
1383           try_unlink(state->dir, (const char*)p->value);
1384         }
1385       }
1386     }
1387 
1388     if (lilv_remove(state->dir)) {
1389       LILV_ERRORF(
1390         "Failed to remove directory %s (%s)\n", state->dir, strerror(errno));
1391     }
1392   } else {
1393     // Still something in the manifest, update and reload bundle
1394     const SerdNode* manifest_node = sord_node_to_serd_node(manifest->node);
1395     SerdEnv*        env           = serd_env_new(manifest_node);
1396 
1397     write_manifest(world, env, model, manifest_node);
1398     lilv_world_load_bundle(world, bundle);
1399     serd_env_free(env);
1400   }
1401 
1402   sord_free(model);
1403   lilv_free(manifest_path);
1404   lilv_node_free(manifest);
1405   lilv_node_free(bundle);
1406 
1407   return 0;
1408 }
1409 
1410 static void
free_property_array(LilvState * state,PropertyArray * array)1411 free_property_array(LilvState* state, PropertyArray* array)
1412 {
1413   for (uint32_t i = 0; i < array->n; ++i) {
1414     Property* prop = &array->props[i];
1415     if ((prop->flags & LV2_STATE_IS_POD) || prop->type == state->atom_Path) {
1416       free(prop->value);
1417     }
1418   }
1419   free(array->props);
1420 }
1421 
1422 void
lilv_state_free(LilvState * state)1423 lilv_state_free(LilvState* state)
1424 {
1425   if (state) {
1426     free_property_array(state, &state->props);
1427     free_property_array(state, &state->metadata);
1428     for (uint32_t i = 0; i < state->n_values; ++i) {
1429       free(state->values[i].atom);
1430       free(state->values[i].symbol);
1431     }
1432     lilv_node_free(state->plugin_uri);
1433     lilv_node_free(state->uri);
1434     zix_tree_free(state->abs2rel);
1435     zix_tree_free(state->rel2abs);
1436     free(state->values);
1437     free(state->label);
1438     free(state->dir);
1439     free(state->scratch_dir);
1440     free(state->copy_dir);
1441     free(state->link_dir);
1442     free(state);
1443   }
1444 }
1445 
1446 bool
lilv_state_equals(const LilvState * a,const LilvState * b)1447 lilv_state_equals(const LilvState* a, const LilvState* b)
1448 {
1449   if (!lilv_node_equals(a->plugin_uri, b->plugin_uri) ||
1450       (a->label && !b->label) || (b->label && !a->label) ||
1451       (a->label && b->label && strcmp(a->label, b->label)) ||
1452       a->props.n != b->props.n || a->n_values != b->n_values) {
1453     return false;
1454   }
1455 
1456   for (uint32_t i = 0; i < a->n_values; ++i) {
1457     PortValue* const av = &a->values[i];
1458     PortValue* const bv = &b->values[i];
1459     if (av->atom->size != bv->atom->size || av->atom->type != bv->atom->type ||
1460         strcmp(av->symbol, bv->symbol) ||
1461         memcmp(av->atom + 1, bv->atom + 1, av->atom->size)) {
1462       return false;
1463     }
1464   }
1465 
1466   for (uint32_t i = 0; i < a->props.n; ++i) {
1467     Property* const ap = &a->props.props[i];
1468     Property* const bp = &b->props.props[i];
1469     if (ap->key != bp->key || ap->type != bp->type || ap->flags != bp->flags) {
1470       return false;
1471     }
1472 
1473     if (ap->type == a->atom_Path) {
1474       if (!lilv_file_equals(lilv_state_rel2abs(a, (char*)ap->value),
1475                             lilv_state_rel2abs(b, (char*)bp->value))) {
1476         return false;
1477       }
1478     } else if (ap->size != bp->size || memcmp(ap->value, bp->value, ap->size)) {
1479       return false;
1480     }
1481   }
1482 
1483   return true;
1484 }
1485 
1486 unsigned
lilv_state_get_num_properties(const LilvState * state)1487 lilv_state_get_num_properties(const LilvState* state)
1488 {
1489   return state->props.n;
1490 }
1491 
1492 const LilvNode*
lilv_state_get_plugin_uri(const LilvState * state)1493 lilv_state_get_plugin_uri(const LilvState* state)
1494 {
1495   return state->plugin_uri;
1496 }
1497 
1498 const LilvNode*
lilv_state_get_uri(const LilvState * state)1499 lilv_state_get_uri(const LilvState* state)
1500 {
1501   return state->uri;
1502 }
1503 
1504 const char*
lilv_state_get_label(const LilvState * state)1505 lilv_state_get_label(const LilvState* state)
1506 {
1507   return state->label;
1508 }
1509 
1510 void
lilv_state_set_label(LilvState * state,const char * label)1511 lilv_state_set_label(LilvState* state, const char* label)
1512 {
1513   const size_t len = strlen(label);
1514   state->label     = (char*)realloc(state->label, len + 1);
1515   memcpy(state->label, label, len + 1);
1516 }
1517 
1518 int
lilv_state_set_metadata(LilvState * state,uint32_t key,const void * value,size_t size,uint32_t type,uint32_t flags)1519 lilv_state_set_metadata(LilvState*  state,
1520                         uint32_t    key,
1521                         const void* value,
1522                         size_t      size,
1523                         uint32_t    type,
1524                         uint32_t    flags)
1525 {
1526   append_property(state, &state->metadata, key, value, size, type, flags);
1527   return LV2_STATE_SUCCESS;
1528 }
1529