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