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"
22 #include <libxml/xmlwriter.h>
27 #include "libpspp/array.h"
28 #include "libpspp/assertion.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/float-format.h"
31 #include "libpspp/integer-format.h"
32 #include "libpspp/temp-file.h"
33 #include "libpspp/version.h"
34 #include "libpspp/zip-writer.h"
35 #include "output/page-setup-item.h"
36 #include "output/pivot-table.h"
37 #include "output/text-item.h"
39 #include "gl/xalloc.h"
40 #include "gl/xvasprintf.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) (msgid)
48 struct zip_writer *zw;
57 struct page_setup *page_setup;
61 char * WARN_UNUSED_RESULT
62 spv_writer_open (const char *filename, struct spv_writer **writerp)
66 struct zip_writer *zw = zip_writer_create (filename);
68 return xasprintf (_("%s: create failed"), filename);
70 struct spv_writer *w = xmalloc (sizeof *w);
71 *w = (struct spv_writer) { .zw = zw };
76 char * WARN_UNUSED_RESULT
77 spv_writer_close (struct spv_writer *w)
82 zip_writer_add_string (w->zw, "META-INF/MANIFEST.MF", "allowPivoting=true");
84 while (w->heading_depth)
85 spv_writer_close_heading (w);
88 if (!zip_writer_close (w->zw))
89 error = xstrdup (_("I/O error writing SPV file"));
91 page_setup_destroy (w->page_setup);
97 spv_writer_set_page_setup (struct spv_writer *w,
98 const struct page_setup *page_setup)
100 page_setup_destroy (w->page_setup);
101 w->page_setup = page_setup_clone (page_setup);
105 write_attr (struct spv_writer *w, const char *name, const char *value)
107 xmlTextWriterWriteAttribute (w->xml,
108 CHAR_CAST (xmlChar *, name),
109 CHAR_CAST (xmlChar *, value));
112 static void PRINTF_FORMAT (3, 4)
113 write_attr_format (struct spv_writer *w, const char *name,
114 const char *format, ...)
117 va_start (args, format);
118 char *value = xvasprintf (format, args);
121 write_attr (w, name, value);
126 start_elem (struct spv_writer *w, const char *name)
128 xmlTextWriterStartElement (w->xml, CHAR_CAST (xmlChar *, name));
132 end_elem (struct spv_writer *w)
134 xmlTextWriterEndElement (w->xml);
138 write_text (struct spv_writer *w, const char *text)
140 xmlTextWriterWriteString (w->xml, CHAR_CAST (xmlChar *, text));
144 write_page_heading (struct spv_writer *w, const struct page_heading *h,
147 start_elem (w, name);
150 start_elem (w, "pageParagraph");
151 for (size_t i = 0; i < h->n; i++)
153 start_elem (w, "text");
154 write_attr (w, "type", "title");
155 write_text (w, h->paragraphs[i].markup); /* XXX */
164 write_page_setup (struct spv_writer *w, const struct page_setup *ps)
166 start_elem (w, "pageSetup");
167 write_attr_format (w, "initial-page-number", "%d", ps->initial_page_number);
168 write_attr (w, "chart-size",
169 (ps->chart_size == PAGE_CHART_AS_IS ? "as-is"
170 : ps->chart_size == PAGE_CHART_FULL_HEIGHT ? "full-height"
171 : ps->chart_size == PAGE_CHART_HALF_HEIGHT ? "half-height"
172 : "quarter-height"));
173 write_attr_format (w, "margin-left", "%.2fin", ps->margins[TABLE_HORZ][0]);
174 write_attr_format (w, "margin-right", "%.2fin", ps->margins[TABLE_HORZ][1]);
175 write_attr_format (w, "margin-top", "%.2fin", ps->margins[TABLE_VERT][0]);
176 write_attr_format (w, "margin-bottom", "%.2fin", ps->margins[TABLE_VERT][1]);
177 write_attr_format (w, "paper-height", "%.2fin", ps->paper[TABLE_VERT]);
178 write_attr_format (w, "paper-width", "%.2fin", ps->paper[TABLE_HORZ]);
179 write_attr (w, "reference-orientation",
180 ps->orientation == PAGE_PORTRAIT ? "portrait" : "landscape");
181 write_attr_format (w, "space-after", "%.1fpt", ps->object_spacing * 72.0);
182 write_page_heading (w, &ps->headings[0], "pageHeader");
183 write_page_heading (w, &ps->headings[1], "pageFooter");
188 spv_writer_open_file (struct spv_writer *w)
190 w->heading = create_temp_file ();
194 w->xml = xmlNewTextWriter (xmlOutputBufferCreateFile (w->heading, NULL));
195 xmlTextWriterStartDocument (w->xml, NULL, "UTF-8", NULL);
196 start_elem (w, "heading");
198 time_t t = time (NULL);
199 struct tm *tm = gmtime (&t);
200 char *tm_s = asctime (tm);
201 write_attr (w, "creation-date-time", tm_s);
203 write_attr (w, "creator", version);
205 write_attr (w, "creator-version", "21");
207 write_attr (w, "xmlns", "http://xml.spss.com/spss/viewer/viewer-tree");
208 write_attr (w, "xmlns:vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
209 write_attr (w, "xmlns:vtx", "http://xml.spss.com/spss/viewer/viewer-text");
210 write_attr (w, "xmlns:vtb", "http://xml.spss.com/spss/viewer/viewer-table");
212 start_elem (w, "label");
213 write_text (w, _("Output"));
218 write_page_setup (w, w->page_setup);
220 page_setup_destroy (w->page_setup);
221 w->page_setup = NULL;
228 spv_writer_open_heading (struct spv_writer *w, const char *command_id,
233 if (!spv_writer_open_file (w))
238 start_elem (w, "heading");
239 write_attr (w, "commandName", command_id);
243 start_elem (w, "label");
244 write_text (w, label);
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 start_container (struct spv_writer *w)
284 start_elem (w, "container");
285 write_attr (w, "visibility", "visible");
286 if (w->need_page_break)
288 write_attr (w, "page-break-before", "always");
289 w->need_page_break = false;
294 spv_writer_put_text (struct spv_writer *w, const struct text_item *text,
295 const char *command_id)
297 bool initial_depth = w->heading_depth;
299 spv_writer_open_file (w);
303 start_elem (w, "label");
304 write_text (w, (text->type == TEXT_ITEM_TITLE ? "Title"
305 : text->type == TEXT_ITEM_PAGE_TITLE ? "Page Title"
309 start_elem (w, "vtx:text");
310 write_attr (w, "type", (text->type == TEXT_ITEM_TITLE ? "title"
311 : text->type == TEXT_ITEM_PAGE_TITLE ? "page-title"
314 write_attr (w, "commandName", command_id);
316 start_elem (w, "html");
317 write_text (w, text->text); /* XXX */
318 end_elem (w); /* html */
319 end_elem (w); /* vtx:text */
320 end_elem (w); /* container */
323 spv_writer_close_file (w, "");
327 spv_writer_eject_page (struct spv_writer *w)
329 w->need_page_break = true;
343 put_uninit (struct buf *b, size_t n)
345 while (b->allocated - b->len < n)
346 b->data = x2nrealloc (b->data, &b->allocated, sizeof b->data);
347 uint8_t *p = &b->data[b->len];
353 put_byte (struct buf *b, uint8_t byte)
355 *put_uninit (b, 1) = byte;
359 put_bool (struct buf *b, bool boolean)
361 put_byte (b, boolean);
365 put_bytes (struct buf *b, const char *bytes, size_t n)
367 memcpy (put_uninit (b, n), bytes, n);
371 put_u16 (struct buf *b, uint16_t x)
373 put_uint16 (native_to_le16 (x), put_uninit (b, sizeof x));
377 put_u32 (struct buf *b, uint32_t x)
379 put_uint32 (native_to_le32 (x), put_uninit (b, sizeof x));
383 put_u64 (struct buf *b, uint64_t x)
385 put_uint64 (native_to_le64 (x), put_uninit (b, sizeof x));
389 put_be32 (struct buf *b, uint32_t x)
391 put_uint32 (native_to_be32 (x), put_uninit (b, sizeof x));
395 put_double (struct buf *b, double x)
397 float_convert (FLOAT_NATIVE_DOUBLE, &x,
398 FLOAT_IEEE_DOUBLE_LE, put_uninit (b, 8));
402 put_float (struct buf *b, float x)
404 float_convert (FLOAT_NATIVE_FLOAT, &x,
405 FLOAT_IEEE_SINGLE_LE, put_uninit (b, 4));
409 put_string (struct buf *b, const char *s_)
411 const char *s = s_ ? s_ : "";
412 size_t len = strlen (s);
414 memcpy (put_uninit (b, len), s, len);
418 put_bestring (struct buf *b, const char *s_)
420 const char *s = s_ ? s_ : "";
421 size_t len = strlen (s);
423 memcpy (put_uninit (b, len), s, len);
427 start_count (struct buf *b)
434 end_count_u32 (struct buf *b, size_t start)
436 put_uint32 (native_to_le32 (b->len - start), &b->data[start - 4]);
440 end_count_be32 (struct buf *b, size_t start)
442 put_uint32 (native_to_be32 (b->len - start), &b->data[start - 4]);
446 put_color (struct buf *buf, const struct cell_color *color)
448 char *s = xasprintf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8,
449 color->r, color->g, color->b);
455 put_font_style (struct buf *buf, const struct font_style *font_style)
457 put_bool (buf, font_style->bold);
458 put_bool (buf, font_style->italic);
459 put_bool (buf, font_style->underline);
461 put_color (buf, &font_style->fg[0]);
462 put_color (buf, &font_style->bg[0]);
463 put_string (buf, font_style->typeface ? font_style->typeface : "SansSerif");
464 put_byte (buf, ceil (font_style->size * 1.33));
468 put_halign (struct buf *buf, enum table_halign halign,
469 uint32_t mixed, uint32_t decimal)
471 put_u32 (buf, (halign == TABLE_HALIGN_RIGHT ? 4
472 : halign == TABLE_HALIGN_LEFT ? 2
473 : halign == TABLE_HALIGN_CENTER ? 0
474 : halign == TABLE_HALIGN_MIXED ? mixed
479 put_valign (struct buf *buf, enum table_valign valign)
481 put_u32 (buf, (valign == TABLE_VALIGN_TOP ? 1
482 : valign == TABLE_VALIGN_CENTER ? 0
487 put_cell_style (struct buf *buf, const struct cell_style *cell_style)
489 put_halign (buf, cell_style->halign, 0xffffffad, 6);
490 put_valign (buf, cell_style->valign);
491 put_double (buf, cell_style->decimal_offset);
492 put_u16 (buf, cell_style->margin[H][0]);
493 put_u16 (buf, cell_style->margin[H][1]);
494 put_u16 (buf, cell_style->margin[V][0]);
495 put_u16 (buf, cell_style->margin[V][1]);
499 put_style_pair (struct buf *buf, const struct font_style *font_style,
500 const struct cell_style *cell_style)
504 put_byte (buf, 0x31);
505 put_font_style (buf, font_style);
508 put_byte (buf, 0x58);
512 put_byte (buf, 0x31);
513 put_cell_style (buf, cell_style);
516 put_byte (buf, 0x58);
520 put_value_mod (struct buf *buf, const struct pivot_value *value,
521 const char *template)
523 if (value->n_footnotes || value->n_subscripts
524 || template || value->font_style || value->cell_style)
526 put_byte (buf, 0x31);
529 put_u32 (buf, value->n_footnotes);
530 for (size_t i = 0; i < value->n_footnotes; i++)
531 put_u16 (buf, value->footnote_indexes[i]);
534 put_u32 (buf, value->n_subscripts);
535 for (size_t i = 0; i < value->n_subscripts; i++)
536 put_string (buf, value->subscripts[i]);
538 /* Template and style. */
539 uint32_t v3_start = start_count (buf);
540 uint32_t template_string_start = start_count (buf);
543 uint32_t inner_start = start_count (buf);
544 end_count_u32 (buf, inner_start);
546 put_byte (buf, 0x31);
547 put_string (buf, template);
549 end_count_u32 (buf, template_string_start);
550 put_style_pair (buf, value->font_style, value->cell_style);
551 end_count_u32 (buf, v3_start);
554 put_byte (buf, 0x58);
558 put_format (struct buf *buf, const struct fmt_spec *f, bool honor_small)
560 int type = f->type == FMT_F && honor_small ? 40 : fmt_to_io (f->type);
561 put_u32 (buf, (type << 16) | (f->w << 8) | f->d);
565 show_values_to_spvlb (enum settings_value_show show)
567 return (show == SETTINGS_VALUE_SHOW_DEFAULT ? 0
568 : show == SETTINGS_VALUE_SHOW_VALUE ? 1
569 : show == SETTINGS_VALUE_SHOW_LABEL ? 2
574 put_show_values (struct buf *buf, enum settings_value_show show)
576 put_byte (buf, show_values_to_spvlb (show));
580 put_value (struct buf *buf, const struct pivot_value *value)
584 case PIVOT_VALUE_NUMERIC:
585 if (value->numeric.var_name || value->numeric.value_label)
588 put_value_mod (buf, value, NULL);
589 put_format (buf, &value->numeric.format, value->numeric.honor_small);
590 put_double (buf, value->numeric.x);
591 put_string (buf, value->numeric.var_name);
592 put_string (buf, value->numeric.value_label);
593 put_show_values (buf, value->numeric.show);
598 put_value_mod (buf, value, NULL);
599 put_format (buf, &value->numeric.format, value->numeric.honor_small);
600 put_double (buf, value->numeric.x);
604 case PIVOT_VALUE_STRING:
606 put_value_mod (buf, value, NULL);
608 &(struct fmt_spec) { FMT_A, strlen (value->string.s), 0 },
610 put_string (buf, value->string.value_label);
611 put_string (buf, value->string.var_name);
612 put_show_values (buf, value->string.show);
613 put_string (buf, value->string.s);
616 case PIVOT_VALUE_VARIABLE:
618 put_value_mod (buf, value, NULL);
619 put_string (buf, value->variable.var_name);
620 put_string (buf, value->variable.var_label);
621 put_show_values (buf, value->variable.show);
624 case PIVOT_VALUE_TEXT:
626 put_string (buf, value->text.local);
627 put_value_mod (buf, value, NULL);
628 put_string (buf, value->text.id);
629 put_string (buf, value->text.c);
630 put_byte (buf, 1); /* XXX user-provided */
633 case PIVOT_VALUE_TEMPLATE:
635 put_value_mod (buf, value, value->template.id);
636 put_string (buf, value->template.local);
637 put_u32 (buf, value->template.n_args);
638 for (size_t i = 0; i < value->template.n_args; i++)
640 const struct pivot_argument *arg = &value->template.args[i];
641 assert (arg->n >= 1);
644 put_u32 (buf, arg->n);
646 for (size_t j = 0; j < arg->n; j++)
649 put_bytes (buf, "\0\0\0\0", 4);
650 put_value (buf, arg->values[j]);
656 put_value (buf, arg->values[0]);
667 put_optional_value (struct buf *buf, const struct pivot_value *value)
671 put_byte (buf, 0x31);
672 put_value (buf, value);
675 put_byte (buf, 0x58);
679 put_category (struct buf *buf, const struct pivot_category *c)
681 put_value (buf, c->name);
682 if (pivot_category_is_leaf (c))
684 put_bytes (buf, "\0\0\0", 3);
686 put_u32 (buf, c->data_index);
691 put_bytes (buf, "\0\0\1", 3);
694 put_u32 (buf, c->n_subs);
695 for (size_t i = 0; i < c->n_subs; i++)
696 put_category (buf, c->subs[i]);
701 put_y0 (struct buf *buf, const struct pivot_table *table)
703 put_u32 (buf, table->settings.epoch);
704 put_byte (buf, table->settings.decimal);
705 put_byte (buf, table->grouping);
709 put_custom_currency (struct buf *buf, const struct pivot_table *table)
712 for (int i = 0; i < 5; i++)
714 enum fmt_type types[5] = { FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE };
715 char *cc = fmt_number_style_to_string (fmt_settings_get_style (
716 &table->settings, types[i]));
717 put_string (buf, cc);
723 put_x1 (struct buf *buf, const struct pivot_table *table)
726 put_byte (buf, table->show_title ? 1 : 10);
729 put_show_values (buf, table->show_variables);
730 put_show_values (buf, table->show_values);
733 for (int i = 0; i < 17; i++)
735 put_bool (buf, false);
736 put_byte (buf, table->show_caption);
740 put_x2 (struct buf *buf)
742 put_u32 (buf, 0); /* n-row-heights */
743 put_u32 (buf, 0); /* n-style-map */
744 put_u32 (buf, 0); /* n-styles */
749 put_x3 (struct buf *buf, const struct pivot_table *table)
751 put_bytes (buf, "\1\0\4\0\0\0", 6);
752 put_string (buf, table->command_c);
753 put_string (buf, table->command_local);
754 put_string (buf, table->language);
755 put_string (buf, "UTF-8"); /* XXX */
756 put_string (buf, table->locale);
757 put_bytes (buf, "\0\0\1\1", 4);
759 put_double (buf, table->small);
761 put_string (buf, table->dataset);
762 put_string (buf, table->datafile);
764 put_u32 (buf, table->date);
768 put_custom_currency (buf, table);
774 put_light_table (struct buf *buf, uint64_t table_id,
775 const struct pivot_table *table)
778 put_bytes (buf, "\1\0", 2);
780 put_bool (buf, true);
781 put_bool (buf, false);
782 put_bool (buf, table->rotate_inner_column_labels);
783 put_bool (buf, table->rotate_outer_row_labels);
784 put_bool (buf, true);
786 put_u32 (buf, table->look->width_ranges[H][0]);
787 put_u32 (buf, table->look->width_ranges[H][1]);
788 put_u32 (buf, table->look->width_ranges[V][0]);
789 put_u32 (buf, table->look->width_ranges[V][1]);
790 put_u64 (buf, table_id);
793 put_value (buf, table->title);
794 put_value (buf, table->subtype);
795 put_optional_value (buf, table->title);
796 put_optional_value (buf, table->corner_text);
797 put_optional_value (buf, table->caption);
800 put_u32 (buf, table->n_footnotes);
801 for (size_t i = 0; i < table->n_footnotes; i++)
803 put_value (buf, table->footnotes[i]->content);
804 put_optional_value (buf, table->footnotes[i]->marker);
809 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
811 const struct table_area_style *a = &table->look->areas[i];
812 put_byte (buf, i + 1);
813 put_byte (buf, 0x31);
814 put_string (buf, (a->font_style.typeface
815 ? a->font_style.typeface
817 put_float (buf, ceil (a->font_style.size * 1.33));
818 put_u32 (buf, ((a->font_style.bold ? 1 : 0)
819 | (a->font_style.italic ? 2 : 0)));
820 put_bool (buf, a->font_style.underline);
821 put_halign (buf, a->cell_style.halign, 64173, 61453);
822 put_valign (buf, a->cell_style.valign);
824 put_color (buf, &a->font_style.fg[0]);
825 put_color (buf, &a->font_style.bg[0]);
828 = (!cell_color_equal (&a->font_style.fg[0], &a->font_style.fg[1])
829 || !cell_color_equal (&a->font_style.bg[0], &a->font_style.bg[1]));
833 put_color (buf, &a->font_style.fg[1]);
834 put_color (buf, &a->font_style.bg[1]);
838 put_string (buf, "");
839 put_string (buf, "");
842 put_u32 (buf, a->cell_style.margin[H][0]);
843 put_u32 (buf, a->cell_style.margin[H][1]);
844 put_u32 (buf, a->cell_style.margin[V][0]);
845 put_u32 (buf, a->cell_style.margin[V][1]);
849 uint32_t borders_start = start_count (buf);
851 put_be32 (buf, PIVOT_N_BORDERS);
852 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
854 const struct table_border_style *b = &table->look->borders[i];
856 put_be32 (buf, (b->stroke == TABLE_STROKE_NONE ? 0
857 : b->stroke == TABLE_STROKE_SOLID ? 1
858 : b->stroke == TABLE_STROKE_DASHED ? 2
859 : b->stroke == TABLE_STROKE_THICK ? 3
860 : b->stroke == TABLE_STROKE_THIN ? 4
862 put_be32 (buf, ((b->color.alpha << 24)
867 put_bool (buf, table->show_grid_lines);
868 put_bytes (buf, "\0\0\0", 3);
869 end_count_u32 (buf, borders_start);
871 /* Print Settings. */
872 uint32_t ps_start = start_count (buf);
874 put_bool (buf, table->look->print_all_layers);
875 put_bool (buf, table->look->paginate_layers);
876 put_bool (buf, table->look->shrink_to_fit[H]);
877 put_bool (buf, table->look->shrink_to_fit[V]);
878 put_bool (buf, table->look->top_continuation);
879 put_bool (buf, table->look->bottom_continuation);
880 put_be32 (buf, table->look->n_orphan_lines);
881 put_bestring (buf, table->look->continuation);
882 end_count_u32 (buf, ps_start);
884 /* Table Settings. */
885 uint32_t ts_start = start_count (buf);
888 put_be32 (buf, 0); /* XXX current_layer */
889 put_bool (buf, table->look->omit_empty);
890 put_bool (buf, table->look->row_labels_in_corner);
891 put_bool (buf, !table->look->show_numeric_markers);
892 put_bool (buf, table->look->footnote_marker_superscripts);
894 uint32_t keep_start = start_count (buf);
895 put_be32 (buf, 0); /* n-row-breaks */
896 put_be32 (buf, 0); /* n-column-breaks */
897 put_be32 (buf, 0); /* n-row-keeps */
898 put_be32 (buf, 0); /* n-column-keeps */
899 put_be32 (buf, 0); /* n-row-point-keeps */
900 put_be32 (buf, 0); /* n-column-point-keeps */
901 end_count_be32 (buf, keep_start);
902 put_bestring (buf, table->notes);
903 put_bestring (buf, table->look->name);
904 for (size_t i = 0; i < 82; i++)
906 end_count_u32 (buf, ts_start);
909 put_u32 (buf, 0); /* n-widths */
910 put_string (buf, "en_US.ISO_8859-1:1987"); /* XXX */
911 put_u32 (buf, 0); /* XXX current-layer */
916 put_custom_currency (buf, table);
917 uint32_t formats_start = start_count (buf);
918 uint32_t x1_start = start_count (buf);
920 uint32_t x2_start = start_count (buf);
922 end_count_u32 (buf, x2_start);
923 end_count_u32 (buf, x1_start);
924 uint32_t x3_start = start_count (buf);
926 end_count_u32 (buf, x3_start);
927 end_count_u32 (buf, formats_start);
930 put_u32 (buf, table->n_dimensions);
931 int *x2 = xnmalloc (table->n_dimensions, sizeof *x2);
932 for (size_t i = 0; i < table->axes[PIVOT_AXIS_LAYER].n_dimensions; i++)
934 for (size_t i = 0; i < table->axes[PIVOT_AXIS_ROW].n_dimensions; i++)
935 x2[i + table->axes[PIVOT_AXIS_LAYER].n_dimensions] = 0;
936 for (size_t i = 0; i < table->axes[PIVOT_AXIS_COLUMN].n_dimensions; i++)
938 + table->axes[PIVOT_AXIS_LAYER].n_dimensions
939 + table->axes[PIVOT_AXIS_ROW].n_dimensions] = 1;
940 for (size_t i = 0; i < table->n_dimensions; i++)
942 const struct pivot_dimension *d = table->dimensions[i];
943 put_value (buf, d->root->name);
945 put_byte (buf, x2[i]);
947 put_bool (buf, !d->root->show_label);
948 put_bool (buf, d->hide_all_labels);
952 put_u32 (buf, d->root->n_subs);
953 for (size_t j = 0; j < d->root->n_subs; j++)
954 put_category (buf, d->root->subs[j]);
959 put_u32 (buf, table->axes[PIVOT_AXIS_LAYER].n_dimensions);
960 put_u32 (buf, table->axes[PIVOT_AXIS_ROW].n_dimensions);
961 put_u32 (buf, table->axes[PIVOT_AXIS_COLUMN].n_dimensions);
962 for (size_t i = 0; i < table->axes[PIVOT_AXIS_LAYER].n_dimensions; i++)
963 put_u32 (buf, table->axes[PIVOT_AXIS_LAYER].dimensions[i]->top_index);
964 for (size_t i = 0; i < table->axes[PIVOT_AXIS_ROW].n_dimensions; i++)
965 put_u32 (buf, table->axes[PIVOT_AXIS_ROW].dimensions[i]->top_index);
966 for (size_t i = 0; i < table->axes[PIVOT_AXIS_COLUMN].n_dimensions; i++)
967 put_u32 (buf, table->axes[PIVOT_AXIS_COLUMN].dimensions[i]->top_index);
970 put_u32 (buf, hmap_count (&table->cells));
971 const struct pivot_cell *cell;
972 HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
975 for (size_t j = 0; j < table->n_dimensions; j++)
976 index = (table->dimensions[j]->n_leaves * index) + cell->idx[j];
977 put_u64 (buf, index);
979 put_value (buf, cell->value);
984 spv_writer_put_table (struct spv_writer *w, const struct pivot_table *table)
986 struct pivot_table *table_rw = CONST_CAST (struct pivot_table *, table);
987 if (!table_rw->subtype)
988 table_rw->subtype = pivot_value_new_user_text ("unknown", -1);
990 int table_id = ++w->n_tables;
992 bool initial_depth = w->heading_depth;
994 spv_writer_open_file (w);
998 char *title = pivot_value_to_string (table->title, table);
999 char *subtype = pivot_value_to_string (table->subtype, table);
1001 start_elem (w, "label");
1002 write_text (w, title);
1005 start_elem (w, "vtb:table");
1006 write_attr (w, "commandName", table->command_c);
1007 write_attr (w, "type", "table"); /* XXX */
1008 write_attr (w, "subType", subtype);
1009 write_attr_format (w, "tableId", "%d", table_id);
1014 start_elem (w, "vtb:tableStructure");
1015 start_elem (w, "vtb:dataPath");
1016 char *data_path = xasprintf ("%010d_lightTableData.bin", table_id);
1017 write_text (w, data_path);
1018 end_elem (w); /* vtb:dataPath */
1019 end_elem (w); /* vtb:tableStructure */
1020 end_elem (w); /* vtb:table */
1021 end_elem (w); /* container */
1024 spv_writer_close_file (w, "");
1026 struct buf buf = { NULL, 0, 0 };
1027 put_light_table (&buf, table_id, table);
1028 zip_writer_add_memory (w->zw, data_path, buf.data, buf.len);