pivot-table: Make pivot_table_look a refcounted object.
[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->footnotes = xnmalloc (vm->n_refs, sizeof *out->footnotes);
397           for (size_t i = 0; i < vm->n_refs; i++)
398             {
399               uint16_t idx = vm->refs[i];
400               if (idx >= table->n_footnotes)
401                 {
402                   pivot_value_destroy (out);
403                   return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
404                                     idx, table->n_footnotes);
405                 }
406
407               out->footnotes[out->n_footnotes++] = table->footnotes[idx];
408             }
409         }
410
411       if (vm->style_pair)
412         {
413           error = decode_spvlb_font_style (vm->style_pair->font_style,
414                                            encoding, &out->font_style);
415           if (!error)
416             error = decode_spvlb_cell_style (vm->style_pair->cell_style,
417                                              &out->cell_style);
418           if (error)
419             {
420               pivot_value_destroy (out);
421               return error;
422             }
423         }
424
425       if (vm->template_string
426           && vm->template_string->id
427           && vm->template_string->id[0]
428           && out->type == PIVOT_VALUE_TEMPLATE)
429         out->template.id = to_utf8 (vm->template_string->id, encoding);
430     }
431
432   *outp = out;
433   return NULL;
434 }
435
436 static char * WARN_UNUSED_RESULT
437 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
438                    const char *encoding)
439 {
440   char *error;
441
442   struct cell_color fg0, fg1, bg0, bg1;
443   error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
444   if (!error)
445     error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
446   if (!error && in->alternate)
447     error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
448   if (!error && in->alternate)
449     error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
450
451   enum table_halign halign;
452   if (!error)
453     {
454       error = decode_spvlb_halign (in->halign, &halign);
455
456       /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
457          is good because there's no way to indicate the decimal offset.  Just
458          in case: */
459       if (!error && halign == TABLE_HALIGN_DECIMAL)
460         halign = TABLE_HALIGN_MIXED;
461     }
462
463   enum table_valign valign;
464   if (!error)
465     error = decode_spvlb_valign (in->valign, &valign);
466
467   if (error)
468     return error;
469
470   *out = (struct table_area_style) {
471     .font_style = {
472       .bold = (in->style & 1) != 0,
473       .italic = (in->style & 2) != 0,
474       .underline = in->underline,
475       .fg = { fg0, in->alternate ? fg1 : fg0 },
476       .bg = { bg0, in->alternate ? bg1 : bg0 },
477       .typeface = to_utf8 (in->typeface, encoding),
478       .size = in->size / 1.33,
479     },
480     .cell_style = {
481       .halign = halign,
482       .valign = valign,
483       .margin = {
484         [TABLE_HORZ] = { in->left_margin, in->right_margin },
485         [TABLE_VERT] = { in->top_margin, in->bottom_margin },
486       },
487     },
488   };
489   return NULL;
490 }
491
492 static char * WARN_UNUSED_RESULT
493 decode_spvlb_group (const struct pivot_table *,
494                     struct spvlb_category **,
495                     size_t n_categories,
496                     bool show_label,
497                     struct pivot_category *parent,
498                     struct pivot_dimension *,
499                     const char *encoding);
500
501 static char * WARN_UNUSED_RESULT
502 decode_spvlb_categories (const struct pivot_table *table,
503                          struct spvlb_category **categories,
504                          size_t n_categories,
505                          struct pivot_category *parent,
506                          struct pivot_dimension *dimension,
507                          const char *encoding)
508 {
509   for (size_t i = 0; i < n_categories; i++)
510     {
511       const struct spvlb_category *in = categories[i];
512       if (in->group && in->group->merge)
513         {
514           char *error = decode_spvlb_categories (
515             table, in->group->subcategories, in->group->n_subcategories,
516             parent, dimension, encoding);
517           if (error)
518             return error;
519
520           continue;
521         }
522
523       struct pivot_value *name;
524       char *error = decode_spvlb_value (table, in->name, encoding, &name);
525       if (error)
526         return error;
527
528       struct pivot_category *out = xzalloc (sizeof *out);
529       out->name = name;
530       out->parent = parent;
531       out->dimension = dimension;
532       if (in->group)
533         {
534           char *error = decode_spvlb_group (table, in->group->subcategories,
535                                             in->group->n_subcategories,
536                                             true, out, dimension, encoding);
537           if (error)
538             {
539               pivot_category_destroy (out);
540               return error;
541             }
542
543           out->data_index = SIZE_MAX;
544           out->presentation_index = SIZE_MAX;
545         }
546       else
547         {
548           out->data_index = in->leaf->leaf_index;
549           out->presentation_index = dimension->n_leaves;
550           dimension->n_leaves++;
551         }
552
553       if (parent->n_subs >= parent->allocated_subs)
554         parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
555                                    sizeof *parent->subs);
556       parent->subs[parent->n_subs++] = out;
557     }
558   return NULL;
559 }
560
561 static char * WARN_UNUSED_RESULT
562 decode_spvlb_group (const struct pivot_table *table,
563                     struct spvlb_category **categories,
564                     size_t n_categories, bool show_label,
565                     struct pivot_category *category,
566                     struct pivot_dimension *dimension,
567                     const char *encoding)
568 {
569   category->subs = XCALLOC (n_categories, struct pivot_category *);
570   category->n_subs = 0;
571   category->allocated_subs = 0;
572   category->show_label = show_label;
573
574   return decode_spvlb_categories (table, categories, n_categories, category,
575                                   dimension, encoding);
576 }
577
578 static char * WARN_UNUSED_RESULT
579 fill_leaves (struct pivot_category *category,
580              struct pivot_dimension *dimension)
581 {
582   if (pivot_category_is_group (category))
583     {
584       for (size_t i = 0; i < category->n_subs; i++)
585         {
586           char *error = fill_leaves (category->subs[i], dimension);
587           if (error)
588             return error;
589         }
590     }
591   else
592     {
593       if (category->data_index >= dimension->n_leaves)
594         return xasprintf ("leaf_index %zu >= n_leaves %zu",
595                           category->data_index, dimension->n_leaves);
596       if (dimension->data_leaves[category->data_index])
597         return xasprintf ("two leaves with data_index %zu",
598                           category->data_index);
599       dimension->data_leaves[category->data_index] = category;
600       dimension->presentation_leaves[category->presentation_index] = category;
601     }
602   return NULL;
603 }
604
605 static char * WARN_UNUSED_RESULT
606 decode_spvlb_dimension (const struct pivot_table *table,
607                         const struct spvlb_dimension *in,
608                         size_t idx, const char *encoding,
609                         struct pivot_dimension **outp)
610 {
611   /* Convert most of the dimension. */
612   struct pivot_value *name;
613   char *error = decode_spvlb_value (table, in->name, encoding, &name);
614   if (error)
615     return error;
616
617   struct pivot_dimension *out = xzalloc (sizeof *out);
618   out->level = UINT_MAX;
619   out->top_index = idx;
620   out->hide_all_labels = in->props->hide_all_labels;
621
622   out->root = xzalloc (sizeof *out->root);
623   *out->root = (struct pivot_category) {
624     .name = name,
625     .dimension = out,
626     .data_index = SIZE_MAX,
627     .presentation_index = SIZE_MAX,
628   };
629   error = decode_spvlb_group (table, in->categories, in->n_categories,
630                               !in->props->hide_dim_label, out->root,
631                               out, encoding);
632   if (error)
633     goto error;
634
635   /* Allocate and fill the array of leaves now that we know how many there
636      are. */
637   out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
638   out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
639   out->allocated_leaves = out->n_leaves;
640   error = fill_leaves (out->root, out);
641   if (error)
642     goto error;
643   for (size_t i = 0; i < out->n_leaves; i++)
644     {
645       assert (out->data_leaves[i] != NULL);
646       assert (out->presentation_leaves[i] != NULL);
647     }
648   *outp = out;
649   return NULL;
650
651 error:
652   pivot_dimension_destroy (out);
653   return error;
654 }
655
656 static char * WARN_UNUSED_RESULT
657 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
658 {
659   enum table_stroke strokes[] = {
660     TABLE_STROKE_NONE,
661     TABLE_STROKE_SOLID,
662     TABLE_STROKE_DASHED,
663     TABLE_STROKE_THICK,
664     TABLE_STROKE_THIN,
665     TABLE_STROKE_DOUBLE,
666   };
667
668   if (stroke_type >= sizeof strokes / sizeof *strokes)
669     return xasprintf ("bad stroke %"PRIu32, stroke_type);
670
671   *strokep = strokes[stroke_type];
672   return NULL;
673 }
674
675 static char * WARN_UNUSED_RESULT
676 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
677
678 {
679   if (in->border_type >= PIVOT_N_BORDERS)
680     return xasprintf ("bad border type %"PRIu32, in->border_type);
681
682   struct table_border_style *out = &table->look->borders[in->border_type];
683   out->color = decode_spvlb_color_u32 (in->color);
684   return decode_spvlb_stroke (in->stroke_type, &out->stroke);
685 }
686
687 static char * WARN_UNUSED_RESULT
688 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
689                    enum pivot_axis_type axis_type, struct pivot_table *table)
690 {
691   struct pivot_axis *axis = &table->axes[axis_type];
692   axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
693   axis->n_dimensions = n_dimensions;
694   axis->extent = 1;
695   for (size_t i = 0; i < n_dimensions; i++)
696     {
697       uint32_t idx = dimension_indexes[i];
698       if (idx >= table->n_dimensions)
699         return xasprintf ("bad dimension index %"PRIu32" >= %zu",
700                           idx, table->n_dimensions);
701
702       struct pivot_dimension *d = table->dimensions[idx];
703       if (d->level != UINT_MAX)
704         return xasprintf ("duplicate dimension %"PRIu32, idx);
705
706       axis->dimensions[i] = d;
707       d->axis_type = axis_type;
708       d->level = i;
709
710       axis->extent *= d->n_leaves;
711     }
712
713   return NULL;
714 }
715
716 static char *
717 decode_data_index (uint64_t in, const struct pivot_table *table,
718                    size_t *out)
719 {
720   uint64_t remainder = in;
721   for (size_t i = table->n_dimensions - 1; i > 0; i--)
722     {
723       const struct pivot_dimension *d = table->dimensions[i];
724       if (d->n_leaves)
725         {
726           out[i] = remainder % d->n_leaves;
727           remainder /= d->n_leaves;
728         }
729       else
730         out[i] = 0;
731     }
732   if (remainder >= table->dimensions[0]->n_leaves)
733     return xasprintf ("out of range cell data index %"PRIu64, in);
734
735   out[0] = remainder;
736   return NULL;
737 }
738
739 static char * WARN_UNUSED_RESULT
740 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
741                     struct pivot_table *table, const char *encoding)
742 {
743   if (!table->n_dimensions)
744     return NULL;
745
746   size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
747   for (size_t i = 0; i < n_in; i++)
748     {
749       struct pivot_value *value;
750       char *error = decode_data_index (in[i]->index, table, dindexes);
751       if (!error)
752         error = decode_spvlb_value (table, in[i]->value, encoding, &value);
753       if (error)
754         {
755           free (dindexes);
756           return error;
757         }
758       pivot_table_put (table, dindexes, table->n_dimensions, value);
759     }
760   free (dindexes);
761
762   return NULL;
763 }
764
765 static char * WARN_UNUSED_RESULT
766 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
767                        size_t idx, struct pivot_table *table)
768 {
769   struct pivot_value *content;
770   char *error = decode_spvlb_value (table, in->text, encoding, &content);
771   if (error)
772     return error;
773
774   struct pivot_value *marker = NULL;
775   if (in->marker)
776     {
777       error = decode_spvlb_value (table, in->marker, encoding, &marker);
778       if (error)
779         {
780           pivot_value_destroy (content);
781           return error;
782         }
783       if (marker->type == PIVOT_VALUE_TEXT)
784         marker->text.user_provided = false;
785     }
786
787   struct pivot_footnote *f = pivot_table_create_footnote__ (
788     table, idx, marker, content);
789   f->show = (int32_t) in->show > 0;
790   return NULL;
791 }
792
793 static char * WARN_UNUSED_RESULT
794 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
795 {
796   const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
797   table->current_layer = xnmalloc (axis->n_dimensions,
798                                    sizeof *table->current_layer);
799
800   for (size_t i = 0; i < axis->n_dimensions; i++)
801     {
802       const struct pivot_dimension *d = axis->dimensions[i];
803       if (d->n_leaves)
804         {
805           table->current_layer[i] = current_layer % d->n_leaves;
806           current_layer /= d->n_leaves;
807         }
808       else
809         table->current_layer[i] = 0;
810     }
811   if (current_layer > 0)
812     return xasprintf ("out of range layer data index %"PRIu64, current_layer);
813   return NULL;
814 }
815
816 char * WARN_UNUSED_RESULT
817 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
818 {
819   *outp = NULL;
820   if (in->header->version != 1 && in->header->version != 3)
821     return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
822                       in->header->version);
823
824   char *error = NULL;
825   struct pivot_table *out = xzalloc (sizeof *out);
826   out->ref_cnt = 1;
827   hmap_init (&out->cells);
828   out->look = pivot_table_look_new_builtin_default ();
829
830   const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
831                                : in->formats->x3 ? in->formats->x3->y1
832                                : NULL);
833   const char *encoding;
834   if (y1)
835     encoding = y1->charset;
836   else
837     {
838       const char *dot = strchr (in->formats->locale, '.');
839       encoding = dot ? dot + 1 : "windows-1252";
840     }
841
842   /* Display settings. */
843   out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
844   out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
845   out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
846   out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
847   out->show_grid_lines = in->borders->show_grid_lines;
848   out->show_caption = true;
849   out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
850   out->look->omit_empty = in->ts->omit_empty;
851
852   const struct spvlb_x1 *x1 = in->formats->x1;
853   if (x1)
854     {
855       error = decode_spvlb_value_show (x1->show_values, &out->show_values);
856       if (!error)
857         error = decode_spvlb_value_show (x1->show_variables,
858                                          &out->show_variables);
859       if (error)
860         goto error;
861
862       out->show_caption = x1->show_caption;
863     }
864
865   /* Column and row display settings. */
866   out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
867   out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
868   out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
869   out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
870
871   convert_widths (in->formats->widths, in->formats->n_widths,
872                   &out->sizing[TABLE_HORZ].widths,
873                   &out->sizing[TABLE_HORZ].n_widths);
874
875   const struct spvlb_x2 *x2 = in->formats->x2;
876   if (x2)
877     convert_widths (x2->row_heights, x2->n_row_heights,
878                     &out->sizing[TABLE_VERT].widths,
879                     &out->sizing[TABLE_VERT].n_widths);
880
881   convert_breakpoints (in->ts->row_breaks,
882                        &out->sizing[TABLE_VERT].breaks,
883                        &out->sizing[TABLE_VERT].n_breaks);
884   convert_breakpoints (in->ts->col_breaks,
885                        &out->sizing[TABLE_HORZ].breaks,
886                        &out->sizing[TABLE_HORZ].n_breaks);
887
888   convert_keeps (in->ts->row_keeps,
889                  &out->sizing[TABLE_VERT].keeps,
890                  &out->sizing[TABLE_VERT].n_keeps);
891   convert_keeps (in->ts->col_keeps,
892                  &out->sizing[TABLE_HORZ].keeps,
893                  &out->sizing[TABLE_HORZ].n_keeps);
894
895   out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
896   out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
897
898   /* Print settings. */
899   out->look->print_all_layers = in->ps->all_layers;
900   out->look->paginate_layers = in->ps->paginate_layers;
901   out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
902   out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
903   out->look->top_continuation = in->ps->top_continuation;
904   out->look->bottom_continuation = in->ps->bottom_continuation;
905   out->look->continuation = xstrdup (in->ps->continuation_string);
906   out->look->n_orphan_lines = in->ps->n_orphan_lines;
907
908   /* Format settings. */
909   out->epoch = in->formats->y0->epoch;
910   out->decimal = in->formats->y0->decimal;
911   out->grouping = in->formats->y0->grouping;
912   const struct spvlb_custom_currency *cc = in->formats->custom_currency;
913   for (int i = 0; i < 5; i++)
914     if (cc && i < cc->n_ccs)
915       out->ccs[i] = xstrdup (cc->ccs[i]);
916   out->small = in->formats->x3 ? in->formats->x3->small : 0;
917
918   /* Command information. */
919   if (y1)
920     {
921       out->command_local = to_utf8 (y1->command_local, encoding);
922       out->command_c = to_utf8 (y1->command, encoding);
923       out->language = xstrdup (y1->language);
924       /* charset? */
925       out->locale = xstrdup (y1->locale);
926     }
927
928   /* Source information. */
929   const struct spvlb_x3 *x3 = in->formats->x3;
930   if (x3)
931     {
932       if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
933         out->dataset = to_utf8 (x3->dataset, encoding);
934       out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
935       out->date = x3->date;
936     }
937
938   /* Footnotes.
939
940      Any pivot_value might refer to footnotes, so it's important to process the
941      footnotes early to ensure that those references can be resolved.  There is
942      a possible problem that a footnote might itself reference an
943      as-yet-unprocessed footnote, but that's OK because footnote references
944      don't actually look at the footnote contents but only resolve a pointer to
945      where the footnote will go later.
946
947      Before we really start, create all the footnotes we'll fill in.  This is
948      because sometimes footnotes refer to themselves or to each other and we
949      don't want to reject those references. */
950   const struct spvlb_footnotes *fn = in->footnotes;
951   if (fn->n_footnotes > 0)
952     {
953       pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
954       for (size_t i = 0; i < fn->n_footnotes; i++)
955         {
956           error = decode_spvlb_footnote (in->footnotes->footnotes[i],
957                                          encoding, i, out);
958           if (error)
959             goto error;
960         }
961     }
962
963   /* Title and caption. */
964   error = decode_spvlb_value (out, in->titles->user_title, encoding,
965                               &out->title);
966   if (error)
967     goto error;
968
969   error = decode_spvlb_value (out, in->titles->subtype, encoding,
970                               &out->subtype);
971   if (error)
972     goto error;
973
974   if (in->titles->corner_text)
975     {
976       error = decode_spvlb_value (out, in->titles->corner_text,
977                                   encoding, &out->corner_text);
978       if (error)
979         goto error;
980     }
981
982   if (in->titles->caption)
983     {
984       error = decode_spvlb_value (out, in->titles->caption, encoding,
985                                   &out->caption);
986       if (error)
987         goto error;
988     }
989
990
991   /* Styles. */
992   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
993     {
994       error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
995                                  encoding);
996       if (error)
997         goto error;
998     }
999   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1000     {
1001       error = decode_spvlb_border (in->borders->borders[i], out);
1002       if (error)
1003         goto error;
1004     }
1005
1006   /* Dimensions. */
1007   out->n_dimensions = in->dimensions->n_dims;
1008   out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1009   for (size_t i = 0; i < out->n_dimensions; i++)
1010     {
1011       error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1012                                       i, encoding, &out->dimensions[i]);
1013       if (error)
1014         goto error;
1015     }
1016
1017   /* Axes. */
1018   size_t a = in->axes->n_layers;
1019   size_t b = in->axes->n_rows;
1020   size_t c = in->axes->n_columns;
1021   if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1022     {
1023       error = xasprintf ("dimensions do not sum correctly "
1024                          "(%zu + %zu + %zu != %zu)",
1025                          a, b, c, out->n_dimensions);
1026       goto error;
1027     }
1028   error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1029                              PIVOT_AXIS_LAYER, out);
1030   if (error)
1031     goto error;
1032   error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1033                              PIVOT_AXIS_ROW, out);
1034   if (error)
1035     goto error;
1036   error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1037                              PIVOT_AXIS_COLUMN, out);
1038   if (error)
1039     goto error;
1040
1041   pivot_table_assign_label_depth (out);
1042
1043   error = decode_current_layer (in->ts->current_layer, out);
1044   if (error)
1045     goto error;
1046
1047   /* Data. */
1048   error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1049                               encoding);
1050
1051   *outp = out;
1052   return NULL;
1053
1054 error:
1055   pivot_table_unref (out);
1056   return error;
1057 }