fast_excel 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -7
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -1
  5. data/examples/example.rb +2 -0
  6. data/examples/example_date_time.rb +38 -0
  7. data/fast_excel.gemspec +2 -2
  8. data/lib/fast_excel/binding/format.rb +17 -0
  9. data/lib/fast_excel/binding/workbook.rb +39 -17
  10. data/lib/fast_excel/binding/worksheet.rb +57 -13
  11. data/lib/fast_excel/binding.rb +7 -7
  12. data/lib/fast_excel.rb +27 -20
  13. data/libxlsxwriter/.github/FUNDING.yml +1 -0
  14. data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
  15. data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
  16. data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
  17. data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
  18. data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
  19. data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
  20. data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
  21. data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
  22. data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
  23. data/libxlsxwriter/.gitignore +16 -1
  24. data/libxlsxwriter/.indent.pro +24 -0
  25. data/libxlsxwriter/CMakeLists.txt +156 -56
  26. data/libxlsxwriter/CONTRIBUTING.md +2 -2
  27. data/libxlsxwriter/Changes.txt +344 -2
  28. data/libxlsxwriter/LICENSE.txt +66 -8
  29. data/libxlsxwriter/Makefile +151 -54
  30. data/libxlsxwriter/Package.swift +42 -0
  31. data/libxlsxwriter/Readme.md +4 -2
  32. data/libxlsxwriter/build.zig +324 -0
  33. data/libxlsxwriter/build.zig.zon +11 -0
  34. data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
  35. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
  36. data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
  37. data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
  38. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
  39. data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  40. data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
  41. data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
  42. data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  43. data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  44. data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
  45. data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
  46. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  47. data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
  48. data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
  49. data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  50. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  51. data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
  52. data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
  53. data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  54. data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
  55. data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
  56. data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
  57. data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
  58. data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
  59. data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  60. data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
  61. data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
  62. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
  63. data/libxlsxwriter/include/xlsxwriter.h +4 -2
  64. data/libxlsxwriter/libxlsxwriter.podspec +8 -5
  65. data/libxlsxwriter/src/Makefile +58 -21
  66. data/libxlsxwriter/src/app.c +5 -2
  67. data/libxlsxwriter/src/chart.c +396 -81
  68. data/libxlsxwriter/src/chartsheet.c +22 -22
  69. data/libxlsxwriter/src/comment.c +443 -0
  70. data/libxlsxwriter/src/content_types.c +40 -1
  71. data/libxlsxwriter/src/core.c +2 -2
  72. data/libxlsxwriter/src/custom.c +1 -1
  73. data/libxlsxwriter/src/drawing.c +160 -40
  74. data/libxlsxwriter/src/format.c +109 -25
  75. data/libxlsxwriter/src/hash_table.c +1 -1
  76. data/libxlsxwriter/src/metadata.c +283 -0
  77. data/libxlsxwriter/src/packager.c +794 -94
  78. data/libxlsxwriter/src/relationships.c +1 -1
  79. data/libxlsxwriter/src/shared_strings.c +2 -4
  80. data/libxlsxwriter/src/styles.c +353 -58
  81. data/libxlsxwriter/src/table.c +304 -0
  82. data/libxlsxwriter/src/theme.c +1 -1
  83. data/libxlsxwriter/src/utility.c +143 -43
  84. data/libxlsxwriter/src/vml.c +1062 -0
  85. data/libxlsxwriter/src/workbook.c +567 -77
  86. data/libxlsxwriter/src/worksheet.c +6668 -1462
  87. data/libxlsxwriter/src/xmlwriter.c +95 -5
  88. data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
  89. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
  90. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
  91. data/libxlsxwriter/third_party/md5/Makefile +42 -0
  92. data/libxlsxwriter/third_party/md5/md5.c +291 -0
  93. data/libxlsxwriter/third_party/md5/md5.h +45 -0
  94. data/libxlsxwriter/third_party/minizip/Makefile +3 -8
  95. data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
  96. data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
  97. data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
  98. data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
  99. data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
  100. data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
  101. data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
  102. data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
  103. data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
  104. data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
  105. data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
  106. data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
  107. data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
  108. data/libxlsxwriter/third_party/minizip/zip.c +165 -218
  109. data/libxlsxwriter/third_party/minizip/zip.h +164 -154
  110. data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
  111. data/libxlsxwriter/version.txt +1 -1
  112. data/test/auto_width_test.rb +20 -0
  113. data/test/default_format_test.rb +1 -1
  114. data/test/validations_test.rb +3 -3
  115. data/test/worksheet_test.rb +6 -1
  116. metadata +33 -7
  117. data/libxlsxwriter/.travis.yml +0 -37
@@ -1,12 +1,49 @@
1
1
  /*****************************************************************************
2
- * packager - A library for creating Excel XLSX packager files.
2
+ * packager - A library for assembling xml files into an Excel XLSX file.
3
3
  *
4
- * Used in conjunction with the libxlsxwriter library.
4
+ * A class for writing the Excel XLSX Packager file.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * This module is used in conjunction with libxlsxwriter to create an
7
+ * Excel XLSX container file.
8
+ *
9
+ * From Wikipedia: The Open Packaging Conventions (OPC) is a
10
+ * container-file technology initially created by Microsoft to store
11
+ * a combination of XML and non-XML files that together form a single
12
+ * entity such as an Open XML Paper Specification (OpenXPS)
13
+ * document. http://en.wikipedia.org/wiki/Open_Packaging_Conventions.
14
+ *
15
+ * At its simplest an Excel XLSX file contains the following elements::
16
+ *
17
+ * ____ [Content_Types].xml
18
+ * |
19
+ * |____ docProps
20
+ * | |____ app.xml
21
+ * | |____ core.xml
22
+ * |
23
+ * |____ xl
24
+ * | |____ workbook.xml
25
+ * | |____ worksheets
26
+ * | | |____ sheet1.xml
27
+ * | |
28
+ * | |____ styles.xml
29
+ * | |
30
+ * | |____ theme
31
+ * | | |____ theme1.xml
32
+ * | |
33
+ * | |_____rels
34
+ * | |____ workbook.xml.rels
35
+ * |
36
+ * |_____rels
37
+ * |____ .rels
38
+ *
39
+ * The Packager class coordinates the classes that represent the
40
+ * elements of the package and writes them into the XLSX file.
41
+ *
42
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
43
  *
8
44
  */
9
45
 
46
+ #include <zlib.h>
10
47
  #include "xlsxwriter/xmlwriter.h"
11
48
  #include "xlsxwriter/packager.h"
12
49
  #include "xlsxwriter/hash_table.h"
@@ -15,9 +52,17 @@
15
52
  STATIC lxw_error _add_file_to_zip(lxw_packager *self, FILE * file,
16
53
  const char *filename);
17
54
 
