Branch data Line data Source code
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 : 0 : 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 : 0 : 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 : 0 : } state = start_parse;
74 : :
75 [ # # ]: 0 : assert (parser != NULL);
76 [ # # ]: 0 : assert (parser->chunks != NULL);
77 [ # # ]: 0 : assert (parser->chunks->begin != NULL);
78 [ # # ]: 0 : assert (parser->chunks->remain != 0);
79 : :
80 : 0 : p = parser->chunks->begin;
81 : 0 : end = p + parser->chunks->remain;
82 : :
83 [ # # ]: 0 : while (p < end) {
84 [ # # # # : 0 : switch (state) {
# # # ]
85 : : case start_parse:
86 : : /* At this point we expect open brace */
87 [ # # ]: 0 : if (*p == '(') {
88 : 0 : state = read_obrace;
89 : 0 : }
90 : : else {
91 : 0 : ucl_create_err (&parser->err, "bad starting character for "
92 : 0 : "sexp block: %x", (int)*p);
93 : 0 : state = parse_err;
94 : : }
95 : 0 : break;
96 : :
97 : : case read_obrace:
98 : 0 : st = calloc (1, sizeof (*st));
99 : :
100 [ # # ]: 0 : if (st == NULL) {
101 : 0 : ucl_create_err (&parser->err, "no memory");
102 : 0 : state = parse_err;
103 : 0 : continue;
104 : : }
105 : :
106 : 0 : st->obj = ucl_object_typed_new (UCL_ARRAY);
107 : :
108 [ # # ]: 0 : if (st->obj == NULL) {
109 : 0 : ucl_create_err (&parser->err, "no memory");
110 : 0 : state = parse_err;
111 : 0 : free (st);
112 : 0 : continue;
113 : : }
114 : :
115 [ # # ]: 0 : if (parser->stack == NULL) {
116 : : /* We have no stack */
117 : 0 : parser->stack = st;
118 : :
119 [ # # ]: 0 : if (parser->top_obj == NULL) {
120 : 0 : parser->top_obj = st->obj;
121 : 0 : }
122 : 0 : }
123 : : else {
124 : : /* Prepend new element to the stack */
125 : 0 : LL_PREPEND (parser->stack, st);
126 : : }
127 : :
128 : 0 : p ++;
129 [ # # # # : 0 : NEXT_STATE;
# # # ]
130 : :
131 : 0 : break;
132 : :
133 : : case read_length:
134 [ # # ]: 0 : if (*p == ':') {
135 [ # # ]: 0 : if (len == 0) {
136 : 0 : ucl_create_err (&parser->err, "zero length element");
137 : 0 : state = parse_err;
138 : 0 : continue;
139 : : }
140 : :
141 : 0 : state = read_value;
142 : 0 : }
143 [ # # # # ]: 0 : else if (*p >= '0' && *p <= '9') {
144 : 0 : len += (*p - '0') * mult;
145 : 0 : mult *= 10;
146 : :
147 [ # # ]: 0 : if (len > UINT32_MAX) {
148 : 0 : ucl_create_err (&parser->err, "too big length of an "
149 : : "element");
150 : 0 : state = parse_err;
151 : 0 : continue;
152 : : }
153 : 0 : }
154 : : else {
155 : 0 : ucl_create_err (&parser->err, "bad length character: %x",
156 : 0 : (int)*p);
157 : 0 : state = parse_err;
158 : 0 : continue;
159 : : }
160 : :
161 : 0 : p ++;
162 : 0 : break;
163 : :
164 : : case read_value:
165 [ # # # # ]: 0 : if ((uint64_t)(end - p) > len || len == 0) {
166 : 0 : ucl_create_err (&parser->err, "invalid length: %llu, %ld "
167 : 0 : "remain", (long long unsigned)len, (long)(end - p));
168 : 0 : state = parse_err;
169 : 0 : continue;
170 : : }
171 : 0 : obj = ucl_object_typed_new (UCL_STRING);
172 : :
173 : 0 : obj->value.sv = (const char*)p;
174 : 0 : obj->len = len;
175 : 0 : obj->flags |= UCL_OBJECT_BINARY;
176 : :
177 [ # # ]: 0 : if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
178 : 0 : ucl_copy_value_trash (obj);
179 : 0 : }
180 : :
181 : 0 : ucl_array_append (parser->stack->obj, obj);
182 : 0 : p += len;
183 [ # # # # : 0 : NEXT_STATE;
# # # ]
184 : 0 : break;
185 : :
186 : : case read_ebrace:
187 [ # # ]: 0 : if (parser->stack == NULL) {
188 : : /* We have an extra end brace */
189 : 0 : ucl_create_err (&parser->err, "invalid length: %llu, %ld "
190 : 0 : "remain", (long long unsigned)len, (long)(end - p));
191 : 0 : state = parse_err;
192 : 0 : continue;
193 : : }
194 : : /* Pop the container */
195 : 0 : st = parser->stack;
196 : 0 : parser->stack = st->next;
197 : :
198 [ # # ]: 0 : if (parser->stack->obj->type == UCL_ARRAY) {
199 : 0 : ucl_array_append (parser->stack->obj, st->obj);
200 : 0 : }
201 : : else {
202 : 0 : ucl_create_err (&parser->err, "bad container object, array "
203 : : "expected");
204 : 0 : state = parse_err;
205 : 0 : continue;
206 : : }
207 : :
208 : 0 : free (st);
209 : 0 : st = NULL;
210 : 0 : p++;
211 [ # # # # : 0 : NEXT_STATE;
# # # ]
212 : 0 : break;
213 : :
214 : : case parse_err:
215 : : default:
216 : 0 : return false;
217 : : }
218 : : }
219 : :
220 [ # # ]: 0 : if (state != read_ebrace) {
221 : 0 : ucl_create_err (&parser->err, "invalid finishing state: %d", state);
222 : 0 : return false;
223 : : }
224 : :
225 : 0 : return true;
226 : 0 : }
|