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 out->n_subscripts = vm->n_subscripts;
397 out->subscripts = xnmalloc (vm->n_subscripts,
398 sizeof *out->subscripts);
399 for (size_t i = 0; i < vm->n_subscripts; i++)
400 out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
405 out->footnote_indexes = xnmalloc (vm->n_refs,
406 sizeof *out->footnote_indexes);
407 for (size_t i = 0; i < vm->n_refs; i++)
409 uint16_t idx = vm->refs[i];
410 if (idx >= table->n_footnotes)
412 pivot_value_destroy (out);
413 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
414 idx, table->n_footnotes);
417 out->footnote_indexes[out->n_footnotes++] = idx;
419 pivot_value_sort_footnotes (out);
424 error = decode_spvlb_font_style (vm->style_pair->font_style,
425 encoding, &out->font_style);
427 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
431 pivot_value_destroy (out);
436 if (vm->template_string
437 && vm->template_string->id
438 && vm->template_string->id[0]
439 && out->type == PIVOT_VALUE_TEMPLATE)
440 out->template.id = to_utf8 (vm->template_string->id, encoding);
447 static char * WARN_UNUSED_RESULT
448 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
449 const char *encoding)
453 struct cell_color fg0, fg1, bg0, bg1;
454 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
456 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
457 if (!error && in->alternate)
458 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
459 if (!error && in->alternate)
460 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
462 enum table_halign halign;
465 error = decode_spvlb_halign (in->halign, &halign);
467 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
468 is good because there's no way to indicate the decimal offset. Just
470 if (!error && halign == TABLE_HALIGN_DECIMAL)
471 halign = TABLE_HALIGN_MIXED;
474 enum table_valign valign;
476 error = decode_spvlb_valign (in->valign, &valign);
481 table_area_style_uninit (out);
482 *out = (struct table_area_style) {
484 .bold = (in->style & 1) != 0,
485 .italic = (in->style & 2) != 0,
486 .underline = in->underline,
487 .fg = { fg0, in->alternate ? fg1 : fg0 },
488 .bg = { bg0, in->alternate ? bg1 : bg0 },
489 .typeface = to_utf8 (in->typeface, encoding),
490 .size = in->size / 1.33,
496 [TABLE_HORZ] = { in->left_margin, in->right_margin },
497 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
504 static char * WARN_UNUSED_RESULT
505 decode_spvlb_group (const struct pivot_table *,
506 struct spvlb_category **,
509 struct pivot_category *parent,
510 struct pivot_dimension *,
511 const char *encoding);
513 static char * WARN_UNUSED_RESULT
514 decode_spvlb_categories (const struct pivot_table *table,
515 struct spvlb_category **categories,
517 struct pivot_category *parent,
518 struct pivot_dimension *dimension,
519 const char *encoding)
521 for (size_t i = 0; i < n_categories; i++)
523 const struct spvlb_category *in = categories[i];
524 if (in->group && in->group->merge)
526 char *error = decode_spvlb_categories (
527 table, in->group->subcategories, in->group->n_subcategories,
528 parent, dimension, encoding);
535 struct pivot_value *name;
536 char *error = decode_spvlb_value (table, in->name, encoding, &name);
540 struct pivot_category *out = xzalloc (sizeof *out);
542 out->parent = parent;
543 out->dimension = dimension;
546 char *error = decode_spvlb_group (table, in->group->subcategories,
547 in->group->n_subcategories,
548 true, out, dimension, encoding);
551 pivot_category_destroy (out);
555 out->data_index = SIZE_MAX;
556 out->presentation_index = SIZE_MAX;
560 out->data_index = in->leaf->leaf_index;
561 out->presentation_index = dimension->n_leaves;
562 dimension->n_leaves++;
565 if (parent->n_subs >= parent->allocated_subs)
566 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
567 sizeof *parent->subs);
568 parent->subs[parent->n_subs++] = out;
573 static char * WARN_UNUSED_RESULT
574 decode_spvlb_group (const struct pivot_table *table,
575 struct spvlb_category **categories,
576 size_t n_categories, bool show_label,
577 struct pivot_category *category,
578 struct pivot_dimension *dimension,
579 const char *encoding)
581 category->subs = XCALLOC (n_categories, struct pivot_category *);
582 category->n_subs = 0;
583 category->allocated_subs = 0;
584 category->show_label = show_label;
586 return decode_spvlb_categories (table, categories, n_categories, category,
587 dimension, encoding);
590 static char * WARN_UNUSED_RESULT
591 fill_leaves (struct pivot_category *category,
592 struct pivot_dimension *dimension)
594 if (pivot_category_is_group (category))
596 for (size_t i = 0; i < category->n_subs; i++)
598 char *error = fill_leaves (category->subs[i], dimension);
605 if (category->data_index >= dimension->n_leaves)
606 return xasprintf ("leaf_index %zu >= n_leaves %zu",
607 category->data_index, dimension->n_leaves);
608 if (dimension->data_leaves[category->data_index])
609 return xasprintf ("two leaves with data_index %zu",
610 category->data_index);
611 dimension->data_leaves[category->data_index] = category;
612 dimension->presentation_leaves[category->presentation_index] = category;
617 static char * WARN_UNUSED_RESULT
618 decode_spvlb_dimension (const struct pivot_table *table,
619 const struct spvlb_dimension *in,
620 size_t idx, const char *encoding,
621 struct pivot_dimension **outp)
623 /* Convert most of the dimension. */
624 struct pivot_value *name;
625 char *error = decode_spvlb_value (table, in->name, encoding, &name);
629 struct pivot_dimension *out = xzalloc (sizeof *out);
630 out->level = UINT_MAX;
631 out->top_index = idx;
632 out->hide_all_labels = in->props->hide_all_labels;
634 out->root = xzalloc (sizeof *out->root);
635 *out->root = (struct pivot_category) {
638 .data_index = SIZE_MAX,
639 .presentation_index = SIZE_MAX,
641 error = decode_spvlb_group (table, in->categories, in->n_categories,
642 !in->props->hide_dim_label, out->root,
647 /* Allocate and fill the array of leaves now that we know how many there
649 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
650 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
651 out->allocated_leaves = out->n_leaves;
652 error = fill_leaves (out->root, out);
655 for (size_t i = 0; i < out->n_leaves; i++)
657 assert (out->data_leaves[i] != NULL);
658 assert (out->presentation_leaves[i] != NULL);
664 pivot_dimension_destroy (out);
668 static char * WARN_UNUSED_RESULT
669 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
671 enum table_stroke strokes[] = {
680 if (stroke_type >= sizeof strokes / sizeof *strokes)
681 return xasprintf ("bad stroke %"PRIu32, stroke_type);
683 *strokep = strokes[stroke_type];
687 static char * WARN_UNUSED_RESULT
688 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
691 if (in->border_type >= PIVOT_N_BORDERS)
692 return xasprintf ("bad border type %"PRIu32, in->border_type);
694 struct table_border_style *out = &table->look->borders[in->border_type];
695 out->color = decode_spvlb_color_u32 (in->color);
696 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
699 static char * WARN_UNUSED_RESULT
700 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
701 enum pivot_axis_type axis_type, struct pivot_table *table)
703 struct pivot_axis *axis = &table->axes[axis_type];
704 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
705 axis->n_dimensions = n_dimensions;
707 for (size_t i = 0; i < n_dimensions; i++)
709 uint32_t idx = dimension_indexes[i];
710 if (idx >= table->n_dimensions)
711 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
712 idx, table->n_dimensions);
714 struct pivot_dimension *d = table->dimensions[idx];
715 if (d->level != UINT_MAX)
716 return xasprintf ("duplicate dimension %"PRIu32, idx);
718 axis->dimensions[i] = d;
719 d->axis_type = axis_type;
722 axis->extent *= d->n_leaves;
729 decode_data_index (uint64_t in, const struct pivot_table *table,
732 uint64_t remainder = in;
733 for (size_t i = table->n_dimensions - 1; i < table->n_dimensions; i--)
735 const struct pivot_dimension *d = table->dimensions[i];
738 out[i] = remainder % d->n_leaves;
739 remainder /= d->n_leaves;
745 return xasprintf ("out of range cell data index %"PRIu64, in);
750 static char * WARN_UNUSED_RESULT
751 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
752 struct pivot_table *table, const char *encoding)
754 if (!table->n_dimensions)
757 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
758 for (size_t i = 0; i < n_in; i++)
760 struct pivot_value *value;
761 char *error = decode_data_index (in[i]->index, table, dindexes);
763 error = decode_spvlb_value (table, in[i]->value, encoding, &value);
769 pivot_table_put (table, dindexes, table->n_dimensions, value);
776 static char * WARN_UNUSED_RESULT
777 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
778 size_t idx, struct pivot_table *table)
780 struct pivot_value *content;
781 char *error = decode_spvlb_value (table, in->text, encoding, &content);
785 struct pivot_value *marker = NULL;
788 error = decode_spvlb_value (table, in->marker, encoding, &marker);
791 pivot_value_destroy (content);
794 if (marker->type == PIVOT_VALUE_TEXT)
795 marker->text.user_provided = false;
798 struct pivot_footnote *f = pivot_table_create_footnote__ (
799 table, idx, marker, content);
800 f->show = (int32_t) in->show > 0;
804 static char * WARN_UNUSED_RESULT
805 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
807 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
808 table->current_layer = xnmalloc (axis->n_dimensions,
809 sizeof *table->current_layer);
811 for (size_t i = 0; i < axis->n_dimensions; i++)
813 const struct pivot_dimension *d = axis->dimensions[i];
816 table->current_layer[i] = current_layer % d->n_leaves;
817 current_layer /= d->n_leaves;
820 table->current_layer[i] = 0;
822 if (current_layer > 0)
823 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
827 char * WARN_UNUSED_RESULT
828 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
831 if (in->header->version != 1 && in->header->version != 3)
832 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
833 in->header->version);
836 struct pivot_table *out = xzalloc (sizeof *out);
838 hmap_init (&out->cells);
839 out->look = pivot_table_look_new_builtin_default ();
840 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
842 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
843 : in->formats->x3 ? in->formats->x3->y1
845 const char *encoding = spvlb_table_get_encoding (in);
847 /* Display settings. */
848 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
849 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
850 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
851 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
852 out->show_grid_lines = in->borders->show_grid_lines;
853 out->show_title = true;
854 out->show_caption = true;
855 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
856 out->look->omit_empty = in->ts->omit_empty;
858 const struct spvlb_x1 *x1 = in->formats->x1;
861 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
863 error = decode_spvlb_value_show (x1->show_variables,
864 &out->show_variables);
868 out->show_caption = x1->show_caption;
869 out->show_title = x1->show_title != 10;
872 /* Column and row display settings. */
873 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
874 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
875 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
876 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
878 convert_widths (in->formats->widths, in->formats->n_widths,
879 &out->sizing[TABLE_HORZ].widths,
880 &out->sizing[TABLE_HORZ].n_widths);
882 const struct spvlb_x2 *x2 = in->formats->x2;
884 convert_widths (x2->row_heights, x2->n_row_heights,
885 &out->sizing[TABLE_VERT].widths,
886 &out->sizing[TABLE_VERT].n_widths);
888 convert_breakpoints (in->ts->row_breaks,
889 &out->sizing[TABLE_VERT].breaks,
890 &out->sizing[TABLE_VERT].n_breaks);
891 convert_breakpoints (in->ts->col_breaks,
892 &out->sizing[TABLE_HORZ].breaks,
893 &out->sizing[TABLE_HORZ].n_breaks);
895 convert_keeps (in->ts->row_keeps,
896 &out->sizing[TABLE_VERT].keeps,
897 &out->sizing[TABLE_VERT].n_keeps);
898 convert_keeps (in->ts->col_keeps,
899 &out->sizing[TABLE_HORZ].keeps,
900 &out->sizing[TABLE_HORZ].n_keeps);
902 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
903 out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
905 /* Print settings. */
906 out->look->print_all_layers = in->ps->all_layers;
907 out->look->paginate_layers = in->ps->paginate_layers;
908 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
909 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
910 out->look->top_continuation = in->ps->top_continuation;
911 out->look->bottom_continuation = in->ps->bottom_continuation;
912 out->look->continuation = to_utf8 (in->ps->continuation_string, encoding);
913 out->look->n_orphan_lines = in->ps->n_orphan_lines;
915 /* Format settings. */
916 int epoch = in->formats->y0->epoch;
917 if (epoch >= 1000 && epoch <= 9999)
918 out->settings.epoch = epoch;
919 char decimal = in->formats->y0->decimal;
920 if (decimal == '.' || decimal == '.')
921 out->settings.decimal = decimal;
924 /* XXX warn about bad decimal point */
926 out->grouping = in->formats->y0->grouping;
927 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
928 for (int i = 0; i < 5; i++)
930 if (cc && i < cc->n_ccs)
932 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
933 /* XXX warn if parsing fails */
936 out->small = in->formats->x3 ? in->formats->x3->small : 0;
938 /* Command information. */
941 out->command_local = to_utf8 (y1->command_local, encoding);
942 out->command_c = to_utf8 (y1->command, encoding);
943 out->language = to_utf8 (y1->language, encoding);
945 out->locale = to_utf8 (y1->locale, encoding);
948 /* Source information. */
949 const struct spvlb_x3 *x3 = in->formats->x3;
952 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
953 out->dataset = to_utf8 (x3->dataset, encoding);
954 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
955 out->date = x3->date;
960 Any pivot_value might refer to footnotes, so it's important to process the
961 footnotes early to ensure that those references can be resolved. There is
962 a possible problem that a footnote might itself reference an
963 as-yet-unprocessed footnote, but that's OK because footnote references
964 don't actually look at the footnote contents but only resolve a pointer to
965 where the footnote will go later.
967 Before we really start, create all the footnotes we'll fill in. This is
968 because sometimes footnotes refer to themselves or to each other and we
969 don't want to reject those references. */
970 const struct spvlb_footnotes *fn = in->footnotes;
971 if (fn->n_footnotes > 0)
973 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
974 for (size_t i = 0; i < fn->n_footnotes; i++)
976 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
983 /* Title and caption. */
984 error = decode_spvlb_value (out, in->titles->user_title, encoding,
989 error = decode_spvlb_value (out, in->titles->subtype, encoding,
994 if (in->titles->corner_text)
996 error = decode_spvlb_value (out, in->titles->corner_text,
997 encoding, &out->corner_text);
1002 if (in->titles->caption)
1004 error = decode_spvlb_value (out, in->titles->caption, encoding,
1012 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1014 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
1019 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1021 error = decode_spvlb_border (in->borders->borders[i], out);
1027 out->n_dimensions = in->dimensions->n_dims;
1028 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1029 for (size_t i = 0; i < out->n_dimensions; i++)
1031 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1032 i, encoding, &out->dimensions[i]);
1038 size_t a = in->axes->n_layers;
1039 size_t b = in->axes->n_rows;
1040 size_t c = in->axes->n_columns;
1041 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1043 error = xasprintf ("dimensions do not sum correctly "
1044 "(%zu + %zu + %zu != %zu)",
1045 a, b, c, out->n_dimensions);
1048 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1049 PIVOT_AXIS_LAYER, out);
1052 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1053 PIVOT_AXIS_ROW, out);
1056 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1057 PIVOT_AXIS_COLUMN, out);
1061 pivot_table_assign_label_depth (out);
1063 error = decode_current_layer (in->ts->current_layer, out);
1068 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1075 pivot_table_unref (out);
1079 /* collect_spvlb_strings */
1082 add_if_nonempty (struct string_array *strings, const char *s)
1085 string_array_append (strings, s);
1089 collect_value_mod_strings (struct string_array *strings,
1090 const struct spvlb_value_mod *vm)
1092 if (vm->template_string)
1093 add_if_nonempty (strings, vm->template_string->id);
1095 if (vm->style_pair && vm->style_pair->font_style)
1096 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1100 collect_value_strings (struct string_array *strings,
1101 const struct spvlb_value *value)
1106 switch (value->type)
1109 collect_value_mod_strings (strings, value->type_01.value_mod);
1113 collect_value_mod_strings (strings, value->type_02.value_mod);
1114 add_if_nonempty (strings, value->type_02.var_name);
1115 add_if_nonempty (strings, value->type_02.value_label);
1119 collect_value_mod_strings (strings, value->type_03.value_mod);
1120 add_if_nonempty (strings, value->type_03.local);
1121 add_if_nonempty (strings, value->type_03.id);
1122 add_if_nonempty (strings, value->type_03.c);
1126 collect_value_mod_strings (strings, value->type_04.value_mod);
1127 add_if_nonempty (strings, value->type_04.value_label);
1128 add_if_nonempty (strings, value->type_04.var_name);
1129 add_if_nonempty (strings, value->type_04.s);
1133 collect_value_mod_strings (strings, value->type_05.value_mod);
1134 add_if_nonempty (strings, value->type_05.var_name);
1135 add_if_nonempty (strings, value->type_05.var_label);
1139 collect_value_mod_strings (strings, value->type_06.value_mod);
1140 add_if_nonempty (strings, value->type_06.local);
1141 add_if_nonempty (strings, value->type_06.id);
1142 add_if_nonempty (strings, value->type_06.c);
1146 collect_value_mod_strings (strings, value->type_else.value_mod);
1147 add_if_nonempty (strings, value->type_else.template);
1148 for (size_t i = 0; i < value->type_else.n_args; i++)
1150 const struct spvlb_argument *a = value->type_else.args[i];
1151 collect_value_strings (strings, a->value);
1152 for (size_t j = 0; j < a->n_values; j++)
1153 collect_value_strings (strings, a->values[j]);
1160 collect_category_strings (struct string_array *strings,
1161 const struct spvlb_category *cat)
1163 collect_value_strings (strings, cat->name);
1165 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1166 collect_category_strings (strings, cat->group->subcategories[i]);
1169 /* Adds all of the characters strings in TABLE to STRINGS. */
1171 collect_spvlb_strings (const struct spvlb_table *table,
1172 struct string_array *strings)
1174 add_if_nonempty (strings, table->ts->notes);
1175 add_if_nonempty (strings, table->ts->table_look);
1176 add_if_nonempty (strings, table->ps->continuation_string);
1178 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1180 for (int i = 0; i < cc->n_ccs; i++)
1181 add_if_nonempty (strings, cc->ccs[i]);
1183 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1184 : table->formats->x3 ? table->formats->x3->y1
1188 add_if_nonempty (strings, y1->command_local);
1189 add_if_nonempty (strings, y1->command);
1190 add_if_nonempty (strings, y1->language);
1191 add_if_nonempty (strings, y1->charset);
1192 add_if_nonempty (strings, y1->locale);
1195 const struct spvlb_x3 *x3 = table->formats->x3;
1198 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1199 add_if_nonempty (strings, x3->dataset);
1200 add_if_nonempty (strings, x3->datafile);
1203 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1205 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1206 collect_value_strings (strings, f->text);
1207 collect_value_strings (strings, f->marker);
1210 collect_value_strings (strings, table->titles->user_title);
1211 collect_value_strings (strings, table->titles->subtype);
1212 collect_value_strings (strings, table->titles->corner_text);
1213 collect_value_strings (strings, table->titles->caption);
1215 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1216 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1218 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1220 const struct spvlb_dimension *d = table->dimensions->dims[i];
1221 collect_value_strings (strings, d->name);
1222 for (size_t j = 0; j < d->n_categories; j++)
1223 collect_category_strings (strings, d->categories[j]);
1226 for (size_t i = 0; i < table->cells->n_cells; i++)
1227 collect_value_strings (strings, table->cells->cells[i]->value);
1230 /* Returns the encoding that TABLE declares to be in use for its strings.
1231 (Watch out, it's not always correct.) */
1233 spvlb_table_get_encoding (const struct spvlb_table *table)
1235 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1236 : table->formats->x3 ? table->formats->x3->y1
1242 const char *dot = strchr (table->formats->locale, '.');
1243 return dot ? dot + 1 : "windows-1252";