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);
310 vm = in->type_02.value_mod;
311 out->type = PIVOT_VALUE_NUMERIC;
312 out->numeric.x = in->type_02.x;
313 error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
315 error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
318 out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
320 out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
325 vm = in->type_03.value_mod;
326 out->type = PIVOT_VALUE_TEXT;
327 out->text.local = to_utf8 (in->type_03.local, encoding);
328 out->text.c = to_utf8 (in->type_03.c, encoding);
329 out->text.id = to_utf8 (in->type_03.id, encoding);
330 out->text.user_provided = !in->type_03.fixed;
334 vm = in->type_04.value_mod;
335 out->type = PIVOT_VALUE_STRING;
336 error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
339 out->string.s = to_utf8 (in->type_04.s, encoding);
340 out->string.hex = (in->type_04.format >> 16) == fmt_to_io (FMT_AHEX);
341 out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
342 out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
347 vm = in->type_05.value_mod;
348 out->type = PIVOT_VALUE_VARIABLE;
349 error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
352 out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
353 out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
358 vm = in->type_06.value_mod;
359 out->type = PIVOT_VALUE_TEXT;
360 out->text.local = to_utf8 (in->type_06.local, encoding);
361 out->text.c = to_utf8 (in->type_06.c, encoding);
362 out->text.id = to_utf8 (in->type_06.id, encoding);
363 out->text.user_provided = false;
367 vm = in->type_else.value_mod;
368 out->type = PIVOT_VALUE_TEMPLATE;
369 out->template.local = to_utf8 (in->type_else.template, encoding);
370 out->template.id = out->template.local;
371 out->template.n_args = 0;
372 out->template.args = xnmalloc (in->type_else.n_args,
373 sizeof *out->template.args);
374 for (size_t i = 0; i < in->type_else.n_args; i++)
376 error = decode_spvlb_argument (table, in->type_else.args[i],
377 encoding, &out->template.args[i]);
380 pivot_value_destroy (out);
383 out->template.n_args++;
393 if (vm->n_subscripts)
395 out->n_subscripts = vm->n_subscripts;
396 out->subscripts = xnmalloc (vm->n_subscripts,
397 sizeof *out->subscripts);
398 for (size_t i = 0; i < vm->n_subscripts; i++)
399 out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
404 out->footnote_indexes = xnmalloc (vm->n_refs,
405 sizeof *out->footnote_indexes);
406 for (size_t i = 0; i < vm->n_refs; i++)
408 uint16_t idx = vm->refs[i];
409 if (idx >= table->n_footnotes)
411 pivot_value_destroy (out);
412 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
413 idx, table->n_footnotes);
416 out->footnote_indexes[out->n_footnotes++] = idx;
418 pivot_value_sort_footnotes (out);
423 error = decode_spvlb_font_style (vm->style_pair->font_style,
424 encoding, &out->font_style);
426 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
430 pivot_value_destroy (out);
435 if (vm->template_string
436 && vm->template_string->id
437 && vm->template_string->id[0]
438 && out->type == PIVOT_VALUE_TEMPLATE)
439 out->template.id = to_utf8 (vm->template_string->id, encoding);
446 static char * WARN_UNUSED_RESULT
447 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
448 const char *encoding)
452 struct cell_color fg0, fg1, bg0, bg1;
453 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
455 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
456 if (!error && in->alternate)
457 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
458 if (!error && in->alternate)
459 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
461 enum table_halign halign;
464 error = decode_spvlb_halign (in->halign, &halign);
466 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
467 is good because there's no way to indicate the decimal offset. Just
469 if (!error && halign == TABLE_HALIGN_DECIMAL)
470 halign = TABLE_HALIGN_MIXED;
473 enum table_valign valign;
475 error = decode_spvlb_valign (in->valign, &valign);
480 table_area_style_uninit (out);
481 *out = (struct table_area_style) {
483 .bold = (in->style & 1) != 0,
484 .italic = (in->style & 2) != 0,
485 .underline = in->underline,
486 .fg = { fg0, in->alternate ? fg1 : fg0 },
487 .bg = { bg0, in->alternate ? bg1 : bg0 },
488 .typeface = to_utf8 (in->typeface, encoding),
489 .size = in->size / 1.33,
495 [TABLE_HORZ] = { in->left_margin, in->right_margin },
496 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
503 static char * WARN_UNUSED_RESULT
504 decode_spvlb_group (const struct pivot_table *,
505 struct spvlb_category **,
508 struct pivot_category *parent,
509 struct pivot_dimension *,
510 const char *encoding);
512 static char * WARN_UNUSED_RESULT
513 decode_spvlb_categories (const struct pivot_table *table,
514 struct spvlb_category **categories,
516 struct pivot_category *parent,
517 struct pivot_dimension *dimension,
518 const char *encoding)
520 for (size_t i = 0; i < n_categories; i++)
522 const struct spvlb_category *in = categories[i];
523 if (in->group && in->group->merge)
525 char *error = decode_spvlb_categories (
526 table, in->group->subcategories, in->group->n_subcategories,
527 parent, dimension, encoding);
534 struct pivot_value *name;
535 char *error = decode_spvlb_value (table, in->name, encoding, &name);
539 struct pivot_category *out = xzalloc (sizeof *out);
541 out->parent = parent;
542 out->dimension = dimension;
545 char *error = decode_spvlb_group (table, in->group->subcategories,
546 in->group->n_subcategories,
547 true, out, dimension, encoding);
550 pivot_category_destroy (out);
554 out->data_index = SIZE_MAX;
555 out->presentation_index = SIZE_MAX;
559 out->data_index = in->leaf->leaf_index;
560 out->presentation_index = dimension->n_leaves;
561 dimension->n_leaves++;
564 if (parent->n_subs >= parent->allocated_subs)
565 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
566 sizeof *parent->subs);
567 parent->subs[parent->n_subs++] = out;
572 static char * WARN_UNUSED_RESULT
573 decode_spvlb_group (const struct pivot_table *table,
574 struct spvlb_category **categories,
575 size_t n_categories, bool show_label,
576 struct pivot_category *category,
577 struct pivot_dimension *dimension,
578 const char *encoding)
580 category->subs = XCALLOC (n_categories, struct pivot_category *);
581 category->n_subs = 0;
582 category->allocated_subs = 0;
583 category->show_label = show_label;
585 return decode_spvlb_categories (table, categories, n_categories, category,
586 dimension, encoding);
589 static char * WARN_UNUSED_RESULT
590 fill_leaves (struct pivot_category *category,
591 struct pivot_dimension *dimension)
593 if (pivot_category_is_group (category))
595 for (size_t i = 0; i < category->n_subs; i++)
597 char *error = fill_leaves (category->subs[i], dimension);
604 if (category->data_index >= dimension->n_leaves)
605 return xasprintf ("leaf_index %zu >= n_leaves %zu",
606 category->data_index, dimension->n_leaves);
607 if (dimension->data_leaves[category->data_index])
608 return xasprintf ("two leaves with data_index %zu",
609 category->data_index);
610 dimension->data_leaves[category->data_index] = category;
611 dimension->presentation_leaves[category->presentation_index] = category;
616 static char * WARN_UNUSED_RESULT
617 decode_spvlb_dimension (const struct pivot_table *table,
618 const struct spvlb_dimension *in,
619 size_t idx, const char *encoding,
620 struct pivot_dimension **outp)
622 /* Convert most of the dimension. */
623 struct pivot_value *name;
624 char *error = decode_spvlb_value (table, in->name, encoding, &name);
628 struct pivot_dimension *out = xzalloc (sizeof *out);
629 out->level = UINT_MAX;
630 out->top_index = idx;
631 out->hide_all_labels = in->props->hide_all_labels;
633 out->root = xzalloc (sizeof *out->root);
634 *out->root = (struct pivot_category) {
637 .data_index = SIZE_MAX,
638 .presentation_index = SIZE_MAX,
640 error = decode_spvlb_group (table, in->categories, in->n_categories,
641 !in->props->hide_dim_label, out->root,
646 /* Allocate and fill the array of leaves now that we know how many there
648 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
649 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
650 out->allocated_leaves = out->n_leaves;
651 error = fill_leaves (out->root, out);
654 for (size_t i = 0; i < out->n_leaves; i++)
656 assert (out->data_leaves[i] != NULL);
657 assert (out->presentation_leaves[i] != NULL);
663 pivot_dimension_destroy (out);
667 static char * WARN_UNUSED_RESULT
668 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
670 enum table_stroke strokes[] = {
679 if (stroke_type >= sizeof strokes / sizeof *strokes)
680 return xasprintf ("bad stroke %"PRIu32, stroke_type);
682 *strokep = strokes[stroke_type];
686 static char * WARN_UNUSED_RESULT
687 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
690 if (in->border_type >= PIVOT_N_BORDERS)
691 return xasprintf ("bad border type %"PRIu32, in->border_type);
693 struct table_border_style *out = &table->look->borders[in->border_type];
694 out->color = decode_spvlb_color_u32 (in->color);
695 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
698 static char * WARN_UNUSED_RESULT
699 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
700 enum pivot_axis_type axis_type, struct pivot_table *table)
702 struct pivot_axis *axis = &table->axes[axis_type];
703 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
704 axis->n_dimensions = n_dimensions;
706 for (size_t i = 0; i < n_dimensions; i++)
708 uint32_t idx = dimension_indexes[i];
709 if (idx >= table->n_dimensions)
710 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
711 idx, table->n_dimensions);
713 struct pivot_dimension *d = table->dimensions[idx];
714 if (d->level != UINT_MAX)
715 return xasprintf ("duplicate dimension %"PRIu32, idx);
717 axis->dimensions[i] = d;
718 d->axis_type = axis_type;
721 axis->extent *= d->n_leaves;
728 decode_data_index (uint64_t in, const struct pivot_table *table,
731 uint64_t remainder = in;
732 for (size_t i = table->n_dimensions - 1; i < table->n_dimensions; i--)
734 const struct pivot_dimension *d = table->dimensions[i];
737 out[i] = remainder % d->n_leaves;
738 remainder /= d->n_leaves;
744 return xasprintf ("out of range cell data index %"PRIu64, in);
749 static char * WARN_UNUSED_RESULT
750 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
751 struct pivot_table *table, const char *encoding)
753 if (!table->n_dimensions)
756 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
757 for (size_t i = 0; i < n_in; i++)
759 struct pivot_value *value;
760 char *error = decode_data_index (in[i]->index, table, dindexes);
762 error = decode_spvlb_value (table, in[i]->value, encoding, &value);
768 pivot_table_put (table, dindexes, table->n_dimensions, value);
775 static char * WARN_UNUSED_RESULT
776 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
777 size_t idx, struct pivot_table *table)
779 struct pivot_value *content;
780 char *error = decode_spvlb_value (table, in->text, encoding, &content);
784 struct pivot_value *marker = NULL;
787 error = decode_spvlb_value (table, in->marker, encoding, &marker);
790 pivot_value_destroy (content);
793 if (marker->type == PIVOT_VALUE_TEXT)
794 marker->text.user_provided = false;
797 struct pivot_footnote *f = pivot_table_create_footnote__ (
798 table, idx, marker, content);
799 f->show = (int32_t) in->show > 0;
803 static char * WARN_UNUSED_RESULT
804 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
806 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
807 table->current_layer = xnmalloc (axis->n_dimensions,
808 sizeof *table->current_layer);
810 for (size_t i = 0; i < axis->n_dimensions; i++)
812 const struct pivot_dimension *d = axis->dimensions[i];
815 table->current_layer[i] = current_layer % d->n_leaves;
816 current_layer /= d->n_leaves;
819 table->current_layer[i] = 0;
821 if (current_layer > 0)
822 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
826 char * WARN_UNUSED_RESULT
827 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
830 if (in->header->version != 1 && in->header->version != 3)
831 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
832 in->header->version);
835 struct pivot_table *out = xzalloc (sizeof *out);
837 hmap_init (&out->cells);
838 out->look = pivot_table_look_new_builtin_default ();
839 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
841 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
842 : in->formats->x3 ? in->formats->x3->y1
844 const char *encoding = spvlb_table_get_encoding (in);
846 /* Display settings. */
847 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
848 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
849 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
850 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
851 out->show_grid_lines = in->borders->show_grid_lines;
852 out->show_title = true;
853 out->show_caption = true;
854 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
855 out->look->omit_empty = in->ts->omit_empty;
857 const struct spvlb_x1 *x1 = in->formats->x1;
860 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
862 error = decode_spvlb_value_show (x1->show_variables,
863 &out->show_variables);
867 out->show_caption = x1->show_caption;
868 out->show_title = x1->show_title != 10;
871 /* Column and row display settings. */
872 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
873 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
874 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
875 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
877 convert_widths (in->formats->widths, in->formats->n_widths,
878 &out->sizing[TABLE_HORZ].widths,
879 &out->sizing[TABLE_HORZ].n_widths);
881 const struct spvlb_x2 *x2 = in->formats->x2;
883 convert_widths (x2->row_heights, x2->n_row_heights,
884 &out->sizing[TABLE_VERT].widths,
885 &out->sizing[TABLE_VERT].n_widths);
887 convert_breakpoints (in->ts->row_breaks,
888 &out->sizing[TABLE_VERT].breaks,
889 &out->sizing[TABLE_VERT].n_breaks);
890 convert_breakpoints (in->ts->col_breaks,
891 &out->sizing[TABLE_HORZ].breaks,
892 &out->sizing[TABLE_HORZ].n_breaks);
894 convert_keeps (in->ts->row_keeps,
895 &out->sizing[TABLE_VERT].keeps,
896 &out->sizing[TABLE_VERT].n_keeps);
897 convert_keeps (in->ts->col_keeps,
898 &out->sizing[TABLE_HORZ].keeps,
899 &out->sizing[TABLE_HORZ].n_keeps);
901 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
902 out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
904 /* Print settings. */
905 out->look->print_all_layers = in->ps->all_layers;
906 out->look->paginate_layers = in->ps->paginate_layers;
907 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
908 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
909 out->look->top_continuation = in->ps->top_continuation;
910 out->look->bottom_continuation = in->ps->bottom_continuation;
911 out->look->continuation = to_utf8 (in->ps->continuation_string, encoding);
912 out->look->n_orphan_lines = in->ps->n_orphan_lines;
914 /* Format settings. */
915 int epoch = in->formats->y0->epoch;
916 if (epoch >= 1000 && epoch <= 9999)
917 out->settings.epoch = epoch;
918 char decimal = in->formats->y0->decimal;
919 if (decimal == '.' || decimal == '.')
920 out->settings.decimal = decimal;
923 /* XXX warn about bad decimal point */
925 out->grouping = in->formats->y0->grouping;
926 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
927 for (int i = 0; i < 5; i++)
929 if (cc && i < cc->n_ccs)
931 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
932 /* XXX warn if parsing fails */
935 out->small = in->formats->x3 ? in->formats->x3->small : 0;
937 /* Command information. */
940 out->command_local = to_utf8 (y1->command_local, encoding);
941 out->command_c = to_utf8 (y1->command, encoding);
942 out->language = to_utf8 (y1->language, encoding);
944 out->locale = to_utf8 (y1->locale, encoding);
947 /* Source information. */
948 const struct spvlb_x3 *x3 = in->formats->x3;
951 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
952 out->dataset = to_utf8 (x3->dataset, encoding);
953 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
954 out->date = x3->date;
959 Any pivot_value might refer to footnotes, so it's important to process the
960 footnotes early to ensure that those references can be resolved. There is
961 a possible problem that a footnote might itself reference an
962 as-yet-unprocessed footnote, but that's OK because footnote references
963 don't actually look at the footnote contents but only resolve a pointer to
964 where the footnote will go later.
966 Before we really start, create all the footnotes we'll fill in. This is
967 because sometimes footnotes refer to themselves or to each other and we
968 don't want to reject those references. */
969 const struct spvlb_footnotes *fn = in->footnotes;
970 if (fn->n_footnotes > 0)
972 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
973 for (size_t i = 0; i < fn->n_footnotes; i++)
975 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
982 /* Title and caption. */
983 error = decode_spvlb_value (out, in->titles->user_title, encoding,
988 error = decode_spvlb_value (out, in->titles->subtype, encoding,
993 if (in->titles->corner_text)
995 error = decode_spvlb_value (out, in->titles->corner_text,
996 encoding, &out->corner_text);
1001 if (in->titles->caption)
1003 error = decode_spvlb_value (out, in->titles->caption, encoding,
1011 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1013 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
1018 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1020 error = decode_spvlb_border (in->borders->borders[i], out);
1026 out->n_dimensions = in->dimensions->n_dims;
1027 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1028 for (size_t i = 0; i < out->n_dimensions; i++)
1030 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1031 i, encoding, &out->dimensions[i]);
1037 size_t a = in->axes->n_layers;
1038 size_t b = in->axes->n_rows;
1039 size_t c = in->axes->n_columns;
1040 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1042 error = xasprintf ("dimensions do not sum correctly "
1043 "(%zu + %zu + %zu != %zu)",
1044 a, b, c, out->n_dimensions);
1047 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1048 PIVOT_AXIS_LAYER, out);
1051 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1052 PIVOT_AXIS_ROW, out);
1055 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1056 PIVOT_AXIS_COLUMN, out);
1060 pivot_table_assign_label_depth (out);
1062 error = decode_current_layer (in->ts->current_layer, out);
1067 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1074 pivot_table_unref (out);
1078 /* collect_spvlb_strings */
1081 add_if_nonempty (struct string_array *strings, const char *s)
1084 string_array_append (strings, s);
1088 collect_value_mod_strings (struct string_array *strings,
1089 const struct spvlb_value_mod *vm)
1091 if (vm->template_string)
1092 add_if_nonempty (strings, vm->template_string->id);
1094 if (vm->style_pair && vm->style_pair->font_style)
1095 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1099 collect_value_strings (struct string_array *strings,
1100 const struct spvlb_value *value)
1105 switch (value->type)
1108 collect_value_mod_strings (strings, value->type_01.value_mod);
1112 collect_value_mod_strings (strings, value->type_02.value_mod);
1113 add_if_nonempty (strings, value->type_02.var_name);
1114 add_if_nonempty (strings, value->type_02.value_label);
1118 collect_value_mod_strings (strings, value->type_03.value_mod);
1119 add_if_nonempty (strings, value->type_03.local);
1120 add_if_nonempty (strings, value->type_03.id);
1121 add_if_nonempty (strings, value->type_03.c);
1125 collect_value_mod_strings (strings, value->type_04.value_mod);
1126 add_if_nonempty (strings, value->type_04.value_label);
1127 add_if_nonempty (strings, value->type_04.var_name);
1128 add_if_nonempty (strings, value->type_04.s);
1132 collect_value_mod_strings (strings, value->type_05.value_mod);
1133 add_if_nonempty (strings, value->type_05.var_name);
1134 add_if_nonempty (strings, value->type_05.var_label);
1138 collect_value_mod_strings (strings, value->type_06.value_mod);
1139 add_if_nonempty (strings, value->type_06.local);
1140 add_if_nonempty (strings, value->type_06.id);
1141 add_if_nonempty (strings, value->type_06.c);
1145 collect_value_mod_strings (strings, value->type_else.value_mod);
1146 add_if_nonempty (strings, value->type_else.template);
1147 for (size_t i = 0; i < value->type_else.n_args; i++)
1149 const struct spvlb_argument *a = value->type_else.args[i];
1150 collect_value_strings (strings, a->value);
1151 for (size_t j = 0; j < a->n_values; j++)
1152 collect_value_strings (strings, a->values[j]);
1159 collect_category_strings (struct string_array *strings,
1160 const struct spvlb_category *cat)
1162 collect_value_strings (strings, cat->name);
1164 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1165 collect_category_strings (strings, cat->group->subcategories[i]);
1168 /* Adds all of the characters strings in TABLE to STRINGS. */
1170 collect_spvlb_strings (const struct spvlb_table *table,
1171 struct string_array *strings)
1173 add_if_nonempty (strings, table->ts->notes);
1174 add_if_nonempty (strings, table->ts->table_look);
1175 add_if_nonempty (strings, table->ps->continuation_string);
1177 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1179 for (int i = 0; i < cc->n_ccs; i++)
1180 add_if_nonempty (strings, cc->ccs[i]);
1182 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1183 : table->formats->x3 ? table->formats->x3->y1
1187 add_if_nonempty (strings, y1->command_local);
1188 add_if_nonempty (strings, y1->command);
1189 add_if_nonempty (strings, y1->language);
1190 add_if_nonempty (strings, y1->charset);
1191 add_if_nonempty (strings, y1->locale);
1194 const struct spvlb_x3 *x3 = table->formats->x3;
1197 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1198 add_if_nonempty (strings, x3->dataset);
1199 add_if_nonempty (strings, x3->datafile);
1202 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1204 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1205 collect_value_strings (strings, f->text);
1206 collect_value_strings (strings, f->marker);
1209 collect_value_strings (strings, table->titles->user_title);
1210 collect_value_strings (strings, table->titles->subtype);
1211 collect_value_strings (strings, table->titles->corner_text);
1212 collect_value_strings (strings, table->titles->caption);
1214 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1215 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1217 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1219 const struct spvlb_dimension *d = table->dimensions->dims[i];
1220 collect_value_strings (strings, d->name);
1221 for (size_t j = 0; j < d->n_categories; j++)
1222 collect_category_strings (strings, d->categories[j]);
1225 for (size_t i = 0; i < table->cells->n_cells; i++)
1226 collect_value_strings (strings, table->cells->cells[i]->value);
1229 /* Returns the encoding that TABLE declares to be in use for its strings.
1230 (Watch out, it's not always correct.) */
1232 spvlb_table_get_encoding (const struct spvlb_table *table)
1234 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1235 : table->formats->x3 ? table->formats->x3->y1
1241 const char *dot = strchr (table->formats->locale, '.');
1242 return dot ? dot + 1 : "windows-1252";