Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/libucl/src/ucl_sexp.c
2066 views
1
/*
2
* Copyright (c) 2015, Vsevolod Stakhov
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
7
* * Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* * Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
*/
24
25
#ifdef HAVE_CONFIG_H
26
#include "config.h"
27
#endif
28
29
#include <ucl.h>
30
#include "ucl.h"
31
#include "ucl_internal.h"
32
#include "utlist.h"
33
34
#define NEXT_STATE do { \
35
if (p >= end) { \
36
if (state != read_ebrace) { \
37
ucl_create_err (&parser->err,\
38
"extra data");\
39
state = parse_err; \
40
} \
41
} \
42
else { \
43
switch (*p) { \
44
case '(': \
45
state = read_obrace; \
46
break; \
47
case ')': \
48
state = read_ebrace; \
49
break; \
50
default: \
51
len = 0; \
52
mult = 1; \
53
state = read_length; \
54
break; \
55
} \
56
} \
57
} while(0)
58
59
bool
60
ucl_parse_csexp (struct ucl_parser *parser)
61
{
62
const unsigned char *p, *end;
63
ucl_object_t *obj;
64
struct ucl_stack *st;
65
uint64_t len = 0, mult = 1;
66
enum {
67
start_parse,
68
read_obrace,
69
read_length,
70
read_value,
71
read_ebrace,
72
parse_err
73
} state = start_parse;
74
75
assert (parser != NULL);
76
assert (parser->chunks != NULL);
77
assert (parser->chunks->begin != NULL);
78
assert (parser->chunks->remain != 0);
79
80
p = parser->chunks->begin;
81
end = p + parser->chunks->remain;
82
83
while (p < end) {
84
switch (state) {
85
case start_parse:
86
/* At this point we expect open brace */
87
if (*p == '(') {
88
state = read_obrace;
89
}
90
else {
91
ucl_create_err (&parser->err, "bad starting character for "
92
"sexp block: %x", (int)*p);
93
state = parse_err;
94
}
95
break;
96
97
case read_obrace:
98
st = calloc (1, sizeof (*st));
99
100
if (st == NULL) {
101
ucl_create_err (&parser->err, "no memory");
102
state = parse_err;
103
continue;
104
}
105
106
st->obj = ucl_object_typed_new (UCL_ARRAY);
107
108
if (st->obj == NULL) {
109
ucl_create_err (&parser->err, "no memory");
110
state = parse_err;
111
free (st);
112
continue;
113
}
114
115
if (parser->stack == NULL) {
116
/* We have no stack */
117
parser->stack = st;
118
119
if (parser->top_obj == NULL) {
120
parser->top_obj = st->obj;
121
}
122
}
123
else {
124
/* Prepend new element to the stack */
125
LL_PREPEND (parser->stack, st);
126
}
127
128
p ++;
129
NEXT_STATE;
130
131
break;
132
133
case read_length:
134
if (*p == ':') {
135
if (len == 0) {
136
ucl_create_err (&parser->err, "zero length element");
137
state = parse_err;
138
continue;
139
}
140
141
state = read_value;
142
}
143
else if (*p >= '0' && *p <= '9') {
144
len += (*p - '0') * mult;
145
mult *= 10;
146
147
if (len > UINT32_MAX) {
148
ucl_create_err (&parser->err, "too big length of an "
149
"element");
150
state = parse_err;
151
continue;
152
}
153
}
154
else {
155
ucl_create_err (&parser->err, "bad length character: %x",
156
(int)*p);
157
state = parse_err;
158
continue;
159
}
160
161
p ++;
162
break;
163
164
case read_value:
165
if ((uint64_t)(end - p) > len || len == 0) {
166
ucl_create_err (&parser->err, "invalid length: %llu, %ld "
167
"remain", (long long unsigned)len, (long)(end - p));
168
state = parse_err;
169
continue;
170
}
171
obj = ucl_object_typed_new (UCL_STRING);
172
173
obj->value.sv = (const char*)p;
174
obj->len = len;
175
obj->flags |= UCL_OBJECT_BINARY;
176
177
if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
178
ucl_copy_value_trash (obj);
179
}
180
181
ucl_array_append (parser->stack->obj, obj);
182
p += len;
183
NEXT_STATE;
184
break;
185
186
case read_ebrace:
187
if (parser->stack == NULL) {
188
/* We have an extra end brace */
189
ucl_create_err (&parser->err, "invalid length: %llu, %ld "
190
"remain", (long long unsigned)len, (long)(end - p));
191
state = parse_err;
192
continue;
193
}
194
/* Pop the container */
195
st = parser->stack;
196
parser->stack = st->next;
197
198
if (parser->stack->obj->type == UCL_ARRAY) {
199
ucl_array_append (parser->stack->obj, st->obj);
200
}
201
else {
202
ucl_create_err (&parser->err, "bad container object, array "
203
"expected");
204
state = parse_err;
205
continue;
206
}
207
208
free (st);
209
st = NULL;
210
p++;
211
NEXT_STATE;
212
break;
213
214
case parse_err:
215
default:
216
return false;
217
}
218
}
219
220
if (state != read_ebrace) {
221
ucl_create_err (&parser->err, "invalid finishing state: %d", state);
222
return false;
223
}
224
225
return true;
226
}
227
228