Coverage Report

Created: 2025-08-28 06:20

/src/h2o/deps/yaml/src/dumper.c
Line
Count
Source (jump to first uncovered line)
1
2
#include "yaml_private.h"
3
4
/*
5
 * API functions.
6
 */
7
8
YAML_DECLARE(int)
9
yaml_emitter_open(yaml_emitter_t *emitter);
10
11
YAML_DECLARE(int)
12
yaml_emitter_close(yaml_emitter_t *emitter);
13
14
YAML_DECLARE(int)
15
yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
16
17
/*
18
 * Clean up functions.
19
 */
20
21
static void
22
yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
23
24
/*
25
 * Anchor functions.
26
 */
27
28
static void
29
yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
30
31
static yaml_char_t *
32
yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
33
34
35
/*
36
 * Serialize functions.
37
 */
38
39
static int
40
yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
41
42
static int
43
yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
44
45
static int
46
yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
47
        yaml_char_t *anchor);
48
49
static int
50
yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
51
        yaml_char_t *anchor);
52
53
static int
54
yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
55
        yaml_char_t *anchor);
56
57
/*
58
 * Issue a STREAM-START event.
59
 */
60
61
YAML_DECLARE(int)
62
yaml_emitter_open(yaml_emitter_t *emitter)
63
0
{
64
0
    yaml_event_t event;
65
0
    yaml_mark_t mark = { 0, 0, 0 };
66
67
0
    assert(emitter);            /* Non-NULL emitter object is required. */
68
0
    assert(!emitter->opened);   /* Emitter should not be opened yet. */
69
70
0
    STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
71
72
0
    if (!yaml_emitter_emit(emitter, &event)) {
73
0
        return 0;
74
0
    }
75
76
0
    emitter->opened = 1;
77
78
0
    return 1;
79
0
}
80
81
/*
82
 * Issue a STREAM-END event.
83
 */
84
85
YAML_DECLARE(int)
86
yaml_emitter_close(yaml_emitter_t *emitter)
87
0
{
88
0
    yaml_event_t event;
89
0
    yaml_mark_t mark = { 0, 0, 0 };
90
91
0
    assert(emitter);            /* Non-NULL emitter object is required. */
92
0
    assert(emitter->opened);    /* Emitter should be opened. */
93
94
0
    if (emitter->closed) return 1;
95
96
0
    STREAM_END_EVENT_INIT(event, mark, mark);
97
98
0
    if (!yaml_emitter_emit(emitter, &event)) {
99
0
        return 0;
100
0
    }
101
102
0
    emitter->closed = 1;
103
104
0
    return 1;
105
0
}
106
107
/*
108
 * Dump a YAML document.
109
 */
110
111
YAML_DECLARE(int)
112
yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
113
0
{
114
0
    yaml_event_t event;
115
0
    yaml_mark_t mark = { 0, 0, 0 };
116
117
0
    assert(emitter);            /* Non-NULL emitter object is required. */
118
0
    assert(document);           /* Non-NULL emitter object is expected. */
119
120
0
    emitter->document = document;
121
122
0
    if (!emitter->opened) {
123
0
        if (!yaml_emitter_open(emitter)) goto error;
124
0
    }
125
126
0
    if (STACK_EMPTY(emitter, document->nodes)) {
127
0
        if (!yaml_emitter_close(emitter)) goto error;
128
0
        yaml_emitter_delete_document_and_anchors(emitter);
129
0
        return 1;
130
0
    }
131
132
0
    assert(emitter->opened);    /* Emitter should be opened. */
133
134
0
    emitter->anchors = (yaml_anchors_t*)yaml_malloc(sizeof(*(emitter->anchors))
135
0
            * (document->nodes.top - document->nodes.start));
136
0
    if (!emitter->anchors) goto error;
137
0
    memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
138
0
            * (document->nodes.top - document->nodes.start));
139
140
0
    DOCUMENT_START_EVENT_INIT(event, document->version_directive,
141
0
            document->tag_directives.start, document->tag_directives.end,
142
0
            document->start_implicit, mark, mark);
143
0
    if (!yaml_emitter_emit(emitter, &event)) goto error;
