Coverage Report

Created: 2025-10-28 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxlsxwriter/src/metadata.c
Line
Count
Source
1
/*****************************************************************************
2
 * metadata - A library for creating Excel XLSX metadata files.
3
 *
4
 * Used in conjunction with the libxlsxwriter library.
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 * Copyright 2014-2025, John McNamara, jmcnamara@cpan.org.
8
 *
9
 */
10
11
#include "xlsxwriter/xmlwriter.h"
12
#include "xlsxwriter/metadata.h"
13
#include "xlsxwriter/utility.h"
14
15
/*
16
 * Forward declarations.
17
 */
18
19
/*****************************************************************************
20
 *
21
 * Private functions.
22
 *
23
 ****************************************************************************/
24
25
/*
26
 * Create a new metadata object.
27
 */
28
lxw_metadata *
29
lxw_metadata_new(void)
30
0
{
31
0
    lxw_metadata *metadata = calloc(1, sizeof(lxw_metadata));
32
0
    GOTO_LABEL_ON_MEM_ERROR(metadata, mem_error);
33
34
0
    return metadata;
35
36
0
mem_error:
37
0
    lxw_metadata_free(metadata);
38
0
    return NULL;
39
0
}
40
41
/*
42
 * Free a metadata object.
43
 */
44
void
45
lxw_metadata_free(lxw_metadata *metadata)
46
0
{
47
0
    if (!metadata)
48
0
        return;
49
50
0
    free(metadata);
51
0
}
52
53
/*****************************************************************************
54
 *
55
 * XML functions.
56
 *
57
 ****************************************************************************/
58
59
/*
60
 * Write the XML declaration.
61
 */
62
STATIC void
63
_metadata_xml_declaration(lxw_metadata *self)
64
0
{
65
0
    lxw_xml_declaration(self->file);
66
0
}
67
68
/*
69
 * Write the <metadata> element.
70
 */
71
STATIC void
72
_metadata_write_metadata(lxw_metadata *self)
73
0
{
74
0
    struct xml_attribute_list attributes;
75
0
    struct xml_attribute *attribute;
76
0
    char xmlns[] = "http://schemas.openxmlformats.org/"
77
0
        "spreadsheetml/2006/main";
78
0
    char xmlns_xda[] = "http://schemas.microsoft.com/office/"
79
0
        "spreadsheetml/2017/dynamicarray";
80
0
    char xmlns_xlrd[] = "http://schemas.microsoft.com/office/"
81
0
        "spreadsheetml/2017/richdata";
82
83
0
    LXW_INIT_ATTRIBUTES();
84
0
    LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
85
86
0
    if (self->has_embedded_images)
87
0
        LXW_PUSH_ATTRIBUTES_STR("xmlns:xlrd", xmlns_xlrd);
88
89
0
    if (self->has_dynamic_functions)
90
0
        LXW_PUSH_ATTRIBUTES_STR("xmlns:xda", xmlns_xda);
91
92
0
    lxw_xml_start_tag(self->file, "metadata", &attributes);
93
94
0
    LXW_FREE_ATTRIBUTES();
95
0
}
96
97
/*
98
 * Write the <metadataType> element for dynamic functions.
99
 */
100
STATIC void
101
_metadata_write_cell_metadata_type(lxw_metadata *self)
102
0
{
103
0
    struct xml_attribute_list attributes;
104
0
    struct xml_attribute *attribute;
105
106
0
    LXW_INIT_ATTRIBUTES();
107
0
    LXW_PUSH_ATTRIBUTES_STR("name", "XLDAPR");
108
0
    LXW_PUSH_ATTRIBUTES_INT("minSupportedVersion", 120000);
109
0
    LXW_PUSH_ATTRIBUTES_INT("copy", 1);
110
0
    LXW_PUSH_ATTRIBUTES_INT("pasteAll", 1);
111
0
    LXW_PUSH_ATTRIBUTES_INT("pasteValues", 1);
112
0
    LXW_PUSH_ATTRIBUTES_INT("merge", 1);
113
0
    LXW_PUSH_ATTRIBUTES_INT("splitFirst", 1);
114
0
    LXW_PUSH_ATTRIBUTES_INT("rowColShift", 1);
115
0
    LXW_PUSH_ATTRIBUTES_INT("clearFormats", 1);
116
0
    LXW_PUSH_ATTRIBUTES_INT("clearComments", 1);
117
0
    LXW_PUSH_ATTRIBUTES_INT("assign", 1);
118
0
    LXW_PUSH_ATTRIBUTES_INT("coerce", 1);
119
0
    LXW_PUSH_ATTRIBUTES_INT("cellMeta", 1);
120
121
0
    lxw_xml_empty_tag(self->file, "metadataType", &attributes);
122
123
0
    LXW_FREE_ATTRIBUTES();
124
0
}
125
126
/*
127
 * Write the <metadataType> element for embedded images.
128
 */
