LMMS
Loading...
Searching...
No Matches
serd_internal.h
Go to the documentation of this file.
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#ifndef SERD_INTERNAL_H
18#define SERD_INTERNAL_H
19
20#define _POSIX_C_SOURCE 200809L /* for posix_memalign and posix_fadvise */
21
22#include <assert.h>
23#include <errno.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "serd/serd.h"
29#include "serd_config.h"
30
31#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FILENO)
32# include <fcntl.h>
33#endif
34
35#define SERD_PAGE_SIZE 4096
36
37#ifndef MIN
38# define MIN(a, b) (((a) < (b)) ? (a) : (b))
39#endif
40
41/* File and Buffer Utilities */
42
43static inline FILE*
44serd_fopen(const char* path, const char* mode)
45{
46 FILE* fd = fopen((const char*)path, mode);
47 if (!fd) {
48 if (errno != ENOTDIR) fprintf(stderr, "Error opening file %s (%s)\n", path, strerror(errno));
49 return NULL;
50 }
51#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FILENO)
52 posix_fadvise(fileno(fd), 0, 0, POSIX_FADV_SEQUENTIAL);
53#endif
54 return fd;
55}
56
57static inline void*
59{
60#ifdef HAVE_POSIX_MEMALIGN
61 void* ptr;
62 const int ret = posix_memalign(&ptr, SERD_PAGE_SIZE, size);
63 return ret ? NULL : ptr;
64#else
65 return malloc(size);
66#endif
67}
68
69/* Stack */
70
72typedef struct {
73 uint8_t* buf;
74 size_t buf_size;
75 size_t size;
76} SerdStack;
77
79#define SERD_STACK_BOTTOM sizeof(void*)
80
81static inline SerdStack
83{
84 SerdStack stack;
85 stack.buf = (uint8_t*)malloc(size);
86 stack.buf_size = size;
87 stack.size = SERD_STACK_BOTTOM;
88 return stack;
89}
90
91static inline bool
93{
94 return stack->size <= SERD_STACK_BOTTOM;
95}
96
97static inline void
99{
100 free(stack->buf);
101 stack->buf = NULL;
102 stack->buf_size = 0;
103 stack->size = 0;
104}
105
106static inline uint8_t*
107serd_stack_push(SerdStack* stack, size_t n_bytes)
108{
109 const size_t new_size = stack->size + n_bytes;
110 if (stack->buf_size < new_size) {
111 stack->buf_size *= 2;
112 stack->buf = (uint8_t*)realloc(stack->buf, stack->buf_size);
113 }
114 uint8_t* const ret = (stack->buf + stack->size);
115 stack->size = new_size;
116 return ret;
117}
118
119static inline void
120serd_stack_pop(SerdStack* stack, size_t n_bytes)
121{
122 assert(stack->size >= n_bytes);
123 stack->size -= n_bytes;
124}
125
126static inline void*
127serd_stack_push_aligned(SerdStack* stack, size_t n_bytes, size_t align)
128{
129 // Push one byte to ensure space for a pad count
130 serd_stack_push(stack, 1);
131
132 // Push padding if necessary
133 const uint8_t pad = align - stack->size % align;
134 if (pad > 0) {
135 serd_stack_push(stack, pad);
136 }
137
138 // Set top of stack to pad count so we can properly pop later
139 stack->buf[stack->size - 1] = pad;
140
141 // Push requested space at aligned location
142 return serd_stack_push(stack, n_bytes);
143}
144
145static inline void
146serd_stack_pop_aligned(SerdStack* stack, size_t n_bytes)
147{
148 // Pop requested space down to aligned location
149 serd_stack_pop(stack, n_bytes);
150
151 // Get amount of padding from top of stack
152 const uint8_t pad = stack->buf[stack->size - 1];
153
154 // Pop padding and pad count
155 serd_stack_pop(stack, pad + 1);
156}
157
158/* Bulk Sink */
159
167
168static inline SerdBulkSink
170{
171 SerdBulkSink bsink;
172 bsink.sink = sink;
173 bsink.stream = stream;
174 bsink.size = 0;
175 bsink.block_size = block_size;
177 return bsink;
178}
179
180static inline void
182{
183 if (bsink->size > 0) {
184 bsink->sink(bsink->buf, bsink->size, bsink->stream);
185 }
186 bsink->size = 0;
187}
188
189static inline void
191{
193 free(bsink->buf);
194 bsink->buf = NULL;
195}
196
197static inline size_t
198serd_bulk_sink_write(const void* buf, size_t len, SerdBulkSink* bsink)
199{
200 const size_t orig_len = len;
201 while (len) {
202 const size_t space = bsink->block_size - bsink->size;
203 const size_t n = MIN(space, len);
204
205 // Write as much as possible into the remaining buffer space
206 memcpy(bsink->buf + bsink->size, buf, n);
207 bsink->size += n;
208 buf = (const uint8_t*)buf + n;
209 len -= n;
210
211 // Flush page if buffer is full
212 if (bsink->size == bsink->block_size) {
213 bsink->sink(bsink->buf, bsink->block_size, bsink->stream);
214 bsink->size = 0;
215 }
216 }
217 return orig_len;
218}
219
220/* Character utilities */
221
223static inline bool
224in_range(const uint8_t c, const uint8_t min, const uint8_t max)
225{
226 return (c >= min && c <= max);
227}
228
230static inline bool
232{
233 return in_range(c, 'A', 'Z') || in_range(c, 'a', 'z');
234}
235
237static inline bool
239{
240 return in_range(c, '0', '9');
241}
242
243static inline bool
244is_space(const char c)
245{
246 switch (c) {
247 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
248 return true;
249 default:
250 return false;
251 }
252}
253
254static inline bool
256{
257 return is_alpha(c) || is_digit(c) || c == '+' || c == '/' || c == '=';
258}
259
260static inline bool
262{
263 return is_alpha(path[0]) && (path[1] == ':' || path[1] == '|')
264 && (path[2] == '/' || path[2] == '\\');
265}
266
267/* URI utilities */
268
269static inline bool
271{
272 return a->len == b->len
273 && !strncmp((const char*)a->buf, (const char*)b->buf, a->len);
274}
275
276static inline size_t
278{
279 return uri->path_base.len + uri->path.len;
280}
281
282static inline uint8_t
283uri_path_at(const SerdURI* uri, size_t i)
284{
285 if (i < uri->path_base.len) {
286 return uri->path_base.buf[i];
287 } else {
288 return uri->path.buf[i - uri->path_base.len];
289 }
290}
291
293static inline bool
294uri_is_under(const SerdURI* uri, const SerdURI* root)
295{
296 if (!root || !root->scheme.len ||
297 !chunk_equals(&root->scheme, &uri->scheme) ||
298 !chunk_equals(&root->authority, &uri->authority)) {
299 return false;
300 }
301
302 bool differ = false;
303 const size_t path_len = uri_path_len(uri);
304 const size_t root_len = uri_path_len(root);
305 for (size_t i = 0; i < path_len && i < root_len; ++i) {
306 if (uri_path_at(uri, i) != uri_path_at(root, i)) {
307 differ = true;
308 }
309 if (differ && uri_path_at(root, i) == '/') {
310 return false;
311 }
312 }
313
314 return true;
315}
316
317/* Error reporting */
318
319static inline void
320serd_error(SerdErrorSink error_sink, void* handle, const SerdError* e)
321{
322 if (error_sink) {
323 error_sink(handle, e);
324 } else {
325 fprintf(stderr, "error: %s:%u:%u: ", e->filename, e->line, e->col);
326 vfprintf(stderr, e->fmt, *e->args);
327 }
328}
329
330#endif // SERD_INTERNAL_H
#define NULL
Definition CarlaBridgeFormat.cpp:30
assert(0)
uint8_t a
Definition Spc_Cpu.h:141
* e
Definition inflate.c:1404
register unsigned i
Definition inflate.c:1575
#define buf_size
SerdStatus(* SerdErrorSink)(void *SERD_NULLABLE handle, const SerdError *SERD_NONNULL error)
Definition serd.h:607
size_t(* SerdSink)(const void *SERD_NONNULL buf, size_t len, void *SERD_NONNULL stream)
Sink function for raw string output.
Definition serd.h:351
#define is_windows_path
static void serd_error(SerdErrorSink error_sink, void *handle, const SerdError *e)
Definition serd_internal.h:36
#define SERD_PAGE_SIZE
Definition serd_internal.h:27
static size_t sink(const void *buf, size_t len, SerdWriter *writer)
Definition writer.c:177
static SordNode * uri(SordWorld *world, int num)
Definition sord_test.c:47
static size_t serd_bulk_sink_write(const void *buf, size_t len, SerdBulkSink *bsink)
Definition serd_internal.h:198
static void serd_stack_pop(SerdStack *stack, size_t n_bytes)
Definition serd_internal.h:120
static bool is_space(const char c)
Definition serd_internal.h:244
#define MIN(a, b)
Definition serd_internal.h:38
static void serd_stack_free(SerdStack *stack)
Definition serd_internal.h:98
static FILE * serd_fopen(const char *path, const char *mode)
Definition serd_internal.h:44
static void serd_bulk_sink_flush(SerdBulkSink *bsink)
Definition serd_internal.h:181
static void * serd_stack_push_aligned(SerdStack *stack, size_t n_bytes, size_t align)
Definition serd_internal.h:127
static uint8_t * serd_stack_push(SerdStack *stack, size_t n_bytes)
Definition serd_internal.h:107
static uint8_t uri_path_at(const SerdURI *uri, size_t i)
Definition serd_internal.h:283
static bool in_range(const uint8_t c, const uint8_t min, const uint8_t max)
Definition serd_internal.h:224
static size_t uri_path_len(const SerdURI *uri)
Definition serd_internal.h:277
struct SerdBulkSinkImpl SerdBulkSink
static bool is_alpha(const uint8_t c)
Definition serd_internal.h:231
static bool serd_stack_is_empty(SerdStack *stack)
Definition serd_internal.h:92
static void * serd_bufalloc(size_t size)
Definition serd_internal.h:58
static void serd_bulk_sink_free(SerdBulkSink *bsink)
Definition serd_internal.h:190
static void serd_stack_pop_aligned(SerdStack *stack, size_t n_bytes)
Definition serd_internal.h:146
static SerdBulkSink serd_bulk_sink_new(SerdSink sink, void *stream, size_t block_size)
Definition serd_internal.h:169
static bool chunk_equals(const SerdChunk *a, const SerdChunk *b)
Definition serd_internal.h:270
static bool is_digit(const uint8_t c)
Definition serd_internal.h:238
static SerdStack serd_stack_new(size_t size)
Definition serd_internal.h:82
static bool is_base64(const uint8_t c)
Definition serd_internal.h:255
static bool uri_is_under(const SerdURI *uri, const SerdURI *root)
Definition serd_internal.h:294
unsigned char uint8_t
Definition mid.cpp:98
#define min(x, y)
Definition os.h:74
#define max(x, y)
Definition os.h:78
png_structrp int mode
Definition png.h:1139
#define SERD_STACK_BOTTOM
Definition stack.h:27
Definition serd_internal.h:160
SerdSink sink
Definition serd_internal.h:161
uint8_t * buf
Definition serd_internal.h:163
void * stream
Definition serd_internal.h:162
size_t size
Definition serd_internal.h:164
size_t block_size
Definition serd_internal.h:165
An unterminated string fragment.
Definition serd.h:208
size_t len
Length of chunk in bytes.
Definition serd.h:210
An error description.
Definition serd.h:214
Definition stack.h:30
size_t size
Conceptual size of stack in buf.
Definition stack.h:33
uint8_t * buf
Stack memory.
Definition stack.h:31
size_t buf_size
Allocated size of buf (>= size).
Definition stack.h:32
Definition serd.h:230
SerdChunk authority
Authority.
Definition serd.h:232
SerdChunk scheme
Scheme.
Definition serd.h:231
static size_t block_size(const block_header_t *block)
Definition tlsf.c:173
int n
Definition crypt.c:458
return c
Definition crypt.c:175
memcpy(hh, h, RAND_HEAD_LEN)
b
Definition crypt.c:628
ulg size
Definition extract.c:2350
char * malloc()
static bool chunk_equals(const SerdChunk *a, const SerdChunk *b)
Definition uri_utils.h:29