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