18
- STATIC lxw_error _add_buffer_to_zip(lxw_packager *self, unsigned char *buffer,
55
+ STATIC lxw_error _add_buffer_to_zip(lxw_packager *self, const char *buffer,
19
56
  size_t buffer_size, const char *filename);
20
57
 
58
+ STATIC lxw_error _add_to_zip(lxw_packager *self, FILE * file,
59
+ char **buffer, size_t *buffer_size,
60
+ const char *filename);
61
+
62
+ STATIC lxw_error _write_vml_drawing_rels_file(lxw_packager *self,
63
+ lxw_worksheet *worksheet,
64
+ uint32_t index);
65
+
21
66
  /*
22
67
  * Forward declarations.
23
68
  */
@@ -36,7 +81,7 @@ STATIC lxw_error _add_buffer_to_zip(lxw_packager *self, unsigned char *buffer,
36
81
  #ifdef _WIN32
37
82
 
38
83
  /* Silence Windows warning with duplicate symbol for SLIST_ENTRY in local
39
- * queue.h and widows.h. */
84
+ * queue.h and windows.h. */
40
85
  #undef SLIST_ENTRY
41
86
 
42
87
  #include <windows.h>
@@ -72,21 +117,75 @@ _open_zipfile_win32(const char *filename)
72
117
 
73
118
  #endif
74
119
 
120
+ STATIC voidpf ZCALLBACK
121
+ _fopen_memstream(voidpf opaque, const char *filename, int mode)
122
+ {
123
+ lxw_packager *packager = (lxw_packager *) opaque;
124
+ (void) filename;
125
+ (void) mode;
126
+ return lxw_get_filehandle(&packager->output_buffer,
127
+ &packager->output_buffer_size,
128
+ packager->tmpdir);
129
+ }
130
+
131
+ STATIC int ZCALLBACK
132
+ _fclose_memstream(voidpf opaque, voidpf stream)
133
+ {
134
+ lxw_packager *packager = (lxw_packager *) opaque;
135
+ FILE *file = (FILE *) stream;
136
+ long size;
137
+
138
+ /* Ensure memstream buffer is updated */
139
+ if (fflush(file))
140
+ goto mem_error;
141
+
142
+ /* If the memstream is backed by a temporary file, no buffer is created,
143
+ so create it manually. */
144
+ if (!packager->output_buffer) {
145
+ if (fseek(file, 0L, SEEK_END))
146
+ goto mem_error;
147
+
148
+ size = ftell(file);
149
+ if (size == -1)
150
+ goto mem_error;
151
+
152
+ packager->output_buffer = malloc(size);
153
+ GOTO_LABEL_ON_MEM_ERROR(packager->output_buffer, mem_error);
154
+
155
+ rewind(file);
156
+ if (fread((void *) packager->output_buffer, size, 1, file) < 1)
157
+ goto mem_error;
158
+
159
+ packager->output_buffer_size = size;
160
+ }
161
+
162
+ return fclose(file);
163
+
164
+ mem_error:
165
+ fclose(file);
166
+ return EOF;
167
+ }
168
+
75
169
  /*
76
170
  * Create a new packager object.
77
171
  */
78
172
  lxw_packager *
79
- lxw_packager_new(const char *filename, char *tmpdir, uint8_t use_zip64)
173
+ lxw_packager_new(const char *filename, const char *tmpdir, uint8_t use_zip64)
80
174
  {
175
+ zlib_filefunc_def filefunc;
81
176
  lxw_packager *packager = calloc(1, sizeof(lxw_packager));
82
177
  GOTO_LABEL_ON_MEM_ERROR(packager, mem_error);
83
178
 
84
179
  packager->buffer = calloc(1, LXW_ZIP_BUFFER_SIZE);
85
180
  GOTO_LABEL_ON_MEM_ERROR(packager->buffer, mem_error);
86
181
 
87
- packager->filename = lxw_strdup(filename);
182
+ packager->filename = NULL;
88
183
  packager->tmpdir = tmpdir;
89
- GOTO_LABEL_ON_MEM_ERROR(packager->filename, mem_error);
184
+
185
+ if (filename) {
186
+ packager->filename = lxw_strdup(filename);
187
+ GOTO_LABEL_ON_MEM_ERROR(packager->filename, mem_error);
188
+ }
90
189
 
91
190
  packager->buffer_size = LXW_ZIP_BUFFER_SIZE;
92
191
  packager->use_zip64 = use_zip64;
@@ -102,12 +201,24 @@ lxw_packager_new(const char *filename, char *tmpdir, uint8_t use_zip64)
102
201
  packager->zipfile_info.internal_fa = 0;
103
202
  packager->zipfile_info.external_fa = 0;
104
203
 
204
+ packager->output_buffer = NULL;
205
+ packager->output_buffer_size = 0;
206
+
105
207
  /* Create a zip container for the xlsx file. */
208
+ if (packager->filename) {
106
209
  #ifdef _WIN32
107
- packager->zipfile = _open_zipfile_win32(packager->filename);
210
+ packager->zipfile = _open_zipfile_win32(packager->filename);
108
211
  #else
109
- packager->zipfile = zipOpen(packager->filename, 0);
212
+ packager->zipfile = zipOpen(packager->filename, 0);
110
213
  #endif
214
+ }
215
+ else {
216
+ fill_fopen_filefunc(&filefunc);
217
+ filefunc.opaque = packager;
218
+ filefunc.zopen_file = _fopen_memstream;
219
+ filefunc.zclose_file = _fclose_memstream;
220
+ packager->zipfile = zipOpen2(packager->filename, 0, NULL, &filefunc);
221
+ }
111
222
 
112
223
  if (packager->zipfile == NULL)
113
224
  goto mem_error;
@@ -128,8 +239,8 @@ lxw_packager_free(lxw_packager *packager)
128
239
  if (!packager)
129
240
  return;
130
241
 
131
- free(packager->buffer);
132
- free(packager->filename);
242
+ free((void *) packager->buffer);
243
+ free((void *) packager->filename);
133
244
  free(packager);
134
245
  }
135
246
 
@@ -147,16 +258,19 @@ _write_workbook_file(lxw_packager *self)
147
258
  lxw_workbook *workbook = self->workbook;
148
259
  lxw_error err;
149
260
 
150
- workbook->file = lxw_tmpfile(self->tmpdir);
261
+ char *buffer = NULL;
262
+ size_t buffer_size = 0;
263
+ workbook->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
151
264
  if (!workbook->file)
152
265
  return LXW_ERROR_CREATING_TMPFILE;
153
266
 
154
267
  lxw_workbook_assemble_xml_file(workbook);
155
268
 
156
- err = _add_file_to_zip(self, workbook->file, "xl/workbook.xml");
157
- RETURN_ON_ERROR(err);
158
-
269
+ err = _add_to_zip(self, workbook->file, &buffer, &buffer_size,
270
+ "xl/workbook.xml");
159
271
  fclose(workbook->file);
272
+ free(buffer);
273
+ RETURN_ON_ERROR(err);
160
274
 
161
275
  return LXW_NO_ERROR;
162
276
  }
@@ -171,6 +285,8 @@ _write_worksheet_files(lxw_packager *self)
171
285
  lxw_sheet *sheet;
172
286
  lxw_worksheet *worksheet;
173
287
  char sheetname[LXW_FILENAME_LENGTH] = { 0 };
288
+ char *buffer = NULL;
289
+ size_t buffer_size = 0;
174
290
  uint32_t index = 1;
175
291
  lxw_error err;
176
292
 
@@ -186,16 +302,18 @@ _write_worksheet_files(lxw_packager *self)
186
302
  if (worksheet->optimize_row)
187
303
  lxw_worksheet_write_single_row(worksheet);
188
304
 
189
- worksheet->file = lxw_tmpfile(self->tmpdir);
305
+ worksheet->file = lxw_get_filehandle(&buffer, &buffer_size,
306
+ self->tmpdir);
190
307
  if (!worksheet->file)
191
308
  return LXW_ERROR_CREATING_TMPFILE;
192
309
 
193
310
  lxw_worksheet_assemble_xml_file(worksheet);
194
311
 
195
- err = _add_file_to_zip(self, worksheet->file, sheetname);
196
- RETURN_ON_ERROR(err);
197
-
312
+ err = _add_to_zip(self, worksheet->file, &buffer, &buffer_size,
313
+ sheetname);
198
314
  fclose(worksheet->file);
315
+ free(buffer);
316
+ RETURN_ON_ERROR(err);
199
317
  }
200
318
 
201
319
  return LXW_NO_ERROR;
@@ -211,6 +329,8 @@ _write_chartsheet_files(lxw_packager *self)
211
329
  lxw_sheet *sheet;
212
330
  lxw_chartsheet *chartsheet;
213
331
  char sheetname[LXW_FILENAME_LENGTH] = { 0 };
332
+ char *buffer = NULL;
333
+ size_t buffer_size = 0;
214
334
  uint32_t index = 1;
215
335
  lxw_error err;
216
336
 
@@ -223,16 +343,18 @@ _write_chartsheet_files(lxw_packager *self)
223
343
  lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
224
344
  "xl/chartsheets/sheet%d.xml", index++);
225
345
 
226
- chartsheet->file = lxw_tmpfile(self->tmpdir);
346
+ chartsheet->file = lxw_get_filehandle(&buffer, &buffer_size,
347
+ self->tmpdir);
227
348
  if (!chartsheet->file)
228
349
  return LXW_ERROR_CREATING_TMPFILE;
229
350
 
230
351
  lxw_chartsheet_assemble_xml_file(chartsheet);
231
352
 
232
- err = _add_file_to_zip(self, chartsheet->file, sheetname);
233
- RETURN_ON_ERROR(err);
234
-
353
+ err = _add_to_zip(self, chartsheet->file, &buffer, &buffer_size,
354
+ sheetname);
235
355
  fclose(chartsheet->file);
