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