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