fast_excel 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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) {