144
145
0
    yaml_emitter_anchor_node(emitter, 1);
146
0
    if (!yaml_emitter_dump_node(emitter, 1)) goto error;
147
148
0
    DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
149
0
    if (!yaml_emitter_emit(emitter, &event)) goto error;
150
151
0
    yaml_emitter_delete_document_and_anchors(emitter);
152
153
0
    return 1;
154
155
0
error:
156
157
0
    yaml_emitter_delete_document_and_anchors(emitter);
158
159
0
    return 0;
160
0
}
161
162
/*
163
 * Clean up the emitter object after a document is dumped.
164
 */
165
166
static void
167
yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
168
0
{
169
0
    int index;
170
171
0
    if (!emitter->anchors) {
172
0
        yaml_document_delete(emitter->document);
173
0
        emitter->document = NULL;
174
0
        return;
175
0
    }
176
177
0
    for (index = 0; emitter->document->nodes.start + index
178
0
            < emitter->document->nodes.top; index ++) {
179
0
        yaml_node_t node = emitter->document->nodes.start[index];
180
0
        if (!emitter->anchors[index].serialized) {
181
0
            yaml_free(node.tag);
182
0
            if (node.type == YAML_SCALAR_NODE) {
183
0
                yaml_free(node.data.scalar.value);
184
0
            }
185
0
        }
186
0
        if (node.type == YAML_SEQUENCE_NODE) {
187
0
            STACK_DEL(emitter, node.data.sequence.items);
188
0
        }
189
0
        if (node.type == YAML_MAPPING_NODE) {
190
0
            STACK_DEL(emitter, node.data.mapping.pairs);
191
0
        }
192
0
    }
193
194
0
    STACK_DEL(emitter, emitter->document->nodes);
195
0
    yaml_free(emitter->anchors);
196
197
0
    emitter->anchors = NULL;
198
0
    emitter->last_anchor_id = 0;
199
0
    emitter->document = NULL;
200
0
}
201
202
/*
203
 * Check the references of a node and assign the anchor id if needed.
204
 */
205
206
static void
207
yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
208
0
{
209
0
    yaml_node_t *node = emitter->document->nodes.start + index - 1;
210
0
    yaml_node_item_t *item;
211
0
    yaml_node_pair_t *pair;
212
213
0
    emitter->anchors[index-1].references ++;
214
215
0
    if (emitter->anchors[index-1].references == 1) {
216
0
        switch (node->type) {
217
0
            case YAML_SEQUENCE_NODE:
218
0
                for (item = node->data.sequence.items.start;
219
0
                        item < node->data.sequence.items.top; item ++) {
220
0
                    yaml_emitter_anchor_node(emitter, *item);
221
0
                }
222
0
                break;
223
0
            case YAML_MAPPING_NODE:
224
0
                for (pair = node->data.mapping.pairs.start;
225
0
                        pair < node->data.mapping.pairs.top; pair ++) {
226
0
                    yaml_emitter_anchor_node(emitter, pair->key);
227
0
                    yaml_emitter_anchor_node(emitter, pair->value);
228
0
                }
229
0
                break;
230
0
            default:
231
0
                break;
232
0
        }
233
0
    }
234
235
0
    else if (emitter->anchors[index-1].references == 2) {
236
0
        emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
237
0
    }
238
0
}
239
240
/*
241
 * Generate a textual representation for an anchor.
242
 */
243
244
0
#define ANCHOR_TEMPLATE         "id%03d"
245
#define ANCHOR_TEMPLATE_LENGTH  16
246
247
static yaml_char_t *
248
yaml_emitter_generate_anchor(SHIM(yaml_emitter_t *emitter), int anchor_id)
249
0
{
250
0
    yaml_char_t *anchor = YAML_MALLOC(ANCHOR_TEMPLATE_LENGTH);
251
252
0
    if (!anchor) return NULL;
253
254
0
    sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
255
256
0
    return anchor;
257
0
}
258
259
/*
260
 * Serialize a node.
261
 */
