1
2#include "yaml_private.h"
3
4/*
5 * Get the library version.
6 */
7
8YAML_DECLARE(const char *)
9yaml_get_version_string(void)
10{
11    return YAML_VERSION_STRING;
12}
13
14/*
15 * Get the library version numbers.
16 */
17
18YAML_DECLARE(void)
19yaml_get_version(int *major, int *minor, int *patch)
20{
21    *major = YAML_VERSION_MAJOR;
22    *minor = YAML_VERSION_MINOR;
23    *patch = YAML_VERSION_PATCH;
24}
25
26/*
27 * Allocate a dynamic memory block.
28 */
29
30YAML_DECLARE(void *)
31yaml_malloc(size_t size)
32{
33    return malloc(size ? size : 1);
34}
35
36/*
37 * Reallocate a dynamic memory block.
38 */
39
40YAML_DECLARE(void *)
41yaml_realloc(void *ptr, size_t size)
42{
43    return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1);
44}
45
46/*
47 * Free a dynamic memory block.
48 */
49
50YAML_DECLARE(void)
51yaml_free(void *ptr)
52{
53    if (ptr) free(ptr);
54}
55
56/*
57 * Duplicate a string.
58 */
59
60YAML_DECLARE(yaml_char_t *)
61yaml_strdup(const yaml_char_t *str)
62{
63    if (!str)
64        return NULL;
65
66    return (yaml_char_t *)strdup((char *)str);
67}
68
69/*
70 * Extend a string.
71 */
72
73YAML_DECLARE(int)
74yaml_string_extend(yaml_char_t **start,
75        yaml_char_t **pointer, yaml_char_t **end)
76{
77    yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2);
78
79    if (!new_start) return 0;
80
81    memset(new_start + (*end - *start), 0, *end - *start);
82
83    *pointer = new_start + (*pointer - *start);
84    *end = new_start + (*end - *start)*2;
85    *start = new_start;
86
87    return 1;
88}
89
90/*
91 * Append a string B to a string A.
92 */
93
94YAML_DECLARE(int)
95yaml_string_join(
96        yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
97        yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end)
98{
99    if (*b_start == *b_pointer)
100        return 1;
101
102    while (*a_end - *a_pointer <= *b_pointer - *b_start) {
103        if (!yaml_string_extend(a_start, a_pointer, a_end))
104            return 0;
105    }
106
107    memcpy(*a_pointer, *b_start, *b_pointer - *b_start);
108    *a_pointer += *b_pointer - *b_start;
109
110    return 1;
111}
112
113/*
114 * Extend a stack.
115 */
116
117YAML_DECLARE(int)
118yaml_stack_extend(void **start, void **top, void **end)
119{
120    void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2);
121
122    if (!new_start) return 0;
123
124    *top = (char *)new_start + ((char *)*top - (char *)*start);
125    *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
126    *start = new_start;
127
128    return 1;
129}
130
131/*
132 * Extend or move a queue.
133 */
134
135YAML_DECLARE(int)
136yaml_queue_extend(void **start, void **head, void **tail, void **end)
137{
138    /* Check if we need to resize the queue. */
139
140    if (*start == *head && *tail == *end) {
141        void *new_start = yaml_realloc(*start,
142                ((char *)*end - (char *)*start)*2);
143
144        if (!new_start) return 0;
145
146        *head = (char *)new_start + ((char *)*head - (char *)*start);
147        *tail = (char *)new_start + ((char *)*tail - (char *)*start);
148        *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
149        *start = new_start;
150    }
151
152    /* Check if we need to move the queue at the beginning of the buffer. */
153
154    if (*tail == *end) {
155        if (*head != *tail) {
156            memmove(*start, *head, (char *)*tail - (char *)*head);
157        }
158        *tail = (char *)*tail - (char *)*head + (char *)*start;
159        *head = *start;
160    }
161
162    return 1;
163}
164
165
166/*
167 * Create a new parser object.
168 */
169
170YAML_DECLARE(int)
171yaml_parser_initialize(yaml_parser_t *parser)
172{
173    assert(parser);     /* Non-NULL parser object expected. */
174
175    memset(parser, 0, sizeof(yaml_parser_t));
176    if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE))
177        goto error;
178    if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE))
179        goto error;
180    if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE))
181        goto error;
182    if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_SIZE))
183        goto error;
184    if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_SIZE))
185        goto error;
186    if (!STACK_INIT(parser, parser->states, INITIAL_STACK_SIZE))
187        goto error;
188    if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_SIZE))
189        goto error;
190    if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_SIZE))
191        goto error;
192
193    return 1;
194
195error:
196
197    BUFFER_DEL(parser, parser->raw_buffer);
198    BUFFER_DEL(parser, parser->buffer);
199    QUEUE_DEL(parser, parser->tokens);
200    STACK_DEL(parser, parser->indents);
201    STACK_DEL(parser, parser->simple_keys);
202    STACK_DEL(parser, parser->states);
203    STACK_DEL(parser, parser->marks);
204    STACK_DEL(parser, parser->tag_directives);
205
206    return 0;
207}
208
209/*
210 * Destroy a parser object.
211 */
212
213YAML_DECLARE(void)
214yaml_parser_delete(yaml_parser_t *parser)
215{
216    assert(parser); /* Non-NULL parser object expected. */
217
218    BUFFER_DEL(parser, parser->raw_buffer);
219    BUFFER_DEL(parser, parser->buffer);
220    while (!QUEUE_EMPTY(parser, parser->tokens)) {
221        yaml_token_delete(&DEQUEUE(parser, parser->tokens));
222    }
223    QUEUE_DEL(parser, parser->tokens);
224    STACK_DEL(parser, parser->indents);
225    STACK_DEL(parser, parser->simple_keys);
226    STACK_DEL(parser, parser->states);
227    STACK_DEL(parser, parser->marks);
228    while (!STACK_EMPTY(parser, parser->tag_directives)) {
229        yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
230        yaml_free(tag_directive.handle);
231        yaml_free(tag_directive.prefix);
232    }
233    STACK_DEL(parser, parser->tag_directives);
234
235    memset(parser, 0, sizeof(yaml_parser_t));
236}
237
238/*
239 * String read handler.
240 */
241
242static int
243yaml_string_read_handler(void *data, unsigned char *buffer, size_t size,
244        size_t *size_read)
245{
246    yaml_parser_t *parser = data;
247
248    if (parser->input.string.current == parser->input.string.end) {
249        *size_read = 0;
250        return 1;
251    }
252
253    if (size > (size_t)(parser->input.string.end
254                - parser->input.string.current)) {
255        size = parser->input.string.end - parser->input.string.current;
256    }
257
258    memcpy(buffer, parser->input.string.current, size);
259    parser->input.string.current += size;
260    *size_read = size;
261    return 1;
262}
263
264/*
265 * File read handler.
266 */
267
268static int
269yaml_file_read_handler(void *data, unsigned char *buffer, size_t size,
270        size_t *size_read)
271{
272    yaml_parser_t *parser = data;
273
274    *size_read = fread(buffer, 1, size, parser->input.file);
275    return !ferror(parser->input.file);
276}
277
278/*
279 * Set a string input.
280 */
281
282YAML_DECLARE(void)
283yaml_parser_set_input_string(yaml_parser_t *parser,
284        const unsigned char *input, size_t size)
285{
286    assert(parser); /* Non-NULL parser object expected. */
287    assert(!parser->read_handler);  /* You can set the source only once. */
288    assert(input);  /* Non-NULL input string expected. */
289
290    parser->read_handler = yaml_string_read_handler;
291    parser->read_handler_data = parser;
292
293    parser->input.string.start = input;
294    parser->input.string.current = input;
295    parser->input.string.end = input+size;
296}
297
298/*
299 * Set a file input.
300 */
301
302YAML_DECLARE(void)
303yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file)
304{
305    assert(parser); /* Non-NULL parser object expected. */
306    assert(!parser->read_handler);  /* You can set the source only once. */
307    assert(file);   /* Non-NULL file object expected. */
308
309    parser->read_handler = yaml_file_read_handler;
310    parser->read_handler_data = parser;
311
312    parser->input.file = file;
313}
314
315/*
316 * Set a generic input.
317 */
318
319YAML_DECLARE(void)
320yaml_parser_set_input(yaml_parser_t *parser,
321        yaml_read_handler_t *handler, void *data)
322{
323    assert(parser); /* Non-NULL parser object expected. */
324    assert(!parser->read_handler);  /* You can set the source only once. */
325    assert(handler);    /* Non-NULL read handler expected. */
326
327    parser->read_handler = handler;
328    parser->read_handler_data = data;
329}
330
331/*
332 * Set the source encoding.
333 */
334
335YAML_DECLARE(void)
336yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
337{
338    assert(parser); /* Non-NULL parser object expected. */
339    assert(!parser->encoding); /* Encoding is already set or detected. */
340
341    parser->encoding = encoding;
342}
343
344/*
345 * Create a new emitter object.
346 */
347
348YAML_DECLARE(int)
349yaml_emitter_initialize(yaml_emitter_t *emitter)
350{
351    assert(emitter);    /* Non-NULL emitter object expected. */
352
353    memset(emitter, 0, sizeof(yaml_emitter_t));
354    if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE))
355        goto error;
356    if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE))
357        goto error;
358    if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE))
359        goto error;
360    if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE))
361        goto error;
362    if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE))
363        goto error;
364    if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE))
365        goto error;
366
367    return 1;
368
369error:
370
371    BUFFER_DEL(emitter, emitter->buffer);
372    BUFFER_DEL(emitter, emitter->raw_buffer);
373    STACK_DEL(emitter, emitter->states);
374    QUEUE_DEL(emitter, emitter->events);
375    STACK_DEL(emitter, emitter->indents);
376    STACK_DEL(emitter, emitter->tag_directives);
377
378    return 0;
379}
380
381/*
382 * Destroy an emitter object.
383 */
384
385YAML_DECLARE(void)
386yaml_emitter_delete(yaml_emitter_t *emitter)
387{
388    assert(emitter);    /* Non-NULL emitter object expected. */
389
390    BUFFER_DEL(emitter, emitter->buffer);
391    BUFFER_DEL(emitter, emitter->raw_buffer);
392    STACK_DEL(emitter, emitter->states);
393    while (!QUEUE_EMPTY(emitter, emitter->events)) {
394        yaml_event_delete(&DEQUEUE(emitter, emitter->events));
395    }
396    QUEUE_DEL(emitter, emitter->events);
397    STACK_DEL(emitter, emitter->indents);
398    while (!STACK_EMPTY(emitter, emitter->tag_directives)) {
399        yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives);
400        yaml_free(tag_directive.handle);
401        yaml_free(tag_directive.prefix);
402    }
403    STACK_DEL(emitter, emitter->tag_directives);
404    yaml_free(emitter->anchors);
405
406    memset(emitter, 0, sizeof(yaml_emitter_t));
407}
408
409/*
410 * String write handler.
411 */
412
413static int
414yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
415{
416    yaml_emitter_t *emitter = data;
417
418    if (emitter->output.string.size + *emitter->output.string.size_written
419            < size) {
420        memcpy(emitter->output.string.buffer
421                + *emitter->output.string.size_written,
422                buffer,
423                emitter->output.string.size
424                - *emitter->output.string.size_written);
425        *emitter->output.string.size_written = emitter->output.string.size;
426        return 0;
427    }
428
429    memcpy(emitter->output.string.buffer
430            + *emitter->output.string.size_written, buffer, size);
431    *emitter->output.string.size_written += size;
432    return 1;
433}
434
435/*
436 * File write handler.
437 */
438
439static int
440yaml_file_write_handler(void *data, unsigned char *buffer, size_t size)
441{
442    yaml_emitter_t *emitter = data;
443
444    return (fwrite(buffer, 1, size, emitter->output.file) == size);
445}
446/*
447 * Set a string output.
448 */
449
450YAML_DECLARE(void)
451yaml_emitter_set_output_string(yaml_emitter_t *emitter,
452        unsigned char *output, size_t size, size_t *size_written)
453{
454    assert(emitter);    /* Non-NULL emitter object expected. */
455    assert(!emitter->write_handler);    /* You can set the output only once. */
456    assert(output);     /* Non-NULL output string expected. */
457
458    emitter->write_handler = yaml_string_write_handler;
459    emitter->write_handler_data = emitter;
460
461    emitter->output.string.buffer = output;
462    emitter->output.string.size = size;
463    emitter->output.string.size_written = size_written;
464    *size_written = 0;
465}
466
467/*
468 * Set a file output.
469 */
470
471YAML_DECLARE(void)
472yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file)
473{
474    assert(emitter);    /* Non-NULL emitter object expected. */
475    assert(!emitter->write_handler);    /* You can set the output only once. */
476    assert(file);       /* Non-NULL file object expected. */
477
478    emitter->write_handler = yaml_file_write_handler;
479    emitter->write_handler_data = emitter;
480
481    emitter->output.file = file;
482}
483
484/*
485 * Set a generic output handler.
486 */
487
488YAML_DECLARE(void)
489yaml_emitter_set_output(yaml_emitter_t *emitter,
490        yaml_write_handler_t *handler, void *data)
491{
492    assert(emitter);    /* Non-NULL emitter object expected. */
493    assert(!emitter->write_handler);    /* You can set the output only once. */
494    assert(handler);    /* Non-NULL handler object expected. */
495
496    emitter->write_handler = handler;
497    emitter->write_handler_data = data;
498}
499
500/*
501 * Set the output encoding.
502 */
503
504YAML_DECLARE(void)
505yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding)
506{
507    assert(emitter);    /* Non-NULL emitter object expected. */
508    assert(!emitter->encoding);     /* You can set encoding only once. */
509
510    emitter->encoding = encoding;
511}
512
513/*
514 * Set the canonical output style.
515 */
516
517YAML_DECLARE(void)
518yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical)
519{
520    assert(emitter);    /* Non-NULL emitter object expected. */
521
522    emitter->canonical = (canonical != 0);
523}
524
525/*
526 * Set the indentation increment.
527 */
528
529YAML_DECLARE(void)
530yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent)
531{
532    assert(emitter);    /* Non-NULL emitter object expected. */
533
534    emitter->best_indent = (1 < indent && indent < 10) ? indent : 2;
535}
536
537/*
538 * Set the preferred line width.
539 */
540
541YAML_DECLARE(void)
542yaml_emitter_set_width(yaml_emitter_t *emitter, int width)
543{
544    assert(emitter);    /* Non-NULL emitter object expected. */
545
546    emitter->best_width = (width >= 0) ? width : -1;
547}
548
549/*
550 * Set if unescaped non-ASCII characters are allowed.
551 */
552
553YAML_DECLARE(void)
554yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode)
555{
556    assert(emitter);    /* Non-NULL emitter object expected. */
557
558    emitter->unicode = (unicode != 0);
559}
560
561/*
562 * Set the preferred line break character.
563 */
564
565YAML_DECLARE(void)
566yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break)
567{
568    assert(emitter);    /* Non-NULL emitter object expected. */
569
570    emitter->line_break = line_break;
571}
572
573/*
574 * Destroy a token object.
575 */
576
577YAML_DECLARE(void)
578yaml_token_delete(yaml_token_t *token)
579{
580    assert(token);  /* Non-NULL token object expected. */
581
582    switch (token->type)
583    {
584        case YAML_TAG_DIRECTIVE_TOKEN:
585            yaml_free(token->data.tag_directive.handle);
586            yaml_free(token->data.tag_directive.prefix);
587            break;
588
589        case YAML_ALIAS_TOKEN:
590            yaml_free(token->data.alias.value);
591            break;
592
593        case YAML_ANCHOR_TOKEN:
594            yaml_free(token->data.anchor.value);
595            break;
596
597        case YAML_TAG_TOKEN:
598            yaml_free(token->data.tag.handle);
599            yaml_free(token->data.tag.suffix);
600            break;
601
602        case YAML_SCALAR_TOKEN:
603            yaml_free(token->data.scalar.value);
604            break;
605
606        default:
607            break;
608    }
609
610    memset(token, 0, sizeof(yaml_token_t));
611}
612
613/*
614 * Check if a string is a valid UTF-8 sequence.
615 *
616 * Check 'reader.c' for more details on UTF-8 encoding.
617 */
618
619static int
620yaml_check_utf8(yaml_char_t *start, size_t length)
621{
622    yaml_char_t *end = start+length;
623    yaml_char_t *pointer = start;
624
625    while (pointer < end) {
626        unsigned char octet;
627        unsigned int width;
628        unsigned int value;
629        size_t k;
630
631        octet = pointer[0];
632        width = (octet & 0x80) == 0x00 ? 1 :
633                (octet & 0xE0) == 0xC0 ? 2 :
634                (octet & 0xF0) == 0xE0 ? 3 :
635                (octet & 0xF8) == 0xF0 ? 4 : 0;
636        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
637                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
638                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
639                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
640        if (!width) return 0;
641        if (pointer+width > end) return 0;
642        for (k = 1; k < width; k ++) {
643            octet = pointer[k];
644            if ((octet & 0xC0) != 0x80) return 0;
645            value = (value << 6) + (octet & 0x3F);
646        }
647        if (!((width == 1) ||
648            (width == 2 && value >= 0x80) ||
649            (width == 3 && value >= 0x800) ||
650            (width == 4 && value >= 0x10000))) return 0;
651
652        pointer += width;
653    }
654
655    return 1;
656}
657
658/*
659 * Create STREAM-START.
660 */
661
662YAML_DECLARE(int)
663yaml_stream_start_event_initialize(yaml_event_t *event,
664        yaml_encoding_t encoding)
665{
666    yaml_mark_t mark = { 0, 0, 0 };
667
668    assert(event);  /* Non-NULL event object is expected. */
669
670    STREAM_START_EVENT_INIT(*event, encoding, mark, mark);
671
672    return 1;
673}
674
675/*
676 * Create STREAM-END.
677 */
678
679YAML_DECLARE(int)
680yaml_stream_end_event_initialize(yaml_event_t *event)
681{
682    yaml_mark_t mark = { 0, 0, 0 };
683
684    assert(event);  /* Non-NULL event object is expected. */
685
686    STREAM_END_EVENT_INIT(*event, mark, mark);
687
688    return 1;
689}
690
691/*
692 * Create DOCUMENT-START.
693 */
694
695YAML_DECLARE(int)
696yaml_document_start_event_initialize(yaml_event_t *event,
697        yaml_version_directive_t *version_directive,
698        yaml_tag_directive_t *tag_directives_start,
699        yaml_tag_directive_t *tag_directives_end,
700        int implicit)
701{
702    struct {
703        yaml_error_type_t error;
704    } context;
705    yaml_mark_t mark = { 0, 0, 0 };
706    yaml_version_directive_t *version_directive_copy = NULL;
707    struct {
708        yaml_tag_directive_t *start;
709        yaml_tag_directive_t *end;
710        yaml_tag_directive_t *top;
711    } tag_directives_copy = { NULL, NULL, NULL };
712    yaml_tag_directive_t value = { NULL, NULL };
713
714    assert(event);          /* Non-NULL event object is expected. */
715    assert((tag_directives_start && tag_directives_end) ||
716            (tag_directives_start == tag_directives_end));
717                            /* Valid tag directives are expected. */
718
719    if (version_directive) {
720        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
721        if (!version_directive_copy) goto error;
722        version_directive_copy->major = version_directive->major;
723        version_directive_copy->minor = version_directive->minor;
724    }
725
726    if (tag_directives_start != tag_directives_end) {
727        yaml_tag_directive_t *tag_directive;
728        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
729            goto error;
730        for (tag_directive = tag_directives_start;
731                tag_directive != tag_directives_end; tag_directive ++) {
732            assert(tag_directive->handle);
733            assert(tag_directive->prefix);
734            if (!yaml_check_utf8(tag_directive->handle,
735                        strlen((char *)tag_directive->handle)))
736                goto error;
737            if (!yaml_check_utf8(tag_directive->prefix,
738                        strlen((char *)tag_directive->prefix)))
739                goto error;
740            value.handle = yaml_strdup(tag_directive->handle);
741            value.prefix = yaml_strdup(tag_directive->prefix);
742            if (!value.handle || !value.prefix) goto error;
743            if (!PUSH(&context, tag_directives_copy, value))
744                goto error;
745            value.handle = NULL;
746            value.prefix = NULL;
747        }
748    }
749
750    DOCUMENT_START_EVENT_INIT(*event, version_directive_copy,
751            tag_directives_copy.start, tag_directives_copy.top,
752            implicit, mark, mark);
753
754    return 1;
755
756error:
757    yaml_free(version_directive_copy);
758    while (!STACK_EMPTY(context, tag_directives_copy)) {
759        yaml_tag_directive_t value = POP(context, tag_directives_copy);
760        yaml_free(value.handle);
761        yaml_free(value.prefix);
762    }
763    STACK_DEL(context, tag_directives_copy);
764    yaml_free(value.handle);
765    yaml_free(value.prefix);
766
767    return 0;
768}
769
770/*
771 * Create DOCUMENT-END.
772 */
773
774YAML_DECLARE(int)
775yaml_document_end_event_initialize(yaml_event_t *event, int implicit)
776{
777    yaml_mark_t mark = { 0, 0, 0 };
778
779    assert(event);      /* Non-NULL emitter object is expected. */
780
781    DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark);
782
783    return 1;
784}
785
786/*
787 * Create ALIAS.
788 */
789
790YAML_DECLARE(int)
791yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
792{
793    yaml_mark_t mark = { 0, 0, 0 };
794    yaml_char_t *anchor_copy = NULL;
795
796    assert(event);      /* Non-NULL event object is expected. */
797    assert(anchor);     /* Non-NULL anchor is expected. */
798
799    if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0;
800
801    anchor_copy = yaml_strdup(anchor);
802    if (!anchor_copy)
803        return 0;
804
805    ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark);
806
807    return 1;
808}
809
810/*
811 * Create SCALAR.
812 */
813
814YAML_DECLARE(int)
815yaml_scalar_event_initialize(yaml_event_t *event,
816        yaml_char_t *anchor, yaml_char_t *tag,
817        yaml_char_t *value, int length,
818        int plain_implicit, int quoted_implicit,
819        yaml_scalar_style_t style)
820{
821    yaml_mark_t mark = { 0, 0, 0 };
822    yaml_char_t *anchor_copy = NULL;
823    yaml_char_t *tag_copy = NULL;
824    yaml_char_t *value_copy = NULL;
825    size_t value_length;
826
827    assert(event);      /* Non-NULL event object is expected. */
828    assert(value);      /* Non-NULL anchor is expected. */
829
830    if (anchor) {
831        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
832        anchor_copy = yaml_strdup(anchor);
833        if (!anchor_copy) goto error;
834    }
835
836    if (tag) {
837        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
838        tag_copy = yaml_strdup(tag);
839        if (!tag_copy) goto error;
840    }
841
842    if (length < 0) {
843        value_length = strlen((char *)value);
844    }
845    else {
846        value_length = (size_t)length;
847    }
848
849    if (!yaml_check_utf8(value, value_length)) goto error;
850    value_copy = yaml_malloc(value_length+1);
851    if (!value_copy) goto error;
852    memcpy(value_copy, value, value_length);
853    value_copy[value_length] = '\0';
854
855    SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, value_length,
856            plain_implicit, quoted_implicit, style, mark, mark);
857
858    return 1;
859
860error:
861    yaml_free(anchor_copy);
862    yaml_free(tag_copy);
863    yaml_free(value_copy);
864
865    return 0;
866}
867
868/*
869 * Create SEQUENCE-START.
870 */
871
872YAML_DECLARE(int)
873yaml_sequence_start_event_initialize(yaml_event_t *event,
874        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
875        yaml_sequence_style_t style)
876{
877    yaml_mark_t mark = { 0, 0, 0 };
878    yaml_char_t *anchor_copy = NULL;
879    yaml_char_t *tag_copy = NULL;
880
881    assert(event);      /* Non-NULL event object is expected. */
882
883    if (anchor) {
884        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
885        anchor_copy = yaml_strdup(anchor);
886        if (!anchor_copy) goto error;
887    }
888
889    if (tag) {
890        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
891        tag_copy = yaml_strdup(tag);
892        if (!tag_copy) goto error;
893    }
894
895    SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy,
896            implicit, style, mark, mark);
897
898    return 1;
899
900error:
901    yaml_free(anchor_copy);
902    yaml_free(tag_copy);
903
904    return 0;
905}
906
907/*
908 * Create SEQUENCE-END.
909 */
910
911YAML_DECLARE(int)
912yaml_sequence_end_event_initialize(yaml_event_t *event)
913{
914    yaml_mark_t mark = { 0, 0, 0 };
915
916    assert(event);      /* Non-NULL event object is expected. */
917
918    SEQUENCE_END_EVENT_INIT(*event, mark, mark);
919
920    return 1;
921}
922
923/*
924 * Create MAPPING-START.
925 */
926
927YAML_DECLARE(int)
928yaml_mapping_start_event_initialize(yaml_event_t *event,
929        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
930        yaml_mapping_style_t style)
931{
932    yaml_mark_t mark = { 0, 0, 0 };
933    yaml_char_t *anchor_copy = NULL;
934    yaml_char_t *tag_copy = NULL;
935
936    assert(event);      /* Non-NULL event object is expected. */
937
938    if (anchor) {
939        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
940        anchor_copy = yaml_strdup(anchor);
941        if (!anchor_copy) goto error;
942    }
943
944    if (tag) {
945        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
946        tag_copy = yaml_strdup(tag);
947        if (!tag_copy) goto error;
948    }
949
950    MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy,
951            implicit, style, mark, mark);
952
953    return 1;
954
955error:
956    yaml_free(anchor_copy);
957    yaml_free(tag_copy);
958
959    return 0;
960}
961
962/*
963 * Create MAPPING-END.
964 */
965
966YAML_DECLARE(int)
967yaml_mapping_end_event_initialize(yaml_event_t *event)
968{
969    yaml_mark_t mark = { 0, 0, 0 };
970
971    assert(event);      /* Non-NULL event object is expected. */
972
973    MAPPING_END_EVENT_INIT(*event, mark, mark);
974
975    return 1;
976}
977
978/*
979 * Destroy an event object.
980 */
981
982YAML_DECLARE(void)
983yaml_event_delete(yaml_event_t *event)
984{
985    yaml_tag_directive_t *tag_directive;
986
987    assert(event);  /* Non-NULL event object expected. */
988
989    switch (event->type)
990    {
991        case YAML_DOCUMENT_START_EVENT:
992            yaml_free(event->data.document_start.version_directive);
993            for (tag_directive = event->data.document_start.tag_directives.start;
994                    tag_directive != event->data.document_start.tag_directives.end;
995                    tag_directive++) {
996                yaml_free(tag_directive->handle);
997                yaml_free(tag_directive->prefix);
998            }
999            yaml_free(event->data.document_start.tag_directives.start);
1000            break;
1001
1002        case YAML_ALIAS_EVENT:
1003            yaml_free(event->data.alias.anchor);
1004            break;
1005
1006        case YAML_SCALAR_EVENT:
1007            yaml_free(event->data.scalar.anchor);
1008            yaml_free(event->data.scalar.tag);
1009            yaml_free(event->data.scalar.value);
1010            break;
1011
1012        case YAML_SEQUENCE_START_EVENT:
1013            yaml_free(event->data.sequence_start.anchor);
1014            yaml_free(event->data.sequence_start.tag);
1015            break;
1016
1017        case YAML_MAPPING_START_EVENT:
1018            yaml_free(event->data.mapping_start.anchor);
1019            yaml_free(event->data.mapping_start.tag);
1020            break;
1021
1022        default:
1023            break;
1024    }
1025
1026    memset(event, 0, sizeof(yaml_event_t));
1027}
1028
1029/*
1030 * Create a document object.
1031 */
1032
1033YAML_DECLARE(int)
1034yaml_document_initialize(yaml_document_t *document,
1035        yaml_version_directive_t *version_directive,
1036        yaml_tag_directive_t *tag_directives_start,
1037        yaml_tag_directive_t *tag_directives_end,
1038        int start_implicit, int end_implicit)
1039{
1040    struct {
1041        yaml_error_type_t error;
1042    } context;
1043    struct {
1044        yaml_node_t *start;
1045        yaml_node_t *end;
1046        yaml_node_t *top;
1047    } nodes = { NULL, NULL, NULL };
1048    yaml_version_directive_t *version_directive_copy = NULL;
1049    struct {
1050        yaml_tag_directive_t *start;
1051        yaml_tag_directive_t *end;
1052        yaml_tag_directive_t *top;
1053    } tag_directives_copy = { NULL, NULL, NULL };
1054    yaml_tag_directive_t value = { NULL, NULL };
1055    yaml_mark_t mark = { 0, 0, 0 };
1056
1057    assert(document);       /* Non-NULL document object is expected. */
1058    assert((tag_directives_start && tag_directives_end) ||
1059            (tag_directives_start == tag_directives_end));
1060                            /* Valid tag directives are expected. */
1061
1062    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
1063
1064    if (version_directive) {
1065        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
1066        if (!version_directive_copy) goto error;
1067        version_directive_copy->major = version_directive->major;
1068        version_directive_copy->minor = version_directive->minor;
1069    }
1070
1071    if (tag_directives_start != tag_directives_end) {
1072        yaml_tag_directive_t *tag_directive;
1073        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
1074            goto error;
1075        for (tag_directive = tag_directives_start;
1076                tag_directive != tag_directives_end; tag_directive ++) {
1077            assert(tag_directive->handle);
1078            assert(tag_directive->prefix);
1079            if (!yaml_check_utf8(tag_directive->handle,
1080                        strlen((char *)tag_directive->handle)))
1081                goto error;
1082            if (!yaml_check_utf8(tag_directive->prefix,
1083                        strlen((char *)tag_directive->prefix)))
1084                goto error;
1085            value.handle = yaml_strdup(tag_directive->handle);
1086            value.prefix = yaml_strdup(tag_directive->prefix);
1087            if (!value.handle || !value.prefix) goto error;
1088            if (!PUSH(&context, tag_directives_copy, value))
1089                goto error;
1090            value.handle = NULL;
1091            value.prefix = NULL;
1092        }
1093    }
1094
1095    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
1096            tag_directives_copy.start, tag_directives_copy.top,
1097            start_implicit, end_implicit, mark, mark);
1098
1099    return 1;
1100
1101error:
1102    STACK_DEL(&context, nodes);
1103    yaml_free(version_directive_copy);
1104    while (!STACK_EMPTY(&context, tag_directives_copy)) {
1105        yaml_tag_directive_t value = POP(&context, tag_directives_copy);
1106        yaml_free(value.handle);
1107        yaml_free(value.prefix);
1108    }
1109    STACK_DEL(&context, tag_directives_copy);
1110    yaml_free(value.handle);
1111    yaml_free(value.prefix);
1112
1113    return 0;
1114}
1115
1116/*
1117 * Destroy a document object.
1118 */
1119
1120YAML_DECLARE(void)
1121yaml_document_delete(yaml_document_t *document)
1122{
1123    struct {
1124        yaml_error_type_t error;
1125    } context;
1126    yaml_tag_directive_t *tag_directive;
1127
1128    context.error = YAML_NO_ERROR;  /* Eliminate a compliler warning. */
1129
1130    assert(document);   /* Non-NULL document object is expected. */
1131
1132    while (!STACK_EMPTY(&context, document->nodes)) {
1133        yaml_node_t node = POP(&context, document->nodes);
1134        yaml_free(node.tag);
1135        switch (node.type) {
1136            case YAML_SCALAR_NODE:
1137                yaml_free(node.data.scalar.value);
1138                break;
1139            case YAML_SEQUENCE_NODE:
1140                STACK_DEL(&context, node.data.sequence.items);
1141                break;
1142            case YAML_MAPPING_NODE:
1143                STACK_DEL(&context, node.data.mapping.pairs);
1144                break;
1145            default:
1146                assert(0);  /* Should not happen. */
1147        }
1148    }
1149    STACK_DEL(&context, document->nodes);
1150
1151    yaml_free(document->version_directive);
1152    for (tag_directive = document->tag_directives.start;
1153            tag_directive != document->tag_directives.end;
1154            tag_directive++) {
1155        yaml_free(tag_directive->handle);
1156        yaml_free(tag_directive->prefix);
1157    }
1158    yaml_free(document->tag_directives.start);
1159
1160    memset(document, 0, sizeof(yaml_document_t));
1161}
1162
1163/**
1164 * Get a document node.
1165 */
1166
1167YAML_DECLARE(yaml_node_t *)
1168yaml_document_get_node(yaml_document_t *document, int index)
1169{
1170    assert(document);   /* Non-NULL document object is expected. */
1171
1172    if (index > 0 && document->nodes.start + index <= document->nodes.top) {
1173        return document->nodes.start + index - 1;
1174    }
1175    return NULL;
1176}
1177
1178/**
1179 * Get the root object.
1180 */
1181
1182YAML_DECLARE(yaml_node_t *)
1183yaml_document_get_root_node(yaml_document_t *document)
1184{
1185    assert(document);   /* Non-NULL document object is expected. */
1186
1187    if (document->nodes.top != document->nodes.start) {
1188        return document->nodes.start;
1189    }
1190    return NULL;
1191}
1192
1193/*
1194 * Add a scalar node to a document.
1195 */
1196
1197YAML_DECLARE(int)
1198yaml_document_add_scalar(yaml_document_t *document,
1199        yaml_char_t *tag, yaml_char_t *value, int length,
1200        yaml_scalar_style_t style)
1201{
1202    struct {
1203        yaml_error_type_t error;
1204    } context;
1205    yaml_mark_t mark = { 0, 0, 0 };
1206    yaml_char_t *tag_copy = NULL;
1207    yaml_char_t *value_copy = NULL;
1208    yaml_node_t node;
1209    size_t value_length;
1210    ptrdiff_t ret;
1211
1212    assert(document);   /* Non-NULL document object is expected. */
1213    assert(value);      /* Non-NULL value is expected. */
1214
1215    if (!tag) {
1216        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG;
1217    }
1218
1219    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1220    tag_copy = yaml_strdup(tag);
1221    if (!tag_copy) goto error;
1222
1223    if (length < 0) {
1224        value_length = strlen((char *)value);
1225    }
1226    else {
1227        value_length = (size_t)length;
1228    }
1229
1230    if (!yaml_check_utf8(value, value_length)) goto error;
1231    value_copy = yaml_malloc(value_length+1);
1232    if (!value_copy) goto error;
1233    memcpy(value_copy, value, value_length);
1234    value_copy[value_length] = '\0';
1235
1236    SCALAR_NODE_INIT(node, tag_copy, value_copy, value_length, style, mark, mark);
1237    if (!PUSH(&context, document->nodes, node)) goto error;
1238
1239    ret = document->nodes.top - document->nodes.start;
1240#if PTRDIFF_MAX > INT_MAX
1241    if (ret > INT_MAX) goto error;
1242#endif
1243    return (int)ret;
1244
1245error:
1246    yaml_free(tag_copy);
1247    yaml_free(value_copy);
1248
1249    return 0;
1250}
1251
1252/*
1253 * Add a sequence node to a document.
1254 */
1255
1256YAML_DECLARE(int)
1257yaml_document_add_sequence(yaml_document_t *document,
1258        yaml_char_t *tag, yaml_sequence_style_t style)
1259{
1260    struct {
1261        yaml_error_type_t error;
1262    } context;
1263    yaml_mark_t mark = { 0, 0, 0 };
1264    yaml_char_t *tag_copy = NULL;
1265    struct {
1266        yaml_node_item_t *start;
1267        yaml_node_item_t *end;
1268        yaml_node_item_t *top;
1269    } items = { NULL, NULL, NULL };
1270    yaml_node_t node;
1271    ptrdiff_t ret;
1272
1273    assert(document);   /* Non-NULL document object is expected. */
1274
1275    if (!tag) {
1276        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG;
1277    }
1278
1279    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1280    tag_copy = yaml_strdup(tag);
1281    if (!tag_copy) goto error;
1282
1283    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
1284
1285    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
1286            style, mark, mark);
1287    if (!PUSH(&context, document->nodes, node)) goto error;
1288
1289    ret = document->nodes.top - document->nodes.start;
1290#if PTRDIFF_MAX > INT_MAX
1291    if (ret > INT_MAX) goto error;
1292#endif
1293    return (int)ret;
1294
1295error:
1296    STACK_DEL(&context, items);
1297    yaml_free(tag_copy);
1298
1299    return 0;
1300}
1301
1302/*
1303 * Add a mapping node to a document.
1304 */
1305
1306YAML_DECLARE(int)
1307yaml_document_add_mapping(yaml_document_t *document,
1308        yaml_char_t *tag, yaml_mapping_style_t style)
1309{
1310    struct {
1311        yaml_error_type_t error;
1312    } context;
1313    yaml_mark_t mark = { 0, 0, 0 };
1314    yaml_char_t *tag_copy = NULL;
1315    struct {
1316        yaml_node_pair_t *start;
1317        yaml_node_pair_t *end;
1318        yaml_node_pair_t *top;
1319    } pairs = { NULL, NULL, NULL };
1320    yaml_node_t node;
1321    ptrdiff_t ret;
1322
1323    assert(document);   /* Non-NULL document object is expected. */
1324
1325    if (!tag) {
1326        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG;
1327    }
1328
1329    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1330    tag_copy = yaml_strdup(tag);
1331    if (!tag_copy) goto error;
1332
1333    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
1334
1335    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
1336            style, mark, mark);
1337    if (!PUSH(&context, document->nodes, node)) goto error;
1338
1339    ret = document->nodes.top - document->nodes.start;
1340#if PTRDIFF_MAX > INT_MAX
1341    if (ret > INT_MAX) goto error;
1342#endif
1343    return (int)ret;
1344
1345error:
1346    STACK_DEL(&context, pairs);
1347    yaml_free(tag_copy);
1348
1349    return 0;
1350}
1351
1352/*
1353 * Append an item to a sequence node.
1354 */
1355
1356YAML_DECLARE(int)
1357yaml_document_append_sequence_item(yaml_document_t *document,
1358        int sequence, int item)
1359{
1360    struct {
1361        yaml_error_type_t error;
1362    } context;
1363
1364    assert(document);       /* Non-NULL document is required. */
1365    assert(sequence > 0
1366            && document->nodes.start + sequence <= document->nodes.top);
1367                            /* Valid sequence id is required. */
1368    assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
1369                            /* A sequence node is required. */
1370    assert(item > 0 && document->nodes.start + item <= document->nodes.top);
1371                            /* Valid item id is required. */
1372
1373    if (!PUSH(&context,
1374                document->nodes.start[sequence-1].data.sequence.items, item))
1375        return 0;
1376
1377    return 1;
1378}
1379
1380/*
1381 * Append a pair of a key and a value to a mapping node.
1382 */
1383
1384YAML_DECLARE(int)
1385yaml_document_append_mapping_pair(yaml_document_t *document,
1386        int mapping, int key, int value)
1387{
1388    struct {
1389        yaml_error_type_t error;
1390    } context;
1391
1392    yaml_node_pair_t pair;
1393
1394    assert(document);       /* Non-NULL document is required. */
1395    assert(mapping > 0
1396            && document->nodes.start + mapping <= document->nodes.top);
1397                            /* Valid mapping id is required. */
1398    assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE);
1399                            /* A mapping node is required. */
1400    assert(key > 0 && document->nodes.start + key <= document->nodes.top);
1401                            /* Valid key id is required. */
1402    assert(value > 0 && document->nodes.start + value <= document->nodes.top);
1403                            /* Valid value id is required. */
1404
1405    pair.key = key;
1406    pair.value = value;
1407
1408    if (!PUSH(&context,
1409                document->nodes.start[mapping-1].data.mapping.pairs, pair))
1410        return 0;
1411
1412    return 1;
1413}
1414
1415
1416