1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/spv/spvbin-helpers.h"
24 #include "libpspp/float-format.h"
25 #include "libpspp/integer-format.h"
26 #include "libpspp/str.h"
28 #include "gl/xmemdup0.h"
31 spvbin_input_init (struct spvbin_input *input, const void *data, size_t size)
33 *input = (struct spvbin_input) { .data = data, .size = size };
37 spvbin_input_at_end (const struct spvbin_input *input)
39 return input->ofs >= input->size;
43 spvbin_input_to_error (const struct spvbin_input *input, const char *name)
45 struct string s = DS_EMPTY_INITIALIZER;
47 ds_put_format (&s, "%s: ", name);
48 ds_put_cstr (&s, "parse error decoding ");
49 for (size_t i = input->n_errors; i-- > 0;)
50 if (i < SPVBIN_MAX_ERRORS)
51 ds_put_format (&s, "/%s@%#zx", input->errors[i].name,
52 input->errors[i].start);
53 ds_put_format (&s, " near %#zx", input->error_ofs);
54 return ds_steal_cstr (&s);
59 spvbin_match_bytes (struct spvbin_input *input, const void *bytes, size_t n)
61 if (input->size - input->ofs < n
62 || memcmp (&input->data[input->ofs], bytes, n))
70 spvbin_match_byte (struct spvbin_input *input, uint8_t byte)
72 return spvbin_match_bytes (input, &byte, 1);
76 spvbin_parse_bool (struct spvbin_input *input, bool *p)
78 if (input->ofs >= input->size || input->data[input->ofs] > 1)
81 *p = input->data[input->ofs];
87 spvbin_parse__ (struct spvbin_input *input, size_t n)
89 if (input->size - input->ofs < n)
92 const void *src = &input->data[input->ofs];
98 spvbin_parse_byte (struct spvbin_input *input, uint8_t *p)
100 const void *src = spvbin_parse__ (input, sizeof *p);
102 *p = *(const uint8_t *) src;
107 spvbin_parse_int16 (struct spvbin_input *input, uint16_t *p)
109 const void *src = spvbin_parse__ (input, sizeof *p);
111 *p = le_to_native16 (get_uint16 (src));
116 spvbin_parse_int32 (struct spvbin_input *input, uint32_t *p)
118 const void *src = spvbin_parse__ (input, sizeof *p);
120 *p = le_to_native32 (get_uint32 (src));
125 spvbin_parse_int64 (struct spvbin_input *input, uint64_t *p)
127 const void *src = spvbin_parse__ (input, sizeof *p);
129 *p = le_to_native64 (get_uint64 (src));
134 spvbin_parse_be16 (struct spvbin_input *input, uint16_t *p)
136 const void *src = spvbin_parse__ (input, sizeof *p);
138 *p = be_to_native16 (get_uint16 (src));
143 spvbin_parse_be32 (struct spvbin_input *input, uint32_t *p)
145 const void *src = spvbin_parse__ (input, sizeof *p);
147 *p = be_to_native32 (get_uint32 (src));
152 spvbin_parse_be64 (struct spvbin_input *input, uint64_t *p)
154 const void *src = spvbin_parse__ (input, sizeof *p);
156 *p = be_to_native64 (get_uint64 (src));
161 spvbin_parse_double (struct spvbin_input *input, double *p)
163 const void *src = spvbin_parse__ (input, 8);
165 *p = float_get_double (FLOAT_IEEE_DOUBLE_LE, src);
170 spvbin_parse_float (struct spvbin_input *input, double *p)
172 const void *src = spvbin_parse__ (input, 4);
174 *p = float_get_double (FLOAT_IEEE_SINGLE_LE, src);
179 spvbin_parse_string__ (struct spvbin_input *input,
180 uint32_t (*raw_to_native32) (uint32_t),
186 if (input->size - input->ofs < sizeof length)
189 const uint8_t *src = &input->data[input->ofs];
190 length = raw_to_native32 (get_uint32 (src));
191 if (input->size - input->ofs - sizeof length < length)
195 *p = xmemdup0 (src + sizeof length, length);
196 input->ofs += sizeof length + length;
201 spvbin_parse_string (struct spvbin_input *input, char **p)
203 return spvbin_parse_string__ (input, le_to_native32, p);
207 spvbin_parse_bestring (struct spvbin_input *input, char **p)
209 return spvbin_parse_string__ (input, be_to_native32, p);
213 spvbin_error (struct spvbin_input *input, const char *name, size_t start)
215 if (!input->n_errors)
216 input->error_ofs = input->ofs;
218 /* We keep track of the error depth regardless of whether we can store all of
219 them. The parser needs this to accurately save and restore error
221 if (input->n_errors < SPVBIN_MAX_ERRORS)
223 input->errors[input->n_errors].name = name;
224 input->errors[input->n_errors].start = start;
230 spvbin_print_header (const char *title, size_t start UNUSED, size_t len UNUSED, int indent)
232 for (int i = 0; i < indent * 4; i++)
234 fputs (title, stdout);
236 if (start != SIZE_MAX)
237 printf (" (0x%zx, %zu)", start, len);
239 fputs (": ", stdout);
243 spvbin_print_presence (const char *title, int indent, bool present)
245 spvbin_print_header (title, -1, -1, indent);
246 puts (present ? "present" : "absent");
250 spvbin_print_bool (const char *title, int indent, bool x)
252 spvbin_print_header (title, -1, -1, indent);
253 printf ("%s\n", x ? "true" : "false");
257 spvbin_print_byte (const char *title, int indent, uint8_t x)
259 spvbin_print_header (title, -1, -1, indent);
260 printf ("%"PRIu8"\n", x);
264 spvbin_print_int16 (const char *title, int indent, uint16_t x)
266 spvbin_print_header (title, -1, -1, indent);
267 printf ("%"PRIu16"\n", x);
271 spvbin_print_int32 (const char *title, int indent, uint32_t x)
273 spvbin_print_header (title, -1, -1, indent);
274 printf ("%"PRIu32"\n", x);
278 spvbin_print_int64 (const char *title, int indent, uint64_t x)
280 spvbin_print_header (title, -1, -1, indent);
281 printf ("%"PRIu64"\n", x);
285 spvbin_print_double (const char *title, int indent, double x)
287 spvbin_print_header (title, -1, -1, indent);
292 spvbin_print_string (const char *title, int indent, const char *s)
294 spvbin_print_header (title, -1, -1, indent);
296 printf ("\"%s\"\n", s);
302 spvbin_print_case (const char *title, int indent, int x)
304 spvbin_print_header (title, -1, -1, indent);
308 struct spvbin_position
309 spvbin_position_save (const struct spvbin_input *input)
311 struct spvbin_position pos = { input->ofs };
316 spvbin_position_restore (struct spvbin_position *pos,
317 struct spvbin_input *input)
319 input->ofs = pos->ofs;
323 spvbin_limit_parse__ (struct spvbin_limit *limit, struct spvbin_input *input,
324 uint32_t (*raw_to_native32) (uint32_t))
326 limit->size = input->size;
329 if (input->size - input->ofs < sizeof count)
332 const uint8_t *src = &input->data[input->ofs];
333 count = raw_to_native32 (get_uint32 (src));
334 if (input->size - input->ofs - sizeof count < count)
337 input->ofs += sizeof count;
338 input->size = input->ofs + count;
343 spvbin_limit_parse (struct spvbin_limit *limit, struct spvbin_input *input)
345 return spvbin_limit_parse__ (limit, input, le_to_native32);
349 spvbin_limit_parse_be (struct spvbin_limit *limit, struct spvbin_input *input)
351 return spvbin_limit_parse__ (limit, input, be_to_native32);
355 spvbin_limit_pop (struct spvbin_limit *limit, struct spvbin_input *input)
357 input->size = limit->size;