129
STATIC void
130
_metadata_write_value_metadata_type(lxw_metadata *self)
131
0
{
132
0
    struct xml_attribute_list attributes;
133
0
    struct xml_attribute *attribute;
134
135
0
    LXW_INIT_ATTRIBUTES();
136
0
    LXW_PUSH_ATTRIBUTES_STR("name", "XLRICHVALUE");
137
0
    LXW_PUSH_ATTRIBUTES_INT("minSupportedVersion", 120000);
138
0
    LXW_PUSH_ATTRIBUTES_INT("copy", 1);
139
0
    LXW_PUSH_ATTRIBUTES_INT("pasteAll", 1);
140
0
    LXW_PUSH_ATTRIBUTES_INT("pasteValues", 1);
141
0
    LXW_PUSH_ATTRIBUTES_INT("merge", 1);
142
0
    LXW_PUSH_ATTRIBUTES_INT("splitFirst", 1);
143
0
    LXW_PUSH_ATTRIBUTES_INT("rowColShift", 1);
144
0
    LXW_PUSH_ATTRIBUTES_INT("clearFormats", 1);
145
0
    LXW_PUSH_ATTRIBUTES_INT("clearComments", 1);
146
0
    LXW_PUSH_ATTRIBUTES_INT("assign", 1);
147
0
    LXW_PUSH_ATTRIBUTES_INT("coerce", 1);
148
149
0
    lxw_xml_empty_tag(self->file, "metadataType", &attributes);
150
151
0
    LXW_FREE_ATTRIBUTES();
152
0
}
153
154
/*
155
 * Write the <metadataTypes> element.
156
 */
157
STATIC void
158
_metadata_write_metadata_types(lxw_metadata *self)
159
0
{
160
0
    struct xml_attribute_list attributes;
161
0
    struct xml_attribute *attribute;
162
0
    uint8_t count = 0;
163
164
0
    if (self->has_dynamic_functions)
165
0
        count++;
166
167
0
    if (self->has_embedded_images)
168
0
        count++;
169
170
0
    LXW_INIT_ATTRIBUTES();
171
0
    LXW_PUSH_ATTRIBUTES_INT("count", count);
172
173
0
    lxw_xml_start_tag(self->file, "metadataTypes", &attributes);
174
175
    /* Write the metadataType element. */
176
0
    if (self->has_dynamic_functions)
177
0
        _metadata_write_cell_metadata_type(self);
178
0
    if (self->has_embedded_images)
179
0
        _metadata_write_value_metadata_type(self);
180
181
0
    lxw_xml_end_tag(self->file, "metadataTypes");
182
183
0
    LXW_FREE_ATTRIBUTES();
184
0
}
185
186
/*
187
 * Write the <xda:dynamicArrayProperties> element.
188
 */
189
STATIC void
190
_metadata_write_xda_dynamic_array_properties(lxw_metadata *self)
191
0
{
192
0
    struct xml_attribute_list attributes;
193
0
    struct xml_attribute *attribute;
194
195
0
    LXW_INIT_ATTRIBUTES();
196
0
    LXW_PUSH_ATTRIBUTES_STR("fDynamic", "1");
197
0
    LXW_PUSH_ATTRIBUTES_STR("fCollapsed", "0");
198
199
0
    lxw_xml_empty_tag(self->file, "xda:dynamicArrayProperties", &attributes);
200
201
0
    LXW_FREE_ATTRIBUTES();
202
0
}
203
204
/*
205
 * Write the <ext> element for dynamic functions.
206
 */
