5311efd049d694ccfe5c973dc9f950ca6bb97622
[ardour.git] / libs / ardour / ardour / lv2_state.h
1 /*
2   Copyright (C) 2011 Paul Davis
3   Author: David Robillard
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef __ardour_lv2_state_h__
21 #define __ardour_lv2_state_h__
22
23 #include <stdint.h>
24 #include <stdlib.h>
25
26 #include <map>
27 #include <string>
28
29 #include "pbd/error.h"
30
31 #include "ardour/uri_map.h"
32 #include "lv2/lv2plug.in/ns/ext/persist/persist.h"
33 #include "rdff.h"
34
35 namespace ARDOUR {
36
37 struct LV2PersistState {
38         LV2PersistState(URIMap& map) : uri_map(map) {}
39
40         struct Value {
41                 inline Value(uint32_t k, const void* v, size_t s, uint32_t t, uint32_t f)
42                         : key(k), value(v), size(s), type(t), flags(f)
43                 {}
44
45                 const uint32_t key;
46                 const void*    value;
47                 const size_t   size;
48                 const uint32_t type;
49                 const uint32_t flags;
50         };
51
52         typedef std::map<uint32_t, std::string> URIs;
53         typedef std::map<uint32_t, Value>       Values;
54
55         uint32_t file_id_to_runtime_id(uint32_t file_id) const {
56                 URIs::const_iterator i = uris.find(file_id);
57                 if (i == uris.end()) {
58                         PBD::error << "LV2 state refers to undefined URI ID" << endmsg;
59                         return 0;
60                 }
61                 return uri_map.uri_to_id(NULL, i->second.c_str());
62         }
63
64         int add_uri(uint32_t file_id, const char* str) {
65                 // TODO: check for clashes (invalid file)
66                 uris.insert(std::make_pair(file_id, str));
67                 return 0;
68         }
69
70         int add_value(uint32_t    file_key,
71                       const void* value,
72                       size_t      size,
73                       uint32_t    file_type,
74                       uint32_t    flags) {
75                 const uint32_t key  = file_id_to_runtime_id(file_key);
76                 const uint32_t type = file_id_to_runtime_id(file_type);
77                 if (!key || !type) {
78                         return 1;
79                 }
80
81                 Values::const_iterator i = values.find(key);
82                 if (i != values.end()) {
83                         PBD::error << "LV2 state contains duplicate keys" << endmsg;
84                         return 1;
85                 } else {
86                         void* value_copy = malloc(size);
87                         memcpy(value_copy, value, size); // FIXME: leak
88                         values.insert(
89                                 std::make_pair(key,
90                                                Value(key, value_copy, size, type, flags)));
91                         return 0;
92                 }
93         }
94
95         void read(RDFF file) {
96                 RDFFChunk* chunk = (RDFFChunk*)malloc(sizeof(RDFFChunk));
97                 chunk->size = 0;
98                 while (!rdff_read_chunk(file, &chunk)) {
99                         if (rdff_chunk_is_uri(chunk)) {
100                                 RDFFURIChunk* body = (RDFFURIChunk*)chunk->data;
101                                 add_uri(body->id, body->uri);
102                         } else if (rdff_chunk_is_triple(chunk)) {
103                                 RDFFTripleChunk* body = (RDFFTripleChunk*)chunk->data;
104                                 add_value(body->predicate,
105                                           body->object,
106                                           body->object_size,
107                                           body->object_type,
108                                           LV2_PERSIST_IS_POD | LV2_PERSIST_IS_PORTABLE);
109                         }
110                 }
111                 free(chunk);
112         }
113
114         void write(RDFF file) {
115                 // Write all referenced URIs to state file
116                 for (URIs::const_iterator i = uris.begin(); i != uris.end(); ++i) {
117                         rdff_write_uri(file,
118                                        i->first,
119                                        i->second.length(),
120                                        i->second.c_str());
121                 }
122
123                 // Write all values to state file
124                 for (Values::const_iterator i = values.begin(); i != values.end(); ++i) {
125                         const uint32_t                key = i->first;
126                         const LV2PersistState::Value& val = i->second;
127                         rdff_write_triple(file,
128                                           0,
129                                           key,
130                                           val.type,
131                                           val.size,
132                                           val.value);
133                 }
134         }
135
136         URIMap& uri_map;
137         URIs    uris;
138         Values  values;
139 };
140
141 } // namespace ARDOUR
142
143 #endif /* __ardour_lv2_state_h__ */