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