1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2019 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "output/spv/spv-writer.h"
23 #include <libxml/xmlwriter.h>
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"
42 #include "gl/xalloc.h"
43 #include "gl/xvasprintf.h"
46 #define _(msgid) gettext (msgid)
47 #define N_(msgid) (msgid)
51 struct zip_writer *zw;
60 struct page_setup *page_setup;
64 static void spv_writer_close_heading (struct spv_writer *);
66 char * WARN_UNUSED_RESULT
67 spv_writer_open (const char *filename, struct spv_writer **writerp)
71 struct zip_writer *zw = zip_writer_create (filename);
73 return xasprintf (_("%s: create failed"), filename);
75 struct spv_writer *w = xmalloc (sizeof *w);
76 *w = (struct spv_writer) { .zw = zw };
81 char * WARN_UNUSED_RESULT
82 spv_writer_close (struct spv_writer *w)
87 zip_writer_add_string (w->zw, "META-INF/MANIFEST.MF", "allowPivoting=true");
89 while (w->heading_depth)
90 spv_writer_close_heading (w);
93 if (!zip_writer_close (w->zw))
94 error = xstrdup (_("I/O error writing SPV file"));
96 page_setup_destroy (w->page_setup);
102 write_attr (struct spv_writer *w, const char *name, const char *value)
104 xmlTextWriterWriteAttribute (w->xml,
105 CHAR_CAST (xmlChar *, name),
106 CHAR_CAST (xmlChar *, value));
109 static void PRINTF_FORMAT (3, 4)
110 write_attr_format (struct spv_writer *w, const char *name,
111 const char *format, ...)
114 va_start (args, format);
115 char *value = xvasprintf (format, args);
118 write_attr (w, name, value);
123 start_elem (struct spv_writer *w, const char *name)
125 xmlTextWriterStartElement (w->xml, CHAR_CAST (xmlChar *, name));
129 end_elem (struct spv_writer *w)
131 xmlTextWriterEndElement (w->xml);
135 write_text (struct spv_writer *w, const char *text)
137 xmlTextWriterWriteString (w->xml, CHAR_CAST (xmlChar *, text));
141 write_page_heading (struct spv_writer *w, const struct page_heading *h,
144 start_elem (w, name);
147 start_elem (w, "pageParagraph");
148 for (size_t i = 0; i < h->n; i++)
150 start_elem (w, "text");
151 write_attr (w, "type", "title");
152 write_text (w, h->paragraphs[i].markup); /* XXX */
161 write_page_setup (struct spv_writer *w, const struct page_setup *ps)
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");
185 spv_writer_open_file (struct spv_writer *w)
187 w->heading = create_temp_file ();
191 w->xml = xmlNewTextWriter (xmlOutputBufferCreateFile (w->heading, NULL));
192 xmlTextWriterStartDocument (w->xml, NULL, "UTF-8", NULL);
193 start_elem (w, "heading");
195 time_t t = time (NULL);
196 struct tm *tm = gmtime (&t);
198 if (strftime (tm_s, sizeof tm_s, "%x %X", tm))
199 write_attr (w, "creation-date-time", tm_s);
201 write_attr (w, "creator", version);
203 write_attr (w, "creator-version", "21");
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");
210 start_elem (w, "label");
211 write_text (w, _("Output"));
216 write_page_setup (w, w->page_setup);
218 page_setup_destroy (w->page_setup);
219 w->page_setup = NULL;
226 spv_writer_open_heading (struct spv_writer *w, const struct output_item *item)
230 if (!spv_writer_open_file (w))
235 start_elem (w, "heading");
236 if (item->command_name)
237 write_attr (w, "commandName", item->command_name);
239 write_attr (w, "visibility", "collapsed");
243 start_elem (w, "label");
244 write_text (w, output_item_get_label (item));
249 spv_writer_close_file (struct spv_writer *w, const char *infix)
255 xmlTextWriterEndDocument (w->xml);
256 xmlFreeTextWriter (w->xml);
258 char *member_name = xasprintf ("outputViewer%010d%s.xml",
259 w->n_headings++, infix);
260 zip_writer_add (w->zw, w->heading, member_name);
267 spv_writer_close_heading (struct spv_writer *w)
269 const char *infix = "";
270 if (w->heading_depth)
277 if (!w->heading_depth)
278 spv_writer_close_file (w, infix);
282 open_container (struct spv_writer *w, const struct output_item *item,
283 const char *inner_elem)
285 start_elem (w, "container");
286 write_attr (w, "visibility", item->show ? "visible" : "hidden");
287 if (w->need_page_break)
289 write_attr (w, "page-break-before", "always");
290 w->need_page_break = false;
293 start_elem (w, "label");
294 write_text (w, output_item_get_label (item));
297 start_elem (w, inner_elem);
298 if (item->command_name)
299 write_attr (w, "commandName", item->command_name);
303 close_container (struct spv_writer *w)
310 spv_writer_put_text (struct spv_writer *w, struct output_item *item)
312 bool initial_depth = w->heading_depth;
314 spv_writer_open_file (w);
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"
322 start_elem (w, "html");
323 char *s = text_item_get_plain_text (item);
331 spv_writer_close_file (w, "");
333 output_item_unref (item);
336 static cairo_status_t
337 write_to_zip (void *zw_, const unsigned char *data, unsigned int length)
339 struct zip_writer *zw = zw_;
341 zip_writer_add_write (zw, data, length);
342 return CAIRO_STATUS_SUCCESS;
346 spv_writer_put_image (struct spv_writer *w, const struct output_item *item,
347 cairo_surface_t *image)
349 bool initial_depth = w->heading_depth;
351 spv_writer_open_file (w);
353 char *uri = xasprintf ("%010d_Imagegeneric.png", ++w->n_tables);
355 open_container (w, item, "object");
356 write_attr (w, "type", "unknown");
357 write_attr (w, "uri", uri);
361 spv_writer_close_file (w, "");
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);
381 put_uninit (struct buf *b, size_t n)
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];
391 put_byte (struct buf *b, uint8_t byte)
393 *put_uninit (b, 1) = byte;
397 put_bool (struct buf *b, bool boolean)
399 put_byte (b, boolean);
403 put_bytes (struct buf *b, const char *bytes, size_t n)
405 memcpy (put_uninit (b, n), bytes, n);
409 put_u16 (struct buf *b, uint16_t x)
411 put_uint16 (native_to_le16 (x), put_uninit (b, sizeof x));
415 put_u32 (struct buf *b, uint32_t x)
417 put_uint32 (native_to_le32 (x), put_uninit (b, sizeof x));
421 put_u64 (struct buf *b, uint64_t x)
423 put_uint64 (native_to_le64 (x), put_uninit (b, sizeof x));
427 put_be32 (struct buf *b, uint32_t x)
429 put_uint32 (native_to_be32 (x), put_uninit (b, sizeof x));
433 put_double (struct buf *b, double x)
435 float_convert (FLOAT_NATIVE_DOUBLE, &x,
436 FLOAT_IEEE_DOUBLE_LE, put_uninit (b, 8));
440 put_float (struct buf *b, float x)
442 float_convert (FLOAT_NATIVE_FLOAT, &x,
443 FLOAT_IEEE_SINGLE_LE, put_uninit (b, 4));
447 put_string (struct buf *b, const char *s_)
449 const char *s = s_ ? s_ : "";
450 size_t len = strlen (s);
452 memcpy (put_uninit (b, len), s, len);
456 put_bestring (struct buf *b, const char *s_)
458 const char *s = s_ ? s_ : "";
459 size_t len = strlen (s);
461 memcpy (put_uninit (b, len), s, len);
465 start_count (struct buf *b)
472 end_count_u32 (struct buf *b, size_t start)
474 put_uint32 (native_to_le32 (b->len - start), &b->data[start - 4]);
478 end_count_be32 (struct buf *b, size_t start)
480 put_uint32 (native_to_be32 (b->len - start), &b->data[start - 4]);
484 put_color (struct buf *buf, const struct cell_color *color)
486 char *s = xasprintf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8,
487 color->r, color->g, color->b);
493 put_font_style (struct buf *buf, const struct font_style *font_style)
495 put_bool (buf, font_style->bold);
496 put_bool (buf, font_style->italic);
497 put_bool (buf, font_style->underline);
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));
506 put_halign (struct buf *buf, enum table_halign halign,
507 uint32_t mixed, uint32_t decimal)
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
517 put_valign (struct buf *buf, enum table_valign valign)
519 put_u32 (buf, (valign == TABLE_VALIGN_TOP ? 1
520 : valign == TABLE_VALIGN_CENTER ? 0
525 put_cell_style (struct buf *buf, const struct cell_style *cell_style)
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]);
537 put_style_pair (struct buf *buf, const struct font_style *font_style,
538 const struct cell_style *cell_style)
542 put_byte (buf, 0x31);
543 put_font_style (buf, font_style);
546 put_byte (buf, 0x58);
550 put_byte (buf, 0x31);
551 put_cell_style (buf, cell_style);
554 put_byte (buf, 0x58);
558 put_value_mod (struct buf *buf, const struct pivot_value *value,
559 const char *template)
562 && (value->ex->n_footnotes
563 || value->ex->n_subscripts
564 || value->ex->font_style
565 || value->ex->cell_style))
568 const struct pivot_value_ex *ex = pivot_value_ex (value);
569 put_byte (buf, 0x31);
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]);
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]);
581 /* Template and style. */
582 uint32_t v3_start = start_count (buf);
583 uint32_t template_string_start = start_count (buf);
586 uint32_t inner_start = start_count (buf);
587 end_count_u32 (buf, inner_start);
589 put_byte (buf, 0x31);
590 put_string (buf, template);
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);
597 put_byte (buf, 0x58);
601 put_format (struct buf *buf, const struct fmt_spec *f, bool honor_small)
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);
608 show_values_to_spvlb (enum settings_value_show show)
610 return (show == SETTINGS_VALUE_SHOW_DEFAULT ? 0
611 : show == SETTINGS_VALUE_SHOW_VALUE ? 1
612 : show == SETTINGS_VALUE_SHOW_LABEL ? 2
617 put_show_values (struct buf *buf, enum settings_value_show show)
619 put_byte (buf, show_values_to_spvlb (show));
623 put_value (struct buf *buf, const struct pivot_value *value)
627 case PIVOT_VALUE_NUMERIC:
628 if (value->numeric.var_name || value->numeric.value_label)
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);
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);
647 case PIVOT_VALUE_STRING:
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 },
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);
662 case PIVOT_VALUE_VARIABLE:
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);
670 case PIVOT_VALUE_TEXT:
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 */
679 case PIVOT_VALUE_TEMPLATE:
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++)
686 const struct pivot_argument *arg = &value->template.args[i];
687 assert (arg->n >= 1);
690 put_u32 (buf, arg->n);
692 for (size_t j = 0; j < arg->n; j++)
695 put_bytes (buf, "\0\0\0\0", 4);
696 put_value (buf, arg->values[j]);
702 put_value (buf, arg->values[0]);
713 put_optional_value (struct buf *buf, const struct pivot_value *value)
717 put_byte (buf, 0x31);
718 put_value (buf, value);
721 put_byte (buf, 0x58);
725 put_category (struct buf *buf, const struct pivot_category *c)
727 put_value (buf, c->name);
728 if (pivot_category_is_leaf (c))
730 put_bytes (buf, "\0\0\0", 3);
732 put_u32 (buf, c->data_index);
737 put_bytes (buf, "\0\0\1", 3);
738 put_u32 (buf, 0); /* x23 */
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]);
747 put_y0 (struct buf *buf, const struct pivot_table *table)
749 put_u32 (buf, table->settings.epoch);
750 put_byte (buf, table->settings.decimal);
755 put_custom_currency (struct buf *buf, const struct pivot_table *table)
758 for (int i = 0; i < 5; i++)
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);
769 put_x1 (struct buf *buf, const struct pivot_table *table)
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++)
781 put_bool (buf, false); /* x20 */
782 put_byte (buf, table->show_caption);
786 put_x2 (struct buf *buf)
788 put_u32 (buf, 0); /* n-row-heights */
789 put_u32 (buf, 0); /* n-style-map */
790 put_u32 (buf, 0); /* n-styles */
795 put_y1 (struct buf *buf, const struct pivot_table *table)
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 */
810 put_y2 (struct buf *buf, const struct pivot_table *table)
812 put_custom_currency (buf, table);
818 put_x3 (struct buf *buf, const struct pivot_table *table)
822 put_byte (buf, 4); /* x21 */
827 put_double (buf, table->small);
829 put_string (buf, table->dataset);
830 put_string (buf, table->datafile);
832 put_u32 (buf, table->date);
838 encode_current_layer (const struct pivot_table *table)
840 uint32_t current_layer = 0;
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--)
845 const struct pivot_dimension *d = axis->dimensions[i];
846 current_layer = current_layer * d->n_leaves + table->current_layer[i];
849 return current_layer;
853 put_light_table (struct buf *buf, uint64_t table_id,
854 const struct pivot_table *table)
857 put_bytes (buf, "\1\0", 2);
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);
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);
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);
879 put_u32 (buf, table->n_footnotes);
880 for (size_t i = 0; i < table->n_footnotes; i++)
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);
889 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
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
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);
904 put_color (buf, &a->font_style.fg[0]);
905 put_color (buf, &a->font_style.bg[0]);
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]));
913 put_color (buf, &a->font_style.fg[1]);
914 put_color (buf, &a->font_style.bg[1]);
918 put_string (buf, "");
919 put_string (buf, "");
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]);
929 uint32_t borders_start = start_count (buf);
931 put_be32 (buf, PIVOT_N_BORDERS);
932 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
934 const struct table_border_style *b = &table->look->borders[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
942 put_be32 (buf, ((b->color.alpha << 24)
947 put_bool (buf, table->show_grid_lines);
948 put_bytes (buf, "\0\0\0", 3);
949 end_count_u32 (buf, borders_start);
951 /* Print Settings. */
952 uint32_t ps_start = start_count (buf);
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);
964 /* Table Settings. */
965 uint32_t ts_start = start_count (buf);
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);
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++)
986 end_count_u32 (buf, ts_start);
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 */
996 put_custom_currency (buf, table);
997 uint32_t formats_start = start_count (buf);
998 uint32_t x1_start = start_count (buf);
1000 uint32_t x2_start = start_count (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);
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++)
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++)
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++)
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);
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]);
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);
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)
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);
1059 put_value (buf, cell->value);
1064 spv_writer_put_table (struct spv_writer *w, const struct output_item *item)
1066 int table_id = ++w->n_tables;
1068 bool initial_depth = w->heading_depth;
1070 spv_writer_open_file (w);
1072 open_container (w, item, "vtb:table");
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);
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 */
1089 close_container (w);
1092 spv_writer_close_file (w, "");
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);
1103 spv_writer_write (struct spv_writer *w, const struct output_item *item)
1107 case OUTPUT_ITEM_CHART:
1109 cairo_surface_t *surface = xr_draw_image_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);
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);
1126 case OUTPUT_ITEM_IMAGE:
1127 spv_writer_put_image (w, item, item->image);
1130 case OUTPUT_ITEM_MESSAGE:
1131 spv_writer_put_text (
1132 w, message_item_to_text_item (output_item_ref (item)));
1135 case OUTPUT_ITEM_PAGE_BREAK:
1136 w->need_page_break = true;
1139 case OUTPUT_ITEM_TABLE:
1140 spv_writer_put_table (w, item);
1143 case OUTPUT_ITEM_TEXT:
1144 spv_writer_put_text (w, output_item_ref (item));
1150 spv_writer_set_page_setup (struct spv_writer *w,
1151 const struct page_setup *ps)
1153 page_setup_destroy (w->page_setup);
1154 w->page_setup = page_setup_clone (ps);