207
STATIC void
208
_metadata_write_cell_ext(lxw_metadata *self)
209
0
{
210
0
    struct xml_attribute_list attributes;
211
0
    struct xml_attribute *attribute;
212
213
0
    LXW_INIT_ATTRIBUTES();
214
0
    LXW_PUSH_ATTRIBUTES_STR("uri", "{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}");
215
216
0
    lxw_xml_start_tag(self->file, "ext", &attributes);
217
218
    /* Write the xda:dynamicArrayProperties element. */
219
0
    _metadata_write_xda_dynamic_array_properties(self);
220
221
0
    lxw_xml_end_tag(self->file, "ext");
222
223
0
    LXW_FREE_ATTRIBUTES();
224
0
}
225
226
/*
227
 * Write the <xlrd:rvb> element.
228
 */
229
STATIC void
230
_metadata_write_xlrd_rvb(lxw_metadata *self, uint32_t index)
231
0
{
232
0
    struct xml_attribute_list attributes;
233
0
    struct xml_attribute *attribute;
234
235
0
    LXW_INIT_ATTRIBUTES();
236
0
    LXW_PUSH_ATTRIBUTES_INT("i", index);
237
238
0
    lxw_xml_empty_tag(self->file, "xlrd:rvb", &attributes);
239
240
0
    LXW_FREE_ATTRIBUTES();
241
0
}
242
243
/*
244
 * Write the <ext> element for embedded images.
245
 */
246
STATIC void
247
_metadata_write_value_ext(lxw_metadata *self, uint32_t index)
248
0
{
249
0
    struct xml_attribute_list attributes;
250
0
    struct xml_attribute *attribute;
251
252
0
    LXW_INIT_ATTRIBUTES();
253
0
    LXW_PUSH_ATTRIBUTES_STR("uri", "{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}");
254
255
0
    lxw_xml_start_tag(self->file, "ext", &attributes);
256
257
    /* Write the xlrd:rvb element. */
258
0
    _metadata_write_xlrd_rvb(self, index);
259
260
0
    lxw_xml_end_tag(self->file, "ext");
261
262
0
    LXW_FREE_ATTRIBUTES();
263
0
}
264
265
/*
266
 * Write the <futureMetadata> element for dynamic functions.
267
 */
268
STATIC void
269
_metadata_write_cell_future_metadata(lxw_metadata *self)
270
0
{
271
0
    struct xml_attribute_list attributes;
272
0
    struct xml_attribute *attribute;
273
274
0
    LXW_INIT_ATTRIBUTES();
275
0
    LXW_PUSH_ATTRIBUTES_STR("name", "XLDAPR");
276
0
    LXW_PUSH_ATTRIBUTES_INT("count", 1);
277
278
0
    lxw_xml_start_tag(self->file, "futureMetadata", &attributes);
279
280
0
    lxw_xml_start_tag(self->file, "bk", NULL);
281
0
    lxw_xml_start_tag(self->file, "extLst", NULL);
282
283
    /* Write the ext element. */
284
0
    _metadata_write_cell_ext(self);
285
286
0
    lxw_xml_end_tag(self->file, "extLst");
287
0
    lxw_xml_end_tag(self->file, "bk");
288
289
0
    lxw_xml_end_tag(self->file, "futureMetadata");
290
291
0
    LXW_FREE_ATTRIBUTES();
292
0
}
293
294
/*
295
 * Write the <futureMetadata> element for embedded images.
296
 */
297
STATIC void
298
_metadata_write_value_future_metadata(lxw_metadata *self)
299
0
{
300
0
    struct xml_attribute_list attributes;
301
0
    struct xml_attribute *attribute;
302
0
    uint32_t i;
303
304
0
    LXW_INIT_ATTRIBUTES();
305
0
    LXW_PUSH_ATTRIBUTES_STR("name", "XLRICHVALUE");
306
0
    LXW_PUSH_ATTRIBUTES_INT("count", self->num_embedded_images);
307
308
0
    lxw_xml_start_tag(self->file, "futureMetadata", &attributes);
309
310
0
    for (i = 0; i < self->num_embedded_images; i++) {
311
0
        lxw_xml_start_tag(self->file, "bk", NULL);
312
313
0
        lxw_xml_start_tag(self->file, "extLst", NULL);
314
315
        /* Write the ext element. */
316
0
        _metadata_write_value_ext(self, i);
317
318
0
        lxw_xml_end_tag(self->file, "extLst");
319
0
        lxw_xml_end_tag(self->file, "bk");
320
321
0
    }
322
323
0
    lxw_xml_end_tag(self->file, "futureMetadata");
324
325
0
    LXW_FREE_ATTRIBUTES();
326
0
}
327
328
/*
329
 * Write the <rc> element.
330
 */
