1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "output/spv/spv-light-decoder.h"
20
21 #include <inttypes.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "output/pivot-table.h"
29 #include "output/spv/light-binary-parser.h"
30 #include "output/spv/spv.h"
31
32 #include "gl/xalloc.h"
33 #include "gl/xsize.h"
34
35 static char *
to_utf8(const char * s,const char * encoding)36 to_utf8 (const char *s, const char *encoding)
37 {
38 return recode_string ("UTF-8", encoding, s, strlen (s));
39 }
40
41 static char *
to_utf8_if_nonempty(const char * s,const char * encoding)42 to_utf8_if_nonempty (const char *s, const char *encoding)
43 {
44 return s && s[0] ? to_utf8 (s, encoding) : NULL;
45 }
46
47 static void
convert_widths(const uint32_t * in,uint32_t n,int ** out,size_t * n_out)48 convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
49 {
50 if (n)
51 {
52 *n_out = n;
53 *out = xnmalloc (n, sizeof **out);
54 for (size_t i = 0; i < n; i++)
55 (*out)[i] = in[i];
56 }
57 }
58
59 static void
convert_breakpoints(const struct spvlb_breakpoints * in,size_t ** out,size_t * n_out)60 convert_breakpoints (const struct spvlb_breakpoints *in,
61 size_t **out, size_t *n_out)
62 {
63 if (in && in->n_breaks)
64 {
65 *n_out = in->n_breaks;
66 *out = xnmalloc (in->n_breaks, sizeof *out);
67 for (size_t i = 0; i < in->n_breaks; i++)
68 (*out)[i] = in->breaks[i];
69 }
70 }
71
72 static void
convert_keeps(const struct spvlb_keeps * in,struct pivot_keep ** out,size_t * n_out)73 convert_keeps (const struct spvlb_keeps *in,
74 struct pivot_keep **out, size_t *n_out)
75 {
76 if (in && in->n_keeps)
77 {
78 *n_out = in->n_keeps;
79 *out = xnmalloc (*n_out, sizeof **out);
80 for (size_t i = 0; i < *n_out; i++)
81 {
82 (*out)[i].ofs = in->keeps[i]->offset;
83 (*out)[i].n = in->keeps[i]->n;
84 }
85 }
86 }
87
88 static char * WARN_UNUSED_RESULT
decode_spvlb_color_string(const char * s,uint8_t def,struct cell_color * colorp)89 decode_spvlb_color_string (const char *s, uint8_t def,
90 struct cell_color *colorp)
91 {
92 int r, g, b;
93 if (!*s)
94 r = g = b = def;
95 else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
96 return xasprintf ("bad color %s", s);
97
98 *colorp = (struct cell_color) CELL_COLOR (r, g, b);
99 return NULL;
100 }
101
102 static struct cell_color
decode_spvlb_color_u32(uint32_t x)103 decode_spvlb_color_u32 (uint32_t x)
104 {
105 return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
106 }
107
108 static char * WARN_UNUSED_RESULT
decode_spvlb_font_style(const struct spvlb_font_style * in,const char * encoding,struct font_style ** outp)109 decode_spvlb_font_style (const struct spvlb_font_style *in,
110 const char *encoding, struct font_style **outp)
111 {
112 if (!in)
113 {
114 *outp = NULL;
115 return NULL;
116 }
117
118 struct cell_color fg, bg;
119 char *error = decode_spvlb_color_string (in->fg_color, 0x00, &fg);
120 if (!error)
121 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg);
122 if (error)
123 return error;
124
125 *outp = xmalloc (sizeof **outp);
126 **outp = (struct font_style) {
127 .bold = in->bold,
128 .italic = in->italic,
129 .underline = in->underline,
130 .fg = { fg, fg },
131 .bg = { bg, bg },
132 .typeface = to_utf8 (in->typeface, encoding),
133 .size = in->size / 1.33,
134 };
135 return NULL;
136 }
137
138 static char * WARN_UNUSED_RESULT
decode_spvlb_halign(uint32_t in,enum table_halign * halignp)139 decode_spvlb_halign (uint32_t in, enum table_halign *halignp)
140 {
141 switch (in)
142 {
143 case 0:
144 *halignp = TABLE_HALIGN_CENTER;
145 return NULL;
146
147 case 2:
148 *halignp = TABLE_HALIGN_LEFT;
149 return NULL;
150
151 case 4:
152 *halignp = TABLE_HALIGN_RIGHT;
153 return NULL;
154
155 case 6:
156 case 61453:
157 *halignp = TABLE_HALIGN_DECIMAL;
158 return NULL;
159
160 case 0xffffffad:
161 case 64173:
162 *halignp = TABLE_HALIGN_MIXED;
163 return NULL;
164
165 default:
166 return xasprintf ("bad cell style halign %"PRIu32, in);
167 }
168 }
169
170 static char * WARN_UNUSED_RESULT
decode_spvlb_valign(uint32_t in,enum table_valign * valignp)171 decode_spvlb_valign (uint32_t in, enum table_valign *valignp)
172 {
173 switch (in)
174 {
175 case 0:
176 *valignp = TABLE_VALIGN_CENTER;
177 return NULL;
178
179 case 1:
180 *valignp = TABLE_VALIGN_TOP;
181 return NULL;
182
183 case 3:
184 *valignp = TABLE_VALIGN_BOTTOM;
185 return NULL;
186
187 default:
188 *valignp = 0;
189 return xasprintf ("bad cell style valign %"PRIu32, in);
190 }
191 }
192
193 static char * WARN_UNUSED_RESULT
decode_spvlb_cell_style(const struct spvlb_cell_style * in,struct cell_style ** outp)194 decode_spvlb_cell_style (const struct spvlb_cell_style *in,
195 struct cell_style **outp)
196 {
197 if (!in)
198 {
199 *outp = NULL;
200 return NULL;
201 }
202
203 enum table_halign halign;
204 char *error = decode_spvlb_halign (in->halign, &halign);
205 if (error)
206 return error;
207
208 enum table_valign valign;
209 error = decode_spvlb_valign (in->valign, &valign);
210 if (error)
211 return error;
212
213 *outp = xzalloc (sizeof **outp);
214 **outp = (struct cell_style) {
215 .halign = halign,
216 .valign = valign,
217 .decimal_offset = in->decimal_offset,
218 .margin = {
219 [TABLE_HORZ] = { in->left_margin, in->right_margin },
220 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
221 },
222 };
223 return NULL;
224 }
225
226 static char *decode_spvlb_value (
227 const struct pivot_table *, const struct spvlb_value *,
228 const char *encoding, struct pivot_value **) WARN_UNUSED_RESULT;
229
230 static char * WARN_UNUSED_RESULT
decode_spvlb_argument(const struct pivot_table * table,const struct spvlb_argument * in,const char * encoding,struct pivot_argument * out)231 decode_spvlb_argument (const struct pivot_table *table,
232 const struct spvlb_argument *in,
233 const char *encoding, struct pivot_argument *out)
234 {
235 if (in->value)
236 {
237 struct pivot_value *value;
238 char *error = decode_spvlb_value (table, in->value, encoding, &value);
239 if (error)
240 return error;
241
242 out->n = 1;
243 out->values = xmalloc (sizeof *out->values);
244 out->values[0] = value;
245 }
246 else
247 {
248 out->n = 0;
249 out->values = xnmalloc (in->n_values, sizeof *out->values);
250 for (size_t i = 0; i < in->n_values; i++)
251 {
252 char *error = decode_spvlb_value (table, in->values[i], encoding,
253 &out->values[i]);
254 if (error)
255 {
256 pivot_argument_uninit (out);
257 return error;
258 }
259 out->n++;
260 }
261 }
262
263 return NULL;
264 }
265
266 static char * WARN_UNUSED_RESULT
decode_spvlb_value_show(uint8_t in,enum settings_value_show * out)267 decode_spvlb_value_show (uint8_t in, enum settings_value_show *out)
268 {
269 switch (in)
270 {
271 case 0: *out = SETTINGS_VALUE_SHOW_DEFAULT; return NULL;
272 case 1: *out = SETTINGS_VALUE_SHOW_VALUE; return NULL;
273 case 2: *out = SETTINGS_VALUE_SHOW_LABEL; return NULL;
274 case 3: *out = SETTINGS_VALUE_SHOW_BOTH; return NULL;
275 default:
276 return xasprintf ("bad value show %"PRIu8, in);
277 }
278 }
279
280 static char * WARN_UNUSED_RESULT
decode_spvlb_value(const struct pivot_table * table,const struct spvlb_value * in,const char * encoding,struct pivot_value ** outp)281 decode_spvlb_value (const struct pivot_table *table,
282 const struct spvlb_value *in,
283 const char *encoding, struct pivot_value **outp)
284 {
285 *outp = NULL;
286
287 struct pivot_value *out = xzalloc (sizeof *out);
288 const struct spvlb_value_mod *vm;
289
290 char *error;
291 switch (in->type)
292 {
293 case 1:
294 vm = in->type_01.value_mod;
295 out->type = PIVOT_VALUE_NUMERIC;
296 out->numeric.x = in->type_01.x;
297 error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format);
298 if (error)
299 return error;
300 break;
301
302 case 2:
303 vm = in->type_02.value_mod;
304 out->type = PIVOT_VALUE_NUMERIC;
305 out->numeric.x = in->type_02.x;
306 error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
307 if (!error)
308 error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
309 if (error)
310 return NULL;
311 out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
312 encoding);
313 out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
314 encoding);
315 break;
316
317 case 3:
318 vm = in->type_03.value_mod;
319 out->type = PIVOT_VALUE_TEXT;
320 out->text.local = to_utf8 (in->type_03.local, encoding);
321 out->text.c = to_utf8 (in->type_03.c, encoding);
322 out->text.id = to_utf8 (in->type_03.id, encoding);
323 out->text.user_provided = !in->type_03.fixed;
324 break;
325
326 case 4:
327 vm = in->type_04.value_mod;
328 out->type = PIVOT_VALUE_STRING;
329 error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
330 if (error)
331 return NULL;
332 out->string.s = to_utf8 (in->type_04.s, encoding);
333 out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
334 out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
335 encoding);
336 break;
337
338 case 5:
339 vm = in->type_05.value_mod;
340 out->type = PIVOT_VALUE_VARIABLE;
341 error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
342 if (error)
343 return error;
344 out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
345 out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
346 encoding);
347 break;
348
349 case 6:
350 vm = in->type_06.value_mod;
351 out->type = PIVOT_VALUE_TEXT;
352 out->text.local = to_utf8 (in->type_06.local, encoding);
353 out->text.c = to_utf8 (in->type_06.c, encoding);
354 out->text.id = to_utf8 (in->type_06.id, encoding);
355 out->text.user_provided = false;
356 break;
357
358 case -1:
359 vm = in->type_else.value_mod;
360 out->type = PIVOT_VALUE_TEMPLATE;
361 out->template.local = to_utf8 (in->type_else.template, encoding);
362 out->template.id = out->template.local;
363 out->template.n_args = 0;
364 out->template.args = xnmalloc (in->type_else.n_args,
365 sizeof *out->template.args);
366 for (size_t i = 0; i < in->type_else.n_args; i++)
367 {
368 error = decode_spvlb_argument (table, in->type_else.args[i],
369 encoding, &out->template.args[i]);
370 if (error)
371 {
372 pivot_value_destroy (out);
373 return error;
374 }
375 out->template.n_args++;
376 }
377 break;
378
379 default:
380 assert (0);
381 }
382
383 if (vm)
384 {
385 if (vm->n_subscripts)
386 {
387 out->n_subscripts = vm->n_subscripts;
388 out->subscripts = xnmalloc (vm->n_subscripts,
389 sizeof *out->subscripts);
390 for (size_t i = 0; i < vm->n_subscripts; i++)
391 out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
392 }
393
394 if (vm->n_refs)
395 {
396 out->footnotes = xnmalloc (vm->n_refs, sizeof *out->footnotes);
397 for (size_t i = 0; i < vm->n_refs; i++)
398 {
399 uint16_t idx = vm->refs[i];
400 if (idx >= table->n_footnotes)
401 {
402 pivot_value_destroy (out);
403 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
404 idx, table->n_footnotes);
405 }
406
407 out->footnotes[out->n_footnotes++] = table->footnotes[idx];
408 }
409 }
410
411 if (vm->style_pair)
412 {
413 error = decode_spvlb_font_style (vm->style_pair->font_style,
414 encoding, &out->font_style);
415 if (!error)
416 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
417 &out->cell_style);
418 if (error)
419 {
420 pivot_value_destroy (out);
421 return error;
422 }
423 }
424
425 if (vm->template_string
426 && vm->template_string->id
427 && vm->template_string->id[0]
428 && out->type == PIVOT_VALUE_TEMPLATE)
429 out->template.id = to_utf8 (vm->template_string->id, encoding);
430 }
431
432 *outp = out;
433 return NULL;
434 }
435
436 static char * WARN_UNUSED_RESULT
decode_spvlb_area(const struct spvlb_area * in,struct area_style * out,const char * encoding)437 decode_spvlb_area (const struct spvlb_area *in, struct area_style *out,
438 const char *encoding)
439 {
440 char *error;
441
442 struct cell_color fg0, fg1, bg0, bg1;
443 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
444 if (!error)
445 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
446 if (!error && in->alternate)
447 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
448 if (!error && in->alternate)
449 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
450
451 enum table_halign halign;
452 if (!error)
453 {
454 error = decode_spvlb_halign (in->halign, &halign);
455
456 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
457 is good because there's no way to indicate the decimal offset. Just
458 in case: */
459 if (!error && halign == TABLE_HALIGN_DECIMAL)
460 halign = TABLE_HALIGN_MIXED;
461 }
462
463 enum table_valign valign;
464 if (!error)
465 error = decode_spvlb_valign (in->valign, &valign);
466
467 if (error)
468 return error;
469
470 *out = (struct area_style) {
471 .font_style = {
472 .bold = (in->style & 1) != 0,
473 .italic = (in->style & 2) != 0,
474 .underline = in->underline,
475 .fg = { fg0, in->alternate ? fg1 : fg0 },
476 .bg = { bg0, in->alternate ? bg1 : bg0 },
477 .typeface = to_utf8 (in->typeface, encoding),
478 .size = in->size / 1.33,
479 },
480 .cell_style = {
481 .halign = halign,
482 .valign = valign,
483 .margin = {
484 [TABLE_HORZ] = { in->left_margin, in->right_margin },
485 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
486 },
487 },
488 };
489 return NULL;
490 }
491
492 static char * WARN_UNUSED_RESULT
493 decode_spvlb_group (const struct pivot_table *,
494 struct spvlb_category **,
495 size_t n_categories,
496 bool show_label,
497 struct pivot_category *parent,
498 struct pivot_dimension *,
499 const char *encoding);
500
501 static char * WARN_UNUSED_RESULT
decode_spvlb_categories(const struct pivot_table * table,struct spvlb_category ** categories,size_t n_categories,struct pivot_category * parent,struct pivot_dimension * dimension,const char * encoding)502 decode_spvlb_categories (const struct pivot_table *table,
503 struct spvlb_category **categories,
504 size_t n_categories,
505 struct pivot_category *parent,
506 struct pivot_dimension *dimension,
507 const char *encoding)
508 {
509 for (size_t i = 0; i < n_categories; i++)
510 {
511 const struct spvlb_category *in = categories[i];
512 if (in->group && in->group->merge)
513 {
514 char *error = decode_spvlb_categories (
515 table, in->group->subcategories, in->group->n_subcategories,
516 parent, dimension, encoding);
517 if (error)
518 return error;
519
520 continue;
521 }
522
523 struct pivot_value *name;
524 char *error = decode_spvlb_value (table, in->name, encoding, &name);
525 if (error)
526 return error;
527
528 struct pivot_category *out = xzalloc (sizeof *out);
529 out->name = name;
530 out->parent = parent;
531 out->dimension = dimension;
532 if (in->group)
533 {
534 char *error = decode_spvlb_group (table, in->group->subcategories,
535 in->group->n_subcategories,
536 true, out, dimension, encoding);
537 if (error)
538 {
539 pivot_category_destroy (out);
540 return error;
541 }
542
543 out->data_index = SIZE_MAX;
544 out->presentation_index = SIZE_MAX;
545 }
546 else
547 {
548 out->data_index = in->leaf->leaf_index;
549 out->presentation_index = dimension->n_leaves;
550 dimension->n_leaves++;
551 }
552
553 if (parent->n_subs >= parent->allocated_subs)
554 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
555 sizeof *parent->subs);
556 parent->subs[parent->n_subs++] = out;
557 }
558 return NULL;
559 }
560
561 static char * WARN_UNUSED_RESULT
decode_spvlb_group(const struct pivot_table * table,struct spvlb_category ** categories,size_t n_categories,bool show_label,struct pivot_category * category,struct pivot_dimension * dimension,const char * encoding)562 decode_spvlb_group (const struct pivot_table *table,
563 struct spvlb_category **categories,
564 size_t n_categories, bool show_label,
565 struct pivot_category *category,
566 struct pivot_dimension *dimension,
567 const char *encoding)
568 {
569 category->subs = XCALLOC (n_categories, struct pivot_category *);
570 category->n_subs = 0;
571 category->allocated_subs = 0;
572 category->show_label = show_label;
573
574 return decode_spvlb_categories (table, categories, n_categories, category,
575 dimension, encoding);
576 }
577
578 static char * WARN_UNUSED_RESULT
fill_leaves(struct pivot_category * category,struct pivot_dimension * dimension)579 fill_leaves (struct pivot_category *category,
580 struct pivot_dimension *dimension)
581 {
582 if (pivot_category_is_group (category))
583 {
584 for (size_t i = 0; i < category->n_subs; i++)
585 {
586 char *error = fill_leaves (category->subs[i], dimension);
587 if (error)
588 return error;
589 }
590 }
591 else
592 {
593 if (category->data_index >= dimension->n_leaves)
594 return xasprintf ("leaf_index %zu >= n_leaves %zu",
595 category->data_index, dimension->n_leaves);
596 if (dimension->data_leaves[category->data_index])
597 return xasprintf ("two leaves with data_index %zu",
598 category->data_index);
599 dimension->data_leaves[category->data_index] = category;
600 dimension->presentation_leaves[category->presentation_index] = category;
601 }
602 return NULL;
603 }
604
605 static char * WARN_UNUSED_RESULT
decode_spvlb_dimension(const struct pivot_table * table,const struct spvlb_dimension * in,size_t idx,const char * encoding,struct pivot_dimension ** outp)606 decode_spvlb_dimension (const struct pivot_table *table,
607 const struct spvlb_dimension *in,
608 size_t idx, const char *encoding,
609 struct pivot_dimension **outp)
610 {
611 /* Convert most of the dimension. */
612 struct pivot_value *name;
613 char *error = decode_spvlb_value (table, in->name, encoding, &name);
614 if (error)
615 return error;
616
617 struct pivot_dimension *out = xzalloc (sizeof *out);
618 out->level = UINT_MAX;
619 out->top_index = idx;
620 out->hide_all_labels = in->props->hide_all_labels;
621
622 out->root = xzalloc (sizeof *out->root);
623 *out->root = (struct pivot_category) {
624 .name = name,
625 .dimension = out,
626 .data_index = SIZE_MAX,
627 .presentation_index = SIZE_MAX,
628 };
629 error = decode_spvlb_group (table, in->categories, in->n_categories,
630 !in->props->hide_dim_label, out->root,
631 out, encoding);
632 if (error)
633 goto error;
634
635 /* Allocate and fill the array of leaves now that we know how many there
636 are. */
637 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
638 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
639 out->allocated_leaves = out->n_leaves;
640 error = fill_leaves (out->root, out);
641 if (error)
642 goto error;
643 for (size_t i = 0; i < out->n_leaves; i++)
644 {
645 assert (out->data_leaves[i] != NULL);
646 assert (out->presentation_leaves[i] != NULL);
647 }
648 *outp = out;
649 return NULL;
650
651 error:
652 pivot_dimension_destroy (out);
653 return error;
654 }
655
656 static char * WARN_UNUSED_RESULT
decode_spvlb_stroke(uint32_t stroke_type,enum table_stroke * strokep)657 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
658 {
659 enum table_stroke strokes[] = {
660 TABLE_STROKE_NONE,
661 TABLE_STROKE_SOLID,
662 TABLE_STROKE_DASHED,
663 TABLE_STROKE_THICK,
664 TABLE_STROKE_THIN,
665 TABLE_STROKE_DOUBLE,
666 };
667
668 if (stroke_type >= sizeof strokes / sizeof *strokes)
669 return xasprintf ("bad stroke %"PRIu32, stroke_type);
670
671 *strokep = strokes[stroke_type];
672 return NULL;
673 }
674
675 static char * WARN_UNUSED_RESULT
decode_spvlb_border(const struct spvlb_border * in,struct pivot_table * table)676 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
677
678 {
679 if (in->border_type >= PIVOT_N_BORDERS)
680 return xasprintf ("bad border type %"PRIu32, in->border_type);
681
682 struct table_border_style *out = &table->borders[in->border_type];
683 out->color = decode_spvlb_color_u32 (in->color);
684 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
685 }
686
687 static char * WARN_UNUSED_RESULT
decode_spvlb_axis(const uint32_t * dimension_indexes,size_t n_dimensions,enum pivot_axis_type axis_type,struct pivot_table * table)688 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
689 enum pivot_axis_type axis_type, struct pivot_table *table)
690 {
691 struct pivot_axis *axis = &table->axes[axis_type];
692 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
693 axis->n_dimensions = n_dimensions;
694 axis->extent = 1;
695 for (size_t i = 0; i < n_dimensions; i++)
696 {
697 uint32_t idx = dimension_indexes[i];
698 if (idx >= table->n_dimensions)
699 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
700 idx, table->n_dimensions);
701
702 struct pivot_dimension *d = table->dimensions[idx];
703 if (d->level != UINT_MAX)
704 return xasprintf ("duplicate dimension %"PRIu32, idx);
705
706 axis->dimensions[i] = d;
707 d->axis_type = axis_type;
708 d->level = i;
709
710 axis->extent *= d->n_leaves;
711 }
712
713 return NULL;
714 }
715
716 static char *
decode_data_index(uint64_t in,const struct pivot_table * table,size_t * out)717 decode_data_index (uint64_t in, const struct pivot_table *table,
718 size_t *out)
719 {
720 uint64_t remainder = in;
721 for (size_t i = table->n_dimensions - 1; i > 0; i--)
722 {
723 const struct pivot_dimension *d = table->dimensions[i];
724 if (d->n_leaves)
725 {
726 out[i] = remainder % d->n_leaves;
727 remainder /= d->n_leaves;
728 }
729 else
730 out[i] = 0;
731 }
732 if (remainder >= table->dimensions[0]->n_leaves)
733 return xasprintf ("out of range cell data index %"PRIu64, in);
734
735 out[0] = remainder;
736 return NULL;
737 }
738
739 static char * WARN_UNUSED_RESULT
decode_spvlb_cells(struct spvlb_cell ** in,size_t n_in,struct pivot_table * table,const char * encoding)740 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
741 struct pivot_table *table, const char *encoding)
742 {
743 if (!table->n_dimensions)
744 return NULL;
745
746 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
747 for (size_t i = 0; i < n_in; i++)
748 {
749 struct pivot_value *value;
750 char *error = decode_data_index (in[i]->index, table, dindexes);
751 if (!error)
752 error = decode_spvlb_value (table, in[i]->value, encoding, &value);
753 if (error)
754 {
755 free (dindexes);
756 return error;
757 }
758 pivot_table_put (table, dindexes, table->n_dimensions, value);
759 }
760 free (dindexes);
761
762 return NULL;
763 }
764
765 static char * WARN_UNUSED_RESULT
decode_spvlb_footnote(const struct spvlb_footnote * in,const char * encoding,size_t idx,struct pivot_table * table)766 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
767 size_t idx, struct pivot_table *table)
768 {
769 struct pivot_value *content;
770 char *error = decode_spvlb_value (table, in->text, encoding, &content);
771 if (error)
772 return error;
773
774 struct pivot_value *marker = NULL;
775 if (in->marker)
776 {
777 error = decode_spvlb_value (table, in->marker, encoding, &marker);
778 if (error)
779 {
780 pivot_value_destroy (content);
781 return error;
782 }
783 if (marker->type == PIVOT_VALUE_TEXT)
784 marker->text.user_provided = false;
785 }
786
787 struct pivot_footnote *f = pivot_table_create_footnote__ (
788 table, idx, marker, content);
789 f->show = (int32_t) in->show > 0;
790 return NULL;
791 }
792
793 static char * WARN_UNUSED_RESULT
decode_current_layer(uint64_t current_layer,struct pivot_table * table)794 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
795 {
796 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
797 table->current_layer = xnmalloc (axis->n_dimensions,
798 sizeof *table->current_layer);
799
800 for (size_t i = 0; i < axis->n_dimensions; i++)
801 {
802 const struct pivot_dimension *d = axis->dimensions[i];
803 if (d->n_leaves)
804 {
805 table->current_layer[i] = current_layer % d->n_leaves;
806 current_layer /= d->n_leaves;
807 }
808 else
809 table->current_layer[i] = 0;
810 }
811 if (current_layer > 0)
812 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
813 return NULL;
814 }
815
816 char * WARN_UNUSED_RESULT
decode_spvlb_table(const struct spvlb_table * in,struct pivot_table ** outp)817 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
818 {
819 *outp = NULL;
820 if (in->header->version != 1 && in->header->version != 3)
821 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
822 in->header->version);
823
824 char *error = NULL;
825 struct pivot_table *out = xzalloc (sizeof *out);
826 out->ref_cnt = 1;
827 hmap_init (&out->cells);
828
829 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
830 : in->formats->x3 ? in->formats->x3->y1
831 : NULL);
832 const char *encoding;
833 if (y1)
834 encoding = y1->charset;
835 else
836 {
837 const char *dot = strchr (in->formats->locale, '.');
838 encoding = dot ? dot + 1 : "windows-1252";
839 }
840
841 /* Display settings. */
842 out->show_numeric_markers = !in->ts->show_alphabetic_markers;
843 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
844 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
845 out->row_labels_in_corner = in->ts->show_row_labels_in_corner;
846 out->show_grid_lines = in->borders->show_grid_lines;
847 out->show_caption = true;
848 out->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
849 out->omit_empty = in->ts->omit_empty;
850
851 const struct spvlb_x1 *x1 = in->formats->x1;
852 if (x1)
853 {
854 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
855 if (!error)
856 error = decode_spvlb_value_show (x1->show_variables,
857 &out->show_variables);
858 if (error)
859 goto error;
860
861 out->show_caption = x1->show_caption;
862 }
863
864 /* Column and row display settings. */
865 out->sizing[TABLE_VERT].range[0] = in->header->min_row_height;
866 out->sizing[TABLE_VERT].range[1] = in->header->max_row_height;
867 out->sizing[TABLE_HORZ].range[0] = in->header->min_col_width;
868 out->sizing[TABLE_HORZ].range[1] = in->header->max_col_width;
869
870 convert_widths (in->formats->widths, in->formats->n_widths,
871 &out->sizing[TABLE_HORZ].widths,
872 &out->sizing[TABLE_HORZ].n_widths);
873
874 const struct spvlb_x2 *x2 = in->formats->x2;
875 if (x2)
876 convert_widths (x2->row_heights, x2->n_row_heights,
877 &out->sizing[TABLE_VERT].widths,
878 &out->sizing[TABLE_VERT].n_widths);
879
880 convert_breakpoints (in->ts->row_breaks,
881 &out->sizing[TABLE_VERT].breaks,
882 &out->sizing[TABLE_VERT].n_breaks);
883 convert_breakpoints (in->ts->col_breaks,
884 &out->sizing[TABLE_HORZ].breaks,
885 &out->sizing[TABLE_HORZ].n_breaks);
886
887 convert_keeps (in->ts->row_keeps,
888 &out->sizing[TABLE_VERT].keeps,
889 &out->sizing[TABLE_VERT].n_keeps);
890 convert_keeps (in->ts->col_keeps,
891 &out->sizing[TABLE_HORZ].keeps,
892 &out->sizing[TABLE_HORZ].n_keeps);
893
894 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
895 out->table_look = to_utf8_if_nonempty (in->ts->table_look, encoding);
896
897 /* Print settings. */
898 out->print_all_layers = in->ps->all_layers;
899 out->paginate_layers = in->ps->paginate_layers;
900 out->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
901 out->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
902 out->top_continuation = in->ps->top_continuation;
903 out->bottom_continuation = in->ps->bottom_continuation;
904 out->continuation = xstrdup (in->ps->continuation_string);
905 out->n_orphan_lines = in->ps->n_orphan_lines;
906
907 /* Format settings. */
908 out->epoch = in->formats->y0->epoch;
909 out->decimal = in->formats->y0->decimal;
910 out->grouping = in->formats->y0->grouping;
911 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
912 for (int i = 0; i < 5; i++)
913 if (cc && i < cc->n_ccs)
914 out->ccs[i] = xstrdup (cc->ccs[i]);
915 out->small = in->formats->x3 ? in->formats->x3->small : 0;
916
917 /* Command information. */
918 if (y1)
919 {
920 out->command_local = to_utf8 (y1->command_local, encoding);
921 out->command_c = to_utf8 (y1->command, encoding);
922 out->language = xstrdup (y1->language);
923 /* charset? */
924 out->locale = xstrdup (y1->locale);
925 }
926
927 /* Source information. */
928 const struct spvlb_x3 *x3 = in->formats->x3;
929 if (x3)
930 {
931 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
932 out->dataset = to_utf8 (x3->dataset, encoding);
933 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
934 out->date = x3->date;
935 }
936
937 /* Footnotes.
938
939 Any pivot_value might refer to footnotes, so it's important to process the
940 footnotes early to ensure that those references can be resolved. There is
941 a possible problem that a footnote might itself reference an
942 as-yet-unprocessed footnote, but that's OK because footnote references
943 don't actually look at the footnote contents but only resolve a pointer to
944 where the footnote will go later.
945
946 Before we really start, create all the footnotes we'll fill in. This is
947 because sometimes footnotes refer to themselves or to each other and we
948 don't want to reject those references. */
949 const struct spvlb_footnotes *fn = in->footnotes;
950 if (fn->n_footnotes > 0)
951 {
952 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
953 for (size_t i = 0; i < fn->n_footnotes; i++)
954 {
955 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
956 encoding, i, out);
957 if (error)
958 goto error;
959 }
960 }
961
962 /* Title and caption. */
963 error = decode_spvlb_value (out, in->titles->user_title, encoding,
964 &out->title);
965 if (error)
966 goto error;
967
968 error = decode_spvlb_value (out, in->titles->subtype, encoding,
969 &out->subtype);
970 if (error)
971 goto error;
972
973 if (in->titles->corner_text)
974 {
975 error = decode_spvlb_value (out, in->titles->corner_text,
976 encoding, &out->corner_text);
977 if (error)
978 goto error;
979 }
980
981 if (in->titles->caption)
982 {
983 error = decode_spvlb_value (out, in->titles->caption, encoding,
984 &out->caption);
985 if (error)
986 goto error;
987 }
988
989
990 /* Styles. */
991 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
992 {
993 error = decode_spvlb_area (in->areas->areas[i], &out->areas[i],
994 encoding);
995 if (error)
996 goto error;
997 }
998 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
999 {
1000 error = decode_spvlb_border (in->borders->borders[i], out);
1001 if (error)
1002 goto error;
1003 }
1004
1005 /* Dimensions. */
1006 out->n_dimensions = in->dimensions->n_dims;
1007 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1008 for (size_t i = 0; i < out->n_dimensions; i++)
1009 {
1010 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1011 i, encoding, &out->dimensions[i]);
1012 if (error)
1013 goto error;
1014 }
1015
1016 /* Axes. */
1017 size_t a = in->axes->n_layers;
1018 size_t b = in->axes->n_rows;
1019 size_t c = in->axes->n_columns;
1020 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1021 {
1022 error = xasprintf ("dimensions do not sum correctly "
1023 "(%zu + %zu + %zu != %zu)",
1024 a, b, c, out->n_dimensions);
1025 goto error;
1026 }
1027 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1028 PIVOT_AXIS_LAYER, out);
1029 if (error)
1030 goto error;
1031 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1032 PIVOT_AXIS_ROW, out);
1033 if (error)
1034 goto error;
1035 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1036 PIVOT_AXIS_COLUMN, out);
1037 if (error)
1038 goto error;
1039
1040 pivot_table_assign_label_depth (out);
1041
1042 error = decode_current_layer (in->ts->current_layer, out);
1043 if (error)
1044 goto error;
1045
1046 /* Data. */
1047 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1048 encoding);
1049
1050 *outp = out;
1051 return NULL;
1052
1053 error:
1054 pivot_table_unref (out);
1055 return error;
1056 }
1057