356
+ free(buffer);
357
+ RETURN_ON_ERROR(err);
236
358
  }
237
359
 
238
360
  return LXW_NO_ERROR;
@@ -247,7 +369,7 @@ _write_image_files(lxw_packager *self)
247
369
  lxw_workbook *workbook = self->workbook;
248
370
  lxw_sheet *sheet;
249
371
  lxw_worksheet *worksheet;
250
- lxw_image_options *image;
372
+ lxw_object_properties *object_props;
251
373
  lxw_error err;
252
374
  FILE *image_stream;
253
375
 
@@ -260,21 +382,25 @@ _write_image_files(lxw_packager *self)
260
382
  else
261
383
  worksheet = sheet->u.worksheet;
262
384
 
263
- if (STAILQ_EMPTY(worksheet->image_data))
385
+ if (STAILQ_EMPTY(worksheet->image_props))
264
386
  continue;
265
387
 
266
- STAILQ_FOREACH(image, worksheet->image_data, list_pointers) {
388
+ STAILQ_FOREACH(object_props, worksheet->image_props, list_pointers) {
389
+
390
+ if (object_props->is_duplicate)
391
+ continue;
267
392
 
268
393
  lxw_snprintf(filename, LXW_FILENAME_LENGTH,
269
- "xl/media/image%d.%s", index++, image->extension);
394
+ "xl/media/image%d.%s", index++,
395
+ object_props->extension);
270
396
 
271
- if (!image->is_image_buffer) {
397
+ if (!object_props->is_image_buffer) {
272
398
  /* Check that the image file exists and can be opened. */
273
- image_stream = fopen(image->filename, "rb");
399
+ image_stream = lxw_fopen(object_props->filename, "rb");
274
400
  if (!image_stream) {
275
401
  LXW_WARN_FORMAT1("Error adding image to xlsx file: file "
276
402
  "doesn't exist or can't be opened: %s.",
277
- image->filename);
403
+ object_props->filename);
278
404
  return LXW_ERROR_CREATING_TMPFILE;
279
405
  }
280
406
 
@@ -283,8 +409,9 @@ _write_image_files(lxw_packager *self)
283
409
  }
284
410
  else {
285
411
  err = _add_buffer_to_zip(self,
286
- image->image_buffer,
287
- image->image_buffer_size, filename);
412
+ object_props->image_buffer,
413
+ object_props->image_buffer_size,
414
+ filename);
288
415
  }
289
416
 
290
417
  RETURN_ON_ERROR(err);
@@ -308,7 +435,7 @@ _add_vba_project(lxw_packager *self)
308
435
  return LXW_NO_ERROR;
309
436
 
310
437
  /* Check that the image file exists and can be opened. */
311
- image_stream = fopen(workbook->vba_project, "rb");
438
+ image_stream = lxw_fopen(workbook->vba_project, "rb");
312
439
  if (!image_stream) {
313
440
  LXW_WARN_FORMAT1("Error adding vbaProject.bin to xlsx file: "
314
441
  "file doesn't exist or can't be opened: %s.",
@@ -323,6 +450,35 @@ _add_vba_project(lxw_packager *self)
323
450
  return LXW_NO_ERROR;
324
451
  }
325
452
 
453
+ /*
454
+ * Write the xl/vbaProjectSignature.bin file.
455
+ */
456
+ STATIC lxw_error
457
+ _add_vba_project_signature(lxw_packager *self)
458
+ {
459
+ lxw_workbook *workbook = self->workbook;
460
+ lxw_error err;
461
+ FILE *image_stream;
462
+
463
+ if (!workbook->vba_project_signature)
464
+ return LXW_NO_ERROR;
465
+
466
+ /* Check that the image file exists and can be opened. */
467
+ image_stream = lxw_fopen(workbook->vba_project_signature, "rb");
468
+ if (!image_stream) {
469
+ LXW_WARN_FORMAT1("Error adding vbaProjectSignature.bin to xlsx file: "
470
+ "file doesn't exist or can't be opened: %s.",
471
+ workbook->vba_project_signature);
472
+ return LXW_ERROR_CREATING_TMPFILE;
473
+ }
474
+
475
+ err = _add_file_to_zip(self, image_stream, "xl/vbaProjectSignature.bin");
476
+ fclose(image_stream);
477
+ RETURN_ON_ERROR(err);
478
+
479
+ return LXW_NO_ERROR;
480
+ }
481
+
326
482
  /*
327
483
  * Write the chart files.
328
484
  */
@@ -332,6 +488,8 @@ _write_chart_files(lxw_packager *self)
332
488
  lxw_workbook *workbook = self->workbook;
333
489
  lxw_chart *chart;
334
490
  char sheetname[LXW_FILENAME_LENGTH] = { 0 };
491
+ char *buffer = NULL;
492
+ size_t buffer_size = 0;
335
493
  uint32_t index = 1;
336
494
  lxw_error err;
337
495
 
@@ -340,16 +498,17 @@ _write_chart_files(lxw_packager *self)
340
498
  lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
341
499
  "xl/charts/chart%d.xml", index++);
342
500
 
343
- chart->file = lxw_tmpfile(self->tmpdir);
501
+ chart->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
344
502
  if (!chart->file)
345
503
  return LXW_ERROR_CREATING_TMPFILE;
346
504
 
347
505
  lxw_chart_assemble_xml_file(chart);
348
506
 
349
- err = _add_file_to_zip(self, chart->file, sheetname);
350
- RETURN_ON_ERROR(err);
351
-
507
+ err = _add_to_zip(self, chart->file, &buffer, &buffer_size,
508
+ sheetname);
352
509
  fclose(chart->file);
510
+ free(buffer);
511
+ RETURN_ON_ERROR(err);
353
512
  }
354
513
 
355
514
  return LXW_NO_ERROR;
@@ -383,6 +542,8 @@ _write_drawing_files(lxw_packager *self)
383
542
  lxw_worksheet *worksheet;
384
543
  lxw_drawing *drawing;
385
544
  char filename[LXW_FILENAME_LENGTH] = { 0 };
545
+ char *buffer = NULL;
546
+ size_t buffer_size = 0;
386
547
  uint32_t index = 1;
387
548
  lxw_error err;
388
549
 
@@ -398,15 +559,18 @@ _write_drawing_files(lxw_packager *self)
398
559
  lxw_snprintf(filename, LXW_FILENAME_LENGTH,
399
560
  "xl/drawings/drawing%d.xml", index++);
400
561
 
401
- drawing->file = lxw_tmpfile(self->tmpdir);
562
+ drawing->file = lxw_get_filehandle(&buffer, &buffer_size,
563
+ self->tmpdir);
402
564
  if (!drawing->file)
403
565
  return LXW_ERROR_CREATING_TMPFILE;
404
566
 
405
567
  lxw_drawing_assemble_xml_file(drawing);
406
- err = _add_file_to_zip(self, drawing->file, filename);
407
- RETURN_ON_ERROR(err);
408
568
 
569
+ err = _add_to_zip(self, drawing->file, &buffer, &buffer_size,
570
+ filename);
409
571
  fclose(drawing->file);
572
+ free(buffer);
573
+ RETURN_ON_ERROR(err);
410
574
  }
411
575
  }
412
576
 
@@ -440,6 +604,263 @@ _get_drawing_count(lxw_packager *self)
440
604
  return drawing_count;
441
605
  }
442
606
 
