1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 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/spv-light-decoder.h"
27 #include "libpspp/i18n.h"
28 #include "libpspp/message.h"
29 #include "libpspp/string-array.h"
30 #include "output/pivot-table.h"
31 #include "output/spv/light-binary-parser.h"
32 #include "output/spv/spv.h"
34 #include "gl/xalloc.h"
37 /* Returns a copy of S converted to UTF-8. S might be in UTF-8 already or it
38 might be in ENCODING (yes, this makes no sense). */
40 to_utf8 (const char *s, const char *encoding)
42 size_t length = strlen (s);
43 return (u8_check (CHAR_CAST (const uint8_t *, s), length)
44 ? recode_string ("UTF-8", encoding, s, length)
49 to_utf8_if_nonempty (const char *s, const char *encoding)
51 return s && s[0] ? to_utf8 (s, encoding) : NULL;
55 convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
60 *out = xnmalloc (n, sizeof **out);
61 for (size_t i = 0; i < n; i++)
67 convert_breakpoints (const struct spvlb_breakpoints *in,
68 size_t **out, size_t *n_out)
70 if (in && in->n_breaks)
72 *n_out = in->n_breaks;
73 *out = xnmalloc (in->n_breaks, sizeof *out);
74 for (size_t i = 0; i < in->n_breaks; i++)
75 (*out)[i] = in->breaks[i];
80 convert_keeps (const struct spvlb_keeps *in,
81 struct pivot_keep **out, size_t *n_out)
83 if (in && in->n_keeps)
86 *out = xnmalloc (*n_out, sizeof **out);
87 for (size_t i = 0; i < *n_out; i++)
89 (*out)[i].ofs = in->keeps[i]->offset;
90 (*out)[i].n = in->keeps[i]->n;
95 static char * WARN_UNUSED_RESULT
96 decode_spvlb_color_string (const char *s, uint8_t def,
97 struct cell_color *colorp)
102 else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
103 return xasprintf ("bad color %s", s);
105 *colorp = (struct cell_color) CELL_COLOR (r, g, b);
109 static struct cell_color
110 decode_spvlb_color_u32 (uint32_t x)
112 return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
115 static char * WARN_UNUSED_RESULT
116 decode_spvlb_font_style (const struct spvlb_font_style *in,
117 const char *encoding, struct font_style **outp)
125 struct cell_color fg, bg;
126 char *error = decode_spvlb_color_string (in->fg_color, 0x00, &fg);
128 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg);
132 *outp = xmalloc (sizeof **outp);
133 **outp = (struct font_style) {
135 .italic = in->italic,
136 .underline = in->underline,
139 .typeface = to_utf8 (in->typeface, encoding),
140 .size = in->size / 1.33,
145 static char * WARN_UNUSED_RESULT
146 decode_spvlb_halign (uint32_t in, enum table_halign *halignp)
151 *halignp = TABLE_HALIGN_CENTER;
155 *halignp = TABLE_HALIGN_LEFT;
159 *halignp = TABLE_HALIGN_RIGHT;
164 *halignp = TABLE_HALIGN_DECIMAL;
169 *halignp = TABLE_HALIGN_MIXED;
173 return xasprintf ("bad cell style halign %"PRIu32, in);
177 static char * WARN_UNUSED_RESULT
178 decode_spvlb_valign (uint32_t in, enum table_valign *valignp)
183 *valignp = TABLE_VALIGN_CENTER;
187 *valignp = TABLE_VALIGN_TOP;
191 *valignp = TABLE_VALIGN_BOTTOM;
196 return xasprintf ("bad cell style valign %"PRIu32, in);
200 static char * WARN_UNUSED_RESULT
201 decode_spvlb_cell_style (const struct spvlb_cell_style *in,
202 struct cell_style **outp)
210 enum table_halign halign;
211 char *error = decode_spvlb_halign (in->halign, &halign);
215 enum table_valign valign;
216 error = decode_spvlb_valign (in->valign, &valign);
220 *outp = xzalloc (sizeof **outp);
221 **outp = (struct cell_style) {
224 .decimal_offset = in->decimal_offset,
226 [TABLE_HORZ] = { in->left_margin, in->right_margin },
227 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
233 static char *decode_spvlb_value (
234 const struct pivot_table *, const struct spvlb_value *,
235 const char *encoding, struct pivot_value **) WARN_UNUSED_RESULT;
237 static char * WARN_UNUSED_RESULT
238 decode_spvlb_argument (const struct pivot_table *table,
239 const struct spvlb_argument *in,
240 const char *encoding, struct pivot_argument *out)
244 struct pivot_value *value;
245 char *error = decode_spvlb_value (table, in->value, encoding, &value);
250 out->values = xmalloc (sizeof *out->values);
251 out->values[0] = value;
256 out->values = xnmalloc (in->n_values, sizeof *out->values);
257 for (size_t i = 0; i < in->n_values; i++)
259 char *error = decode_spvlb_value (table, in->values[i], encoding,
263 pivot_argument_uninit (out);
273 static char * WARN_UNUSED_RESULT
274 decode_spvlb_value_show (uint8_t in, enum settings_value_show *out)
278 case 0: *out = SETTINGS_VALUE_SHOW_DEFAULT; return NULL;
279 case 1: *out = SETTINGS_VALUE_SHOW_VALUE; return NULL;
280 case 2: *out = SETTINGS_VALUE_SHOW_LABEL; return NULL;
281 case 3: *out = SETTINGS_VALUE_SHOW_BOTH; return NULL;
283 return xasprintf ("bad value show %"PRIu8, in);
287 static char * WARN_UNUSED_RESULT
288 decode_spvlb_value (const struct pivot_table *table,
289 const struct spvlb_value *in,
290 const char *encoding, struct pivot_value **outp)
294 struct pivot_value *out = xzalloc (sizeof *out);
295 const struct spvlb_value_mod *vm;
301 vm = in->type_01.value_mod;
302 out->type = PIVOT_VALUE_NUMERIC;
303 out->numeric.x = in->type_01.x;
304 error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format);
305 out->numeric.honor_small = (in->type_01.format >> 16) == 40;
311 vm = in->type_02.value_mod;
312 out->type = PIVOT_VALUE_NUMERIC;
313 out->numeric.x = in->type_02.x;
314 error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
316 error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
319 out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
321 out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
326 vm = in->type_03.value_mod;
327 out->type = PIVOT_VALUE_TEXT;
328 out->text.local = to_utf8 (in->type_03.local, encoding);
329 out->text.c = to_utf8 (in->type_03.c, encoding);
330 out->text.id = to_utf8 (in->type_03.id, encoding);
331 out->text.user_provided = !in->type_03.fixed;
335 vm = in->type_04.value_mod;
336 out->type = PIVOT_VALUE_STRING;
337 error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
340 out->string.s = to_utf8 (in->type_04.s, encoding);
341 out->string.hex = (in->type_04.format >> 16) == fmt_to_io (FMT_AHEX);
342 out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
343 out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
348 vm = in->type_05.value_mod;
349 out->type = PIVOT_VALUE_VARIABLE;
350 error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
353 out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
354 out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
359 vm = in->type_06.value_mod;
360 out->type = PIVOT_VALUE_TEXT;
361 out->text.local = to_utf8 (in->type_06.local, encoding);
362 out->text.c = to_utf8 (in->type_06.c, encoding);
363 out->text.id = to_utf8 (in->type_06.id, encoding);
364 out->text.user_provided = false;
368 vm = in->type_else.value_mod;
369 out->type = PIVOT_VALUE_TEMPLATE;
370 out->template.local = to_utf8 (in->type_else.template, encoding);
371 out->template.id = out->template.local;
372 out->template.n_args = 0;
373 out->template.args = xnmalloc (in->type_else.n_args,
374 sizeof *out->template.args);
375 for (size_t i = 0; i < in->type_else.n_args; i++)
377 error = decode_spvlb_argument (table, in->type_else.args[i],
378 encoding, &out->template.args[i]);
381 pivot_value_destroy (out);
384 out->template.n_args++;
394 if (vm->n_subscripts)
396 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
397 ex->n_subscripts = vm->n_subscripts;
398 ex->subscripts = xnmalloc (vm->n_subscripts, sizeof *ex->subscripts);
399 for (size_t i = 0; i < vm->n_subscripts; i++)
400 ex->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
405 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
406 ex->footnote_indexes = xnmalloc (vm->n_refs,
407 sizeof *ex->footnote_indexes);
409 for (size_t i = 0; i < vm->n_refs; i++)
411 uint16_t idx = vm->refs[i];
412 if (idx >= table->n_footnotes)
414 pivot_value_destroy (out);
415 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
416 idx, table->n_footnotes);
419 ex->footnote_indexes[ex->n_footnotes++] = idx;
421 pivot_value_sort_footnotes (out);
426 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
427 error = decode_spvlb_font_style (vm->style_pair->font_style,
428 encoding, &ex->font_style);
430 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
434 pivot_value_destroy (out);
439 if (vm->template_string
440 && vm->template_string->id
441 && vm->template_string->id[0]
442 && out->type == PIVOT_VALUE_TEMPLATE)
443 out->template.id = to_utf8 (vm->template_string->id, encoding);
450 static char * WARN_UNUSED_RESULT
451 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
452 const char *encoding)
456 struct cell_color fg0, fg1, bg0, bg1;
457 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
459 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
460 if (!error && in->alternate)
461 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
462 if (!error && in->alternate)
463 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
465 enum table_halign halign;
468 error = decode_spvlb_halign (in->halign, &halign);
470 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
471 is good because there's no way to indicate the decimal offset. Just
473 if (!error && halign == TABLE_HALIGN_DECIMAL)
474 halign = TABLE_HALIGN_MIXED;
477 enum table_valign valign;
479 error = decode_spvlb_valign (in->valign, &valign);
484 table_area_style_uninit (out);
485 *out = (struct table_area_style) {
487 .bold = (in->style & 1) != 0,
488 .italic = (in->style & 2) != 0,
489 .underline = in->underline,
490 .fg = { fg0, in->alternate ? fg1 : fg0 },
491 .bg = { bg0, in->alternate ? bg1 : bg0 },
492 .typeface = to_utf8 (in->typeface, encoding),
493 .size = in->size / 1.33,
499 [TABLE_HORZ] = { in->left_margin, in->right_margin },
500 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
507 static char * WARN_UNUSED_RESULT
508 decode_spvlb_group (const struct pivot_table *,
509 struct spvlb_category **,
512 struct pivot_category *parent,
513 struct pivot_dimension *,
514 const char *encoding);
516 static char * WARN_UNUSED_RESULT
517 decode_spvlb_categories (const struct pivot_table *table,
518 struct spvlb_category **categories,
520 struct pivot_category *parent,
521 struct pivot_dimension *dimension,
522 const char *encoding)
524 for (size_t i = 0; i < n_categories; i++)
526 const struct spvlb_category *in = categories[i];
527 if (in->group && in->group->merge)
529 char *error = decode_spvlb_categories (
530 table, in->group->subcategories, in->group->n_subcategories,
531 parent, dimension, encoding);
538 struct pivot_value *name;
539 char *error = decode_spvlb_value (table, in->name, encoding, &name);
543 struct pivot_category *out = xzalloc (sizeof *out);
545 out->parent = parent;
546 out->dimension = dimension;
549 char *error = decode_spvlb_group (table, in->group->subcategories,
550 in->group->n_subcategories,
551 true, out, dimension, encoding);
554 pivot_category_destroy (out);
558 out->data_index = SIZE_MAX;
559 out->presentation_index = SIZE_MAX;
563 out->data_index = in->leaf->leaf_index;
564 out->presentation_index = dimension->n_leaves;
565 dimension->n_leaves++;
568 if (parent->n_subs >= parent->allocated_subs)
569 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
570 sizeof *parent->subs);
571 parent->subs[parent->n_subs++] = out;
576 static char * WARN_UNUSED_RESULT
577 decode_spvlb_group (const struct pivot_table *table,
578 struct spvlb_category **categories,
579 size_t n_categories, bool show_label,
580 struct pivot_category *category,
581 struct pivot_dimension *dimension,
582 const char *encoding)
584 category->subs = XCALLOC (n_categories, struct pivot_category *);
585 category->n_subs = 0;
586 category->allocated_subs = 0;
587 category->show_label = show_label;
589 return decode_spvlb_categories (table, categories, n_categories, category,
590 dimension, encoding);
593 static char * WARN_UNUSED_RESULT
594 fill_leaves (struct pivot_category *category,
595 struct pivot_dimension *dimension)
597 if (pivot_category_is_group (category))
599 for (size_t i = 0; i < category->n_subs; i++)
601 char *error = fill_leaves (category->subs[i], dimension);
608 if (category->data_index >= dimension->n_leaves)
609 return xasprintf ("leaf_index %zu >= n_leaves %zu",
610 category->data_index, dimension->n_leaves);
611 if (dimension->data_leaves[category->data_index])
612 return xasprintf ("two leaves with data_index %zu",
613 category->data_index);
614 dimension->data_leaves[category->data_index] = category;
615 dimension->presentation_leaves[category->presentation_index] = category;
620 static char * WARN_UNUSED_RESULT
621 decode_spvlb_dimension (const struct pivot_table *table,
622 const struct spvlb_dimension *in,
623 size_t idx, const char *encoding,
624 struct pivot_dimension **outp)
626 /* Convert most of the dimension. */
627 struct pivot_value *name;
628 char *error = decode_spvlb_value (table, in->name, encoding, &name);
632 struct pivot_dimension *out = xzalloc (sizeof *out);
633 out->level = UINT_MAX;
634 out->top_index = idx;
635 out->hide_all_labels = in->props->hide_all_labels;
637 out->root = xzalloc (sizeof *out->root);
638 *out->root = (struct pivot_category) {
641 .data_index = SIZE_MAX,
642 .presentation_index = SIZE_MAX,
644 error = decode_spvlb_group (table, in->categories, in->n_categories,
645 !in->props->hide_dim_label, out->root,
650 /* Allocate and fill the array of leaves now that we know how many there
652 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
653 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
654 out->allocated_leaves = out->n_leaves;
655 error = fill_leaves (out->root, out);
658 for (size_t i = 0; i < out->n_leaves; i++)
660 assert (out->data_leaves[i] != NULL);
661 assert (out->presentation_leaves[i] != NULL);
667 pivot_dimension_destroy (out);
671 static char * WARN_UNUSED_RESULT
672 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
674 enum table_stroke strokes[] = {
683 if (stroke_type >= sizeof strokes / sizeof *strokes)
684 return xasprintf ("bad stroke %"PRIu32, stroke_type);
686 *strokep = strokes[stroke_type];
690 static char * WARN_UNUSED_RESULT
691 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
694 if (in->border_type >= PIVOT_N_BORDERS)
695 return xasprintf ("bad border type %"PRIu32, in->border_type);
697 struct table_border_style *out = &table->look->borders[in->border_type];
698 out->color = decode_spvlb_color_u32 (in->color);
699 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
702 static char * WARN_UNUSED_RESULT
703 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
704 enum pivot_axis_type axis_type, struct pivot_table *table)
706 struct pivot_axis *axis = &table->axes[axis_type];
707 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
708 axis->n_dimensions = n_dimensions;
710 for (size_t i = 0; i < n_dimensions; i++)
712 uint32_t idx = dimension_indexes[i];
713 if (idx >= table->n_dimensions)
714 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
715 idx, table->n_dimensions);
717 struct pivot_dimension *d = table->dimensions[idx];
718 if (d->level != UINT_MAX)
719 return xasprintf ("duplicate dimension %"PRIu32, idx);
721 axis->dimensions[i] = d;
722 d->axis_type = axis_type;
725 axis->extent *= d->n_leaves;
732 decode_data_index (uint64_t in, const struct pivot_table *table,
735 uint64_t remainder = in;
736 for (size_t i = table->n_dimensions - 1; i < table->n_dimensions; i--)
738 const struct pivot_dimension *d = table->dimensions[i];
741 out[i] = remainder % d->n_leaves;
742 remainder /= d->n_leaves;
748 return xasprintf ("out of range cell data index %"PRIu64, in);
753 static char * WARN_UNUSED_RESULT
754 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
755 struct pivot_table *table, const char *encoding)
757 if (!table->n_dimensions)
760 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
761 for (size_t i = 0; i < n_in; i++)
763 struct pivot_value *value;
764 char *error = decode_data_index (in[i]->index, table, dindexes);
766 error = decode_spvlb_value (table, in[i]->value, encoding, &value);
772 pivot_table_put (table, dindexes, table->n_dimensions, value);
779 static char * WARN_UNUSED_RESULT
780 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
781 size_t idx, struct pivot_table *table)
783 struct pivot_value *content;
784 char *error = decode_spvlb_value (table, in->text, encoding, &content);
788 struct pivot_value *marker = NULL;
791 error = decode_spvlb_value (table, in->marker, encoding, &marker);
794 pivot_value_destroy (content);
797 if (marker->type == PIVOT_VALUE_TEXT)
798 marker->text.user_provided = false;
801 struct pivot_footnote *f = pivot_table_create_footnote__ (
802 table, idx, marker, content);
803 f->show = (int32_t) in->show > 0;
807 static char * WARN_UNUSED_RESULT
808 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
810 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
811 table->current_layer = xnmalloc (axis->n_dimensions,
812 sizeof *table->current_layer);
814 uint64_t remainder = current_layer;
815 for (size_t i = 0; i < axis->n_dimensions; i++)
817 const struct pivot_dimension *d = axis->dimensions[i];
820 table->current_layer[i] = remainder % d->n_leaves;
821 remainder /= d->n_leaves;
824 table->current_layer[i] = 0;
827 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
832 char * WARN_UNUSED_RESULT
833 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
836 if (in->header->version != 1 && in->header->version != 3)
837 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
838 in->header->version);
841 struct pivot_table *out = xzalloc (sizeof *out);
843 hmap_init (&out->cells);
844 out->look = pivot_table_look_new_builtin_default ();
845 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
847 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
848 : in->formats->x3 ? in->formats->x3->y1
850 const char *encoding = spvlb_table_get_encoding (in);
852 /* Display settings. */
853 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
854 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
855 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
856 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
857 out->show_grid_lines = in->borders->show_grid_lines;
858 out->show_title = true;
859 out->show_caption = true;
860 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
861 out->look->omit_empty = in->ts->omit_empty;
863 const struct spvlb_x1 *x1 = in->formats->x1;
866 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
868 error = decode_spvlb_value_show (x1->show_variables,
869 &out->show_variables);
873 out->show_caption = x1->show_caption;
874 out->show_title = x1->show_title != 10;
877 /* Column and row display settings. */
878 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
879 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
880 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
881 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
883 convert_widths (in->formats->widths, in->formats->n_widths,
884 &out->sizing[TABLE_HORZ].widths,
885 &out->sizing[TABLE_HORZ].n_widths);
887 const struct spvlb_x2 *x2 = in->formats->x2;
889 convert_widths (x2->row_heights, x2->n_row_heights,
890 &out->sizing[TABLE_VERT].widths,
891 &out->sizing[TABLE_VERT].n_widths);
893 convert_breakpoints (in->ts->row_breaks,
894 &out->sizing[TABLE_VERT].breaks,
895 &out->sizing[TABLE_VERT].n_breaks);
896 convert_breakpoints (in->ts->col_breaks,
897 &out->sizing[TABLE_HORZ].breaks,
898 &out->sizing[TABLE_HORZ].n_breaks);
900 convert_keeps (in->ts->row_keeps,
901 &out->sizing[TABLE_VERT].keeps,
902 &out->sizing[TABLE_VERT].n_keeps);
903 convert_keeps (in->ts->col_keeps,
904 &out->sizing[TABLE_HORZ].keeps,
905 &out->sizing[TABLE_HORZ].n_keeps);
907 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
908 out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
910 /* Print settings. */
911 out->look->print_all_layers = in->ps->all_layers;
912 out->look->paginate_layers = in->ps->paginate_layers;
913 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
914 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
915 out->look->top_continuation = in->ps->top_continuation;
916 out->look->bottom_continuation = in->ps->bottom_continuation;
917 out->look->continuation = to_utf8 (in->ps->continuation_string, encoding);
918 out->look->n_orphan_lines = in->ps->n_orphan_lines;
920 /* Format settings. */
921 int epoch = in->formats->y0->epoch;
922 if (epoch >= 1000 && epoch <= 9999)
923 out->settings.epoch = epoch;
924 char decimal = in->formats->y0->decimal;
925 if (decimal == '.' || decimal == ',')
926 out->settings.decimal = decimal;
929 /* XXX warn about bad decimal point */
931 out->grouping = in->formats->y0->grouping;
932 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
933 for (int i = 0; i < 5; i++)
935 if (cc && i < cc->n_ccs)
937 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
938 /* XXX warn if parsing fails */
941 out->small = in->formats->x3 ? in->formats->x3->small : 0;
943 /* Command information. */
946 out->command_local = to_utf8 (y1->command_local, encoding);
947 out->command_c = to_utf8 (y1->command, encoding);
948 out->language = to_utf8 (y1->language, encoding);
950 out->locale = to_utf8 (y1->locale, encoding);
953 /* Source information. */
954 const struct spvlb_x3 *x3 = in->formats->x3;
957 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
958 out->dataset = to_utf8 (x3->dataset, encoding);
959 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
960 out->date = x3->date;
965 Any pivot_value might refer to footnotes, so it's important to process the
966 footnotes early to ensure that those references can be resolved. There is
967 a possible problem that a footnote might itself reference an
968 as-yet-unprocessed footnote, but that's OK because footnote references
969 don't actually look at the footnote contents but only resolve a pointer to
970 where the footnote will go later.
972 Before we really start, create all the footnotes we'll fill in. This is
973 because sometimes footnotes refer to themselves or to each other and we
974 don't want to reject those references. */
975 const struct spvlb_footnotes *fn = in->footnotes;
976 if (fn->n_footnotes > 0)
978 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
979 for (size_t i = 0; i < fn->n_footnotes; i++)
981 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
988 /* Title and caption. */
989 error = decode_spvlb_value (out, in->titles->user_title, encoding,
994 error = decode_spvlb_value (out, in->titles->subtype, encoding,
999 if (in->titles->corner_text)
1001 error = decode_spvlb_value (out, in->titles->corner_text,
1002 encoding, &out->corner_text);
1007 if (in->titles->caption)
1009 error = decode_spvlb_value (out, in->titles->caption, encoding,
1017 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1019 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
1024 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1026 error = decode_spvlb_border (in->borders->borders[i], out);
1032 out->n_dimensions = in->dimensions->n_dims;
1033 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1034 for (size_t i = 0; i < out->n_dimensions; i++)
1036 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1037 i, encoding, &out->dimensions[i]);
1043 size_t a = in->axes->n_layers;
1044 size_t b = in->axes->n_rows;
1045 size_t c = in->axes->n_columns;
1046 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1048 error = xasprintf ("dimensions do not sum correctly "
1049 "(%zu + %zu + %zu != %zu)",
1050 a, b, c, out->n_dimensions);
1053 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1054 PIVOT_AXIS_LAYER, out);
1057 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1058 PIVOT_AXIS_ROW, out);
1061 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1062 PIVOT_AXIS_COLUMN, out);
1066 pivot_table_assign_label_depth (out);
1068 error = decode_current_layer (in->ts->current_layer, out);
1073 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1080 pivot_table_unref (out);
1084 /* collect_spvlb_strings */
1087 add_if_nonempty (struct string_array *strings, const char *s)
1090 string_array_append (strings, s);
1094 collect_value_mod_strings (struct string_array *strings,
1095 const struct spvlb_value_mod *vm)
1097 if (vm->template_string)
1098 add_if_nonempty (strings, vm->template_string->id);
1100 if (vm->style_pair && vm->style_pair->font_style)
1101 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1105 collect_value_strings (struct string_array *strings,
1106 const struct spvlb_value *value)
1111 switch (value->type)
1114 collect_value_mod_strings (strings, value->type_01.value_mod);
1118 collect_value_mod_strings (strings, value->type_02.value_mod);
1119 add_if_nonempty (strings, value->type_02.var_name);
1120 add_if_nonempty (strings, value->type_02.value_label);
1124 collect_value_mod_strings (strings, value->type_03.value_mod);
1125 add_if_nonempty (strings, value->type_03.local);
1126 add_if_nonempty (strings, value->type_03.id);
1127 add_if_nonempty (strings, value->type_03.c);
1131 collect_value_mod_strings (strings, value->type_04.value_mod);
1132 add_if_nonempty (strings, value->type_04.value_label);
1133 add_if_nonempty (strings, value->type_04.var_name);
1134 add_if_nonempty (strings, value->type_04.s);
1138 collect_value_mod_strings (strings, value->type_05.value_mod);
1139 add_if_nonempty (strings, value->type_05.var_name);
1140 add_if_nonempty (strings, value->type_05.var_label);
1144 collect_value_mod_strings (strings, value->type_06.value_mod);
1145 add_if_nonempty (strings, value->type_06.local);
1146 add_if_nonempty (strings, value->type_06.id);
1147 add_if_nonempty (strings, value->type_06.c);
1151 collect_value_mod_strings (strings, value->type_else.value_mod);
1152 add_if_nonempty (strings, value->type_else.template);
1153 for (size_t i = 0; i < value->type_else.n_args; i++)
1155 const struct spvlb_argument *a = value->type_else.args[i];
1156 collect_value_strings (strings, a->value);
1157 for (size_t j = 0; j < a->n_values; j++)
1158 collect_value_strings (strings, a->values[j]);
1165 collect_category_strings (struct string_array *strings,
1166 const struct spvlb_category *cat)
1168 collect_value_strings (strings, cat->name);
1170 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1171 collect_category_strings (strings, cat->group->subcategories[i]);
1174 /* Adds all of the characters strings in TABLE to STRINGS. */
1176 collect_spvlb_strings (const struct spvlb_table *table,
1177 struct string_array *strings)
1179 add_if_nonempty (strings, table->ts->notes);
1180 add_if_nonempty (strings, table->ts->table_look);
1181 add_if_nonempty (strings, table->ps->continuation_string);
1183 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1185 for (int i = 0; i < cc->n_ccs; i++)
1186 add_if_nonempty (strings, cc->ccs[i]);
1188 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1189 : table->formats->x3 ? table->formats->x3->y1
1193 add_if_nonempty (strings, y1->command_local);
1194 add_if_nonempty (strings, y1->command);
1195 add_if_nonempty (strings, y1->language);
1196 add_if_nonempty (strings, y1->charset);
1197 add_if_nonempty (strings, y1->locale);
1200 const struct spvlb_x3 *x3 = table->formats->x3;
1203 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1204 add_if_nonempty (strings, x3->dataset);
1205 add_if_nonempty (strings, x3->datafile);
1208 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1210 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1211 collect_value_strings (strings, f->text);
1212 collect_value_strings (strings, f->marker);
1215 collect_value_strings (strings, table->titles->user_title);
1216 collect_value_strings (strings, table->titles->subtype);
1217 collect_value_strings (strings, table->titles->corner_text);
1218 collect_value_strings (strings, table->titles->caption);
1220 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1221 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1223 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1225 const struct spvlb_dimension *d = table->dimensions->dims[i];
1226 collect_value_strings (strings, d->name);
1227 for (size_t j = 0; j < d->n_categories; j++)
1228 collect_category_strings (strings, d->categories[j]);
1231 for (size_t i = 0; i < table->cells->n_cells; i++)
1232 collect_value_strings (strings, table->cells->cells[i]->value);
1235 /* Returns the encoding that TABLE declares to be in use for its strings.
1236 (Watch out, it's not always correct.) */
1238 spvlb_table_get_encoding (const struct spvlb_table *table)
1240 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1241 : table->formats->x3 ? table->formats->x3->y1
1247 const char *dot = strchr (table->formats->locale, '.');
1248 return dot ? dot + 1 : "windows-1252";