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 \
35 do { \
36 if (p >= end) { \
37 if (state != read_ebrace) { \
38 ucl_create_err(&parser->err, \
39 "extra data"); \
40 state = parse_err; \
41 } \
42 } \
43 else { \
44 switch (*p) { \
45 case '(': \
46 state = read_obrace; \
47 break; \
48 case ')': \
49 state = read_ebrace; \
50 break; \
51 default: \
52 len = 0; \
53 mult = 1; \
54 state = read_length; \
55 break; \
56 } \
57 } \
58 } while (0)
59
ucl_parse_csexp(struct ucl_parser * parser)60 bool 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",
93 (int) *p);
94 state = parse_err;
95 }
96 break;
97
98 case read_obrace:
99 st = calloc(1, sizeof(*st));
100
101 if (st == NULL) {
102 ucl_create_err(&parser->err, "no memory");
103 state = parse_err;
104 continue;
105 }
106
107 st->obj = ucl_object_typed_new(UCL_ARRAY);
108
109 if (st->obj == NULL) {
110 ucl_create_err(&parser->err, "no memory");
111 state = parse_err;
112 free(st);
113 continue;
114 }
115
116 if (parser->stack == NULL) {
117 /* We have no stack */
118 parser->stack = st;
119
120 if (parser->top_obj == NULL) {
121 parser->top_obj = st->obj;
122 }
123 }
124 else {
125 /* Prepend new element to the stack */
126 LL_PREPEND(parser->stack, st);
127 }
128
129 p++;
130 NEXT_STATE;
131
132 break;
133
134 case read_length:
135 if (*p == ':') {
136 if (len == 0) {
137 ucl_create_err(&parser->err, "zero length element");
138 state = parse_err;
139 continue;
140 }
141
142 state = read_value;
143 }
144 else if (*p >= '0' && *p <= '9') {
145 len += (*p - '0') * mult;
146 mult *= 10;
147
148 if (len > UINT32_MAX) {
149 ucl_create_err(&parser->err, "too big length of an "
150 "element");
151 state = parse_err;
152 continue;
153 }
154 }
155 else {
156 ucl_create_err(&parser->err, "bad length character: %x",
157 (int) *p);
158 state = parse_err;
159 continue;
160 }
161
162 p++;
163 break;
164
165 case read_value:
166 if ((uint64_t) (end - p) > len || len == 0) {
167 ucl_create_err(&parser->err, "invalid length: %llu, %ld "
168 "remain",
169 (long long unsigned) len, (long) (end - p));
170 state = parse_err;
171 continue;
172 }
173 obj = ucl_object_typed_new(UCL_STRING);
174
175 obj->value.sv = (const char *) p;
176 obj->len = len;
177 obj->flags |= UCL_OBJECT_BINARY;
178
179 if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
180 ucl_copy_value_trash(obj);
181 }
182
183 ucl_array_append(parser->stack->obj, obj);
184 p += len;
185 NEXT_STATE;
186 break;
187
188 case read_ebrace:
189 if (parser->stack == NULL) {
190 /* We have an extra end brace */
191 ucl_create_err(&parser->err, "invalid length: %llu, %ld "
192 "remain",
193 (long long unsigned) len, (long) (end - p));
194 state = parse_err;
195 continue;
196 }
197 /* Pop the container */
198 st = parser->stack;
199 parser->stack = st->next;
200
201 if (parser->stack->obj->type == UCL_ARRAY) {
202 ucl_array_append(parser->stack->obj, st->obj);
203 }
204 else {
205 ucl_create_err(&parser->err, "bad container object, array "
206 "expected");
207 state = parse_err;
208 continue;
209 }
210
211 free(st);
212 st = NULL;
213 p++;
214 NEXT_STATE;
215 break;
216
217 case parse_err:
218 default:
219 return false;
220 }
221 }
222
223 if (state != read_ebrace) {
224 ucl_create_err(&parser->err, "invalid finishing state: %d", state);
225 return false;
226 }
227
228 return true;
229 }
230