607
+ /*
608
+ * Write the worksheet table files.
609
+ */
610
+ STATIC lxw_error
611
+ _write_table_files(lxw_packager *self)
612
+ {
613
+ lxw_workbook *workbook = self->workbook;
614
+ lxw_sheet *sheet;
615
+ lxw_worksheet *worksheet;
616
+ lxw_table *table;
617
+ lxw_table_obj *table_obj;
618
+ lxw_error err;
619
+
620
+ char filename[LXW_FILENAME_LENGTH] = { 0 };
621
+ char *buffer = NULL;
622
+ size_t buffer_size = 0;
623
+ uint32_t index = 1;
624
+
625
+ STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
626
+ if (sheet->is_chartsheet)
627
+ continue;
628
+ else
629
+ worksheet = sheet->u.worksheet;
630
+
631
+ if (STAILQ_EMPTY(worksheet->table_objs))
632
+ continue;
633
+
634
+ STAILQ_FOREACH(table_obj, worksheet->table_objs, list_pointers) {
635
+
636
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
637
+ "xl/tables/table%d.xml", index++);
638
+
639
+ table = lxw_table_new();
640
+ if (!table) {
641
+ err = LXW_ERROR_MEMORY_MALLOC_FAILED;
642
+ RETURN_ON_ERROR(err);
643
+ }
644
+
645
+ table->file = lxw_get_filehandle(&buffer, &buffer_size,
646
+ self->tmpdir);
647
+ if (!table->file) {
648
+ lxw_table_free(table);
649
+ return LXW_ERROR_CREATING_TMPFILE;
650
+ }
651
+
652
+ table->table_obj = table_obj;
653
+
654
+ lxw_table_assemble_xml_file(table);
655
+
656
+ err = _add_to_zip(self, table->file, &buffer, &buffer_size,
657
+ filename);
658
+ fclose(table->file);
659
+ free(buffer);
660
+ lxw_table_free(table);
661
+ RETURN_ON_ERROR(err);
662
+ }
663
+ }
664
+
665
+ return LXW_NO_ERROR;
666
+ }
667
+
668
+ /*
669
+ * Count the table files.
670
+ */
671
+ uint32_t
672
+ _get_table_count(lxw_packager *self)
673
+ {
674
+ lxw_workbook *workbook = self->workbook;
675
+ lxw_sheet *sheet;
676
+ lxw_worksheet *worksheet;
677
+ uint32_t table_count = 0;
678
+
679
+ STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
680
+ if (sheet->is_chartsheet)
681
+ worksheet = sheet->u.chartsheet->worksheet;
682
+ else
683
+ worksheet = sheet->u.worksheet;
684
+
685
+ table_count += worksheet->table_count;
686
+ }
687
+
688
+ return table_count;
689
+ }
690
+
691
+ /*
692
+ * Write the comment/header VML files.
693
+ */
694
+ STATIC lxw_error
695
+ _write_vml_files(lxw_packager *self)
696
+ {
697
+ lxw_workbook *workbook = self->workbook;
698
+ lxw_sheet *sheet;
699
+ lxw_worksheet *worksheet;
700
+ lxw_vml *vml;
701
+ char filename[LXW_FILENAME_LENGTH] = { 0 };
702
+ char *buffer = NULL;
703
+ size_t buffer_size = 0;
704
+ uint32_t index = 1;
705
+ lxw_error err;
706
+
707
+ STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
708
+ if (sheet->is_chartsheet)
709
+ continue;
710
+ else
711
+ worksheet = sheet->u.worksheet;
712
+
713
+ if (!worksheet->has_vml && !worksheet->has_header_vml)
714
+ continue;
715
+
716
+ if (worksheet->has_vml) {
717
+
718
+ vml = lxw_vml_new();
719
+ if (!vml)
720
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
721
+
722
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
723
+ "xl/drawings/vmlDrawing%d.vml", index++);
724
+
725
+ vml->file = lxw_get_filehandle(&buffer, &buffer_size,
726
+ self->tmpdir);
727
+ if (!vml->file) {
728
+ lxw_vml_free(vml);
729
+ return LXW_ERROR_CREATING_TMPFILE;
730
+ }
731
+
732
+ vml->comment_objs = worksheet->comment_objs;
733
+ vml->button_objs = worksheet->button_objs;
734
+ vml->vml_shape_id = worksheet->vml_shape_id;
735
+ vml->comment_display_default = worksheet->comment_display_default;
736
+
737
+ if (worksheet->vml_data_id_str) {
738
+ vml->vml_data_id_str = worksheet->vml_data_id_str;
739
+ }
740
+ else {
741
+ fclose(vml->file);
742
+ free(buffer);
743
+ lxw_vml_free(vml);
744
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
745
+ }
746
+
747
+ lxw_vml_assemble_xml_file(vml);
748
+
749
+ err = _add_to_zip(self, vml->file, &buffer, &buffer_size,
750
+ filename);
751
+
752
+ fclose(vml->file);
753
+ free(buffer);
754
+ lxw_vml_free(vml);
755
+
756
+ RETURN_ON_ERROR(err);
757
+ }
758
+
759
+ if (worksheet->has_header_vml) {
760
+
761
+ err = _write_vml_drawing_rels_file(self, worksheet, index);
762
+ RETURN_ON_ERROR(err);
763
+
764
+ vml = lxw_vml_new();
765
+ if (!vml)
766
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
767
+
768
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
769
+ "xl/drawings/vmlDrawing%d.vml", index++);
770
+
771
+ vml->file = lxw_get_filehandle(&buffer, &buffer_size,
772
+ self->tmpdir);
773
+ if (!vml->file) {
774
+ lxw_vml_free(vml);
775
+ return LXW_ERROR_CREATING_TMPFILE;
776
+ }
777
+
778
+ vml->image_objs = worksheet->header_image_objs;
779
+ vml->vml_shape_id = worksheet->vml_header_id * 1024;
780
+
781
+ if (worksheet->vml_header_id_str) {
782
+ vml->vml_data_id_str = worksheet->vml_header_id_str;
783
+ }
784
+ else {
785
+ fclose(vml->file);
786
+ free(buffer);
787
+ lxw_vml_free(vml);
788
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
789
+ }
790
+
791
+ lxw_vml_assemble_xml_file(vml);
792
+
793
+ err = _add_to_zip(self, vml->file, &buffer, &buffer_size,
794
+ filename);
795
+
796
+ fclose(vml->file);
797
+ free(buffer);
798
+ lxw_vml_free(vml);
799
+
800
+ RETURN_ON_ERROR(err);
801
+ }
802
+ }
803
+
804
+ return LXW_NO_ERROR;
805
+ }
806
+
807
+ /*
808
+ * Write the comment files.
809
+ */
810
+ STATIC lxw_error
811
+ _write_comment_files(lxw_packager *self)
812
+ {
813
+ lxw_workbook *workbook = self->workbook;
814
+ lxw_sheet *sheet;
815
+ lxw_worksheet *worksheet;
816
+ lxw_comment *comment;
817
+ char filename[LXW_FILENAME_LENGTH] = { 0 };
818
+ char *buffer = NULL;
819
+ size_t buffer_size = 0;
820
+ uint32_t index = 1;
821
+ lxw_error err;
822
+
823
+ STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
824
+ if (sheet->is_chartsheet)
825
+ continue;
826
+ else
827
+ worksheet = sheet->u.worksheet;
828
+
829
+ if (!worksheet->has_comments)
830
+ continue;
831
+
832
+ comment = lxw_comment_new();
833
+ if (!comment)
834
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
835
+
836
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
837
+ "xl/comments%d.xml", index++);
838
+
839
+ comment->file = lxw_get_filehandle(&buffer, &buffer_size,
840
+ self->tmpdir);
841
+ if (!comment->file) {
842
+ lxw_comment_free(comment);
843
+ return LXW_ERROR_CREATING_TMPFILE;
844
+ }
845
+
846
+ comment->comment_objs = worksheet->comment_objs;
847
+ comment->comment_author = worksheet->comment_author;
848
+
849
+ lxw_comment_assemble_xml_file(comment);
850
+
851
+ err = _add_to_zip(self, comment->file, &buffer, &buffer_size,
852
+ filename);
853
+
854
+ fclose(comment->file);
855
+ free(buffer);
856
+ lxw_comment_free(comment);
857
+
858
+ RETURN_ON_ERROR(err);
859
+ }
860
+
861
+ return LXW_NO_ERROR;
862
+ }
863
+
443
864
  /*
444
865
  * Write the sharedStrings.xml file.
445
866
  */
@@ -447,22 +868,25 @@ STATIC lxw_error
447
868
  _write_shared_strings_file(lxw_packager *self)
448
869
  {
449
870
  lxw_sst *sst = self->workbook->sst;
871
+ char *buffer = NULL;
872
+ size_t buffer_size = 0;
450
873
  lxw_error err;
451
874
 
452
875
  /* Skip the sharedStrings file if there are no shared strings. */
453
876
  if (!sst->string_count)
454
877
  return LXW_NO_ERROR;
455
878
 
456
- sst->file = lxw_tmpfile(self->tmpdir);
879
+ sst->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
457
880
  if (!sst->file)
458
881
  return LXW_ERROR_CREATING_TMPFILE;
459
882
 
460
883
  lxw_sst_assemble_xml_file(sst);
461
884
 
462
- err = _add_file_to_zip(self, sst->file, "xl/sharedStrings.xml");
463
- RETURN_ON_ERROR(err);
464
-
885
+ err = _add_to_zip(self, sst->file, &buffer, &buffer_size,
886
+ "xl/sharedStrings.xml");
465
887
  fclose(sst->file);
888
+ free(buffer);
889
+ RETURN_ON_ERROR(err);
466
890
 
467
891
  return LXW_NO_ERROR;
468
892
  }
