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 continue; 112 } 113 114 if (parser->stack == NULL) { 115 /* We have no stack */ 116 parser->stack = st; 117 118 if (parser->top_obj == NULL) { 119 parser->top_obj = st->obj; 120 } 121 } 122 else { 123 /* Prepend new element to the stack */ 124 LL_PREPEND (parser->stack, st); 125 } 126 127 p ++; 128 NEXT_STATE; 129 130 break; 131 132 case read_length: 133 if (*p == ':') { 134 if (len == 0) { 135 ucl_create_err (&parser->err, "zero length element"); 136 state = parse_err; 137 continue; 138 } 139 140 state = read_value; 141 } 142 else if (*p >= '0' && *p <= '9') { 143 len += (*p - '0') * mult; 144 mult *= 10; 145 146 if (len > UINT32_MAX) { 147 ucl_create_err (&parser->err, "too big length of an " 148 "element"); 149 state = parse_err; 150 continue; 151 } 152 } 153 else { 154 ucl_create_err (&parser->err, "bad length character: %x", 155 (int)*p); 156 state = parse_err; 157 continue; 158 } 159 160 p ++; 161 break; 162 163 case read_value: 164 if ((uint64_t)(end - p) > len || len == 0) { 165 ucl_create_err (&parser->err, "invalid length: %llu, %ld " 166 "remain", (long long unsigned)len, (long)(end - p)); 167 state = parse_err; 168 continue; 169 } 170 obj = ucl_object_typed_new (UCL_STRING); 171 172 obj->value.sv = (const char*)p; 173 obj->len = len; 174 obj->flags |= UCL_OBJECT_BINARY; 175 176 if (!(parser->flags & UCL_PARSER_ZEROCOPY)) { 177 ucl_copy_value_trash (obj); 178 } 179 180 ucl_array_append (parser->stack->obj, obj); 181 p += len; 182 NEXT_STATE; 183 break; 184 185 case read_ebrace: 186 if (parser->stack == NULL) { 187 /* We have an extra end brace */ 188 ucl_create_err (&parser->err, "invalid length: %llu, %ld " 189 "remain", (long long unsigned)len, (long)(end - p)); 190 state = parse_err; 191 continue; 192 } 193 /* Pop the container */ 194 st = parser->stack; 195 parser->stack = st->next; 196 197 if (parser->stack->obj->type == UCL_ARRAY) { 198 ucl_array_append (parser->stack->obj, st->obj); 199 } 200 else { 201 ucl_create_err (&parser->err, "bad container object, array " 202 "expected"); 203 state = parse_err; 204 continue; 205 } 206 207 free (st); 208 p++; 209 NEXT_STATE; 210 break; 211 212 case parse_err: 213 default: 214 return false; 215 } 216 } 217 218 if (state != read_ebrace) { 219 ucl_create_err (&parser->err, "invalid finishing state: %d", state); 220 return false; 221 } 222 223 return true; 224 }