output: Make table_item a pivot_table, table_cell a pivot_value.
[pspp] / src / output / spv / spv-light-decoder.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2017, 2018 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "output/spv/spv-light-decoder.h"
20
21 #include <inttypes.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "output/pivot-table.h"
29 #include "output/spv/light-binary-parser.h"
30 #include "output/spv/spv.h"
31
32 #include "gl/xalloc.h"
33 #include "gl/xsize.h"
34
35 static char *
36 to_utf8 (const char *s, const char *encoding)
37 {
38   return recode_string ("UTF-8", encoding, s, strlen (s));
39 }
40
41 static char *
42 to_utf8_if_nonempty (const char *s, const char *encoding)
43 {
44   return s && s[0] ? to_utf8 (s, encoding) : NULL;
45 }
46
47 static void
48 convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
49 {
50   if (n)
51     {
52       *n_out = n;
53       *out = xnmalloc (n, sizeof **out);
54       for (size_t i = 0; i < n; i++)
55         (*out)[i] = in[i];
56     }
57 }
58
59 static void
60 convert_breakpoints (const struct spvlb_breakpoints *in,
61                      size_t **out, size_t *n_out)
62 {
63   if (in && in->n_breaks)
64     {
65       *n_out = in->n_breaks;
66       *out = xnmalloc (in->n_breaks, sizeof *out);
67       for (size_t i = 0; i < in->n_breaks; i++)
68         (*out)[i] = in->breaks[i];
69     }
70 }
71
72 static void
73 convert_keeps (const struct spvlb_keeps *in,
74                struct pivot_keep **out, size_t *n_out)
75 {
76   if (in && in->n_keeps)
77     {
78       *n_out = in->n_keeps;
79       *out = xnmalloc (*n_out, sizeof **out);
80       for (size_t i = 0; i < *n_out; i++)
81         {
82           (*out)[i].ofs = in->keeps[i]->offset;
83           (*out)[i].n = in->keeps[i]->n;
84         }
85     }
86 }
87
88 static char * WARN_UNUSED_RESULT
89 decode_spvlb_color_string (const char *s, uint8_t def,
90                            struct cell_color *colorp)
91 {
92   int r, g, b;
93   if (!*s)
94     r = g = b = def;
95   else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
96     return xasprintf ("bad color %s", s);
97
98   *colorp = (struct cell_color) CELL_COLOR (r, g, b);
99   return NULL;
100 }
101
102 static struct cell_color
103 decode_spvlb_color_u32 (uint32_t x)
104 {
105   return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
106 }
107
108 static char * WARN_UNUSED_RESULT
109 decode_spvlb_font_style (const struct spvlb_font_style *in,
110                          const char *encoding, struct font_style **outp)
111 {
112   if (!in)
113     {
114       *outp = NULL;
115       return NULL;
116     }
117
118   struct cell_color fg, bg;
119   char *error = decode_spvlb_color_string (in->fg_color, 0x00, &fg);
120   if (!error)
121     error = decode_spvlb_color_string (in->bg_color, 0xff, &bg);
122   if (error)
123     return error;
124
125   *outp = xmalloc (sizeof **outp);
126   **outp = (struct font_style) {
127     .bold = in->bold,
128     .italic = in->italic,
129     .underline = in->underline,
130     .fg = { fg, fg },
131     .bg = { bg, bg },
132     .typeface = to_utf8 (in->typeface, encoding),
133     .size = in->size / 1.33,
134   };
135   return NULL;
136 }
137
138 static char * WARN_UNUSED_RESULT
139 decode_spvlb_halign (uint32_t in, enum table_halign *halignp)
140 {
141   switch (in)
142     {
143     case 0:
144       *halignp = TABLE_HALIGN_CENTER;
145       return NULL;
146
147     case 2:
148       *halignp = TABLE_HALIGN_LEFT;
149       return NULL;
150
151     case 4:
152       *halignp = TABLE_HALIGN_RIGHT;
153       return NULL;
154
155     case 6:
156     case 61453:
157       *halignp = TABLE_HALIGN_DECIMAL;
158       return NULL;
159
160     case 0xffffffad:
161     case 64173:
162       *halignp = TABLE_HALIGN_MIXED;
163       return NULL;
164
165     default:
166       return xasprintf ("bad cell style halign %"PRIu32, in);
167     }
168 }
169
170 static char * WARN_UNUSED_RESULT
171 decode_spvlb_valign (uint32_t in, enum table_valign *valignp)
172 {
173   switch (in)
174     {
175     case 0:
176       *valignp = TABLE_VALIGN_CENTER;
177       return NULL;
178
179     case 1:
180       *valignp = TABLE_VALIGN_TOP;
181       return NULL;
182
183     case 3:
184       *valignp = TABLE_VALIGN_BOTTOM;
185       return NULL;
186
187     default:
188       *valignp = 0;
189       return xasprintf ("bad cell style valign %"PRIu32, in);
190     }
191 }
192
193 static char * WARN_UNUSED_RESULT
194 decode_spvlb_cell_style (const struct spvlb_cell_style *in,
195                          struct cell_style **outp)
196 {
197   if (!in)
198     {
199       *outp = NULL;
200       return NULL;
201     }
202
203   enum table_halign halign;
204   char *error = decode_spvlb_halign (in->halign, &halign);
205   if (error)
206     return error;
207
208   enum table_valign valign;
209   error = decode_spvlb_valign (in->valign, &valign);
210   if (error)
211     return error;
212
213   *outp = xzalloc (sizeof **outp);
214   **outp = (struct cell_style) {
215     .halign = halign,
216     .valign = valign,
217     .decimal_offset = in->decimal_offset,
218     .margin = {
219       [TABLE_HORZ] = { in->left_margin, in->right_margin },
220       [TABLE_VERT] = { in->top_margin, in->bottom_margin },
221     },
222   };
223   return NULL;
224 }
225
226 static char *decode_spvlb_value (
227   const struct pivot_table *, const struct spvlb_value *,
228   const char *encoding, struct pivot_value **) WARN_UNUSED_RESULT;
229
230 static char * WARN_UNUSED_RESULT
231 decode_spvlb_argument (const struct pivot_table *table,
232                        const struct spvlb_argument *in,
233                        const char *encoding, struct pivot_argument *out)
234 {
235   if (in->value)
236     {
237       struct pivot_value *value;
238       char *error = decode_spvlb_value (table, in->value, encoding, &value);
239       if (error)
240         return error;
241
242       out->n = 1;
243       out->values = xmalloc (sizeof *out->values);
244       out->values[0] = value;
245     }
246   else
247     {
248       out->n = 0;
249       out->values = xnmalloc (in->n_values, sizeof *out->values);
250       for (size_t i = 0; i < in->n_values; i++)
251         {
252           char *error = decode_spvlb_value (table, in->values[i], encoding,
253                                             &out->values[i]);
254           if (error)
255             {
256               pivot_argument_uninit (out);
257               return error;
258             }
259           out->n++;
260         }
261     }
262
263   return NULL;
264 }
265
266 static char * WARN_UNUSED_RESULT
267 decode_spvlb_value_show (uint8_t in, enum settings_value_show *out)
268 {
269   switch (in)
270     {
271     case 0: *out = SETTINGS_VALUE_SHOW_DEFAULT; return NULL;
272     case 1: *out = SETTINGS_VALUE_SHOW_VALUE; return NULL;
273     case 2: *out = SETTINGS_VALUE_SHOW_LABEL; return NULL;
274     case 3: *out = SETTINGS_VALUE_SHOW_BOTH; return NULL;
275     default:
276       return xasprintf ("bad value show %"PRIu8, in);
277     }
278 }
279
280 static char * WARN_UNUSED_RESULT
281 decode_spvlb_value (const struct pivot_table *table,
282                     const struct spvlb_value *in,
283                     const char *encoding, struct pivot_value **outp)
284 {
285   *outp = NULL;
286
287   struct pivot_value *out = xzalloc (sizeof *out);
288   const struct spvlb_value_mod *vm;
289
290   char *error;
291   switch (in->type)
292     {
293     case 1:
294       vm = in->type_01.value_mod;
295       out->type = PIVOT_VALUE_NUMERIC;
296       out->numeric.x = in->type_01.x;
297       error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format);
298       if (error)
299         return error;
300       break;
301
302     case 2:
303       vm = in->type_02.value_mod;
304       out->type = PIVOT_VALUE_NUMERIC;
305       out->numeric.x = in->type_02.x;
306       error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
307       if (!error)
308         error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
309       if (error)
310         return NULL;
311       out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
312                                                    encoding);
313       out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
314                                                       encoding);
315       break;
316
317     case 3:
318       vm = in->type_03.value_mod;
319       out->type = PIVOT_VALUE_TEXT;
320       out->text.local = to_utf8 (in->type_03.local, encoding);
321       out->text.c = to_utf8 (in->type_03.c, encoding);
322       out->text.id = to_utf8 (in->type_03.id, encoding);
323       out->text.user_provided = !in->type_03.fixed;
324       break;
325
326     case 4:
327       vm = in->type_04.value_mod;
328       out->type = PIVOT_VALUE_STRING;
329       error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
330       if (error)
331         return NULL;
332       out->string.s = to_utf8 (in->type_04.s, encoding);
333       out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
334       out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
335                                                      encoding);
336       break;
337
338     case 5:
339       vm = in->type_05.value_mod;
340       out->type = PIVOT_VALUE_VARIABLE;
341       error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
342       if (error)
343         return error;
344       out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
345       out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
346                                                      encoding);
347       break;
348
349     case 6:
350       vm = in->type_06.value_mod;
351       out->type = PIVOT_VALUE_TEXT;
352       out->text.local = to_utf8 (in->type_06.local, encoding);
353       out->text.c = to_utf8 (in->type_06.c, encoding);
354       out->text.id = to_utf8 (in->type_06.id, encoding);
355       out->text.user_provided = false;
356       break;
357
358     case -1:
359       vm = in->type_else.value_mod;
360       out->type = PIVOT_VALUE_TEMPLATE;
361       out->template.local = to_utf8 (in->type_else.template, encoding);
362       out->template.id = out->template.local;
363       out->template.n_args = 0;
364       out->template.args = xnmalloc (in->type_else.n_args,
365                                      sizeof *out->template.args);
366       for (size_t i = 0; i < in->type_else.n_args; i++)
367         {
368           error = decode_spvlb_argument (table, in->type_else.args[i],
369                                          encoding, &out->template.args[i]);
370           if (error)
371             {
372               pivot_value_destroy (out);
373               return error;
374             }
375           out->template.n_args++;
376         }
377       break;
378
379     default:
380       abort ();
381     }
382
383   if (vm)
384     {
385       if (vm->n_subscripts)
386         {
387           out->n_subscripts = vm->n_subscripts;
388           out->subscripts = xnmalloc (vm->n_subscripts,
389                                       sizeof *out->subscripts);
390           for (size_t i = 0; i < vm->n_subscripts; i++)
391             out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
392         }
393
394       if (vm->n_refs)
395         {
396           out->footnote_indexes = xnmalloc (vm->n_refs,
397                                             sizeof *out->footnote_indexes);
398           for (size_t i = 0; i < vm->n_refs; i++)
399             {
400               uint16_t idx = vm->refs[i];
401               if (idx >= table->n_footnotes)
402                 {
403                   pivot_value_destroy (out);
404                   return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
405                                     idx, table->n_footnotes);
406                 }
407
408               out->footnote_indexes[out->n_footnotes++] = idx;
409             }
410         }
411
412       if (vm->style_pair)
413         {
414           error = decode_spvlb_font_style (vm->style_pair->font_style,
415                                            encoding, &out->font_style);
416           if (!error)
417             error = decode_spvlb_cell_style (vm->style_pair->cell_style,
418                                              &out->cell_style);
419           if (error)
420             {
421               pivot_value_destroy (out);
422               return error;
423             }
424         }
425
426       if (vm->template_string
427           && vm->template_string->id
428           && vm->template_string->id[0]
429           && out->type == PIVOT_VALUE_TEMPLATE)
430         out->template.id = to_utf8 (vm->template_string->id, encoding);
431     }
432
433   *outp = out;
434   return NULL;
435 }
436
437 static char * WARN_UNUSED_RESULT
438 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
439                    const char *encoding)
440 {
441   char *error;
442
443   struct cell_color fg0, fg1, bg0, bg1;
444   error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
445   if (!error)
446     error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
447   if (!error && in->alternate)
448     error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
449   if (!error && in->alternate)
450     error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
451
452   enum table_halign halign;
453   if (!error)
454     {
455       error = decode_spvlb_halign (in->halign, &halign);
456
457       /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
458          is good because there's no way to indicate the decimal offset.  Just
459          in case: */
460       if (!error && halign == TABLE_HALIGN_DECIMAL)
461         halign = TABLE_HALIGN_MIXED;
462     }
463
464   enum table_valign valign;
465   if (!error)
466     error = decode_spvlb_valign (in->valign, &valign);
467
468   if (error)
469     return error;
470
471   table_area_style_uninit (out);
472   *out = (struct table_area_style) {
473     .font_style = {
474       .bold = (in->style & 1) != 0,
475       .italic = (in->style & 2) != 0,
476       .underline = in->underline,
477       .fg = { fg0, in->alternate ? fg1 : fg0 },
478       .bg = { bg0, in->alternate ? bg1 : bg0 },
479       .typeface = to_utf8 (in->typeface, encoding),
480       .size = in->size / 1.33,
481     },
482     .cell_style = {
483       .halign = halign,
484       .valign = valign,
485       .margin = {
486         [TABLE_HORZ] = { in->left_margin, in->right_margin },
487         [TABLE_VERT] = { in->top_margin, in->bottom_margin },
488       },
489     },
490   };
491   return NULL;
492 }
493
494 static char * WARN_UNUSED_RESULT
495 decode_spvlb_group (const struct pivot_table *,
496                     struct spvlb_category **,
497                     size_t n_categories,
498                     bool show_label,
499                     struct pivot_category *parent,
500                     struct pivot_dimension *,
501                     const char *encoding);
502
503 static char * WARN_UNUSED_RESULT
504 decode_spvlb_categories (const struct pivot_table *table,
505                          struct spvlb_category **categories,
506                          size_t n_categories,
507                          struct pivot_category *parent,
508                          struct pivot_dimension *dimension,
509                          const char *encoding)
510 {
511   for (size_t i = 0; i < n_categories; i++)
512     {
513       const struct spvlb_category *in = categories[i];
514       if (in->group && in->group->merge)
515         {
516           char *error = decode_spvlb_categories (
517             table, in->group->subcategories, in->group->n_subcategories,
518             parent, dimension, encoding);
519           if (error)
520             return error;
521
522           continue;
523         }
524
525       struct pivot_value *name;
526       char *error = decode_spvlb_value (table, in->name, encoding, &name);
527       if (error)
528         return error;
529
530       struct pivot_category *out = xzalloc (sizeof *out);
531       out->name = name;
532       out->parent = parent;
533       out->dimension = dimension;
534       if (in->group)
535         {
536           char *error = decode_spvlb_group (table, in->group->subcategories,
537                                             in->group->n_subcategories,
538                                             true, out, dimension, encoding);
539           if (error)
540             {
541               pivot_category_destroy (out);
542               return error;
543             }
544
545           out->data_index = SIZE_MAX;
546           out->presentation_index = SIZE_MAX;
547         }
548       else
549         {
550           out->data_index = in->leaf->leaf_index;
551           out->presentation_index = dimension->n_leaves;
552           dimension->n_leaves++;
553         }
554
555       if (parent->n_subs >= parent->allocated_subs)
556         parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
557                                    sizeof *parent->subs);
558       parent->subs[parent->n_subs++] = out;
559     }
560   return NULL;
561 }
562
563 static char * WARN_UNUSED_RESULT
564 decode_spvlb_group (const struct pivot_table *table,
565                     struct spvlb_category **categories,
566                     size_t n_categories, bool show_label,
567                     struct pivot_category *category,
568                     struct pivot_dimension *dimension,
569                     const char *encoding)
570 {
571   category->subs = XCALLOC (n_categories, struct pivot_category *);
572   category->n_subs = 0;
573   category->allocated_subs = 0;
574   category->show_label = show_label;
575
576   return decode_spvlb_categories (table, categories, n_categories, category,
577                                   dimension, encoding);
578 }
579
580 static char * WARN_UNUSED_RESULT
581 fill_leaves (struct pivot_category *category,
582              struct pivot_dimension *dimension)
583 {
584   if (pivot_category_is_group (category))
585     {
586       for (size_t i = 0; i < category->n_subs; i++)
587         {
588           char *error = fill_leaves (category->subs[i], dimension);
589           if (error)
590             return error;
591         }
592     }
593   else
594     {
595       if (category->data_index >= dimension->n_leaves)
596         return xasprintf ("leaf_index %zu >= n_leaves %zu",
597                           category->data_index, dimension->n_leaves);
598       if (dimension->data_leaves[category->data_index])
599         return xasprintf ("two leaves with data_index %zu",
600                           category->data_index);
601       dimension->data_leaves[category->data_index] = category;
602       dimension->presentation_leaves[category->presentation_index] = category;
603     }
604   return NULL;
605 }
606
607 static char * WARN_UNUSED_RESULT
608 decode_spvlb_dimension (const struct pivot_table *table,
609                         const struct spvlb_dimension *in,
610                         size_t idx, const char *encoding,
611                         struct pivot_dimension **outp)
612 {
613   /* Convert most of the dimension. */
614   struct pivot_value *name;
615   char *error = decode_spvlb_value (table, in->name, encoding, &name);
616   if (error)
617     return error;
618
619   struct pivot_dimension *out = xzalloc (sizeof *out);
620   out->level = UINT_MAX;
621   out->top_index = idx;
622   out->hide_all_labels = in->props->hide_all_labels;
623
624   out->root = xzalloc (sizeof *out->root);
625   *out->root = (struct pivot_category) {
626     .name = name,
627     .dimension = out,
628     .data_index = SIZE_MAX,
629     .presentation_index = SIZE_MAX,
630   };
631   error = decode_spvlb_group (table, in->categories, in->n_categories,
632                               !in->props->hide_dim_label, out->root,
633                               out, encoding);
634   if (error)
635     goto error;
636
637   /* Allocate and fill the array of leaves now that we know how many there
638      are. */
639   out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
640   out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
641   out->allocated_leaves = out->n_leaves;
642   error = fill_leaves (out->root, out);
643   if (error)
644     goto error;
645   for (size_t i = 0; i < out->n_leaves; i++)
646     {
647       assert (out->data_leaves[i] != NULL);
648       assert (out->presentation_leaves[i] != NULL);
649     }
650   *outp = out;
651   return NULL;
652
653 error:
654   pivot_dimension_destroy (out);
655   return error;
656 }
657
658 static char * WARN_UNUSED_RESULT
659 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
660 {
661   enum table_stroke strokes[] = {
662     TABLE_STROKE_NONE,
663     TABLE_STROKE_SOLID,
664     TABLE_STROKE_DASHED,
665     TABLE_STROKE_THICK,
666     TABLE_STROKE_THIN,
667     TABLE_STROKE_DOUBLE,
668   };
669
670   if (stroke_type >= sizeof strokes / sizeof *strokes)
671     return xasprintf ("bad stroke %"PRIu32, stroke_type);
672
673   *strokep = strokes[stroke_type];
674   return NULL;
675 }
676
677 static char * WARN_UNUSED_RESULT
678 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
679
680 {
681   if (in->border_type >= PIVOT_N_BORDERS)
682     return xasprintf ("bad border type %"PRIu32, in->border_type);
683
684   struct table_border_style *out = &table->look->borders[in->border_type];
685   out->color = decode_spvlb_color_u32 (in->color);
686   return decode_spvlb_stroke (in->stroke_type, &out->stroke);
687 }
688
689 static char * WARN_UNUSED_RESULT
690 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
691                    enum pivot_axis_type axis_type, struct pivot_table *table)
692 {
693   struct pivot_axis *axis = &table->axes[axis_type];
694   axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
695   axis->n_dimensions = n_dimensions;
696   axis->extent = 1;
697   for (size_t i = 0; i < n_dimensions; i++)
698     {
699       uint32_t idx = dimension_indexes[i];
700       if (idx >= table->n_dimensions)
701         return xasprintf ("bad dimension index %"PRIu32" >= %zu",
702                           idx, table->n_dimensions);
703
704       struct pivot_dimension *d = table->dimensions[idx];
705       if (d->level != UINT_MAX)
706         return xasprintf ("duplicate dimension %"PRIu32, idx);
707
708       axis->dimensions[i] = d;
709       d->axis_type = axis_type;
710       d->level = i;
711
712       axis->extent *= d->n_leaves;
713     }
714
715   return NULL;
716 }
717
718 static char *
719 decode_data_index (uint64_t in, const struct pivot_table *table,
720                    size_t *out)
721 {
722   uint64_t remainder = in;
723   for (size_t i = table->n_dimensions - 1; i > 0; i--)
724     {
725       const struct pivot_dimension *d = table->dimensions[i];
726       if (d->n_leaves)
727         {
728           out[i] = remainder % d->n_leaves;
729           remainder /= d->n_leaves;
730         }
731       else
732         out[i] = 0;
733     }
734   if (remainder >= table->dimensions[0]->n_leaves)
735     return xasprintf ("out of range cell data index %"PRIu64, in);
736
737   out[0] = remainder;
738   return NULL;
739 }
740
741 static char * WARN_UNUSED_RESULT
742 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
743                     struct pivot_table *table, const char *encoding)
744 {
745   if (!table->n_dimensions)
746     return NULL;
747
748   size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
749   for (size_t i = 0; i < n_in; i++)
750     {
751       struct pivot_value *value;
752       char *error = decode_data_index (in[i]->index, table, dindexes);
753       if (!error)
754         error = decode_spvlb_value (table, in[i]->value, encoding, &value);
755       if (error)
756         {
757           free (dindexes);
758           return error;
759         }
760       pivot_table_put (table, dindexes, table->n_dimensions, value);
761     }
762   free (dindexes);
763
764   return NULL;
765 }
766
767 static char * WARN_UNUSED_RESULT
768 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
769                        size_t idx, struct pivot_table *table)
770 {
771   struct pivot_value *content;
772   char *error = decode_spvlb_value (table, in->text, encoding, &content);
773   if (error)
774     return error;
775
776   struct pivot_value *marker = NULL;
777   if (in->marker)
778     {
779       error = decode_spvlb_value (table, in->marker, encoding, &marker);
780       if (error)
781         {
782           pivot_value_destroy (content);
783           return error;
784         }
785       if (marker->type == PIVOT_VALUE_TEXT)
786         marker->text.user_provided = false;
787     }
788
789   struct pivot_footnote *f = pivot_table_create_footnote__ (
790     table, idx, marker, content);
791   f->show = (int32_t) in->show > 0;
792   return NULL;
793 }
794
795 static char * WARN_UNUSED_RESULT
796 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
797 {
798   const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
799   table->current_layer = xnmalloc (axis->n_dimensions,
800                                    sizeof *table->current_layer);
801
802   for (size_t i = 0; i < axis->n_dimensions; i++)
803     {
804       const struct pivot_dimension *d = axis->dimensions[i];
805       if (d->n_leaves)
806         {
807           table->current_layer[i] = current_layer % d->n_leaves;
808           current_layer /= d->n_leaves;
809         }
810       else
811         table->current_layer[i] = 0;
812     }
813   if (current_layer > 0)
814     return xasprintf ("out of range layer data index %"PRIu64, current_layer);
815   return NULL;
816 }
817
818 char * WARN_UNUSED_RESULT
819 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
820 {
821   *outp = NULL;
822   if (in->header->version != 1 && in->header->version != 3)
823     return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
824                       in->header->version);
825
826   char *error = NULL;
827   struct pivot_table *out = xzalloc (sizeof *out);
828   out->ref_cnt = 1;
829   hmap_init (&out->cells);
830   out->look = pivot_table_look_new_builtin_default ();
831
832   const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
833                                : in->formats->x3 ? in->formats->x3->y1
834                                : NULL);
835   const char *encoding;
836   if (y1)
837     encoding = y1->charset;
838   else
839     {
840       const char *dot = strchr (in->formats->locale, '.');
841       encoding = dot ? dot + 1 : "windows-1252";
842     }
843
844   /* Display settings. */
845   out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
846   out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
847   out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
848   out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
849   out->show_grid_lines = in->borders->show_grid_lines;
850   out->show_title = true;
851   out->show_caption = true;
852   out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
853   out->look->omit_empty = in->ts->omit_empty;
854
855   const struct spvlb_x1 *x1 = in->formats->x1;
856   if (x1)
857     {
858       error = decode_spvlb_value_show (x1->show_values, &out->show_values);
859       if (!error)
860         error = decode_spvlb_value_show (x1->show_variables,
861                                          &out->show_variables);
862       if (error)
863         goto error;
864
865       out->show_caption = x1->show_caption;
866       out->show_title = x1->show_title != 10;
867     }
868
869   /* Column and row display settings. */
870   out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
871   out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
872   out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
873   out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
874
875   convert_widths (in->formats->widths, in->formats->n_widths,
876                   &out->sizing[TABLE_HORZ].widths,
877                   &out->sizing[TABLE_HORZ].n_widths);
878
879   const struct spvlb_x2 *x2 = in->formats->x2;
880   if (x2)
881     convert_widths (x2->row_heights, x2->n_row_heights,
882                     &out->sizing[TABLE_VERT].widths,
883                     &out->sizing[TABLE_VERT].n_widths);
884
885   convert_breakpoints (in->ts->row_breaks,
886                        &out->sizing[TABLE_VERT].breaks,
887                        &out->sizing[TABLE_VERT].n_breaks);
888   convert_breakpoints (in->ts->col_breaks,
889                        &out->sizing[TABLE_HORZ].breaks,
890                        &out->sizing[TABLE_HORZ].n_breaks);
891
892   convert_keeps (in->ts->row_keeps,
893                  &out->sizing[TABLE_VERT].keeps,
894                  &out->sizing[TABLE_VERT].n_keeps);
895   convert_keeps (in->ts->col_keeps,
896                  &out->sizing[TABLE_HORZ].keeps,
897                  &out->sizing[TABLE_HORZ].n_keeps);
898
899   out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
900   out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
901
902   /* Print settings. */
903   out->look->print_all_layers = in->ps->all_layers;
904   out->look->paginate_layers = in->ps->paginate_layers;
905   out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
906   out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
907   out->look->top_continuation = in->ps->top_continuation;
908   out->look->bottom_continuation = in->ps->bottom_continuation;
909   out->look->continuation = xstrdup (in->ps->continuation_string);
910   out->look->n_orphan_lines = in->ps->n_orphan_lines;
911
912   /* Format settings. */
913   out->epoch = in->formats->y0->epoch;
914   out->decimal = in->formats->y0->decimal;
915   out->grouping = in->formats->y0->grouping;
916   const struct spvlb_custom_currency *cc = in->formats->custom_currency;
917   for (int i = 0; i < 5; i++)
918     if (cc && i < cc->n_ccs)
919       out->ccs[i] = xstrdup (cc->ccs[i]);
920   out->small = in->formats->x3 ? in->formats->x3->small : 0;
921
922   /* Command information. */
923   if (y1)
924     {
925       out->command_local = to_utf8 (y1->command_local, encoding);
926       out->command_c = to_utf8 (y1->command, encoding);
927       out->language = xstrdup (y1->language);
928       /* charset? */
929       out->locale = xstrdup (y1->locale);
930     }
931
932   /* Source information. */
933   const struct spvlb_x3 *x3 = in->formats->x3;
934   if (x3)
935     {
936       if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
937         out->dataset = to_utf8 (x3->dataset, encoding);
938       out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
939       out->date = x3->date;
940     }
941
942   /* Footnotes.
943
944      Any pivot_value might refer to footnotes, so it's important to process the
945      footnotes early to ensure that those references can be resolved.  There is
946      a possible problem that a footnote might itself reference an
947      as-yet-unprocessed footnote, but that's OK because footnote references
948      don't actually look at the footnote contents but only resolve a pointer to
949      where the footnote will go later.
950
951      Before we really start, create all the footnotes we'll fill in.  This is
952      because sometimes footnotes refer to themselves or to each other and we
953      don't want to reject those references. */
954   const struct spvlb_footnotes *fn = in->footnotes;
955   if (fn->n_footnotes > 0)
956     {
957       pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
958       for (size_t i = 0; i < fn->n_footnotes; i++)
959         {
960           error = decode_spvlb_footnote (in->footnotes->footnotes[i],
961                                          encoding, i, out);
962           if (error)
963             goto error;
964         }
965     }
966
967   /* Title and caption. */
968   error = decode_spvlb_value (out, in->titles->user_title, encoding,
969                               &out->title);
970   if (error)
971     goto error;
972
973   error = decode_spvlb_value (out, in->titles->subtype, encoding,
974                               &out->subtype);
975   if (error)
976     goto error;
977
978   if (in->titles->corner_text)
979     {
980       error = decode_spvlb_value (out, in->titles->corner_text,
981                                   encoding, &out->corner_text);
982       if (error)
983         goto error;
984     }
985
986   if (in->titles->caption)
987     {
988       error = decode_spvlb_value (out, in->titles->caption, encoding,
989                                   &out->caption);
990       if (error)
991         goto error;
992     }
993
994
995   /* Styles. */
996   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
997     {
998       error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
999                                  encoding);
1000       if (error)
1001         goto error;
1002     }
1003   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1004     {
1005       error = decode_spvlb_border (in->borders->borders[i], out);
1006       if (error)
1007         goto error;
1008     }
1009
1010   /* Dimensions. */
1011   out->n_dimensions = in->dimensions->n_dims;
1012   out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1013   for (size_t i = 0; i < out->n_dimensions; i++)
1014     {
1015       error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1016                                       i, encoding, &out->dimensions[i]);
1017       if (error)
1018         goto error;
1019     }
1020
1021   /* Axes. */
1022   size_t a = in->axes->n_layers;
1023   size_t b = in->axes->n_rows;
1024   size_t c = in->axes->n_columns;
1025   if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1026     {
1027       error = xasprintf ("dimensions do not sum correctly "
1028                          "(%zu + %zu + %zu != %zu)",
1029                          a, b, c, out->n_dimensions);
1030       goto error;
1031     }
1032   error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1033                              PIVOT_AXIS_LAYER, out);
1034   if (error)
1035     goto error;
1036   error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1037                              PIVOT_AXIS_ROW, out);
1038   if (error)
1039     goto error;
1040   error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1041                              PIVOT_AXIS_COLUMN, out);
1042   if (error)
1043     goto error;
1044
1045   pivot_table_assign_label_depth (out);
1046
1047   error = decode_current_layer (in->ts->current_layer, out);
1048   if (error)
1049     goto error;
1050
1051   /* Data. */
1052   error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1053                               encoding);
1054
1055   *outp = out;
1056   return NULL;
1057
1058 error:
1059   pivot_table_unref (out);
1060   return error;
1061 }