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