331
STATIC void
332
_metadata_write_rc(lxw_metadata *self, uint8_t type, uint32_t index)
333
0
{
334
0
    struct xml_attribute_list attributes;
335
0
    struct xml_attribute *attribute;
336
337
0
    LXW_INIT_ATTRIBUTES();
338
0
    LXW_PUSH_ATTRIBUTES_INT("t", type);
339
0
    LXW_PUSH_ATTRIBUTES_INT("v", index);
340
341
0
    lxw_xml_empty_tag(self->file, "rc", &attributes);
342
343
0
    LXW_FREE_ATTRIBUTES();
344
0
}
345
346
/*
347
 * Write the <cellMetadata> element for dynamic functions.
348
 */
349
STATIC void
350
_metadata_write_cell_metadata(lxw_metadata *self)
351
0
{
352
0
    struct xml_attribute_list attributes;
353
0
    struct xml_attribute *attribute;
354
355
0
    LXW_INIT_ATTRIBUTES();
356
0
    LXW_PUSH_ATTRIBUTES_STR("count", "1");
357
358
0
    lxw_xml_start_tag(self->file, "cellMetadata", &attributes);
359
360
0
    lxw_xml_start_tag(self->file, "bk", NULL);
361
362
    /* Write the rc element. */
363
0
    _metadata_write_rc(self, 1, 0);
364
365
0
    lxw_xml_end_tag(self->file, "bk");
366
367
0
    lxw_xml_end_tag(self->file, "cellMetadata");
368
369
0
    LXW_FREE_ATTRIBUTES();
370
0
}
371
372
/*
373
 * Write the <cellMetadata> element for embedded images.
374
 */
375
STATIC void
376
_metadata_write_value_metadata(lxw_metadata *self)
377
0
{
378
0
    struct xml_attribute_list attributes;
379
0
    struct xml_attribute *attribute;
380
0
    uint8_t type = 1;
381
0
    uint32_t i;
382
383
0
    if (self->has_dynamic_functions)
384
0
        type = 2;
385
386
0
    LXW_INIT_ATTRIBUTES();
387
0
    LXW_PUSH_ATTRIBUTES_INT("count", self->num_embedded_images);
388
389
0
    lxw_xml_start_tag(self->file, "valueMetadata", &attributes);
390
391
0
    for (i = 0; i < self->num_embedded_images; i++) {
392
0
        lxw_xml_start_tag(self->file, "bk", NULL);
393
394
        /* Write the rc element. */
395
0
        _metadata_write_rc(self, type, i);
396
397
0
        lxw_xml_end_tag(self->file, "bk");
398
0
    }
399
400
0
    lxw_xml_end_tag(self->file, "valueMetadata");
401
402
0
    LXW_FREE_ATTRIBUTES();
403
0
}
404
405
/*****************************************************************************
406
 *
407
 * XML file assembly functions.
408
 *
409
 ****************************************************************************/
410
411
/*
412
 * Assemble and write the XML file.
413
 */
414
void
415
lxw_metadata_assemble_xml_file(lxw_metadata *self)
416
0
{
417
    /* Write the XML declaration. */
418
0
    _metadata_xml_declaration(self);
419
420
    /* Write the metadata element. */
421
0
    _metadata_write_metadata(self);
422
423
    /* Write the metadataTypes element. */
424
0
    _metadata_write_metadata_types(self);
425
426
    /* Write the futureMetadata element. */
427
0
    if (self->has_dynamic_functions)
428
0
        _metadata_write_cell_future_metadata(self);
429
0
    if (self->has_embedded_images)
430
0
        _metadata_write_value_future_metadata(self);
431
432
    /* Write the cellMetadata element. */
433
0
    if (self->has_dynamic_functions)
434
0
        _metadata_write_cell_metadata(self);
435
0
    if (self->has_embedded_images)
436
0
        _metadata_write_value_metadata(self);
437
438
0
    lxw_xml_end_tag(self->file, "metadata");
439
0
}