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),
187 if (input->size - input->ofs < sizeof length)
190 const uint8_t *src = &input->data[input->ofs];
191 length = raw_to_native32 (get_uint32 (src));
192 if (input->size - input->ofs - sizeof length < length)
196 *p = xmemdup0 (src + sizeof length, length);
197 input->ofs += sizeof length + length;
202 spvbin_parse_string (struct spvbin_input *input, char **p)
204 return spvbin_parse_string__ (input, le_to_native32, p);
208 spvbin_parse_bestring (struct spvbin_input *input, char **p)
210 return spvbin_parse_string__ (input, be_to_native32, p);
214 spvbin_error (struct spvbin_input *input, const char *name, size_t start)
216 if (!input->n_errors)
217 input->error_ofs = input->ofs;
219 /* We keep track of the error depth regardless of whether we can store all of
220 them. The parser needs this to accurately save and restore error
222 if (input->n_errors < SPVBIN_MAX_ERRORS)
224 input->errors[input->n_errors].name = name;
225 input->errors[input->n_errors].start = start;
231 spvbin_print_header (const char *title, size_t start UNUSED, size_t len UNUSED, int indent)
233 for (int i = 0; i < indent * 4; i++)
235 fputs (title, stdout);
237 if (start != SIZE_MAX)
238 printf (" (0x%zx, %zu)", start, len);
240 fputs (": ", stdout);
244 spvbin_print_presence (const char *title, int indent, bool present)
246 spvbin_print_header (title, -1, -1, indent);
247 puts (present ? "present" : "absent");
251 spvbin_print_bool (const char *title, int indent, bool x)
253 spvbin_print_header (title, -1, -1, indent);
254 printf ("%s\n", x ? "true" : "false");
258 spvbin_print_byte (const char *title, int indent, uint8_t x)
260 spvbin_print_header (title, -1, -1, indent);
261 printf ("%"PRIu8"\n", x);
265 spvbin_print_int16 (const char *title, int indent, uint16_t x)
267 spvbin_print_header (title, -1, -1, indent);
268 printf ("%"PRIu16"\n", x);
272 spvbin_print_int32 (const char *title, int indent, uint32_t x)
274 spvbin_print_header (title, -1, -1, indent);
275 printf ("%"PRIu32"\n", x);
279 spvbin_print_int64 (const char *title, int indent, uint64_t x)
281 spvbin_print_header (title, -1, -1, indent);
282 printf ("%"PRIu64"\n", x);
286 spvbin_print_double (const char *title, int indent, double x)
288 spvbin_print_header (title, -1, -1, indent);
293 spvbin_print_string (const char *title, int indent, const char *s)
295 spvbin_print_header (title, -1, -1, indent);
297 printf ("\"%s\"\n", s);
303 spvbin_print_case (const char *title, int indent, int x)
305 spvbin_print_header (title, -1, -1, indent);
309 struct spvbin_position
310 spvbin_position_save (const struct spvbin_input *input)
312 struct spvbin_position pos = { input->ofs };
317 spvbin_position_restore (struct spvbin_position *pos,
318 struct spvbin_input *input)
320 input->ofs = pos->ofs;
324 spvbin_limit_parse__ (struct spvbin_limit *limit, struct spvbin_input *input,
325 uint32_t (*raw_to_native32) (uint32_t))
327 limit->size = input->size;
330 if (input->size - input->ofs < sizeof count)
333 const uint8_t *src = &input->data[input->ofs];
334 count = raw_to_native32 (get_uint32 (src));
335 if (input->size - input->ofs - sizeof count < count)
338 input->ofs += sizeof count;
339 input->size = input->ofs + count;
344 spvbin_limit_parse (struct spvbin_limit *limit, struct spvbin_input *input)
346 return spvbin_limit_parse__ (limit, input, le_to_native32);
350 spvbin_limit_parse_be (struct spvbin_limit *limit, struct spvbin_input *input)
352 return spvbin_limit_parse__ (limit, input, be_to_native32);
356 spvbin_limit_pop (struct spvbin_limit *limit, struct spvbin_input *input)
358 input->size = limit->size;