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