comparison ext/serd/src/env.c @ 226:c5cdc9e6a4bf

Add these external library files
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 09 Jun 2017 16:41:31 +0100
parents
children
comparison
equal deleted inserted replaced
225:025b3e2f7c17 226:c5cdc9e6a4bf
1 /*
2 Copyright 2011-2016 David Robillard <http://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 "serd_internal.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 typedef struct {
23 SerdNode name;
24 SerdNode uri;
25 } SerdPrefix;
26
27 struct SerdEnvImpl {
28 SerdPrefix* prefixes;
29 size_t n_prefixes;
30 SerdNode base_uri_node;
31 SerdURI base_uri;
32 };
33
34 SERD_API
35 SerdEnv*
36 serd_env_new(const SerdNode* base_uri)
37 {
38 SerdEnv* env = (SerdEnv*)calloc(sizeof(struct SerdEnvImpl), 1);
39 if (env && base_uri) {
40 serd_env_set_base_uri(env, base_uri);
41 }
42 return env;
43 }
44
45 SERD_API
46 void
47 serd_env_free(SerdEnv* env)
48 {
49 for (size_t i = 0; i < env->n_prefixes; ++i) {
50 serd_node_free(&env->prefixes[i].name);
51 serd_node_free(&env->prefixes[i].uri);
52 }
53 free(env->prefixes);
54 serd_node_free(&env->base_uri_node);
55 free(env);
56 }
57
58 SERD_API
59 const SerdNode*
60 serd_env_get_base_uri(const SerdEnv* env,
61 SerdURI* out)
62 {
63 if (out) {
64 *out = env->base_uri;
65 }
66 return &env->base_uri_node;
67 }
68
69 SERD_API
70 SerdStatus
71 serd_env_set_base_uri(SerdEnv* env,
72 const SerdNode* uri_node)
73 {
74 if (!env || !uri_node) {
75 return SERD_ERR_BAD_ARG;
76 }
77
78 // Resolve base URI and create a new node and URI for it
79 SerdURI base_uri;
80 SerdNode base_uri_node = serd_node_new_uri_from_node(
81 uri_node, &env->base_uri, &base_uri);
82
83 if (base_uri_node.buf) {
84 // Replace the current base URI
85 serd_node_free(&env->base_uri_node);
86 env->base_uri_node = base_uri_node;
87 env->base_uri = base_uri;
88 return SERD_SUCCESS;
89 }
90 return SERD_ERR_BAD_ARG;
91 }
92
93 static inline SerdPrefix*
94 serd_env_find(const SerdEnv* env,
95 const uint8_t* name,
96 size_t name_len)
97 {
98 for (size_t i = 0; i < env->n_prefixes; ++i) {
99 const SerdNode* const prefix_name = &env->prefixes[i].name;
100 if (prefix_name->n_bytes == name_len) {
101 if (!memcmp(prefix_name->buf, name, name_len)) {
102 return &env->prefixes[i];
103 }
104 }
105 }
106 return NULL;
107 }
108
109 static void
110 serd_env_add(SerdEnv* env,
111 const SerdNode* name,
112 const SerdNode* uri)
113 {
114 SerdPrefix* const prefix = serd_env_find(env, name->buf, name->n_bytes);
115 if (prefix) {
116 SerdNode old_prefix_uri = prefix->uri;
117 prefix->uri = serd_node_copy(uri);
118 serd_node_free(&old_prefix_uri);
119 } else {
120 env->prefixes = (SerdPrefix*)realloc(
121 env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix));
122 env->prefixes[env->n_prefixes - 1].name = serd_node_copy(name);
123 env->prefixes[env->n_prefixes - 1].uri = serd_node_copy(uri);
124 }
125 }
126
127 SERD_API
128 SerdStatus
129 serd_env_set_prefix(SerdEnv* env,
130 const SerdNode* name,
131 const SerdNode* uri_node)
132 {
133 if (!name->buf || uri_node->type != SERD_URI) {
134 return SERD_ERR_BAD_ARG;
135 } else if (serd_uri_string_has_scheme(uri_node->buf)) {
136 // Set prefix to absolute URI
137 serd_env_add(env, name, uri_node);
138 } else {
139 // Resolve relative URI and create a new node and URI for it
140 SerdURI abs_uri;
141 SerdNode abs_uri_node = serd_node_new_uri_from_node(
142 uri_node, &env->base_uri, &abs_uri);
143
144 // Set prefix to resolved (absolute) URI
145 serd_env_add(env, name, &abs_uri_node);
146 serd_node_free(&abs_uri_node);
147 }
148 return SERD_SUCCESS;
149 }
150
151 SERD_API
152 SerdStatus
153 serd_env_set_prefix_from_strings(SerdEnv* env,
154 const uint8_t* name,
155 const uint8_t* uri)
156 {
157 const SerdNode name_node = serd_node_from_string(SERD_LITERAL, name);
158 const SerdNode uri_node = serd_node_from_string(SERD_URI, uri);
159
160 return serd_env_set_prefix(env, &name_node, &uri_node);
161 }
162
163 static inline bool
164 is_nameChar(const uint8_t c)
165 {
166 return is_alpha(c) || is_digit(c) || c == '_';
167 }
168
169 /**
170 Return true iff `buf` is a valid prefixed name suffix.
171 TODO: This is more strict than it should be.
172 */
173 static inline bool
174 is_name(const uint8_t* buf, size_t len)
175 {
176 for (size_t i = 0; i < len; ++i) {
177 if (!is_nameChar(buf[i])) {
178 return false;
179 }
180 }
181 return true;
182 }
183
184 SERD_API
185 bool
186 serd_env_qualify(const SerdEnv* env,
187 const SerdNode* uri,
188 SerdNode* prefix_name,
189 SerdChunk* suffix)
190 {
191 for (size_t i = 0; i < env->n_prefixes; ++i) {
192 const SerdNode* const prefix_uri = &env->prefixes[i].uri;
193 if (uri->n_bytes >= prefix_uri->n_bytes) {
194 if (!strncmp((const char*)uri->buf,
195 (const char*)prefix_uri->buf,
196 prefix_uri->n_bytes)) {
197 *prefix_name = env->prefixes[i].name;
198 suffix->buf = uri->buf + prefix_uri->n_bytes;
199 suffix->len = uri->n_bytes - prefix_uri->n_bytes;
200 if (is_name(suffix->buf, suffix->len)) {
201 return true;
202 }
203 }
204 }
205 }
206 return false;
207 }
208
209 SERD_API
210 SerdStatus
211 serd_env_expand(const SerdEnv* env,
212 const SerdNode* qname,
213 SerdChunk* uri_prefix,
214 SerdChunk* uri_suffix)
215 {
216 const uint8_t* const colon = (const uint8_t*)memchr(
217 qname->buf, ':', qname->n_bytes + 1);
218 if (!colon) {
219 return SERD_ERR_BAD_ARG; // Invalid qname
220 }
221
222 const size_t name_len = colon - qname->buf;
223 const SerdPrefix* const prefix = serd_env_find(env, qname->buf, name_len);
224 if (prefix) {
225 uri_prefix->buf = prefix->uri.buf;
226 uri_prefix->len = prefix->uri.n_bytes;
227 uri_suffix->buf = colon + 1;
228 uri_suffix->len = qname->n_bytes - (colon - qname->buf) - 1;
229 return SERD_SUCCESS;
230 }
231 return SERD_ERR_NOT_FOUND;
232 }
233
234 SERD_API
235 SerdNode
236 serd_env_expand_node(const SerdEnv* env,
237 const SerdNode* node)
238 {
239 switch (node->type) {
240 case SERD_CURIE: {
241 SerdChunk prefix;
242 SerdChunk suffix;
243 if (serd_env_expand(env, node, &prefix, &suffix)) {
244 return SERD_NODE_NULL;
245 }
246 const size_t len = prefix.len + suffix.len;
247 uint8_t* buf = (uint8_t*)malloc(len + 1);
248 SerdNode ret = { buf, len, 0, 0, SERD_URI };
249 snprintf((char*)buf, len + 1, "%s%s", prefix.buf, suffix.buf);
250 ret.n_chars = serd_strlen(buf, NULL, NULL);
251 return ret;
252 }
253 case SERD_URI: {
254 SerdURI ignored;
255 return serd_node_new_uri_from_node(node, &env->base_uri, &ignored);
256 }
257 default:
258 return SERD_NODE_NULL;
259 }
260 }
261
262 SERD_API
263 void
264 serd_env_foreach(const SerdEnv* env,
265 SerdPrefixSink func,
266 void* handle)
267 {
268 for (size_t i = 0; i < env->n_prefixes; ++i) {
269 func(handle, &env->prefixes[i].name, &env->prefixes[i].uri);
270 }
271 }