X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fspv%2Fspv-light-decoder.c;fp=src%2Foutput%2Fspv%2Fspv-light-decoder.c;h=f8b07d0b087ce35e4c8a8d65760832d7bf65b39d;hb=bcaaee5f0bd21f443c8dcb5f67114e63d43673af;hp=0000000000000000000000000000000000000000;hpb=1abd7f599dd0d773add0a98fa3b612bc15aaf422;p=pspp
diff --git a/src/output/spv/spv-light-decoder.c b/src/output/spv/spv-light-decoder.c
new file mode 100644
index 0000000000..f8b07d0b08
--- /dev/null
+++ b/src/output/spv/spv-light-decoder.c
@@ -0,0 +1,856 @@
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2017, 2018 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#include
+
+#include "output/spv/spv-light-decoder.h"
+
+#include
+#include
+#include
+#include
+
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "output/pivot-table.h"
+#include "output/spv/light-binary-parser.h"
+#include "output/spv/spv.h"
+
+#include "gl/xalloc.h"
+#include "gl/xsize.h"
+
+static char *
+to_utf8 (const char *s, const char *encoding)
+{
+ return recode_string ("UTF-8", encoding, s, strlen (s));
+}
+
+static char *
+to_utf8_if_nonempty (const char *s, const char *encoding)
+{
+ return s && s[0] ? to_utf8 (s, encoding) : NULL;
+}
+
+static void
+convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
+{
+ if (n)
+ {
+ *n_out = n;
+ *out = xnmalloc (n, sizeof **out);
+ for (size_t i = 0; i < n; i++)
+ (*out)[i] = in[i];
+ }
+}
+
+static void
+convert_breakpoints (const struct spvlb_breakpoints *in,
+ size_t **out, size_t *n_out)
+{
+ if (in && in->n_breaks)
+ {
+ *n_out = in->n_breaks;
+ *out = xnmalloc (in->n_breaks, sizeof *out);
+ for (size_t i = 0; i < in->n_breaks; i++)
+ (*out)[i] = in->breaks[i];
+ }
+}
+
+static void
+convert_keeps (const struct spvlb_keeps *in,
+ struct pivot_keep **out, size_t *n_out)
+{
+ if (in && in->n_keeps)
+ {
+ *n_out = in->n_keeps;
+ *out = xnmalloc (*n_out, sizeof **out);
+ for (size_t i = 0; i < *n_out; i++)
+ {
+ (*out)[i].ofs = in->keeps[i]->offset;
+ (*out)[i].n = in->keeps[i]->n;
+ }
+ }
+}
+
+static struct cell_color
+decode_spvlb_color_string (const char *s, uint8_t def)
+{
+ int r, g, b;
+ if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
+ {
+ if (*s)
+ {
+ fprintf (stderr, "bad color %s\n", s);
+ exit (1);
+ }
+ r = g = b = def;
+ }
+ return (struct cell_color) CELL_COLOR (r, g, b);
+}
+
+static struct cell_color
+decode_spvlb_color_u32 (uint32_t x)
+{
+ return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
+}
+
+static struct font_style *
+decode_spvlb_font_style (const struct spvlb_font_style *in,
+ const char *encoding)
+{
+ if (!in)
+ return NULL;
+
+ struct font_style *out = xmalloc (sizeof *out);
+ *out = (struct font_style) {
+ .bold = in->bold,
+ .italic = in->italic,
+ .underline = in->underline,
+ .fg[0] = decode_spvlb_color_string (in->fg_color, 0x00),
+ .bg[0] = decode_spvlb_color_string (in->bg_color, 0xff),
+ .typeface = to_utf8 (in->typeface, encoding),
+ .size = in->size / 1.33,
+ };
+ out->fg[1] = out->fg[0];
+ out->bg[1] = out->bg[0];
+ return out;
+}
+
+static enum table_halign
+decode_spvlb_halign (uint32_t in)
+{
+ switch (in)
+ {
+ case 0:
+ return TABLE_HALIGN_CENTER;
+
+ case 2:
+ return TABLE_HALIGN_LEFT;
+
+ case 4:
+ return TABLE_HALIGN_RIGHT;
+
+ case 6:
+ case 61453:
+ return TABLE_HALIGN_DECIMAL;
+
+ case 0xffffffad:
+ case 64173:
+ return TABLE_HALIGN_MIXED;
+
+ default:
+ fprintf (stderr, "bad cell style halign %"PRIu32"\n", in);
+ exit (1);
+ }
+}
+
+static enum table_valign
+decode_spvlb_valign (uint32_t in)
+{
+ switch (in)
+ {
+ case 0:
+ return TABLE_VALIGN_CENTER;
+
+ case 1:
+ return TABLE_VALIGN_TOP;
+
+ case 3:
+ return TABLE_VALIGN_BOTTOM;
+
+ default:
+ fprintf (stderr, "bad cell style valign %"PRIu32"\n", in);
+ exit (1);
+ }
+}
+
+static struct cell_style *
+decode_spvlb_cell_style (const struct spvlb_cell_style *in)
+{
+ if (!in)
+ return NULL;
+
+ struct cell_style *out = xzalloc (sizeof *out);
+
+ out->halign = decode_spvlb_halign (in->halign);
+ out->valign = decode_spvlb_valign (in->valign);
+ out->decimal_offset = in->decimal_offset;
+ out->margin[TABLE_HORZ][0] = in->left_margin;
+ out->margin[TABLE_HORZ][1] = in->right_margin;
+ out->margin[TABLE_VERT][0] = in->top_margin;
+ out->margin[TABLE_VERT][1] = in->bottom_margin;
+
+ return out;
+}
+
+static struct pivot_value *decode_spvlb_value (const struct pivot_table *,
+ const struct spvlb_value *,
+ const char *encoding);
+
+static void
+decode_spvlb_argument (const struct pivot_table *table,
+ const struct spvlb_argument *in,
+ struct pivot_argument *out,
+ const char *encoding)
+{
+ if (in->value)
+ {
+ out->n = 1;
+ out->values = xmalloc (sizeof *out->values);
+ out->values[0] = decode_spvlb_value (table, in->value, encoding);
+ }
+ else
+ {
+ out->n = in->n_values;
+ out->values = xnmalloc (out->n, sizeof *out->values);
+ for (size_t i = 0; i < out->n; i++)
+ out->values[i] = decode_spvlb_value (table, in->values[i], encoding);
+ }
+}
+
+static enum settings_value_show
+decode_spvlb_value_show (uint8_t in)
+{
+ switch (in)
+ {
+ case 0: return SETTINGS_VALUE_SHOW_DEFAULT;
+ case 1: return SETTINGS_VALUE_SHOW_VALUE;
+ case 2: return SETTINGS_VALUE_SHOW_LABEL;
+ case 3: return SETTINGS_VALUE_SHOW_BOTH;
+ default:
+ fprintf (stderr, "bad value show %"PRIu8"\n", in);
+ exit (1);
+ }
+}
+
+static struct pivot_value *
+decode_spvlb_value (const struct pivot_table *table,
+ const struct spvlb_value *in,
+ const char *encoding)
+{
+ struct pivot_value *out = xzalloc (sizeof *out);
+ const struct spvlb_value_mod *vm;
+
+ switch (in->type)
+ {
+ case 1:
+ vm = in->type_01.value_mod;
+ out->type = PIVOT_VALUE_NUMERIC;
+ out->numeric.x = in->type_01.x;
+ out->numeric.format = spv_decode_fmt_spec (in->type_01.format);
+ break;
+
+ case 2:
+ vm = in->type_02.value_mod;
+ out->type = PIVOT_VALUE_NUMERIC;
+ out->numeric.x = in->type_02.x;
+ out->numeric.format = spv_decode_fmt_spec (in->type_02.format);
+ out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
+ encoding);
+ out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
+ encoding);
+ out->numeric.show = decode_spvlb_value_show (in->type_02.show);
+ break;
+
+ case 3:
+ vm = in->type_03.value_mod;
+ out->type = PIVOT_VALUE_TEXT;
+ out->text.local = to_utf8 (in->type_03.local, encoding);
+ out->text.c = to_utf8 (in->type_03.c, encoding);
+ out->text.id = to_utf8 (in->type_03.id, encoding);
+ out->text.user_provided = !in->type_03.fixed;
+ break;
+
+ case 4:
+ vm = in->type_04.value_mod;
+ out->type = PIVOT_VALUE_STRING;
+ out->string.s = to_utf8 (in->type_04.s, encoding);
+ out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
+ out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
+ encoding);
+ out->string.show = decode_spvlb_value_show (in->type_04.show);
+ break;
+
+ case 5:
+ vm = in->type_05.value_mod;
+ out->type = PIVOT_VALUE_VARIABLE;
+ out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
+ out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
+ encoding);
+ out->variable.show = decode_spvlb_value_show (in->type_05.show);
+ break;
+
+ case 6:
+ vm = in->type_06.value_mod;
+ out->type = PIVOT_VALUE_TEXT;
+ out->text.local = to_utf8 (in->type_06.local, encoding);
+ out->text.c = to_utf8 (in->type_06.c, encoding);
+ out->text.id = to_utf8 (in->type_06.id, encoding);
+ out->text.user_provided = false;
+ break;
+
+ case -1:
+ vm = in->type_else.value_mod;
+ out->type = PIVOT_VALUE_TEMPLATE;
+ out->template.local = to_utf8 (in->type_else.template, encoding);
+ out->template.id = out->template.local;
+ out->template.n_args = in->type_else.n_args;
+ out->template.args = xnmalloc (in->type_else.n_args,
+ sizeof *out->template.args);
+ for (size_t i = 0; i < out->template.n_args; i++)
+ decode_spvlb_argument (table, in->type_else.args[i],
+ &out->template.args[i], encoding);
+ break;
+
+ default:
+ assert (0);
+ }
+
+ if (vm)
+ {
+ if (vm->subscript)
+ out->subscript = to_utf8 (vm->subscript, encoding);
+
+ if (vm->n_refs)
+ {
+ out->footnotes = xnmalloc (vm->n_refs, sizeof *out->footnotes);
+ for (size_t i = 0; i < vm->n_refs; i++)
+ {
+ uint16_t idx = vm->refs[i];
+ if (idx < table->n_footnotes)
+ out->footnotes[out->n_footnotes++] = table->footnotes[idx];
+ else
+ {
+ fprintf (stderr, "bad footnote index: %"PRIu16" >= %zu\n",
+ idx, table->n_footnotes);
+ exit (1);
+ }
+ }
+ }
+
+ if (vm->style_pair)
+ {
+ out->font_style = decode_spvlb_font_style (
+ vm->style_pair->font_style, encoding);
+ out->cell_style = decode_spvlb_cell_style (
+ vm->style_pair->cell_style);
+ }
+
+ if (vm->template_string
+ && vm->template_string->id
+ && vm->template_string->id[0]
+ && out->type == PIVOT_VALUE_TEMPLATE)
+ out->template.id = to_utf8 (vm->template_string->id, encoding);
+ }
+
+ return out;
+}
+
+static void
+decode_spvlb_area (const struct spvlb_area *in, struct area_style *out,
+ const char *encoding)
+{
+ out->font_style.bold = (in->style & 1) != 0;
+ out->font_style.italic = (in->style & 2) != 0;
+ out->font_style.underline = in->underline;
+ out->font_style.fg[0] = decode_spvlb_color_string (in->fg_color, 0x00);
+ out->font_style.bg[0] = decode_spvlb_color_string (in->bg_color, 0xff);
+ out->font_style.typeface = to_utf8 (in->typeface, encoding);
+ out->font_style.size = in->size / 1.33;
+ out->font_style.fg[1] = (in->alternate
+ ? decode_spvlb_color_string (in->alt_fg_color, 0x00)
+ : out->font_style.fg[0]);
+ out->font_style.bg[1] = (in->alternate
+ ? decode_spvlb_color_string (in->alt_bg_color, 0xff)
+ : out->font_style.bg[0]);
+ assert (in->halign != 61453);
+ out->cell_style.halign = decode_spvlb_halign (in->halign);
+ out->cell_style.valign = decode_spvlb_valign (in->valign);
+
+ /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which is
+ good because there's no way to indicate the decimal offset. Just in
+ case: */
+ if (out->cell_style.halign == TABLE_HALIGN_DECIMAL)
+ out->cell_style.halign = TABLE_HALIGN_MIXED;
+
+ out->cell_style.margin[TABLE_HORZ][0] = in->left_margin;
+ out->cell_style.margin[TABLE_HORZ][1] = in->right_margin;
+ out->cell_style.margin[TABLE_VERT][0] = in->top_margin;
+ out->cell_style.margin[TABLE_VERT][1] = in->bottom_margin;
+}
+
+static void decode_spvlb_group (const struct pivot_table *,
+ struct spvlb_category **,
+ size_t n_categories,
+ bool show_label,
+ struct pivot_category *parent,
+ struct pivot_dimension *,
+ const char *encoding);
+
+static void
+decode_spvlb_categories (const struct pivot_table *table,
+ struct spvlb_category **categories,
+ size_t n_categories,
+ struct pivot_category *parent,
+ struct pivot_dimension *dimension,
+ const char *encoding)
+{
+ for (size_t i = 0; i < n_categories; i++)
+ {
+ const struct spvlb_category *in = categories[i];
+ if (in->group && in->group->merge)
+ {
+ decode_spvlb_categories (table, in->group->subcategories,
+ in->group->n_subcategories,
+ parent, dimension, encoding);
+ continue;
+ }
+
+ struct pivot_category *out = xzalloc (sizeof *out);
+ out->name = decode_spvlb_value (table, in->name, encoding);
+ out->parent = parent;
+ out->dimension = dimension;
+ if (in->group)
+ {
+ decode_spvlb_group (table, in->group->subcategories,
+ in->group->n_subcategories,
+ true, out, dimension, encoding);
+ out->data_index = SIZE_MAX;
+ out->presentation_index = SIZE_MAX;
+ }
+ else
+ {
+ out->data_index = in->leaf->leaf_index;
+ out->presentation_index = dimension->n_leaves;
+ dimension->n_leaves++;
+ }
+
+ if (parent->n_subs >= parent->allocated_subs)
+ parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
+ sizeof *parent->subs);
+ parent->subs[parent->n_subs++] = out;
+ }
+}
+
+static void
+decode_spvlb_group (const struct pivot_table *table,
+ struct spvlb_category **categories,
+ size_t n_categories, bool show_label,
+ struct pivot_category *category,
+ struct pivot_dimension *dimension,
+ const char *encoding)
+{
+ category->subs = xcalloc (n_categories, sizeof *category->subs);
+ category->n_subs = 0;
+ category->allocated_subs = 0;
+ category->show_label = show_label;
+
+ decode_spvlb_categories (table, categories, n_categories, category,
+ dimension, encoding);
+}
+
+static void
+fill_leaves (struct pivot_category *category,
+ struct pivot_dimension *dimension)
+{
+ if (pivot_category_is_group (category))
+ {
+ for (size_t i = 0; i < category->n_subs; i++)
+ fill_leaves (category->subs[i], dimension);
+ }
+ else
+ {
+ if (category->data_index >= dimension->n_leaves)
+ {
+ fprintf (stderr, "leaf_index %zu >= n_leaves %zu\n",
+ category->data_index, dimension->n_leaves);
+ exit (1);
+ }
+ if (dimension->data_leaves[category->data_index])
+ {
+ fprintf (stderr, "two leaves with data_index %zu\n",
+ category->data_index);
+ exit (1);
+ }
+ dimension->data_leaves[category->data_index] = category;
+ dimension->presentation_leaves[category->presentation_index] = category;
+ }
+}
+
+static struct pivot_dimension *
+decode_spvlb_dimension (const struct pivot_table *table,
+ const struct spvlb_dimension *in,
+ size_t idx, const char *encoding)
+{
+ /* Convert most of the dimension. */
+ struct pivot_dimension *out = xzalloc (sizeof *out);
+ out->level = UINT_MAX;
+ out->top_index = idx;
+ out->hide_all_labels = in->props->hide_all_labels;
+
+ out->root = xzalloc (sizeof *out->root);
+ *out->root = (struct pivot_category) {
+ .name = decode_spvlb_value (table, in->name, encoding),
+ .dimension = out,
+ .data_index = SIZE_MAX,
+ .presentation_index = SIZE_MAX,
+ };
+ decode_spvlb_group (table, in->categories, in->n_categories,
+ !in->props->hide_dim_label, out->root, out, encoding);
+
+ /* Allocate and fill the array of leaves now that we know how many there
+ are. */
+ out->data_leaves = xcalloc (out->n_leaves, sizeof *out->data_leaves);
+ out->presentation_leaves = xcalloc (out->n_leaves,
+ sizeof *out->presentation_leaves);
+ out->allocated_leaves = out->n_leaves;
+ fill_leaves (out->root, out);
+ for (size_t i = 0; i < out->n_leaves; i++)
+ {
+ assert (out->data_leaves[i] != NULL);
+ assert (out->presentation_leaves[i] != NULL);
+ }
+
+ return out;
+}
+
+static enum table_stroke
+decode_spvlb_stroke (uint32_t stroke_type)
+{
+ switch (stroke_type)
+ {
+ case 0: return TABLE_STROKE_NONE;
+ case 1: return TABLE_STROKE_SOLID;
+ case 2: return TABLE_STROKE_DASHED;
+ case 3: return TABLE_STROKE_THICK;
+ case 4: return TABLE_STROKE_THIN;
+ case 5: return TABLE_STROKE_DOUBLE;
+
+ default:
+ fprintf (stderr, "bad stroke %"PRIu32"\n", stroke_type);
+ exit (1);
+ }
+}
+
+static void
+decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
+
+{
+ if (in->border_type >= PIVOT_N_BORDERS)
+ {
+ fprintf (stderr, "bad border type %"PRIu32"\n", in->border_type);
+ exit (1);
+ }
+
+ struct table_border_style *out = &table->borders[in->border_type];
+ out->stroke = decode_spvlb_stroke (in->stroke_type);
+ out->color = decode_spvlb_color_u32 (in->color);
+}
+
+static void
+decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
+ enum pivot_axis_type axis_type, struct pivot_table *table)
+{
+ struct pivot_axis *axis = &table->axes[axis_type];
+ axis->dimensions = xnmalloc (n_dimensions, sizeof *axis->dimensions);
+ axis->n_dimensions = n_dimensions;
+ axis->extent = 1;
+ for (size_t i = 0; i < n_dimensions; i++)
+ {
+ uint32_t idx = dimension_indexes[i];
+ if (idx >= table->n_dimensions)
+ {
+ fprintf (stderr, "bad dimension index %"PRIu32" >= %zu",
+ idx, table->n_dimensions);
+ exit (1);
+ }
+
+ struct pivot_dimension *d = table->dimensions[idx];
+ if (d->level != UINT_MAX)
+ {
+ fprintf (stderr, "duplicate dimension %"PRIu32, idx);
+ exit (1);
+ }
+
+ axis->dimensions[i] = d;
+ d->axis_type = axis_type;
+ d->level = i;
+
+ axis->extent *= d->n_leaves;
+ }
+}
+
+static void
+decode_data_index (uint64_t in, const struct pivot_table *table,
+ size_t *out)
+{
+ uint64_t remainder = in;
+ for (size_t i = table->n_dimensions - 1; i > 0; i--)
+ {
+ const struct pivot_dimension *d = table->dimensions[i];
+ if (d->n_leaves)
+ {
+ out[i] = remainder % d->n_leaves;
+ remainder /= d->n_leaves;
+ }
+ else
+ out[i] = 0;
+ }
+ if (remainder >= table->dimensions[0]->n_leaves)
+ {
+ fprintf (stderr, "out of range cell data index %"PRIu64, in);
+ exit (1);
+ }
+ out[0] = remainder;
+}
+
+static void
+decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
+ struct pivot_table *table, const char *encoding)
+{
+ if (!table->n_dimensions)
+ return;
+
+ size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
+ for (size_t i = 0; i < n_in; i++)
+ {
+ decode_data_index (in[i]->index, table, dindexes);
+ struct pivot_value *value = decode_spvlb_value (table, in[i]->value,
+ encoding);
+ pivot_table_put (table, dindexes, table->n_dimensions, value);
+ }
+ free (dindexes);
+}
+
+static void
+decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
+ size_t idx, struct pivot_table *table)
+{
+ struct pivot_value *content = decode_spvlb_value (table, in->text, encoding);
+ struct pivot_value *marker = NULL;
+ if (in->marker)
+ {
+ marker = decode_spvlb_value (table, in->marker, encoding);
+ if (marker->type == PIVOT_VALUE_TEXT)
+ marker->text.user_provided = false;
+ }
+ pivot_table_create_footnote__ (table, idx, marker, content);
+}
+
+static void
+decode_current_layer (uint64_t current_layer, struct pivot_table *table)
+{
+ const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
+ table->current_layer = xnmalloc (axis->n_dimensions,
+ sizeof *table->current_layer);
+
+ for (size_t i = 0; i < axis->n_dimensions; i++)
+ {
+ const struct pivot_dimension *d = axis->dimensions[i];
+ if (d->n_leaves)
+ {
+ table->current_layer[i] = current_layer % d->n_leaves;
+ current_layer /= d->n_leaves;
+ }
+ else
+ table->current_layer[i] = 0;
+ }
+ if (current_layer > 0)
+ {
+ fprintf (stderr, "out of range layer data index %"PRIu64, current_layer);
+ exit (1);
+ }
+}
+
+char *
+decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
+{
+ if (in->header->version != 1 && in->header->version != 3)
+ return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
+ in->header->version);
+
+ struct pivot_table *out = xzalloc (sizeof *out);
+ out->ref_cnt = 1;
+ hmap_init (&out->cells);
+
+ const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
+ : in->formats->x3 ? in->formats->x3->y1
+ : NULL);
+ const char *encoding;
+ if (y1)
+ encoding = y1->charset;
+ else
+ {
+ const char *dot = strchr (in->formats->locale, '.');
+ encoding = dot ? dot + 1 : "windows-1252";
+ }
+
+ /* Display settings. */
+ out->show_numeric_markers = !in->ts->show_alphabetic_markers;
+ out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
+ out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
+ out->row_labels_in_corner = in->ts->show_row_labels_in_corner;
+ out->show_grid_lines = in->borders->show_grid_lines;
+ out->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
+ out->omit_empty = in->ts->omit_empty;
+
+ const struct spvlb_x1 *x1 = in->formats->x1;
+ if (x1)
+ {
+ out->show_values = decode_spvlb_value_show (x1->show_values);
+ out->show_variables = decode_spvlb_value_show (x1->show_variables);
+ }
+
+ /* Column and row display settings. */
+ out->sizing[TABLE_VERT].range[0] = in->header->min_row_height;
+ out->sizing[TABLE_VERT].range[1] = in->header->max_row_height;
+ out->sizing[TABLE_HORZ].range[0] = in->header->min_col_width;
+ out->sizing[TABLE_HORZ].range[1] = in->header->max_col_width;
+
+ convert_widths (in->formats->widths, in->formats->n_widths,
+ &out->sizing[TABLE_HORZ].widths,
+ &out->sizing[TABLE_HORZ].n_widths);
+
+ const struct spvlb_x2 *x2 = in->formats->x2;
+ if (x2)
+ convert_widths (x2->row_heights, x2->n_row_heights,
+ &out->sizing[TABLE_VERT].widths,
+ &out->sizing[TABLE_VERT].n_widths);
+
+ convert_breakpoints (in->ts->row_breaks,
+ &out->sizing[TABLE_VERT].breaks,
+ &out->sizing[TABLE_VERT].n_breaks);
+ convert_breakpoints (in->ts->col_breaks,
+ &out->sizing[TABLE_HORZ].breaks,
+ &out->sizing[TABLE_HORZ].n_breaks);
+
+ convert_keeps (in->ts->row_keeps,
+ &out->sizing[TABLE_VERT].keeps,
+ &out->sizing[TABLE_VERT].n_keeps);
+ convert_keeps (in->ts->col_keeps,
+ &out->sizing[TABLE_HORZ].keeps,
+ &out->sizing[TABLE_HORZ].n_keeps);
+
+ out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
+ out->table_look = to_utf8_if_nonempty (in->ts->table_look, encoding);
+
+ /* Print settings. */
+ out->print_all_layers = in->ps->all_layers;
+ out->paginate_layers = in->ps->paginate_layers;
+ out->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
+ out->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
+ out->top_continuation = in->ps->top_continuation;
+ out->bottom_continuation = in->ps->bottom_continuation;
+ out->continuation = xstrdup (in->ps->continuation_string);
+ out->n_orphan_lines = in->ps->n_orphan_lines;
+
+ /* Format settings. */
+ out->epoch = in->formats->y0->epoch;
+ out->decimal = in->formats->y0->decimal;
+ out->grouping = in->formats->y0->grouping;
+ const struct spvlb_custom_currency *cc = in->formats->custom_currency;
+ for (int i = 0; i < 5; i++)
+ if (cc && i < cc->n_ccs)
+ out->ccs[i] = xstrdup (cc->ccs[i]);
+ out->small = in->formats->x3 ? in->formats->x3->small : 0;
+
+ /* Command information. */
+ if (y1)
+ {
+ out->command_local = to_utf8 (y1->command_local, encoding);
+ out->command_c = to_utf8 (y1->command, encoding);
+ out->language = xstrdup (y1->language);
+ /* charset? */
+ out->locale = xstrdup (y1->locale);
+ }
+
+ /* Source information. */
+ const struct spvlb_x3 *x3 = in->formats->x3;
+ if (x3)
+ {
+ if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
+ out->dataset = to_utf8 (x3->dataset, encoding);
+ out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
+ out->date = x3->date;
+ }
+
+ /* Footnotes.
+
+ Any pivot_value might refer to footnotes, so it's important to process the
+ footnotes early to ensure that those references can be resolved. There is
+ a possible problem that a footnote might itself reference an
+ as-yet-unprocessed footnote, but that's OK because footnote references
+ don't actually look at the footnote contents but only resolve a pointer to
+ where the footnote will go later.
+
+ Before we really start, create all the footnotes we'll fill in. This is
+ because sometimes footnotes refer to themselves or to each other and we
+ don't want to reject those references. */
+ const struct spvlb_footnotes *fn = in->footnotes;
+ if (fn->n_footnotes > 0)
+ {
+ pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
+ for (size_t i = 0; i < fn->n_footnotes; i++)
+ decode_spvlb_footnote (in->footnotes->footnotes[i], encoding, i, out);
+ }
+
+ /* Title and caption. */
+ out->title = decode_spvlb_value (out, in->titles->user_title, encoding);
+ out->subtype = decode_spvlb_value (out, in->titles->subtype, encoding);
+ if (in->titles->corner_text)
+ out->corner_text = decode_spvlb_value (out, in->titles->corner_text,
+ encoding);
+ if (in->titles->caption)
+ out->caption = decode_spvlb_value (out, in->titles->caption, encoding);
+
+ /* Styles. */
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ decode_spvlb_area (in->areas->areas[i], &out->areas[i], encoding);
+ for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
+ decode_spvlb_border (in->borders->borders[i], out);
+
+ /* Dimensions. */
+ out->n_dimensions = in->dimensions->n_dims;
+ out->dimensions = xcalloc (out->n_dimensions, sizeof *out->dimensions);
+ for (size_t i = 0; i < out->n_dimensions; i++)
+ out->dimensions[i] = decode_spvlb_dimension (out, in->dimensions->dims[i],
+ i, encoding);
+
+ /* Axes. */
+ size_t a = in->axes->n_layers;
+ size_t b = in->axes->n_rows;
+ size_t c = in->axes->n_columns;
+ if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
+ {
+ fprintf (stderr, "wrong number of dimensions\n");
+ exit (1);
+ }
+ decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
+ PIVOT_AXIS_LAYER, out);
+ decode_spvlb_axis (in->axes->rows, in->axes->n_rows, PIVOT_AXIS_ROW, out);
+ decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
+ PIVOT_AXIS_COLUMN, out);
+
+ pivot_table_assign_label_depth (out);
+
+ decode_current_layer (in->ts->current_layer, out);
+
+ /* Data. */
+ decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out, encoding);
+
+ *outp = out;
+ return NULL;
+}