@@ -479,6 +903,8 @@ _write_app_file(lxw_packager *self)
479
903
  lxw_chartsheet *chartsheet;
480
904
  lxw_defined_name *defined_name;
481
905
  lxw_app *app;
906
+ char *buffer = NULL;
907
+ size_t buffer_size = 0;
482
908
  uint32_t named_range_count = 0;
483
909
  char *autofilter;
484
910
  char *has_range;
@@ -491,7 +917,7 @@ _write_app_file(lxw_packager *self)
491
917
  goto mem_error;
492
918
  }
493
919
 
494
- app->file = lxw_tmpfile(self->tmpdir);
920
+ app->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
495
921
  if (!app->file) {
496
922
  err = LXW_ERROR_CREATING_TMPFILE;
497
923
  goto mem_error;
@@ -545,11 +971,15 @@ _write_app_file(lxw_packager *self)
545
971
  /* Set the app/doc properties. */
546
972
  app->properties = workbook->properties;
547
973
 
974
+ app->doc_security = workbook->read_only;
975
+
548
976
  lxw_app_assemble_xml_file(app);
549
977
 
550
- err = _add_file_to_zip(self, app->file, "docProps/app.xml");
978
+ err = _add_to_zip(self, app->file, &buffer, &buffer_size,
979
+ "docProps/app.xml");
551
980
 
552
981
  fclose(app->file);
982
+ free(buffer);
553
983
 
554
984
  mem_error:
555
985
  lxw_app_free(app);
@@ -565,13 +995,15 @@ _write_core_file(lxw_packager *self)
565
995
  {
566
996
  lxw_error err = LXW_NO_ERROR;
567
997
  lxw_core *core = lxw_core_new();
998
+ char *buffer = NULL;
999
+ size_t buffer_size = 0;
568
1000
 
569
1001
  if (!core) {
570
1002
  err = LXW_ERROR_MEMORY_MALLOC_FAILED;
571
1003
  goto mem_error;
572
1004
  }
573
1005
 
574
- core->file = lxw_tmpfile(self->tmpdir);
1006
+ core->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
575
1007
  if (!core->file) {
576
1008
  err = LXW_ERROR_CREATING_TMPFILE;
577
1009
  goto mem_error;
@@ -581,9 +1013,11 @@ _write_core_file(lxw_packager *self)
581
1013
 
582
1014
  lxw_core_assemble_xml_file(core);
583
1015
 
584
- err = _add_file_to_zip(self, core->file, "docProps/core.xml");
1016
+ err = _add_to_zip(self, core->file, &buffer, &buffer_size,
1017
+ "docProps/core.xml");
585
1018
 
586
1019
  fclose(core->file);
1020
+ free(buffer);
587
1021
 
588
1022
  mem_error:
589
1023
  lxw_core_free(core);
@@ -591,6 +1025,47 @@ mem_error:
591
1025
  return err;
592
1026
  }
593
1027
 
1028
+ /*
1029
+ * Write the metadata.xml file.
1030
+ */
1031
+ STATIC lxw_error
1032
+ _write_metadata_file(lxw_packager *self)
1033
+ {
1034
+ lxw_error err = LXW_NO_ERROR;
1035
+ lxw_metadata *metadata;
1036
+ char *buffer = NULL;
1037
+ size_t buffer_size = 0;
1038
+
1039
+ if (!self->workbook->has_metadata)
1040
+ return LXW_NO_ERROR;
1041
+
1042
+ metadata = lxw_metadata_new();
1043
+
1044
+ if (!metadata) {
1045
+ err = LXW_ERROR_MEMORY_MALLOC_FAILED;
1046
+ goto mem_error;
1047
+ }
1048
+
1049
+ metadata->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
1050
+ if (!metadata->file) {
1051
+ err = LXW_ERROR_CREATING_TMPFILE;
1052
+ goto mem_error;
1053
+ }
1054
+
1055
+ lxw_metadata_assemble_xml_file(metadata);
1056
+
1057
+ err = _add_to_zip(self, metadata->file, &buffer, &buffer_size,
1058
+ "xl/metadata.xml");
1059
+
1060
+ fclose(metadata->file);
1061
+ free(buffer);
1062
+
1063
+ mem_error:
1064
+ lxw_metadata_free(metadata);
1065
+
1066
+ return err;
1067
+ }
1068
+
594
1069
  /*
595
1070
  * Write the custom.xml file.
596
1071
  */
@@ -598,6 +1073,8 @@ STATIC lxw_error
598
1073
  _write_custom_file(lxw_packager *self)
599
1074
  {
600
1075
  lxw_custom *custom;
1076
+ char *buffer = NULL;
1077
+ size_t buffer_size = 0;
601
1078
  lxw_error err = LXW_NO_ERROR;
602
1079
 
603
1080
  if (STAILQ_EMPTY(self->workbook->custom_properties))
@@ -609,7 +1086,7 @@ _write_custom_file(lxw_packager *self)
609
1086
  goto mem_error;
610
1087
  }
611
1088
 
612
- custom->file = lxw_tmpfile(self->tmpdir);
1089
+ custom->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
613
1090
  if (!custom->file) {
614
1091
  err = LXW_ERROR_CREATING_TMPFILE;
615
1092
  goto mem_error;
@@ -619,9 +1096,11 @@ _write_custom_file(lxw_packager *self)
619
1096
 
620
1097
  lxw_custom_assemble_xml_file(custom);
621
1098
 
622
- err = _add_file_to_zip(self, custom->file, "docProps/custom.xml");
1099
+ err = _add_to_zip(self, custom->file, &buffer, &buffer_size,
1100
+ "docProps/custom.xml");
623
1101
 
624
1102
  fclose(custom->file);
1103
+ free(buffer);
625
1104
 
626
1105
  mem_error:
627
1106
  lxw_custom_free(custom);
@@ -636,13 +1115,15 @@ _write_theme_file(lxw_packager *self)
636
1115
  {
637
1116
  lxw_error err = LXW_NO_ERROR;
638
1117
  lxw_theme *theme = lxw_theme_new();
1118
+ char *buffer = NULL;
1119
+ size_t buffer_size = 0;
639
1120
 
640
1121
  if (!theme) {
641
1122
  err = LXW_ERROR_MEMORY_MALLOC_FAILED;
642
1123
  goto mem_error;
643
1124
  }
644
1125
 
645
- theme->file = lxw_tmpfile(self->tmpdir);
1126
+ theme->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
646
1127
  if (!theme->file) {
647
1128
  err = LXW_ERROR_CREATING_TMPFILE;
648
1129
  goto mem_error;
@@ -650,9 +1131,11 @@ _write_theme_file(lxw_packager *self)
650
1131
 
651
1132
  lxw_theme_assemble_xml_file(theme);
652
1133
 
653
- err = _add_file_to_zip(self, theme->file, "xl/theme/theme1.xml");
1134
+ err = _add_to_zip(self, theme->file, &buffer, &buffer_size,
1135
+ "xl/theme/theme1.xml");
654
1136
 
655
1137
  fclose(theme->file);
1138
+ free(buffer);
656
1139
 
657
1140
  mem_error:
658
1141
  lxw_theme_free(theme);
@@ -667,6 +1150,8 @@ STATIC lxw_error
667
1150
  _write_styles_file(lxw_packager *self)
668
1151
  {
669
1152
  lxw_styles *styles = lxw_styles_new();
1153
+ char *buffer = NULL;
1154
+ size_t buffer_size = 0;
670
1155
  lxw_hash_element *hash_element;
671
1156
  lxw_error err = LXW_NO_ERROR;
672
1157
 
@@ -690,13 +1175,30 @@ _write_styles_file(lxw_packager *self)
690
1175
  STAILQ_INSERT_TAIL(styles->xf_formats, style_format, list_pointers);
691
1176
  }
692
1177
 
1178
+ /* Copy the unique and in-use dxf formats from the workbook to the styles
1179
+ * dxf_format list. */
1180
+ LXW_FOREACH_ORDERED(hash_element, self->workbook->used_dxf_formats) {
1181
+ lxw_format *workbook_format = (lxw_format *) hash_element->value;
1182
+ lxw_format *style_format = lxw_format_new();
1183
+
1184
+ if (!style_format) {
1185
+ err = LXW_ERROR_MEMORY_MALLOC_FAILED;
1186
+ goto mem_error;
1187
+ }
1188
+
1189
+ memcpy(style_format, workbook_format, sizeof(lxw_format));
1190
+ STAILQ_INSERT_TAIL(styles->dxf_formats, style_format, list_pointers);
1191
+ }
1192
+
693
1193
  styles->font_count = self->workbook->font_count;
694
1194
  styles->border_count = self->workbook->border_count;
695
1195
  styles->fill_count = self->workbook->fill_count;
696
1196
  styles->num_format_count = self->workbook->num_format_count;
697
1197
  styles->xf_count = self->workbook->used_xf_formats->unique_count;
1198
+ styles->dxf_count = self->workbook->used_dxf_formats->unique_count;
1199
+ styles->has_comments = self->workbook->has_comments;
698
1200
 
699
- styles->file = lxw_tmpfile(self->tmpdir);
1201
+ styles->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
700
1202
  if (!styles->file) {
701
1203
  err = LXW_ERROR_CREATING_TMPFILE;
702
1204
  goto mem_error;
@@ -704,9 +1206,11 @@ _write_styles_file(lxw_packager *self)
704
1206
 
705
1207
  lxw_styles_assemble_xml_file(styles);
706
1208
 
707
- err = _add_file_to_zip(self, styles->file, "xl/styles.xml");
1209
+ err = _add_to_zip(self, styles->file, &buffer, &buffer_size,
1210
+ "xl/styles.xml");
708
1211
 
709
1212
  fclose(styles->file);
1213
+ free(buffer);
710
1214
 
711
1215
  mem_error:
712
1216
  lxw_styles_free(styles);
@@ -721,6 +1225,8 @@ STATIC lxw_error
721
1225
  _write_content_types_file(lxw_packager *self)
722
1226
  {
723
1227
  lxw_content_types *content_types = lxw_content_types_new();
1228
+ char *buffer = NULL;
1229
+ size_t buffer_size = 0;
724
1230
  lxw_workbook *workbook = self->workbook;
725
1231
  lxw_sheet *sheet;
726
1232
  char filename[LXW_MAX_ATTRIBUTE_LENGTH] = { 0 };
@@ -729,6 +1235,7 @@ _write_content_types_file(lxw_packager *self)
729
1235
  uint32_t chartsheet_index = 1;
730
1236
  uint32_t drawing_count = _get_drawing_count(self);
731
1237
  uint32_t chart_count = _get_chart_count(self);
1238
+ uint32_t table_count = _get_table_count(self);
732
1239
  lxw_error err = LXW_NO_ERROR;
733
1240
 
734
1241
  if (!content_types) {
@@ -736,7 +1243,8 @@ _write_content_types_file(lxw_packager *self)
736
1243
  goto mem_error;
737
1244
  }
738
1245
 
739
- content_types->file = lxw_tmpfile(self->tmpdir);
1246
+ content_types->file = lxw_get_filehandle(&buffer, &buffer_size,
1247
+ self->tmpdir);
740
1248
  if (!content_types->file) {
741
1249
  err = LXW_ERROR_CREATING_TMPFILE;
742
1250
  goto mem_error;
@@ -751,6 +1259,9 @@ _write_content_types_file(lxw_packager *self)
751
1259
  if (workbook->has_bmp)
752
1260
  lxw_ct_add_default(content_types, "bmp", "image/bmp");
753
1261
 
1262
+ if (workbook->has_gif)
1263
+ lxw_ct_add_default(content_types, "gif", "image/gif");
1264
+
754
1265
  if (workbook->vba_project)
755
1266
  lxw_ct_add_default(content_types, "bin",
756
1267
  "application/vnd.ms-office.vbaProject");
@@ -762,6 +1273,10 @@ _write_content_types_file(lxw_packager *self)
762
1273
  lxw_ct_add_override(content_types, "/xl/workbook.xml",
763
1274
  LXW_APP_DOCUMENT "spreadsheetml.sheet.main+xml");
764
1275
 
1276
+ if (workbook->vba_project_signature)
1277
+ lxw_ct_add_override(content_types, "/xl/vbaProjectSignature.bin",
1278
+ "application/vnd.ms-office.vbaProjectSignature");
1279
+
765
1280
  STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
766
1281
  if (sheet->is_chartsheet) {
767
1282
  lxw_snprintf(filename, LXW_FILENAME_LENGTH,
@@ -787,17 +1302,37 @@ _write_content_types_file(lxw_packager *self)
787
1302
  lxw_ct_add_drawing_name(content_types, filename);
788
1303
  }
789
1304
 
1305
+ for (index = 1; index <= table_count; index++) {
1306
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
1307
+ "/xl/tables/table%d.xml", index);
1308
+ lxw_ct_add_table_name(content_types, filename);
1309
+ }
1310
+
1311
+ if (workbook->has_vml)
1312
+ lxw_ct_add_vml_name(content_types);
1313
+
1314
+ for (index = 1; index <= workbook->comment_count; index++) {
1315
+ lxw_snprintf(filename, LXW_FILENAME_LENGTH,
1316
+ "/xl/comments%d.xml", index);
1317
+ lxw_ct_add_comment_name(content_types, filename);
1318
+ }
1319
+
790
1320
  if (workbook->sst->string_count)
791
1321
  lxw_ct_add_shared_strings(content_types);
792
1322
 
793
1323
  if (!STAILQ_EMPTY(self->workbook->custom_properties))
794
1324
  lxw_ct_add_custom_properties(content_types);
795
1325
 
1326
+ if (workbook->has_metadata)
1327
+ lxw_ct_add_metadata(content_types);
1328
+
796
1329
  lxw_content_types_assemble_xml_file(content_types);
797
1330
 
798
- err = _add_file_to_zip(self, content_types->file, "[Content_Types].xml");
1331
+ err = _add_to_zip(self, content_types->file, &buffer, &buffer_size,
1332
+ "[Content_Types].xml");
799
1333
 
800
1334
  fclose(content_types->file);
1335
+ free(buffer);
801
1336
 
802
1337
  mem_error:
803
1338
  lxw_content_types_free(content_types);
@@ -812,6 +1347,8 @@ STATIC lxw_error
812
1347
  _write_workbook_rels_file(lxw_packager *self)
813
1348
  {
814
1349
  lxw_relationships *rels = lxw_relationships_new();
1350
+ char *buffer = NULL;
1351
+ size_t buffer_size = 0;
815
1352
  lxw_workbook *workbook = self->workbook;
816
1353
  lxw_sheet *sheet;
817
1354
  char sheetname[LXW_FILENAME_LENGTH] = { 0 };
@@ -824,7 +1361,7 @@ _write_workbook_rels_file(lxw_packager *self)
824
1361
  goto mem_error;
825
1362
  }
826
1363
 
827
- rels->file = lxw_tmpfile(self->tmpdir);
1364
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
828
1365
  if (!rels->file) {
829
1366
  err = LXW_ERROR_CREATING_TMPFILE;
830
1367
  goto mem_error;
@@ -856,11 +1393,16 @@ _write_workbook_rels_file(lxw_packager *self)
856
1393
  lxw_add_ms_package_relationship(rels, "/vbaProject",
857
1394
  "vbaProject.bin");
858
1395
 
1396
+ if (workbook->has_metadata)
1397
+ lxw_add_document_relationship(rels, "/sheetMetadata", "metadata.xml");
1398
+
859
1399
  lxw_relationships_assemble_xml_file(rels);
860
1400
 
861
- err = _add_file_to_zip(self, rels->file, "xl/_rels/workbook.xml.rels");
1401
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size,
1402
+ "xl/_rels/workbook.xml.rels");
862
1403
 
863
1404
  fclose(rels->file);
1405
+ free(buffer);
864
1406
 
865
1407
  mem_error:
866
1408
  lxw_free_relationships(rels);
@@ -876,6 +1418,8 @@ STATIC lxw_error
876
1418
  _write_worksheet_rels_file(lxw_packager *self)
877
1419
  {
878
1420
  lxw_relationships *rels;
1421
+ char *buffer = NULL;
1422
+ size_t buffer_size = 0;
879
1423
  lxw_rel_tuple *rel;
880
1424
  lxw_workbook *workbook = self->workbook;
881
1425
  lxw_sheet *sheet;
@@ -893,12 +1437,17 @@ _write_worksheet_rels_file(lxw_packager *self)
893
1437
  index++;
894
1438
 
895
1439
  if (STAILQ_EMPTY(worksheet->external_hyperlinks) &&
896
- STAILQ_EMPTY(worksheet->external_drawing_links))
1440
+ STAILQ_EMPTY(worksheet->external_drawing_links) &&
1441
+ STAILQ_EMPTY(worksheet->external_table_links) &&
1442
+ !worksheet->external_vml_header_link &&
1443
+ !worksheet->external_vml_comment_link &&
1444
+ !worksheet->external_background_link &&
1445
+ !worksheet->external_comment_link)
897
1446
  continue;
898
1447
 
899
1448
  rels = lxw_relationships_new();
900
1449
 
901
- rels->file = lxw_tmpfile(self->tmpdir);
1450
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
902
1451
  if (!rels->file) {
903
1452
  lxw_free_relationships(rels);
904
1453
  return LXW_ERROR_CREATING_TMPFILE;
@@ -914,14 +1463,40 @@ _write_worksheet_rels_file(lxw_packager *self)
914
1463
  rel->target_mode);
915
1464
  }
916
1465
 
1466
+ rel = worksheet->external_vml_comment_link;
1467
+ if (rel)
1468
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1469
+ rel->target_mode);
1470
+
1471
+ rel = worksheet->external_vml_header_link;
1472
+ if (rel)
1473
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1474
+ rel->target_mode);
1475
+
1476
+ rel = worksheet->external_background_link;
1477
+ if (rel)
1478
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1479
+ rel->target_mode);
1480
+
1481
+ STAILQ_FOREACH(rel, worksheet->external_table_links, list_pointers) {
1482
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1483
+ rel->target_mode);
1484
+ }
1485
+
1486
+ rel = worksheet->external_comment_link;
1487
+ if (rel)
1488
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1489
+ rel->target_mode);
1490
+
917
1491
  lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
918
1492
  "xl/worksheets/_rels/sheet%d.xml.rels", index);
919
1493
 
920
1494
  lxw_relationships_assemble_xml_file(rels);
921
1495
 
922
- err = _add_file_to_zip(self, rels->file, sheetname);
1496
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
923
1497
 
924
1498
  fclose(rels->file);
1499
+ free(buffer);
925
1500
  lxw_free_relationships(rels);
926
1501
 
927
1502
  RETURN_ON_ERROR(err);
@@ -938,6 +1513,8 @@ STATIC lxw_error
938
1513
  _write_chartsheet_rels_file(lxw_packager *self)
939
1514
  {
940
1515
  lxw_relationships *rels;
1516
+ char *buffer = NULL;
1517
+ size_t buffer_size = 0;
941
1518
  lxw_rel_tuple *rel;
942
1519
  lxw_workbook *workbook = self->workbook;
943
1520
  lxw_sheet *sheet;
@@ -954,13 +1531,12 @@ _write_chartsheet_rels_file(lxw_packager *self)
954
1531
 
955
1532
  index++;
956
1533
 
957
- /* TODO. This should never be empty. Put check higher up. */
958
1534
  if (STAILQ_EMPTY(worksheet->external_drawing_links))
959
1535
  continue;
960
1536
 
961
1537
  rels = lxw_relationships_new();
962
1538
 
963
- rels->file = lxw_tmpfile(self->tmpdir);
1539
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
964
1540
  if (!rels->file) {
965
1541
  lxw_free_relationships(rels);
966
1542
  return LXW_ERROR_CREATING_TMPFILE;
@@ -981,9 +1557,10 @@ _write_chartsheet_rels_file(lxw_packager *self)
981
1557
 
982
1558
  lxw_relationships_assemble_xml_file(rels);
983
1559
 
984
- err = _add_file_to_zip(self, rels->file, sheetname);
1560
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
985
1561
 
986
1562
  fclose(rels->file);
1563
+ free(buffer);
987
1564
  lxw_free_relationships(rels);
988
1565
 
989
1566
  RETURN_ON_ERROR(err);
@@ -1000,6 +1577,8 @@ STATIC lxw_error
1000
1577
  _write_drawing_rels_file(lxw_packager *self)
1001
1578
  {
1002
1579
  lxw_relationships *rels;
1580
+ char *buffer = NULL;
1581
+ size_t buffer_size = 0;
1003
1582
  lxw_rel_tuple *rel;
1004
1583
  lxw_workbook *workbook = self->workbook;
1005
1584
  lxw_sheet *sheet;
@@ -1019,7 +1598,7 @@ _write_drawing_rels_file(lxw_packager *self)
1019
1598
 
1020
1599
  rels = lxw_relationships_new();
1021
1600
 
1022
- rels->file = lxw_tmpfile(self->tmpdir);
1601
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
1023
1602
  if (!rels->file) {
1024
1603
  lxw_free_relationships(rels);
1025
1604
  return LXW_ERROR_CREATING_TMPFILE;
@@ -1036,9 +1615,10 @@ _write_drawing_rels_file(lxw_packager *self)
1036
1615
 
1037
1616
  lxw_relationships_assemble_xml_file(rels);
1038
1617
 
1039
- err = _add_file_to_zip(self, rels->file, sheetname);
1618
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
1040
1619
 
1041
1620
  fclose(rels->file);
1621
+ free(buffer);
1042
1622
  lxw_free_relationships(rels);
1043
1623
 
1044
1624
  RETURN_ON_ERROR(err);
@@ -1047,6 +1627,93 @@ _write_drawing_rels_file(lxw_packager *self)
1047
1627
  return LXW_NO_ERROR;
1048
1628
  }
1049
1629
 
1630
+ /*
1631
+ * Write the vmlDrawing .rels files for worksheets that contain images in
1632
+ * headers or footers.
1633
+ */
1634
+ STATIC lxw_error
1635
+ _write_vml_drawing_rels_file(lxw_packager *self, lxw_worksheet *worksheet,
1636
+ uint32_t index)
1637
+ {
1638
+ lxw_relationships *rels;
1639
+ char *buffer = NULL;
1640
+ size_t buffer_size = 0;
1641
+ lxw_rel_tuple *rel;
1642
+ char sheetname[LXW_FILENAME_LENGTH] = { 0 };
1643
+ lxw_error err = LXW_NO_ERROR;
1644
+
1645
+ rels = lxw_relationships_new();
1646
+
1647
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
1648
+ if (!rels->file) {
1649
+ lxw_free_relationships(rels);
1650
+ return LXW_ERROR_CREATING_TMPFILE;
1651
+ }
1652
+
1653
+ STAILQ_FOREACH(rel, worksheet->vml_drawing_links, list_pointers) {
1654
+ lxw_add_worksheet_relationship(rels, rel->type, rel->target,
1655
+ rel->target_mode);
1656
+
1657
+ }
1658
+
1659
+ lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
1660
+ "xl/drawings/_rels/vmlDrawing%d.vml.rels", index);
1661
+
1662
+ lxw_relationships_assemble_xml_file(rels);
1663
+
1664
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
1665
+
1666
+ fclose(rels->file);
1667
+ free(buffer);
1668
+ lxw_free_relationships(rels);
1669
+
1670
+ return err;
1671
+ }
1672
+
1673
+ /*
1674
+ * Write the vbaProject .rels xml file.
1675
+ */
1676
+ STATIC lxw_error
1677
+ _write_vba_project_rels_file(lxw_packager *self)
1678
+ {
1679
+ lxw_relationships *rels;
1680
+ lxw_workbook *workbook = self->workbook;
1681
+ lxw_error err = LXW_NO_ERROR;
1682
+ char *buffer = NULL;
1683
+ size_t buffer_size = 0;
1684
+
1685
+ if (!workbook->vba_project_signature)
1686
+ return LXW_NO_ERROR;
1687
+
1688
+ rels = lxw_relationships_new();
1689
+ if (!rels) {
1690
+ err = LXW_ERROR_MEMORY_MALLOC_FAILED;
1691
+ goto mem_error;
1692
+ }
1693
+
1694
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
1695
+ if (!rels->file) {
1696
+ err = LXW_ERROR_CREATING_TMPFILE;
1697
+ goto mem_error;
1698
+ }
1699
+
1700
+ lxw_add_ms_package_relationship(rels, "/vbaProjectSignature",
1701
+ "vbaProjectSignature.bin");
1702
+
1703
+ lxw_relationships_assemble_xml_file(rels);
1704
+
1705
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size,
1706
+ "xl/_rels/vbaProject.bin.rels");
1707
+
1708
+ fclose(rels->file);
1709
+ free(buffer);
1710
+
1711
+ mem_error:
1712
+ lxw_free_relationships(rels);
1713
+
1714
+ return err;
1715
+ }
1716
+
1050
1717
  /*
1051
1718
  * Write the _rels/.rels xml file.
1052
1719
  */
@@ -1054,6 +1721,8 @@ STATIC lxw_error
1054
1721
  _write_root_rels_file(lxw_packager *self)
1055
1722
  {
1056
1723
  lxw_relationships *rels = lxw_relationships_new();
1724
+ char *buffer = NULL;
1725
+ size_t buffer_size = 0;
1057
1726
  lxw_error err = LXW_NO_ERROR;
1058
1727
 
1059
1728
  if (!rels) {
@@ -1061,7 +1730,7 @@ _write_root_rels_file(lxw_packager *self)
1061
1730
  goto mem_error;
1062
1731
  }
1063
1732
 
1064
- rels->file = lxw_tmpfile(self->tmpdir);
1733
+ rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
1065
1734
  if (!rels->file) {
1066
1735
  err = LXW_ERROR_CREATING_TMPFILE;
1067
1736
  goto mem_error;
@@ -1083,9 +1752,10 @@ _write_root_rels_file(lxw_packager *self)
1083
1752
 
1084
1753
  lxw_relationships_assemble_xml_file(rels);
1085
1754
 
1086
- err = _add_file_to_zip(self, rels->file, "_rels/.rels");
1755
+ err = _add_to_zip(self, rels->file, &buffer, &buffer_size, "_rels/.rels");
1087
1756
 
1088
1757
  fclose(rels->file);
1758
+ free(buffer);
1089
1759
 
1090
1760
  mem_error:
1091
1761
  lxw_free_relationships(rels);
@@ -1122,12 +1792,12 @@ _add_file_to_zip(lxw_packager *self, FILE * file, const char *filename)
1122
1792
  fflush(file);
1123
1793
  rewind(file);
1124
1794
 
1125
- size_read = fread(self->buffer, 1, self->buffer_size, file);
1795
+ size_read = fread((void *) self->buffer, 1, self->buffer_size, file);
1126
1796
 
1127
1797
  while (size_read) {
1128
1798
 
1129
1799
  if (size_read < self->buffer_size) {
1130
- if (feof(file) == 0) {
1800
+ if (ferror(file)) {
1131
1801
  LXW_ERROR("Error reading member file data");
1132
1802
  RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
1133
1803
  }
@@ -1141,7 +1811,8 @@ _add_file_to_zip(lxw_packager *self, FILE * file, const char *filename)
1141
1811
  RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
1142
1812
  }
1143
1813
 
1144
- size_read = fread(self->buffer, 1, self->buffer_size, file);
1814
+ size_read =
1815
+ fread((void *) (void *) self->buffer, 1, self->buffer_size, file);
1145
1816
  }
1146
1817
 
1147
1818
  error = zipCloseFileInZip(self->zipfile);
@@ -1154,8 +1825,8 @@ _add_file_to_zip(lxw_packager *self, FILE * file, const char *filename)
1154
1825
  }
1155
1826
 
1156
1827
  STATIC lxw_error
1157
- _add_buffer_to_zip(lxw_packager *self, unsigned char *buffer,
1158
- size_t buffer_size, const char *filename)
1828
+ _add_buffer_to_zip(lxw_packager *self, const char *buffer, size_t buffer_size,
1829
+ const char *filename)
1159
1830
  {
1160
1831
  int16_t error = ZIP_OK;
1161
1832
 
@@ -1190,8 +1861,19 @@ _add_buffer_to_zip(lxw_packager *self, unsigned char *buffer,
1190
1861
  return LXW_NO_ERROR;
1191
1862
  }
1192
1863
 
1864
+ STATIC lxw_error
1865
+ _add_to_zip(lxw_packager *self, FILE * file, char **buffer,
1866
+ size_t *buffer_size, const char *filename)
1867
+ {
1868
+ /* Flush to ensure buffer is updated when using a memory-backed file. */
1869
+ fflush(file);
1870
+ return *buffer ?
1871
+ _add_buffer_to_zip(self, *buffer, *buffer_size, filename) :
1872
+ _add_file_to_zip(self, file, filename);
1873
+ }
1874
+
1193
1875
  /*
1194
- * Write the xml files that make up the XLXS OPC package.
1876
+ * Write the xml files that make up the XLSX OPC package.
1195
1877
  */
1196
1878
  lxw_error
1197
1879
  lxw_create_package(lxw_packager *self)
@@ -1200,61 +1882,79 @@ lxw_create_package(lxw_packager *self)
1200
1882
  int8_t zip_error;
1201
1883
 
1202
1884
  error = _write_content_types_file(self);
1203
- RETURN_ON_ERROR(error);
1885
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1204
1886
 
1205
1887
  error = _write_root_rels_file(self);
1206
- RETURN_ON_ERROR(error);
1888
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1207
1889
 
1208
1890
  error = _write_workbook_rels_file(self);
1209
- RETURN_ON_ERROR(error);
1891
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1210
1892
 
1211
1893
  error = _write_worksheet_files(self);
1212
- RETURN_ON_ERROR(error);
1894
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1213
1895
 
1214
1896
  error = _write_chartsheet_files(self);
1215
- RETURN_ON_ERROR(error);
1897
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1216
1898
 
1217
1899
  error = _write_workbook_file(self);
1218
- RETURN_ON_ERROR(error);
1900
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1219
1901
 
1220
1902
  error = _write_chart_files(self);
1221
- RETURN_ON_ERROR(error);
1903
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1222
1904
 
1223
1905
  error = _write_drawing_files(self);
1224
- RETURN_ON_ERROR(error);
1906
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1907
+
1908
+ error = _write_vml_files(self);
1909
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1910
+
1911
+ error = _write_comment_files(self);
1912
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1913
+
1914
+ error = _write_table_files(self);
1915
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1225
1916
 
1226
1917
  error = _write_shared_strings_file(self);
1227
- RETURN_ON_ERROR(error);
1918
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1228
1919
 
1229
1920
  error = _write_custom_file(self);
1230
- RETURN_ON_ERROR(error);
1921
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1231
1922
 
1232
1923
  error = _write_theme_file(self);
1233
- RETURN_ON_ERROR(error);
1924
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1234
1925
 
1235
1926
  error = _write_styles_file(self);
1236
- RETURN_ON_ERROR(error);
1927
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1237
1928
 
1238
1929
  error = _write_worksheet_rels_file(self);
1239
- RETURN_ON_ERROR(error);
1930
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1240
1931
 
1241
1932
  error = _write_chartsheet_rels_file(self);
1242
- RETURN_ON_ERROR(error);
1933
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1243
1934
 
1244
1935
  error = _write_drawing_rels_file(self);
1245
- RETURN_ON_ERROR(error);
1936
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1246
1937
 
1247
1938
  error = _write_image_files(self);
1248
- RETURN_ON_ERROR(error);
1939
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1249
1940
 
1250
1941
  error = _add_vba_project(self);
1251
- RETURN_ON_ERROR(error);
1942
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1943
+
1944
+ error = _add_vba_project_signature(self);
1945
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1946
+
1947
+ error = _write_vba_project_rels_file(self);
1948
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1252
1949
 
1253
1950
  error = _write_core_file(self);
1254
- RETURN_ON_ERROR(error);
1951
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1952
+
1953
+ error = _write_metadata_file(self);
1954
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1255
1955
 
1256
1956
  error = _write_app_file(self);
1257
- RETURN_ON_ERROR(error);
1957
+ RETURN_AND_ZIPCLOSE_ON_ERROR(error);
1258
1958
 
1259
1959
  zip_error = zipClose(self->zipfile, NULL);
1260
1960
  if (zip_error) {