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 uint64_t remainder = current_layer;
812 for (size_t i = 0; i < axis->n_dimensions; i++)
814 const struct pivot_dimension *d = axis->dimensions[i];
817 table->current_layer[i] = remainder % d->n_leaves;
818 remainder /= d->n_leaves;
821 table->current_layer[i] = 0;
824 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
829 char * WARN_UNUSED_RESULT
830 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
833 if (in->header->version != 1 && in->header->version != 3)
834 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
835 in->header->version);
838 struct pivot_table *out = xzalloc (sizeof *out);
840 hmap_init (&out->cells);
841 out->look = pivot_table_look_new_builtin_default ();
842 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
844 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
845 : in->formats->x3 ? in->formats->x3->y1
847 const char *encoding = spvlb_table_get_encoding (in);
849 /* Display settings. */
850 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
851 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
852 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
853 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
854 out->show_grid_lines = in->borders->show_grid_lines;
855 out->show_title = true;
856 out->show_caption = true;
857 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
858 out->look->omit_empty = in->ts->omit_empty;
860 const struct spvlb_x1 *x1 = in->formats->x1;
863 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
865 error = decode_spvlb_value_show (x1->show_variables,
866 &out->show_variables);
870 out->show_caption = x1->show_caption;
871 out->show_title = x1->show_title != 10;
874 /* Column and row display settings. */
875 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
876 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
877 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
878 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
880 convert_widths (in->formats->widths, in->formats->n_widths,
881 &out->sizing[TABLE_HORZ].widths,
882 &out->sizing[TABLE_HORZ].n_widths);
884 const struct spvlb_x2 *x2 = in->formats->x2;
886 convert_widths (x2->row_heights, x2->n_row_heights,
887 &out->sizing[TABLE_VERT].widths,
888 &out->sizing[TABLE_VERT].n_widths);
890 convert_breakpoints (in->ts->row_breaks,
891 &out->sizing[TABLE_VERT].breaks,
892 &out->sizing[TABLE_VERT].n_breaks);
893 convert_breakpoints (in->ts->col_breaks,
894 &out->sizing[TABLE_HORZ].breaks,
895 &out->sizing[TABLE_HORZ].n_breaks);
897 convert_keeps (in->ts->row_keeps,
898 &out->sizing[TABLE_VERT].keeps,
899 &out->sizing[TABLE_VERT].n_keeps);
900 convert_keeps (in->ts->col_keeps,
901 &out->sizing[TABLE_HORZ].keeps,
902 &out->sizing[TABLE_HORZ].n_keeps);
904 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
905 out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
907 /* Print settings. */
908 out->look->print_all_layers = in->ps->all_layers;
909 out->look->paginate_layers = in->ps->paginate_layers;
910 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
911 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
912 out->look->top_continuation = in->ps->top_continuation;
913 out->look->bottom_continuation = in->ps->bottom_continuation;
914 out->look->continuation = to_utf8 (in->ps->continuation_string, encoding);
915 out->look->n_orphan_lines = in->ps->n_orphan_lines;
917 /* Format settings. */
918 int epoch = in->formats->y0->epoch;
919 if (epoch >= 1000 && epoch <= 9999)
920 out->settings.epoch = epoch;
921 char decimal = in->formats->y0->decimal;
922 if (decimal == '.' || decimal == ',')
923 out->settings.decimal = decimal;
926 /* XXX warn about bad decimal point */
928 out->grouping = in->formats->y0->grouping;
929 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
930 for (int i = 0; i < 5; i++)
932 if (cc && i < cc->n_ccs)
934 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
935 /* XXX warn if parsing fails */
938 out->small = in->formats->x3 ? in->formats->x3->small : 0;
940 /* Command information. */
943 out->command_local = to_utf8 (y1->command_local, encoding);
944 out->command_c = to_utf8 (y1->command, encoding);
945 out->language = to_utf8 (y1->language, encoding);
947 out->locale = to_utf8 (y1->locale, encoding);
950 /* Source information. */
951 const struct spvlb_x3 *x3 = in->formats->x3;
954 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
955 out->dataset = to_utf8 (x3->dataset, encoding);
956 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
957 out->date = x3->date;
962 Any pivot_value might refer to footnotes, so it's important to process the
963 footnotes early to ensure that those references can be resolved. There is
964 a possible problem that a footnote might itself reference an
965 as-yet-unprocessed footnote, but that's OK because footnote references
966 don't actually look at the footnote contents but only resolve a pointer to
967 where the footnote will go later.
969 Before we really start, create all the footnotes we'll fill in. This is
970 because sometimes footnotes refer to themselves or to each other and we
971 don't want to reject those references. */
972 const struct spvlb_footnotes *fn = in->footnotes;
973 if (fn->n_footnotes > 0)
975 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
976 for (size_t i = 0; i < fn->n_footnotes; i++)
978 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
985 /* Title and caption. */
986 error = decode_spvlb_value (out, in->titles->user_title, encoding,
991 error = decode_spvlb_value (out, in->titles->subtype, encoding,
996 if (in->titles->corner_text)
998 error = decode_spvlb_value (out, in->titles->corner_text,
999 encoding, &out->corner_text);
1004 if (in->titles->caption)
1006 error = decode_spvlb_value (out, in->titles->caption, encoding,
1014 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1016 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
1021 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1023 error = decode_spvlb_border (in->borders->borders[i], out);
1029 out->n_dimensions = in->dimensions->n_dims;
1030 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1031 for (size_t i = 0; i < out->n_dimensions; i++)
1033 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1034 i, encoding, &out->dimensions[i]);
1040 size_t a = in->axes->n_layers;
1041 size_t b = in->axes->n_rows;
1042 size_t c = in->axes->n_columns;
1043 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1045 error = xasprintf ("dimensions do not sum correctly "
1046 "(%zu + %zu + %zu != %zu)",
1047 a, b, c, out->n_dimensions);
1050 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1051 PIVOT_AXIS_LAYER, out);
1054 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1055 PIVOT_AXIS_ROW, out);
1058 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1059 PIVOT_AXIS_COLUMN, out);
1063 pivot_table_assign_label_depth (out);
1065 error = decode_current_layer (in->ts->current_layer, out);
1070 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1077 pivot_table_unref (out);
1081 /* collect_spvlb_strings */
1084 add_if_nonempty (struct string_array *strings, const char *s)
1087 string_array_append (strings, s);
1091 collect_value_mod_strings (struct string_array *strings,
1092 const struct spvlb_value_mod *vm)
1094 if (vm->template_string)
1095 add_if_nonempty (strings, vm->template_string->id);
1097 if (vm->style_pair && vm->style_pair->font_style)
1098 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1102 collect_value_strings (struct string_array *strings,
1103 const struct spvlb_value *value)
1108 switch (value->type)
1111 collect_value_mod_strings (strings, value->type_01.value_mod);
1115 collect_value_mod_strings (strings, value->type_02.value_mod);
1116 add_if_nonempty (strings, value->type_02.var_name);
1117 add_if_nonempty (strings, value->type_02.value_label);
1121 collect_value_mod_strings (strings, value->type_03.value_mod);
1122 add_if_nonempty (strings, value->type_03.local);
1123 add_if_nonempty (strings, value->type_03.id);
1124 add_if_nonempty (strings, value->type_03.c);
1128 collect_value_mod_strings (strings, value->type_04.value_mod);
1129 add_if_nonempty (strings, value->type_04.value_label);
1130 add_if_nonempty (strings, value->type_04.var_name);
1131 add_if_nonempty (strings, value->type_04.s);
1135 collect_value_mod_strings (strings, value->type_05.value_mod);
1136 add_if_nonempty (strings, value->type_05.var_name);
1137 add_if_nonempty (strings, value->type_05.var_label);
1141 collect_value_mod_strings (strings, value->type_06.value_mod);
1142 add_if_nonempty (strings, value->type_06.local);
1143 add_if_nonempty (strings, value->type_06.id);
1144 add_if_nonempty (strings, value->type_06.c);
1148 collect_value_mod_strings (strings, value->type_else.value_mod);
1149 add_if_nonempty (strings, value->type_else.template);
1150 for (size_t i = 0; i < value->type_else.n_args; i++)
1152 const struct spvlb_argument *a = value->type_else.args[i];
1153 collect_value_strings (strings, a->value);
1154 for (size_t j = 0; j < a->n_values; j++)
1155 collect_value_strings (strings, a->values[j]);
1162 collect_category_strings (struct string_array *strings,
1163 const struct spvlb_category *cat)
1165 collect_value_strings (strings, cat->name);
1167 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1168 collect_category_strings (strings, cat->group->subcategories[i]);
1171 /* Adds all of the characters strings in TABLE to STRINGS. */
1173 collect_spvlb_strings (const struct spvlb_table *table,
1174 struct string_array *strings)
1176 add_if_nonempty (strings, table->ts->notes);
1177 add_if_nonempty (strings, table->ts->table_look);
1178 add_if_nonempty (strings, table->ps->continuation_string);
1180 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1182 for (int i = 0; i < cc->n_ccs; i++)
1183 add_if_nonempty (strings, cc->ccs[i]);
1185 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1186 : table->formats->x3 ? table->formats->x3->y1
1190 add_if_nonempty (strings, y1->command_local);
1191 add_if_nonempty (strings, y1->command);
1192 add_if_nonempty (strings, y1->language);
1193 add_if_nonempty (strings, y1->charset);
1194 add_if_nonempty (strings, y1->locale);
1197 const struct spvlb_x3 *x3 = table->formats->x3;
1200 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1201 add_if_nonempty (strings, x3->dataset);
1202 add_if_nonempty (strings, x3->datafile);
1205 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1207 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1208 collect_value_strings (strings, f->text);
1209 collect_value_strings (strings, f->marker);
1212 collect_value_strings (strings, table->titles->user_title);
1213 collect_value_strings (strings, table->titles->subtype);
1214 collect_value_strings (strings, table->titles->corner_text);
1215 collect_value_strings (strings, table->titles->caption);
1217 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1218 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1220 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1222 const struct spvlb_dimension *d = table->dimensions->dims[i];
1223 collect_value_strings (strings, d->name);
1224 for (size_t j = 0; j < d->n_categories; j++)
1225 collect_category_strings (strings, d->categories[j]);
1228 for (size_t i = 0; i < table->cells->n_cells; i++)
1229 collect_value_strings (strings, table->cells->cells[i]->value);
1232 /* Returns the encoding that TABLE declares to be in use for its strings.
1233 (Watch out, it's not always correct.) */
1235 spvlb_table_get_encoding (const struct spvlb_table *table)
1237 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1238 : table->formats->x3 ? table->formats->x3->y1
1244 const char *dot = strchr (table->formats->locale, '.');
1245 return dot ? dot + 1 : "windows-1252";