262
263
static int
264
yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
265
0
{
266
0
    yaml_node_t *node = emitter->document->nodes.start + index - 1;
267
0
    int anchor_id = emitter->anchors[index-1].anchor;
268
0
    yaml_char_t *anchor = NULL;
269
270
0
    if (anchor_id) {
271
0
        anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
272
0
        if (!anchor) return 0;
273
0
    }
274
275
0
    if (emitter->anchors[index-1].serialized) {
276
0
        return yaml_emitter_dump_alias(emitter, anchor);
277
0
    }
278
279
0
    emitter->anchors[index-1].serialized = 1;
280
281
0
    switch (node->type) {
282
0
        case YAML_SCALAR_NODE:
283
0
            return yaml_emitter_dump_scalar(emitter, node, anchor);
284
0
        case YAML_SEQUENCE_NODE:
285
0
            return yaml_emitter_dump_sequence(emitter, node, anchor);
286
0
        case YAML_MAPPING_NODE:
287
0
            return yaml_emitter_dump_mapping(emitter, node, anchor);
288
0
        default:
289
0
            assert(0);      /* Could not happen. */
290
0
            break;
291
0
    }
292
293
0
    return 0;       /* Could not happen. */
294
0
}
295
296
/*
297
 * Serialize an alias.
298
 */
299
300
static int
301
yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
302
0
{
303
0
    yaml_event_t event;
304
0
    yaml_mark_t mark  = { 0, 0, 0 };
305
306
0
    ALIAS_EVENT_INIT(event, anchor, mark, mark);
307
308
0
    return yaml_emitter_emit(emitter, &event);
309
0
}
310
311
/*
312
 * Serialize a scalar.
313
 */
314
315
static int
316
yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
317
        yaml_char_t *anchor)
318
0
{
319
0
    yaml_event_t event;
320
0
    yaml_mark_t mark  = { 0, 0, 0 };
321
322
0
    int plain_implicit = (strcmp((char *)node->tag,
323
0
                YAML_DEFAULT_SCALAR_TAG) == 0);
324
0
    int quoted_implicit = (strcmp((char *)node->tag,
325
0
                YAML_DEFAULT_SCALAR_TAG) == 0);
326
327
0
    SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
328
0
            node->data.scalar.length, plain_implicit, quoted_implicit,
329
0
            node->data.scalar.style, mark, mark);
330
331
0
    return yaml_emitter_emit(emitter, &event);
332
0
}
333
334
/*
335
 * Serialize a sequence.
336
 */
337
338
static int
339
yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
340
        yaml_char_t *anchor)
341
0
{
342
0
    yaml_event_t event;
343
0
    yaml_mark_t mark  = { 0, 0, 0 };
344
345
0
    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
346
347
0
    yaml_node_item_t *item;
348
349
0
    SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
350
0
            node->data.sequence.style, mark, mark);
351
0
    if (!yaml_emitter_emit(emitter, &event)) return 0;
352
353
0
    for (item = node->data.sequence.items.start;
354
0
            item < node->data.sequence.items.top; item ++) {
355
0
        if (!yaml_emitter_dump_node(emitter, *item)) return 0;
356
0
    }
357
358
0
    SEQUENCE_END_EVENT_INIT(event, mark, mark);
359
0
    if (!yaml_emitter_emit(emitter, &event)) return 0;
360
361
0
    return 1;
362
0
}
363
364
/*
365
 * Serialize a mapping.
366
 */
367
368
static int
369
yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
370
        yaml_char_t *anchor)
371
0
{
372
0
    yaml_event_t event;
373
0
    yaml_mark_t mark  = { 0, 0, 0 };
374
375
0
    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
376
377
0
    yaml_node_pair_t *pair;
378
379
0
    MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
380
0
            node->data.mapping.style, mark, mark);
381
0
    if (!yaml_emitter_emit(emitter, &event)) return 0;
382
383
0
    for (pair = node->data.mapping.pairs.start;
384
0
            pair < node->data.mapping.pairs.top; pair ++) {
385
0
        if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
386
0
        if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
387
0
    }
388
389
0
    MAPPING_END_EVENT_INIT(event, mark, mark);
390
0
    if (!yaml_emitter_emit(emitter, &event)) return 0;
391
392
0
    return 1;
393
0
}
394