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;
422 error = decode_spvlb_font_style (vm->style_pair->font_style,
423 encoding, &out->font_style);
425 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
429 pivot_value_destroy (out);
434 if (vm->template_string
435 && vm->template_string->id
436 && vm->template_string->id[0]
437 && out->type == PIVOT_VALUE_TEMPLATE)
438 out->template.id = to_utf8 (vm->template_string->id, encoding);
445 static char * WARN_UNUSED_RESULT
446 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
447 const char *encoding)
451 struct cell_color fg0, fg1, bg0, bg1;
452 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
454 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
455 if (!error && in->alternate)
456 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
457 if (!error && in->alternate)
458 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
460 enum table_halign halign;
463 error = decode_spvlb_halign (in->halign, &halign);
465 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
466 is good because there's no way to indicate the decimal offset. Just
468 if (!error && halign == TABLE_HALIGN_DECIMAL)
469 halign = TABLE_HALIGN_MIXED;
472 enum table_valign valign;
474 error = decode_spvlb_valign (in->valign, &valign);
479 table_area_style_uninit (out);
480 *out = (struct table_area_style) {
482 .bold = (in->style & 1) != 0,
483 .italic = (in->style & 2) != 0,
484 .underline = in->underline,
485 .fg = { fg0, in->alternate ? fg1 : fg0 },
486 .bg = { bg0, in->alternate ? bg1 : bg0 },
487 .typeface = to_utf8 (in->typeface, encoding),
488 .size = in->size / 1.33,
494 [TABLE_HORZ] = { in->left_margin, in->right_margin },
495 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
502 static char * WARN_UNUSED_RESULT
503 decode_spvlb_group (const struct pivot_table *,
504 struct spvlb_category **,
507 struct pivot_category *parent,
508 struct pivot_dimension *,
509 const char *encoding);
511 static char * WARN_UNUSED_RESULT
512 decode_spvlb_categories (const struct pivot_table *table,
513 struct spvlb_category **categories,
515 struct pivot_category *parent,
516 struct pivot_dimension *dimension,
517 const char *encoding)
519 for (size_t i = 0; i < n_categories; i++)
521 const struct spvlb_category *in = categories[i];
522 if (in->group && in->group->merge)
524 char *error = decode_spvlb_categories (
525 table, in->group->subcategories, in->group->n_subcategories,
526 parent, dimension, encoding);
533 struct pivot_value *name;
534 char *error = decode_spvlb_value (table, in->name, encoding, &name);
538 struct pivot_category *out = xzalloc (sizeof *out);
540 out->parent = parent;
541 out->dimension = dimension;
544 char *error = decode_spvlb_group (table, in->group->subcategories,
545 in->group->n_subcategories,
546 true, out, dimension, encoding);
549 pivot_category_destroy (out);
553 out->data_index = SIZE_MAX;
554 out->presentation_index = SIZE_MAX;
558 out->data_index = in->leaf->leaf_index;
559 out->presentation_index = dimension->n_leaves;
560 dimension->n_leaves++;
563 if (parent->n_subs >= parent->allocated_subs)
564 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
565 sizeof *parent->subs);
566 parent->subs[parent->n_subs++] = out;
571 static char * WARN_UNUSED_RESULT
572 decode_spvlb_group (const struct pivot_table *table,
573 struct spvlb_category **categories,
574 size_t n_categories, bool show_label,
575 struct pivot_category *category,
576 struct pivot_dimension *dimension,
577 const char *encoding)
579 category->subs = XCALLOC (n_categories, struct pivot_category *);
580 category->n_subs = 0;
581 category->allocated_subs = 0;
582 category->show_label = show_label;
584 return decode_spvlb_categories (table, categories, n_categories, category,
585 dimension, encoding);
588 static char * WARN_UNUSED_RESULT
589 fill_leaves (struct pivot_category *category,
590 struct pivot_dimension *dimension)
592 if (pivot_category_is_group (category))
594 for (size_t i = 0; i < category->n_subs; i++)
596 char *error = fill_leaves (category->subs[i], dimension);
603 if (category->data_index >= dimension->n_leaves)
604 return xasprintf ("leaf_index %zu >= n_leaves %zu",
605 category->data_index, dimension->n_leaves);
606 if (dimension->data_leaves[category->data_index])
607 return xasprintf ("two leaves with data_index %zu",
608 category->data_index);
609 dimension->data_leaves[category->data_index] = category;
610 dimension->presentation_leaves[category->presentation_index] = category;
615 static char * WARN_UNUSED_RESULT
616 decode_spvlb_dimension (const struct pivot_table *table,
617 const struct spvlb_dimension *in,
618 size_t idx, const char *encoding,
619 struct pivot_dimension **outp)
621 /* Convert most of the dimension. */
622 struct pivot_value *name;
623 char *error = decode_spvlb_value (table, in->name, encoding, &name);
627 struct pivot_dimension *out = xzalloc (sizeof *out);
628 out->level = UINT_MAX;
629 out->top_index = idx;
630 out->hide_all_labels = in->props->hide_all_labels;
632 out->root = xzalloc (sizeof *out->root);
633 *out->root = (struct pivot_category) {
636 .data_index = SIZE_MAX,
637 .presentation_index = SIZE_MAX,
639 error = decode_spvlb_group (table, in->categories, in->n_categories,
640 !in->props->hide_dim_label, out->root,
645 /* Allocate and fill the array of leaves now that we know how many there
647 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
648 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
649 out->allocated_leaves = out->n_leaves;
650 error = fill_leaves (out->root, out);
653 for (size_t i = 0; i < out->n_leaves; i++)
655 assert (out->data_leaves[i] != NULL);
656 assert (out->presentation_leaves[i] != NULL);
662 pivot_dimension_destroy (out);
666 static char * WARN_UNUSED_RESULT
667 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
669 enum table_stroke strokes[] = {
678 if (stroke_type >= sizeof strokes / sizeof *strokes)
679 return xasprintf ("bad stroke %"PRIu32, stroke_type);
681 *strokep = strokes[stroke_type];
685 static char * WARN_UNUSED_RESULT
686 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
689 if (in->border_type >= PIVOT_N_BORDERS)
690 return xasprintf ("bad border type %"PRIu32, in->border_type);
692 struct table_border_style *out = &table->look->borders[in->border_type];
693 out->color = decode_spvlb_color_u32 (in->color);
694 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
697 static char * WARN_UNUSED_RESULT
698 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
699 enum pivot_axis_type axis_type, struct pivot_table *table)
701 struct pivot_axis *axis = &table->axes[axis_type];
702 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
703 axis->n_dimensions = n_dimensions;
705 for (size_t i = 0; i < n_dimensions; i++)
707 uint32_t idx = dimension_indexes[i];
708 if (idx >= table->n_dimensions)
709 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
710 idx, table->n_dimensions);
712 struct pivot_dimension *d = table->dimensions[idx];
713 if (d->level != UINT_MAX)
714 return xasprintf ("duplicate dimension %"PRIu32, idx);
716 axis->dimensions[i] = d;
717 d->axis_type = axis_type;
720 axis->extent *= d->n_leaves;
727 decode_data_index (uint64_t in, const struct pivot_table *table,
730 uint64_t remainder = in;
731 for (size_t i = table->n_dimensions - 1; i > 0; i--)
733 const struct pivot_dimension *d = table->dimensions[i];
736 out[i] = remainder % d->n_leaves;
737 remainder /= d->n_leaves;
742 if (remainder >= table->dimensions[0]->n_leaves)
743 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";