Implement SET LEADZERO.
[pspp] / src / output / spv / spv-writer.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2019 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-writer.h"
20
21 #include <cairo.h>
22 #include <inttypes.h>
23 #include <libxml/xmlwriter.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <time.h>
27
28 #include "libpspp/array.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/cast.h"
31 #include "libpspp/float-format.h"
32 #include "libpspp/integer-format.h"
33 #include "libpspp/temp-file.h"
34 #include "libpspp/version.h"
35 #include "libpspp/zip-writer.h"
36 #include "output/cairo-chart.h"
37 #include "output/driver.h"
38 #include "output/output-item.h"
39 #include "output/page-setup.h"
40 #include "output/pivot-table.h"
41
42 #include "gl/xalloc.h"
43 #include "gl/xvasprintf.h"
44
45 #include "gettext.h"
46 #define _(msgid) gettext (msgid)
47 #define N_(msgid) (msgid)
48
49 struct spv_writer
50   {
51     struct zip_writer *zw;
52
53     FILE *heading;
54     int heading_depth;
55     xmlTextWriter *xml;
56
57     int n_tables;
58
59     int n_headings;
60     struct page_setup *page_setup;
61     bool need_page_break;
62   };
63
64 static void spv_writer_close_heading (struct spv_writer *);
65
66 char * WARN_UNUSED_RESULT
67 spv_writer_open (const char *filename, struct spv_writer **writerp)
68 {
69   *writerp = NULL;
70
71   struct zip_writer *zw = zip_writer_create (filename);
72   if (!zw)
73     return xasprintf (_("%s: create failed"), filename);
74
75   struct spv_writer *w = xmalloc (sizeof *w);
76   *w = (struct spv_writer) { .zw = zw };
77   *writerp = w;
78   return NULL;
79 }
80
81 char * WARN_UNUSED_RESULT
82 spv_writer_close (struct spv_writer *w)
83 {
84   if (!w)
85     return NULL;
86
87   zip_writer_add_string (w->zw, "META-INF/MANIFEST.MF", "allowPivoting=true");
88
89   while (w->heading_depth)
90     spv_writer_close_heading (w);
91
92   char *error = NULL;
93   if (!zip_writer_close (w->zw))
94     error = xstrdup (_("I/O error writing SPV file"));
95
96   page_setup_destroy (w->page_setup);
97   free (w);
98   return error;
99 }
100
101 static void
102 write_attr (struct spv_writer *w, const char *name, const char *value)
103 {
104   xmlTextWriterWriteAttribute (w->xml,
105                                CHAR_CAST (xmlChar *, name),
106                                CHAR_CAST (xmlChar *, value));
107 }
108
109 static void PRINTF_FORMAT (3, 4)
110 write_attr_format (struct spv_writer *w, const char *name,
111                    const char *format, ...)
112 {
113   va_list args;
114   va_start (args, format);
115   char *value = xvasprintf (format, args);
116   va_end (args);
117
118   write_attr (w, name, value);
119   free (value);
120 }
121
122 static void
123 start_elem (struct spv_writer *w, const char *name)
124 {
125   xmlTextWriterStartElement (w->xml, CHAR_CAST (xmlChar *, name));
126 }
127
128 static void
129 end_elem (struct spv_writer *w)
130 {
131   xmlTextWriterEndElement (w->xml);
132 }
133
134 static void
135 write_text (struct spv_writer *w, const char *text)
136 {
137   xmlTextWriterWriteString (w->xml, CHAR_CAST (xmlChar *, text));
138 }
139
140 static void
141 write_page_heading (struct spv_writer *w, const struct page_heading *h,
142                     const char *name)
143 {
144   start_elem (w, name);
145   if (h->n)
146     {
147       start_elem (w, "pageParagraph");
148       for (size_t i = 0; i < h->n; i++)
149         {
150           start_elem (w, "text");
151           write_attr (w, "type", "title");
152           write_text (w, h->paragraphs[i].markup); /* XXX */
153           end_elem (w);
154         }
155       end_elem (w);
156     }
157   end_elem (w);
158 }
159
160 static void
161 write_page_setup (struct spv_writer *w, const struct page_setup *ps)
162 {
163   start_elem (w, "pageSetup");
164   write_attr_format (w, "initial-page-number", "%d", ps->initial_page_number);
165   write_attr (w, "chart-size",
166               (ps->chart_size == PAGE_CHART_AS_IS ? "as-is"
167                : ps->chart_size == PAGE_CHART_FULL_HEIGHT ? "full-height"
168                : ps->chart_size == PAGE_CHART_HALF_HEIGHT ? "half-height"
169                : "quarter-height"));
170   write_attr_format (w, "margin-left", "%.2fin", ps->margins[TABLE_HORZ][0]);
171   write_attr_format (w, "margin-right", "%.2fin", ps->margins[TABLE_HORZ][1]);
172   write_attr_format (w, "margin-top", "%.2fin", ps->margins[TABLE_VERT][0]);
173   write_attr_format (w, "margin-bottom", "%.2fin", ps->margins[TABLE_VERT][1]);
174   write_attr_format (w, "paper-height", "%.2fin", ps->paper[TABLE_VERT]);
175   write_attr_format (w, "paper-width", "%.2fin", ps->paper[TABLE_HORZ]);
176   write_attr (w, "reference-orientation",
177               ps->orientation == PAGE_PORTRAIT ? "portrait" : "landscape");
178   write_attr_format (w, "space-after", "%.1fpt", ps->object_spacing * 72.0);
179   write_page_heading (w, &ps->headings[0], "pageHeader");
180   write_page_heading (w, &ps->headings[1], "pageFooter");
181   end_elem (w);
182 }
183
184 static bool
185 spv_writer_open_file (struct spv_writer *w)
186 {
187   w->heading = create_temp_file ();
188   if (!w->heading)
189     return false;
190
191   w->xml = xmlNewTextWriter (xmlOutputBufferCreateFile (w->heading, NULL));
192   xmlTextWriterStartDocument (w->xml, NULL, "UTF-8", NULL);
193   start_elem (w, "heading");
194
195   time_t t = time (NULL);
196   struct tm *tm = gmtime (&t);
197   char tm_s[128];
198   if (strftime (tm_s, sizeof tm_s, "%x %X", tm))
199     write_attr (w, "creation-date-time", tm_s);
200
201   write_attr (w, "creator", version);
202
203   write_attr (w, "creator-version", "21");
204
205   write_attr (w, "xmlns", "http://xml.spss.com/spss/viewer/viewer-tree");
206   write_attr (w, "xmlns:vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
207   write_attr (w, "xmlns:vtx", "http://xml.spss.com/spss/viewer/viewer-text");
208   write_attr (w, "xmlns:vtb", "http://xml.spss.com/spss/viewer/viewer-table");
209
210   start_elem (w, "label");
211   write_text (w, _("Output"));
212   end_elem (w);
213
214   if (w->page_setup)
215     {
216       write_page_setup (w, w->page_setup);
217
218       page_setup_destroy (w->page_setup);
219       w->page_setup = NULL;
220     }
221
222   return true;
223 }
224
225 static void
226 spv_writer_open_heading (struct spv_writer *w, const struct output_item *item)
227 {
228   if (!w->heading)
229     {
230       if (!spv_writer_open_file (w))
231         return;
232     }
233
234   w->heading_depth++;
235   start_elem (w, "heading");
236   if (item->command_name)
237     write_attr (w, "commandName", item->command_name);
238   if (!item->show)
239     write_attr (w, "visibility", "collapsed");
240   /* XXX locale */
241   /* XXX olang */
242
243   start_elem (w, "label");
244   write_text (w, output_item_get_label (item));
245   end_elem (w);
246 }
247
248 static void
249 spv_writer_close_file (struct spv_writer *w, const char *infix)
250 {
251   if (!w->heading)
252     return;
253
254   end_elem (w);
255   xmlTextWriterEndDocument (w->xml);
256   xmlFreeTextWriter (w->xml);
257
258   char *member_name = xasprintf ("outputViewer%010d%s.xml",
259                                  w->n_headings++, infix);
260   zip_writer_add (w->zw, w->heading, member_name);
261   free (member_name);
262
263   w->heading = NULL;
264 }
265
266 static void
267 spv_writer_close_heading (struct spv_writer *w)
268 {
269   const char *infix = "";
270   if (w->heading_depth)
271     {
272       infix = "_heading";
273       end_elem (w);
274       w->heading_depth--;
275     }
276
277   if (!w->heading_depth)
278     spv_writer_close_file (w, infix);
279 }
280
281 static void
282 open_container (struct spv_writer *w, const struct output_item *item,
283                 const char *inner_elem)
284 {
285   start_elem (w, "container");
286   write_attr (w, "visibility", item->show ? "visible" : "hidden");
287   if (w->need_page_break)
288     {
289       write_attr (w, "page-break-before", "always");
290       w->need_page_break = false;
291     }
292
293   start_elem (w, "label");
294   write_text (w, output_item_get_label (item));
295   end_elem (w);
296
297   start_elem (w, inner_elem);
298   if (item->command_name)
299     write_attr (w, "commandName", item->command_name);
300 }
301
302 static void
303 close_container (struct spv_writer *w)
304 {
305   end_elem (w);
306   end_elem (w);
307 }
308
309 static void
310 spv_writer_put_text (struct spv_writer *w, struct output_item *item)
311 {
312   bool initial_depth = w->heading_depth;
313   if (!initial_depth)
314     spv_writer_open_file (w);
315
316   open_container (w, item, "vtx:text");
317   write_attr (w, "type",
318               (item->text.subtype == TEXT_ITEM_TITLE ? "title"
319                : item->text.subtype == TEXT_ITEM_PAGE_TITLE ? "page-title"
320                : "log"));
321
322   start_elem (w, "html");
323   char *s = text_item_get_plain_text (item);
324   write_text (w, s);
325   free (s);
326   end_elem (w);
327
328   close_container (w);
329
330   if (!initial_depth)
331     spv_writer_close_file (w, "");
332
333   output_item_unref (item);
334 }
335
336 static cairo_status_t
337 write_to_zip (void *zw_, const unsigned char *data, unsigned int length)
338 {
339   struct zip_writer *zw = zw_;
340
341   zip_writer_add_write (zw, data, length);
342   return CAIRO_STATUS_SUCCESS;
343 }
344
345 static void
346 spv_writer_put_image (struct spv_writer *w, const struct output_item *item,
347                       cairo_surface_t *image)
348 {
349   bool initial_depth = w->heading_depth;
350   if (!initial_depth)
351     spv_writer_open_file (w);
352
353   char *uri = xasprintf ("%010d_Imagegeneric.png", ++w->n_tables);
354
355   open_container (w, item, "object");
356   write_attr (w, "type", "unknown");
357   write_attr (w, "uri", uri);
358   close_container (w);
359
360   if (!initial_depth)
361     spv_writer_close_file (w, "");
362
363   zip_writer_add_start (w->zw, uri);
364   cairo_surface_write_to_png_stream (image, write_to_zip, w->zw);
365   zip_writer_add_finish (w->zw);
366
367   free (uri);
368 }
369 \f
370 #define H TABLE_HORZ
371 #define V TABLE_VERT
372
373 struct buf
374   {
375     uint8_t *data;
376     size_t len;
377     size_t allocated;
378   };
379
380 static uint8_t *
381 put_uninit (struct buf *b, size_t n)
382 {
383   while (b->allocated - b->len < n)
384     b->data = x2nrealloc (b->data, &b->allocated, sizeof b->data);
385   uint8_t *p = &b->data[b->len];
386   b->len += n;
387   return p;
388 }
389
390 static void
391 put_byte (struct buf *b, uint8_t byte)
392 {
393   *put_uninit (b, 1) = byte;
394 }
395
396 static void
397 put_bool (struct buf *b, bool boolean)
398 {
399   put_byte (b, boolean);
400 }
401
402 static void
403 put_bytes (struct buf *b, const char *bytes, size_t n)
404 {
405   memcpy (put_uninit (b, n), bytes, n);
406 }
407
408 static void
409 put_u16 (struct buf *b, uint16_t x)
410 {
411   put_uint16 (native_to_le16 (x), put_uninit (b, sizeof x));
412 }
413
414 static void
415 put_u32 (struct buf *b, uint32_t x)
416 {
417   put_uint32 (native_to_le32 (x), put_uninit (b, sizeof x));
418 }
419
420 static void
421 put_u64 (struct buf *b, uint64_t x)
422 {
423   put_uint64 (native_to_le64 (x), put_uninit (b, sizeof x));
424 }
425
426 static void
427 put_be32 (struct buf *b, uint32_t x)
428 {
429   put_uint32 (native_to_be32 (x), put_uninit (b, sizeof x));
430 }
431
432 static void
433 put_double (struct buf *b, double x)
434 {
435   float_convert (FLOAT_NATIVE_DOUBLE, &x,
436                  FLOAT_IEEE_DOUBLE_LE, put_uninit (b, 8));
437 }
438
439 static void
440 put_float (struct buf *b, float x)
441 {
442   float_convert (FLOAT_NATIVE_FLOAT, &x,
443                  FLOAT_IEEE_SINGLE_LE, put_uninit (b, 4));
444 }
445
446 static void
447 put_string (struct buf *b, const char *s_)
448 {
449   const char *s = s_ ? s_ : "";
450   size_t len = strlen (s);
451   put_u32 (b, len);
452   memcpy (put_uninit (b, len), s, len);
453 }
454
455 static void
456 put_bestring (struct buf *b, const char *s_)
457 {
458   const char *s = s_ ? s_ : "";
459   size_t len = strlen (s);
460   put_be32 (b, len);
461   memcpy (put_uninit (b, len), s, len);
462 }
463
464 static size_t
465 start_count (struct buf *b)
466 {
467   put_u32 (b, 0);
468   return b->len;
469 }
470
471 static void
472 end_count_u32 (struct buf *b, size_t start)
473 {
474   put_uint32 (native_to_le32 (b->len - start), &b->data[start - 4]);
475 }
476
477 static void
478 end_count_be32 (struct buf *b, size_t start)
479 {
480   put_uint32 (native_to_be32 (b->len - start), &b->data[start - 4]);
481 }
482
483 static void
484 put_color (struct buf *buf, const struct cell_color *color)
485 {
486   char *s = xasprintf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8,
487                        color->r, color->g, color->b);
488   put_string (buf, s);
489   free (s);
490 }
491
492 static void
493 put_font_style (struct buf *buf, const struct font_style *font_style)
494 {
495   put_bool (buf, font_style->bold);
496   put_bool (buf, font_style->italic);
497   put_bool (buf, font_style->underline);
498   put_bool (buf, 1);
499   put_color (buf, &font_style->fg[0]);
500   put_color (buf, &font_style->bg[0]);
501   put_string (buf, font_style->typeface ? font_style->typeface : "SansSerif");
502   put_byte (buf, ceil (font_style->size * 1.33));
503 }
504
505 static void
506 put_halign (struct buf *buf, enum table_halign halign,
507             uint32_t mixed, uint32_t decimal)
508 {
509   put_u32 (buf, (halign == TABLE_HALIGN_RIGHT ? 4
510                  : halign == TABLE_HALIGN_LEFT ? 2
511                  : halign == TABLE_HALIGN_CENTER ? 0
512                  : halign == TABLE_HALIGN_MIXED ? mixed
513                  : decimal));
514 }
515
516 static void
517 put_valign (struct buf *buf, enum table_valign valign)
518 {
519   put_u32 (buf, (valign == TABLE_VALIGN_TOP ? 1
520                  : valign == TABLE_VALIGN_CENTER ? 0
521                  : 3));
522 }
523
524 static void
525 put_cell_style (struct buf *buf, const struct cell_style *cell_style)
526 {
527   put_halign (buf, cell_style->halign, 0xffffffad, 6);
528   put_valign (buf, cell_style->valign);
529   put_double (buf, cell_style->decimal_offset);
530   put_u16 (buf, cell_style->margin[H][0]);
531   put_u16 (buf, cell_style->margin[H][1]);
532   put_u16 (buf, cell_style->margin[V][0]);
533   put_u16 (buf, cell_style->margin[V][1]);
534 }
535
536 static void UNUSED
537 put_style_pair (struct buf *buf, const struct font_style *font_style,
538                 const struct cell_style *cell_style)
539 {
540   if (font_style)
541     {
542       put_byte (buf, 0x31);
543       put_font_style (buf, font_style);
544     }
545   else
546     put_byte (buf, 0x58);
547
548   if (cell_style)
549     {
550       put_byte (buf, 0x31);
551       put_cell_style (buf, cell_style);
552     }
553   else
554     put_byte (buf, 0x58);
555 }
556
557 static void
558 put_value_mod (struct buf *buf, const struct pivot_value *value,
559                const char *template)
560 {
561   if ((value->ex
562        && (value->ex->n_footnotes
563            || value->ex->n_subscripts
564            || value->ex->font_style
565            || value->ex->cell_style))
566       || template)
567     {
568       const struct pivot_value_ex *ex = pivot_value_ex (value);
569       put_byte (buf, 0x31);
570
571       /* Footnotes. */
572       put_u32 (buf, ex->n_footnotes);
573       for (size_t i = 0; i < ex->n_footnotes; i++)
574         put_u16 (buf, ex->footnote_indexes[i]);
575
576       /* Subscripts. */
577       put_u32 (buf, ex->n_subscripts);
578       for (size_t i = 0; i < ex->n_subscripts; i++)
579         put_string (buf, ex->subscripts[i]);
580
581       /* Template and style. */
582       uint32_t v3_start = start_count (buf);
583       uint32_t template_string_start = start_count (buf);
584       if (template)
585         {
586           uint32_t inner_start = start_count (buf);
587           end_count_u32 (buf, inner_start);
588
589           put_byte (buf, 0x31);
590           put_string (buf, template);
591         }
592       end_count_u32 (buf, template_string_start);
593       put_style_pair (buf, ex->font_style, ex->cell_style);
594       end_count_u32 (buf, v3_start);
595     }
596   else
597     put_byte (buf, 0x58);
598 }
599
600 static void
601 put_format (struct buf *buf, const struct fmt_spec *f, bool honor_small)
602 {
603   int type = f->type == FMT_F && honor_small ? 40 : fmt_to_io (f->type);
604   put_u32 (buf, (type << 16) | (f->w << 8) | f->d);
605 }
606
607 static int
608 show_values_to_spvlb (enum settings_value_show show)
609 {
610   return (show == SETTINGS_VALUE_SHOW_DEFAULT ? 0
611           : show == SETTINGS_VALUE_SHOW_VALUE ? 1
612           : show == SETTINGS_VALUE_SHOW_LABEL ? 2
613           : 3);
614 }
615
616 static void
617 put_show_values (struct buf *buf, enum settings_value_show show)
618 {
619   put_byte (buf, show_values_to_spvlb (show));
620 }
621
622 static void
623 put_value (struct buf *buf, const struct pivot_value *value)
624 {
625   switch (value->type)
626     {
627     case PIVOT_VALUE_NUMERIC:
628       if (value->numeric.var_name || value->numeric.value_label)
629         {
630           put_byte (buf, 2);
631           put_value_mod (buf, value, NULL);
632           put_format (buf, &value->numeric.format, value->numeric.honor_small);
633           put_double (buf, value->numeric.x);
634           put_string (buf, value->numeric.var_name);
635           put_string (buf, value->numeric.value_label);
636           put_show_values (buf, value->numeric.show);
637         }
638       else
639         {
640           put_byte (buf, 1);
641           put_value_mod (buf, value, NULL);
642           put_format (buf, &value->numeric.format, value->numeric.honor_small);
643           put_double (buf, value->numeric.x);
644         }
645       break;
646
647     case PIVOT_VALUE_STRING:
648       put_byte (buf, 4);
649       put_value_mod (buf, value, NULL);
650       size_t len = strlen (value->string.s);
651       if (value->string.hex)
652         put_format (buf, &(struct fmt_spec) { .type = FMT_AHEX, .w = len * 2 },
653                     false);
654       else
655         put_format (buf, &(struct fmt_spec) { .type = FMT_A, .w = len }, false);
656       put_string (buf, value->string.value_label);
657       put_string (buf, value->string.var_name);
658       put_show_values (buf, value->string.show);
659       put_string (buf, value->string.s);
660       break;
661
662     case PIVOT_VALUE_VARIABLE:
663       put_byte (buf, 5);
664       put_value_mod (buf, value, NULL);
665       put_string (buf, value->variable.var_name);
666       put_string (buf, value->variable.var_label);
667       put_show_values (buf, value->variable.show);
668       break;
669
670     case PIVOT_VALUE_TEXT:
671       put_byte (buf, 3);
672       put_string (buf, value->text.local);
673       put_value_mod (buf, value, NULL);
674       put_string (buf, value->text.id);
675       put_string (buf, value->text.c);
676       put_byte (buf, 1);        /* XXX user-provided */
677       break;
678
679     case PIVOT_VALUE_TEMPLATE:
680       put_byte (buf, 0);
681       put_value_mod (buf, value, value->template.id);
682       put_string (buf, value->template.local);
683       put_u32 (buf, value->template.n_args);
684       for (size_t i = 0; i < value->template.n_args; i++)
685         {
686           const struct pivot_argument *arg = &value->template.args[i];
687           assert (arg->n >= 1);
688           if (arg->n > 1)
689             {
690               put_u32 (buf, arg->n);
691               put_u32 (buf, 0);
692               for (size_t j = 0; j < arg->n; j++)
693                 {
694                   if (j > 0)
695                     put_bytes (buf, "\0\0\0\0", 4);
696                   put_value (buf, arg->values[j]);
697                 }
698             }
699           else
700             {
701               put_u32 (buf, 0);
702               put_value (buf, arg->values[0]);
703             }
704         }
705       break;
706
707     default:
708       NOT_REACHED ();
709     }
710 }
711
712 static void
713 put_optional_value (struct buf *buf, const struct pivot_value *value)
714 {
715   if (value)
716     {
717       put_byte (buf, 0x31);
718       put_value (buf, value);
719     }
720   else
721     put_byte (buf, 0x58);
722 }
723
724 static void
725 put_category (struct buf *buf, const struct pivot_category *c)
726 {
727   put_value (buf, c->name);
728   if (pivot_category_is_leaf (c))
729     {
730       put_bytes (buf, "\0\0\0", 3);
731       put_u32 (buf, 2);
732       put_u32 (buf, c->data_index);
733       put_u32 (buf, 0);
734     }
735   else
736     {
737       put_bytes (buf, "\0\0\1", 3);
738       put_u32 (buf, 0);         /* x23 */
739       put_u32 (buf, -1);
740       put_u32 (buf, c->n_subs);
741       for (size_t i = 0; i < c->n_subs; i++)
742         put_category (buf, c->subs[i]);
743     }
744 }
745
746 static void
747 put_y0 (struct buf *buf, const struct pivot_table *table)
748 {
749   put_u32 (buf, table->settings.epoch);
750   put_byte (buf, table->settings.decimal);
751   put_byte (buf, ',');
752 }
753
754 static void
755 put_custom_currency (struct buf *buf, const struct pivot_table *table)
756 {
757   put_u32 (buf, 5);
758   for (int i = 0; i < 5; i++)
759     {
760       enum fmt_type types[5] = { FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE };
761       char *cc = fmt_number_style_to_string (fmt_settings_get_style (
762                                                &table->settings, types[i]));
763       put_string (buf, cc);
764       free (cc);
765     }
766 }
767
768 static void
769 put_x1 (struct buf *buf, const struct pivot_table *table)
770 {
771   put_byte (buf, 0);            /* x14 */
772   put_byte (buf, table->show_title ? 1 : 10);
773   put_byte (buf, 0);            /* x16 */
774   put_byte (buf, 0);            /* lang */
775   put_show_values (buf, table->show_variables);
776   put_show_values (buf, table->show_values);
777   put_u32 (buf, -1);            /* x18 */
778   put_u32 (buf, -1);            /* x19 */
779   for (int i = 0; i < 17; i++)
780     put_byte (buf, 0);
781   put_bool (buf, false);        /* x20 */
782   put_byte (buf, table->show_caption);
783 }
784
785 static void
786 put_x2 (struct buf *buf)
787 {
788   put_u32 (buf, 0);             /* n-row-heights */
789   put_u32 (buf, 0);             /* n-style-map */
790   put_u32 (buf, 0);             /* n-styles */
791   put_u32 (buf, 0);
792 }
793
794 static void
795 put_y1 (struct buf *buf, const struct pivot_table *table)
796 {
797   put_string (buf, table->command_c);
798   put_string (buf, table->command_local);
799   put_string (buf, table->language);
800   put_string (buf, "UTF-8");    /* XXX */
801   put_string (buf, table->locale);
802   put_bool (buf, false);        /* x10 */
803   put_bool (buf, table->settings.include_leading_zero);
804   put_bool (buf, true);         /* x12 */
805   put_bool (buf, true);         /* x13 */
806   put_y0 (buf, table);
807 }
808
809 static void
810 put_y2 (struct buf *buf, const struct pivot_table *table)
811 {
812   put_custom_currency (buf, table);
813   put_byte (buf, '.');
814   put_bool (buf, 0);
815 }
816
817 static void
818 put_x3 (struct buf *buf, const struct pivot_table *table)
819 {
820   put_byte (buf, 1);
821   put_byte (buf, 0);
822   put_byte (buf, 4);            /* x21 */
823   put_byte (buf, 0);
824   put_byte (buf, 0);
825   put_byte (buf, 0);
826   put_y1 (buf, table);
827   put_double (buf, table->small);
828   put_byte (buf, 1);
829   put_string (buf, table->dataset);
830   put_string (buf, table->datafile);
831   put_u32 (buf, 0);
832   put_u32 (buf, table->date);
833   put_u32 (buf, 0);
834   put_y2 (buf, table);
835 }
836
837 static uint32_t
838 encode_current_layer (const struct pivot_table *table)
839 {
840   uint32_t current_layer = 0;
841
842   const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
843   for (size_t i = axis->n_dimensions - 1; i < axis->n_dimensions; i--)
844     {
845       const struct pivot_dimension *d = axis->dimensions[i];
846       current_layer = current_layer * d->n_leaves + table->current_layer[i];
847     }
848
849   return current_layer;
850 }
851
852 static void
853 put_light_table (struct buf *buf, uint64_t table_id,
854                  const struct pivot_table *table)
855 {
856   /* Header. */
857   put_bytes (buf, "\1\0", 2);
858   put_u32 (buf, 3);
859   put_bool (buf, true);
860   put_bool (buf, false);
861   put_bool (buf, table->rotate_inner_column_labels);
862   put_bool (buf, table->rotate_outer_row_labels);
863   put_bool (buf, true);
864   put_u32 (buf, 0x15);
865   put_u32 (buf, table->look->width_ranges[H][0]);
866   put_u32 (buf, table->look->width_ranges[H][1]);
867   put_u32 (buf, table->look->width_ranges[V][0]);
868   put_u32 (buf, table->look->width_ranges[V][1]);
869   put_u64 (buf, table_id);
870
871   /* Titles. */
872   put_value (buf, table->title);
873   put_value (buf, table->subtype);
874   put_optional_value (buf, table->title);
875   put_optional_value (buf, table->corner_text);
876   put_optional_value (buf, table->caption);
877
878   /* Footnotes. */
879   put_u32 (buf, table->n_footnotes);
880   for (size_t i = 0; i < table->n_footnotes; i++)
881     {
882       const struct pivot_footnote *f = table->footnotes[i];
883       put_value (buf, f->content);
884       put_optional_value (buf, f->marker);
885       put_u32 (buf, f->show ? 1 : -1);
886     }
887
888   /* Areas. */
889   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
890     {
891       const struct table_area_style *a = &table->look->areas[i];
892       put_byte (buf, i + 1);
893       put_byte (buf, 0x31);
894       put_string (buf, (a->font_style.typeface
895                         ? a->font_style.typeface
896                         : "SansSerif"));
897       put_float (buf, ceil (a->font_style.size * 1.33));
898       put_u32 (buf, ((a->font_style.bold ? 1 : 0)
899                      | (a->font_style.italic ? 2 : 0)));
900       put_bool (buf, a->font_style.underline);
901       put_halign (buf, a->cell_style.halign, 64173, 61453);
902       put_valign (buf, a->cell_style.valign);
903
904       put_color (buf, &a->font_style.fg[0]);
905       put_color (buf, &a->font_style.bg[0]);
906
907       bool alt
908         = (!cell_color_equal (&a->font_style.fg[0], &a->font_style.fg[1])
909            || !cell_color_equal (&a->font_style.bg[0], &a->font_style.bg[1]));
910       put_bool (buf, alt);
911       if (alt)
912         {
913           put_color (buf, &a->font_style.fg[1]);
914           put_color (buf, &a->font_style.bg[1]);
915         }
916       else
917         {
918           put_string (buf, "");
919           put_string (buf, "");
920         }
921
922       put_u32 (buf, a->cell_style.margin[H][0]);
923       put_u32 (buf, a->cell_style.margin[H][1]);
924       put_u32 (buf, a->cell_style.margin[V][0]);
925       put_u32 (buf, a->cell_style.margin[V][1]);
926     }
927
928   /* Borders. */
929   uint32_t borders_start = start_count (buf);
930   put_be32 (buf, 1);
931   put_be32 (buf, PIVOT_N_BORDERS);
932   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
933     {
934       const struct table_border_style *b = &table->look->borders[i];
935       put_be32 (buf, i);
936       put_be32 (buf, (b->stroke == TABLE_STROKE_NONE ? 0
937                       : b->stroke == TABLE_STROKE_SOLID ? 1
938                       : b->stroke == TABLE_STROKE_DASHED ? 2
939                       : b->stroke == TABLE_STROKE_THICK ? 3
940                       : b->stroke == TABLE_STROKE_THIN ? 4
941                       : 5));
942       put_be32 (buf, ((b->color.alpha << 24)
943                       | (b->color.r << 16)
944                       | (b->color.g << 8)
945                       | b->color.b));
946     }
947   put_bool (buf, table->show_grid_lines);
948   put_bytes (buf, "\0\0\0", 3);
949   end_count_u32 (buf, borders_start);
950
951   /* Print Settings. */
952   uint32_t ps_start = start_count (buf);
953   put_be32 (buf, 1);
954   put_bool (buf, table->look->print_all_layers);
955   put_bool (buf, table->look->paginate_layers);
956   put_bool (buf, table->look->shrink_to_fit[H]);
957   put_bool (buf, table->look->shrink_to_fit[V]);
958   put_bool (buf, table->look->top_continuation);
959   put_bool (buf, table->look->bottom_continuation);
960   put_be32 (buf, table->look->n_orphan_lines);
961   put_bestring (buf, table->look->continuation);
962   end_count_u32 (buf, ps_start);
963
964   /* Table Settings. */
965   uint32_t ts_start = start_count (buf);
966   put_be32 (buf, 1);
967   put_be32 (buf, 4);
968   put_be32 (buf, encode_current_layer (table));
969   put_bool (buf, table->look->omit_empty);
970   put_bool (buf, table->look->row_labels_in_corner);
971   put_bool (buf, !table->look->show_numeric_markers);
972   put_bool (buf, table->look->footnote_marker_superscripts);
973   put_byte (buf, 0);
974   uint32_t keep_start = start_count (buf);
975   put_be32 (buf, 0);            /* n-row-breaks */
976   put_be32 (buf, 0);            /* n-column-breaks */
977   put_be32 (buf, 0);            /* n-row-keeps */
978   put_be32 (buf, 0);            /* n-column-keeps */
979   put_be32 (buf, 0);            /* n-row-point-keeps */
980   put_be32 (buf, 0);            /* n-column-point-keeps */
981   end_count_be32 (buf, keep_start);
982   put_bestring (buf, table->notes);
983   put_bestring (buf, table->look->name);
984   for (size_t i = 0; i < 82; i++)
985     put_byte (buf, 0);
986   end_count_u32 (buf, ts_start);
987
988   /* Formats. */
989   put_u32 (buf, 0);             /* n-widths */
990   put_string (buf, "en_US.ISO_8859-1:1987"); /* XXX */
991   put_u32 (buf, 0);                /* XXX current-layer */
992   put_bool (buf, 0);
993   put_bool (buf, 0);
994   put_bool (buf, 1);
995   put_y0 (buf, table);
996   put_custom_currency (buf, table);
997   uint32_t formats_start = start_count (buf);
998   uint32_t x1_start = start_count (buf);
999   put_x1 (buf, table);
1000   uint32_t x2_start = start_count (buf);
1001   put_x2 (buf);
1002   end_count_u32 (buf, x2_start);
1003   end_count_u32 (buf, x1_start);
1004   uint32_t x3_start = start_count (buf);
1005   put_x3 (buf, table);
1006   end_count_u32 (buf, x3_start);
1007   end_count_u32 (buf, formats_start);
1008
1009   /* Dimensions. */
1010   put_u32 (buf, table->n_dimensions);
1011   int *x2 = xnmalloc (table->n_dimensions, sizeof *x2);
1012   for (size_t i = 0; i < table->axes[PIVOT_AXIS_LAYER].n_dimensions; i++)
1013     x2[i] = 2;
1014   for (size_t i = 0; i < table->axes[PIVOT_AXIS_ROW].n_dimensions; i++)
1015     x2[i + table->axes[PIVOT_AXIS_LAYER].n_dimensions] = 0;
1016   for (size_t i = 0; i < table->axes[PIVOT_AXIS_COLUMN].n_dimensions; i++)
1017     x2[i
1018        + table->axes[PIVOT_AXIS_LAYER].n_dimensions
1019        + table->axes[PIVOT_AXIS_ROW].n_dimensions] = 1;
1020   for (size_t i = 0; i < table->n_dimensions; i++)
1021     {
1022       const struct pivot_dimension *d = table->dimensions[i];
1023       put_value (buf, d->root->name);
1024       put_byte (buf, 0);        /* x1 */
1025       put_byte (buf, x2[i]);
1026       put_u32 (buf, 2);         /* x3 */
1027       put_bool (buf, !d->root->show_label);
1028       put_bool (buf, d->hide_all_labels);
1029       put_bool (buf, 1);
1030       put_u32 (buf, i);
1031
1032       put_u32 (buf, d->root->n_subs);
1033       for (size_t j = 0; j < d->root->n_subs; j++)
1034         put_category (buf, d->root->subs[j]);
1035     }
1036   free (x2);
1037
1038   /* Axes. */
1039   put_u32 (buf, table->axes[PIVOT_AXIS_LAYER].n_dimensions);
1040   put_u32 (buf, table->axes[PIVOT_AXIS_ROW].n_dimensions);
1041   put_u32 (buf, table->axes[PIVOT_AXIS_COLUMN].n_dimensions);
1042   for (size_t i = 0; i < table->axes[PIVOT_AXIS_LAYER].n_dimensions; i++)
1043     put_u32 (buf, table->axes[PIVOT_AXIS_LAYER].dimensions[i]->top_index);
1044   for (size_t i = 0; i < table->axes[PIVOT_AXIS_ROW].n_dimensions; i++)
1045     put_u32 (buf, table->axes[PIVOT_AXIS_ROW].dimensions[i]->top_index);
1046   for (size_t i = 0; i < table->axes[PIVOT_AXIS_COLUMN].n_dimensions; i++)
1047     put_u32 (buf, table->axes[PIVOT_AXIS_COLUMN].dimensions[i]->top_index);
1048
1049   /* Cells. */
1050   put_u32 (buf, hmap_count (&table->cells));
1051   const struct pivot_cell *cell;
1052   HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
1053     {
1054       uint64_t index = 0;
1055       for (size_t j = 0; j < table->n_dimensions; j++)
1056         index = (table->dimensions[j]->n_leaves * index) + cell->idx[j];
1057       put_u64 (buf, index);
1058
1059       put_value (buf, cell->value);
1060     }
1061 }
1062
1063 static void
1064 spv_writer_put_table (struct spv_writer *w, const struct output_item *item)
1065 {
1066   int table_id = ++w->n_tables;
1067
1068   bool initial_depth = w->heading_depth;
1069   if (!initial_depth)
1070     spv_writer_open_file (w);
1071
1072   open_container (w, item, "vtb:table");
1073
1074   write_attr (w, "type", "table"); /* XXX */
1075   write_attr_format (w, "tableId", "%d", table_id);
1076   char *subtype = (item->table->subtype
1077                    ? pivot_value_to_string (item->table->subtype, item->table)
1078                    : xstrdup ("unknown"));
1079   write_attr (w, "subType", subtype);
1080   free (subtype);
1081
1082   start_elem (w, "vtb:tableStructure");
1083   start_elem (w, "vtb:dataPath");
1084   char *data_path = xasprintf ("%010d_lightTableData.bin", table_id);
1085   write_text (w, data_path);
1086   end_elem (w); /* vtb:dataPath */
1087   end_elem (w); /* vtb:tableStructure */
1088
1089   close_container (w);
1090
1091   if (!initial_depth)
1092     spv_writer_close_file (w, "");
1093
1094   struct buf buf = { NULL, 0, 0 };
1095   put_light_table (&buf, table_id, item->table);
1096   zip_writer_add_memory (w->zw, data_path, buf.data, buf.len);
1097   free (buf.data);
1098
1099   free (data_path);
1100 }
1101 \f
1102 void
1103 spv_writer_write (struct spv_writer *w, const struct output_item *item)
1104 {
1105   switch (item->type)
1106     {
1107     case OUTPUT_ITEM_CHART:
1108       {
1109         cairo_surface_t *surface = xr_draw_image_chart (
1110           item->chart,
1111           &(struct cell_color) CELL_COLOR_BLACK,
1112           &(struct cell_color) CELL_COLOR_WHITE);
1113         if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
1114           spv_writer_put_image (w, item, surface);
1115         cairo_surface_destroy (surface);
1116       }
1117       break;
1118
1119     case OUTPUT_ITEM_GROUP:
1120       spv_writer_open_heading (w, item);
1121       for (size_t i = 0; i < item->group.n_children; i++)
1122         spv_writer_write (w, item->group.children[i]);
1123       spv_writer_close_heading (w);
1124       break;
1125
1126     case OUTPUT_ITEM_IMAGE:
1127       spv_writer_put_image (w, item, item->image);
1128       break;
1129
1130     case OUTPUT_ITEM_MESSAGE:
1131       spv_writer_put_text (
1132         w, message_item_to_text_item (output_item_ref (item)));
1133       break;
1134
1135     case OUTPUT_ITEM_PAGE_BREAK:
1136       w->need_page_break = true;
1137       break;
1138
1139     case OUTPUT_ITEM_TABLE:
1140       spv_writer_put_table (w, item);
1141       break;
1142
1143     case OUTPUT_ITEM_TEXT:
1144       spv_writer_put_text (w, output_item_ref (item));
1145       break;
1146     }
1147 }
1148
1149 void
1150 spv_writer_set_page_setup (struct spv_writer *w,
1151                            const struct page_setup *ps)
1152 {
1153   page_setup_destroy (w->page_setup);
1154   w->page_setup = page_setup_clone (ps);
1155 }