1 /*
2 * This file is part of libmodulemd
3 * Copyright (C) 2017-2020 Stephen Gallagher
4 *
5 * Fedora-License-Identifier: MIT
6 * SPDX-2.0-License-Identifier: MIT
7 * SPDX-3.0-License-Identifier: MIT
8 *
9 * This program is free software.
10 * For more information on the license, see COPYING.
11 * For more information on free software, see <https://www.gnu.org/philosophy/free-sw.en.html>.
12 */
13
14 #include "modulemd-errors.h"
15 #include "private/modulemd-subdocument-info-private.h"
16 #include "private/modulemd-util.h"
17 #include "private/modulemd-yaml.h"
18 #include <errno.h>
19 #include <glib.h>
20 #include <inttypes.h>
21 #include <yaml.h>
22
23
24 GQuark
modulemd_yaml_error_quark(void)25 modulemd_yaml_error_quark (void)
26 {
27 return g_quark_from_static_string ("modulemd-yaml-error-quark");
28 }
29
30
31 void
modulemd_yaml_string_free(modulemd_yaml_string * yaml_string)32 modulemd_yaml_string_free (modulemd_yaml_string *yaml_string)
33 {
34 g_clear_pointer (&yaml_string->str, g_free);
35 g_clear_pointer (&yaml_string, g_free);
36 }
37
38
39 int
write_yaml_string(void * data,unsigned char * buffer,size_t size)40 write_yaml_string (void *data, unsigned char *buffer, size_t size)
41 {
42 modulemd_yaml_string *yaml_string = (modulemd_yaml_string *)data;
43 gsize total;
44
45 if (!g_size_checked_add (&total, yaml_string->len, size + 1))
46 {
47 return 0;
48 }
49
50 yaml_string->str = g_realloc_n (yaml_string->str, total, sizeof (char));
51
52 memcpy (yaml_string->str + yaml_string->len, buffer, size);
53 yaml_string->len += size;
54 yaml_string->str[yaml_string->len] = '\0';
55
56 return 1;
57 }
58
59
60 const gchar *
mmd_yaml_get_event_name(yaml_event_type_t type)61 mmd_yaml_get_event_name (yaml_event_type_t type)
62 {
63 switch (type)
64 {
65 case YAML_NO_EVENT: return "YAML_NO_EVENT";
66
67 case YAML_STREAM_START_EVENT: return "YAML_STREAM_START_EVENT";
68
69 case YAML_STREAM_END_EVENT: return "YAML_STREAM_END_EVENT";
70
71 case YAML_DOCUMENT_START_EVENT: return "YAML_DOCUMENT_START_EVENT";
72
73 case YAML_DOCUMENT_END_EVENT: return "YAML_DOCUMENT_END_EVENT";
74
75 case YAML_ALIAS_EVENT: return "YAML_ALIAS_EVENT";
76
77 case YAML_SCALAR_EVENT: return "YAML_SCALAR_EVENT";
78
79 case YAML_SEQUENCE_START_EVENT: return "YAML_SEQUENCE_START_EVENT";
80
81 case YAML_SEQUENCE_END_EVENT: return "YAML_SEQUENCE_END_EVENT";
82
83 case YAML_MAPPING_START_EVENT: return "YAML_MAPPING_START_EVENT";
84
85 case YAML_MAPPING_END_EVENT: return "YAML_MAPPING_END_EVENT";
86 }
87
88 /* Should be unreachable */
89 return "Unknown YAML Event";
90 }
91
92
93 gboolean
mmd_emitter_start_stream(yaml_emitter_t * emitter,GError ** error)94 mmd_emitter_start_stream (yaml_emitter_t *emitter, GError **error)
95 {
96 int ret;
97 MMD_INIT_YAML_EVENT (event);
98
99 yaml_emitter_set_unicode (emitter, TRUE);
100
101 ret = yaml_stream_start_event_initialize (&event, YAML_UTF8_ENCODING);
102 if (!ret)
103 {
104 g_set_error (error,
105 MODULEMD_YAML_ERROR,
106 MMD_YAML_ERROR_EVENT_INIT,
107 "Could not initialize the stream start event");
108 return FALSE;
109 }
110
111 MMD_EMIT_WITH_EXIT (
112 emitter, &event, error, "Could not start the YAML stream");
113
114 return TRUE;
115 }
116
117
118 gboolean
mmd_emitter_end_stream(yaml_emitter_t * emitter,GError ** error)119 mmd_emitter_end_stream (yaml_emitter_t *emitter, GError **error)
120 {
121 int ret;
122 MMD_INIT_YAML_EVENT (event);
123
124 ret = yaml_stream_end_event_initialize (&event);
125 if (!ret)
126 {
127 g_set_error (error,
128 MODULEMD_YAML_ERROR,
129 MMD_YAML_ERROR_EVENT_INIT,
130 "Could not initialize the stream end event");
131 return FALSE;
132 }
133
134 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not end the YAML stream");
135
136 return TRUE;
137 }
138
139
140 gboolean
mmd_emitter_start_document(yaml_emitter_t * emitter,GError ** error)141 mmd_emitter_start_document (yaml_emitter_t *emitter, GError **error)
142 {
143 int ret;
144 MMD_INIT_YAML_EVENT (event);
145
146 ret = yaml_document_start_event_initialize (&event, NULL, NULL, NULL, 0);
147 if (!ret)
148 {
149 g_set_error (error,
150 MODULEMD_YAML_ERROR,
151 MMD_YAML_ERROR_EVENT_INIT,
152 "Could not initialize the document start event");
153 return FALSE;
154 }
155
156 MMD_EMIT_WITH_EXIT (
157 emitter, &event, error, "Could not start the YAML document");
158
159 return TRUE;
160 }
161
162
163 gboolean
mmd_emitter_end_document(yaml_emitter_t * emitter,GError ** error)164 mmd_emitter_end_document (yaml_emitter_t *emitter, GError **error)
165 {
166 int ret;
167 MMD_INIT_YAML_EVENT (event);
168
169 ret = yaml_document_end_event_initialize (&event, 0);
170 if (!ret)
171 {
172 g_set_error (error,
173 MODULEMD_YAML_ERROR,
174 MMD_YAML_ERROR_EVENT_INIT,
175 "Could not initialize the document end event");
176 return FALSE;
177 }
178
179 MMD_EMIT_WITH_EXIT (
180 emitter, &event, error, "Could not end the YAML document");
181
182 return TRUE;
183 }
184
185
186 gboolean
mmd_emitter_start_mapping(yaml_emitter_t * emitter,yaml_mapping_style_t style,GError ** error)187 mmd_emitter_start_mapping (yaml_emitter_t *emitter,
188 yaml_mapping_style_t style,
189 GError **error)
190 {
191 int ret;
192 MMD_INIT_YAML_EVENT (event);
193
194 ret = yaml_mapping_start_event_initialize (&event, NULL, NULL, 1, style);
195 if (!ret)
196 {
197 g_set_error (error,
198 MODULEMD_YAML_ERROR,
199 MMD_YAML_ERROR_EVENT_INIT,
200 "Could not initialize the mapping start event");
201 return FALSE;
202 }
203
204 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not start the mapping");
205
206 return TRUE;
207 }
208
209
210 gboolean
mmd_emitter_end_mapping(yaml_emitter_t * emitter,GError ** error)211 mmd_emitter_end_mapping (yaml_emitter_t *emitter, GError **error)
212 {
213 int ret;
214 MMD_INIT_YAML_EVENT (event);
215
216 ret = yaml_mapping_end_event_initialize (&event);
217 if (!ret)
218 {
219 g_set_error (error,
220 MODULEMD_YAML_ERROR,
221 MMD_YAML_ERROR_EVENT_INIT,
222 "Could not initialize the mapping end event");
223 return FALSE;
224 }
225
226 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not end the mapping");
227
228 return TRUE;
229 }
230
231
232 gboolean
mmd_emitter_start_sequence(yaml_emitter_t * emitter,yaml_sequence_style_t style,GError ** error)233 mmd_emitter_start_sequence (yaml_emitter_t *emitter,
234 yaml_sequence_style_t style,
235 GError **error)
236 {
237 int ret;
238 MMD_INIT_YAML_EVENT (event);
239
240 ret = yaml_sequence_start_event_initialize (&event, NULL, NULL, 1, style);
241 if (!ret)
242 {
243 g_set_error (error,
244 MODULEMD_YAML_ERROR,
245 MMD_YAML_ERROR_EVENT_INIT,
246 "Could not initialize the sequence start event");
247 return FALSE;
248 }
249
250 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not start the sequence");
251
252 return TRUE;
253 }
254
255
256 gboolean
mmd_emitter_end_sequence(yaml_emitter_t * emitter,GError ** error)257 mmd_emitter_end_sequence (yaml_emitter_t *emitter, GError **error)
258 {
259 int ret;
260 MMD_INIT_YAML_EVENT (event);
261
262 ret = yaml_sequence_end_event_initialize (&event);
263 if (!ret)
264 {
265 g_set_error (error,
266 MODULEMD_YAML_ERROR,
267 MMD_YAML_ERROR_EVENT_INIT,
268 "Could not initialize the sequence end event");
269 return FALSE;
270 }
271
272 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not end the sequence");
273
274 return TRUE;
275 }
276
277
278 gboolean
mmd_emitter_scalar(yaml_emitter_t * emitter,const gchar * scalar,yaml_scalar_style_t style,GError ** error)279 mmd_emitter_scalar (yaml_emitter_t *emitter,
280 const gchar *scalar,
281 yaml_scalar_style_t style,
282 GError **error)
283 {
284 int ret;
285 MMD_INIT_YAML_EVENT (event);
286
287 g_debug ("SCALAR: %s", scalar);
288 ret = yaml_scalar_event_initialize (&event,
289 NULL,
290 NULL,
291 (yaml_char_t *)scalar,
292 (int)strlen (scalar),
293 1,
294 1,
295 style);
296 if (!ret)
297 {
298 g_set_error (error,
299 MODULEMD_YAML_ERROR,
300 MMD_YAML_ERROR_EVENT_INIT,
301 "Could not initialize the scalar event");
302 return FALSE;
303 }
304
305 MMD_EMIT_WITH_EXIT (emitter, &event, error, "Could not emit scalar value");
306
307 return TRUE;
308 }
309
310
311 gboolean
mmd_emitter_strv(yaml_emitter_t * emitter,yaml_sequence_style_t seq_style,const GStrv list,GError ** error)312 mmd_emitter_strv (yaml_emitter_t *emitter,
313 yaml_sequence_style_t seq_style,
314 const GStrv list,
315 GError **error)
316 {
317 int ret;
318 g_autoptr (GError) nested_error = NULL;
319 MMD_INIT_YAML_EVENT (event);
320 int numentries = g_strv_length (list);
321
322 ret = mmd_emitter_start_sequence (emitter, seq_style, &nested_error);
323 if (!ret)
324 {
325 g_propagate_prefixed_error (
326 error, nested_error, "Failed to emit list start: ");
327 return FALSE;
328 }
329
330 for (int i = 0; i < numentries; i++)
331 {
332 ret = mmd_emitter_scalar (
333 emitter, list[i], YAML_PLAIN_SCALAR_STYLE, &nested_error);
334 if (!ret)
335 {
336 g_propagate_prefixed_error (
337 error, nested_error, "Failed to emit list entry: ");
338 return FALSE;
339 }
340 }
341
342 ret = mmd_emitter_end_sequence (emitter, &nested_error);
343 if (!ret)
344 {
345 g_propagate_prefixed_error (
346 error, nested_error, "Failed to emit list end: ");
347 return FALSE;
348 }
349 return TRUE;
350 }
351
352
353 GDate *
modulemd_yaml_parse_date(yaml_parser_t * parser,GError ** error)354 modulemd_yaml_parse_date (yaml_parser_t *parser, GError **error)
355 {
356 MMD_INIT_YAML_EVENT (event);
357 g_auto (GStrv) strv = NULL;
358
359 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
360 if (event.type != YAML_SCALAR_EVENT)
361 {
362 MMD_YAML_ERROR_EVENT_EXIT (error, event, "Date was not a scalar");
363 }
364
365 g_debug ("Parsing scalar: %s", (const gchar *)event.data.scalar.value);
366
367 strv = g_strsplit ((const gchar *)event.data.scalar.value, "-", 4);
368
369 if (!strv[0] || !strv[1] || !strv[2])
370 {
371 MMD_YAML_ERROR_EVENT_EXIT (
372 error, event, "Date not in the form YYYY-MM-DD");
373 }
374
375 return g_date_new_dmy (g_ascii_strtoull (strv[2], NULL, 10), /* Day */
376 g_ascii_strtoull (strv[1], NULL, 10), /* Month */
377 g_ascii_strtoull (strv[0], NULL, 10)); /* Year */
378 }
379
380 gchar *
modulemd_yaml_parse_string(yaml_parser_t * parser,GError ** error)381 modulemd_yaml_parse_string (yaml_parser_t *parser, GError **error)
382 {
383 MMD_INIT_YAML_EVENT (event);
384
385 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
386 if (event.type != YAML_SCALAR_EVENT)
387 {
388 MMD_YAML_ERROR_EVENT_EXIT (error, event, "String was not a scalar");
389 }
390
391 g_debug ("Parsing scalar: %s", (const gchar *)event.data.scalar.value);
392
393 return g_strdup ((const gchar *)event.data.scalar.value);
394 }
395
396
397 gboolean
modulemd_yaml_parse_bool(yaml_parser_t * parser,GError ** error)398 modulemd_yaml_parse_bool (yaml_parser_t *parser, GError **error)
399 {
400 MMD_INIT_YAML_EVENT (event);
401
402 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
403 if (event.type != YAML_SCALAR_EVENT)
404 {
405 MMD_YAML_ERROR_EVENT_EXIT_INT (
406 error, event, "Expected a scalar boolean");
407 }
408
409 if (g_str_equal ((const gchar *)event.data.scalar.value, "false"))
410 {
411 return FALSE;
412 }
413 if (g_str_equal ((const gchar *)event.data.scalar.value, "true"))
414 {
415 return TRUE;
416 }
417
418 MMD_YAML_ERROR_EVENT_EXIT_INT (
419 error,
420 event,
421 "Boolean value was neither \"true\" nor \"false\": %s",
422 (const gchar *)event.data.scalar.value);
423 }
424
425
426 gint64
modulemd_yaml_parse_int64(yaml_parser_t * parser,GError ** error)427 modulemd_yaml_parse_int64 (yaml_parser_t *parser, GError **error)
428 {
429 gint64 value;
430 gchar *endptr;
431 MMD_INIT_YAML_EVENT (event);
432
433 YAML_PARSER_PARSE_WITH_EXIT_INT (parser, &event, error);
434 if (event.type != YAML_SCALAR_EVENT)
435 {
436 MMD_YAML_ERROR_EVENT_EXIT_INT (error, event, "String was not a scalar");
437 }
438
439 value =
440 g_ascii_strtoll ((const gchar *)event.data.scalar.value, &endptr, 10);
441
442 if ((value == G_MAXINT64 && errno == ERANGE))
443 {
444 g_set_error (error,
445 MODULEMD_YAML_ERROR,
446 MODULEMD_ERROR_VALIDATE,
447 "%s: The integer value is larger than %" G_GINT64_FORMAT,
448 (const gchar *)event.data.scalar.value,
449 G_MAXINT64);
450 return 0;
451 }
452
453 if ((value == G_MININT64 && errno == ERANGE))
454 {
455 g_set_error (error,
456 MODULEMD_YAML_ERROR,
457 MODULEMD_ERROR_VALIDATE,
458 "%s: The integer value is samller than %" G_GINT64_FORMAT,
459 (const gchar *)event.data.scalar.value,
460 G_MININT64);
461 return 0;
462 }
463
464 if (value == 0 && errno == EINVAL)
465 {
466 g_set_error_literal (
467 error,
468 MODULEMD_YAML_ERROR,
469 MODULEMD_ERROR_NOT_IMPLEMENTED,
470 "Your GLib library does not support parsing integers in 10 base");
471 return 0;
472 }
473
474 if ((value == 0 && endptr == (gchar *)event.data.scalar.value) ||
475 *endptr != '\0')
476 {
477 g_set_error (error,
478 MODULEMD_YAML_ERROR,
479 MMD_ERROR_VALIDATE,
480 "%s: The string is not a valid integer",
481 (const gchar *)event.data.scalar.value);
482 return 0;
483 }
484
485 return value;
486 }
487
488
489 guint64
modulemd_yaml_parse_uint64(yaml_parser_t * parser,GError ** error)490 modulemd_yaml_parse_uint64 (yaml_parser_t *parser, GError **error)
491 {
492 guint64 value;
493 gchar *endptr;
494 MMD_INIT_YAML_EVENT (event);
495
496 YAML_PARSER_PARSE_WITH_EXIT_INT (parser, &event, error);
497 if (event.type != YAML_SCALAR_EVENT)
498 {
499 MMD_YAML_ERROR_EVENT_EXIT_INT (error, event, "String was not a scalar");
500 }
501
502 g_debug ("Parsing scalar: %s", (const gchar *)event.data.scalar.value);
503
504 /* g_ascii_strtoull() accepts negative values by definition. */
505 if (event.data.scalar.value[0] == '-')
506 {
507 g_set_error (error,
508 MODULEMD_YAML_ERROR,
509 MODULEMD_ERROR_VALIDATE,
510 "%s: The integer value is negative",
511 (const gchar *)event.data.scalar.value);
512 return 0u;
513 }
514
515 value =
516 g_ascii_strtoull ((const gchar *)event.data.scalar.value, &endptr, 10);
517
518 if (value == G_MAXUINT64 && errno == ERANGE)
519 {
520 g_set_error (error,
521 MODULEMD_YAML_ERROR,
522 MODULEMD_ERROR_VALIDATE,
523 "%s: The integer value is larger than %" G_GUINT64_FORMAT,
524 (const gchar *)event.data.scalar.value,
525 G_MAXUINT64);
526 return 0u;
527 }
528
529 if (value == 0u && errno == EINVAL)
530 {
531 g_set_error_literal (
532 error,
533 MODULEMD_YAML_ERROR,
534 MODULEMD_ERROR_NOT_IMPLEMENTED,
535 "Your GLib library does not support parsing integers in 10 base");
536 return 0u;
537 }
538
539 if ((value == 0u && endptr == (gchar *)event.data.scalar.value) ||
540 *endptr != '\0')
541 {
542 g_set_error (error,
543 MODULEMD_YAML_ERROR,
544 MMD_ERROR_VALIDATE,
545 "%s: The string is not a valid integer",
546 (const gchar *)event.data.scalar.value);
547 return 0u;
548 }
549
550 return value;
551 }
552
553
554 GHashTable *
modulemd_yaml_parse_string_set(yaml_parser_t * parser,GError ** error)555 modulemd_yaml_parse_string_set (yaml_parser_t *parser, GError **error)
556 {
557 MMD_INIT_YAML_EVENT (event);
558 gboolean done = FALSE;
559 gboolean in_list = FALSE;
560 g_autoptr (GHashTable) result =
561 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
562
563 while (!done)
564 {
565 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
566
567 switch (event.type)
568 {
569 case YAML_SEQUENCE_START_EVENT: in_list = TRUE; break;
570
571 case YAML_SEQUENCE_END_EVENT:
572 if (!in_list)
573 {
574 MMD_YAML_ERROR_EVENT_EXIT (
575 error, event, "Unexpected end of list");
576 }
577 in_list = FALSE;
578 done = TRUE;
579 break;
580
581 case YAML_SCALAR_EVENT:
582 g_debug ("Parsing scalar: %s",
583 (const gchar *)event.data.scalar.value);
584 g_hash_table_add (result,
585 g_strdup ((const gchar *)event.data.scalar.value));
586
587 if (!in_list)
588 {
589 /* We got a scalar instead of a sequence. Treat it as a list with
590 * a single entry
591 */
592 done = TRUE;
593 }
594 break;
595
596 default:
597 MMD_YAML_ERROR_EVENT_EXIT (
598 error, event, "Unexpected YAML event in list");
599 break;
600 }
601 yaml_event_delete (&event);
602 }
603
604 /* Work around false-positive in clang static analysis which thinks it's
605 * possible for this function to return NULL and not set error.
606 */
607 if (G_UNLIKELY (result == NULL))
608 {
609 g_set_error (error,
610 MODULEMD_YAML_ERROR,
611 MMD_YAML_ERROR_EMIT,
612 "Somehow got a NULL hash table here.");
613 }
614
615 return g_steal_pointer (&result);
616 }
617
618
619 GHashTable *
modulemd_yaml_parse_string_set_from_map(yaml_parser_t * parser,const gchar * key,gboolean strict,GError ** error)620 modulemd_yaml_parse_string_set_from_map (yaml_parser_t *parser,
621 const gchar *key,
622 gboolean strict,
623 GError **error)
624 {
625 MMD_INIT_YAML_EVENT (event);
626 gboolean done = FALSE;
627 gboolean in_map = FALSE;
628 g_autoptr (GHashTable) set = NULL;
629 g_autoptr (GError) nested_error = NULL;
630
631 while (!done)
632 {
633 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
634
635 switch (event.type)
636 {
637 case YAML_MAPPING_START_EVENT: in_map = TRUE; break;
638
639 case YAML_MAPPING_END_EVENT:
640 if (!in_map)
641 {
642 MMD_YAML_ERROR_EVENT_EXIT (
643 error, event, "Unexpected end of map");
644 }
645 in_map = FALSE;
646 done = TRUE;
647 break;
648
649 case YAML_SCALAR_EVENT:
650 if (!in_map)
651 {
652 MMD_YAML_ERROR_EVENT_EXIT (
653 error, event, "Unexpected scalar outside of map.");
654 }
655
656 if (g_str_equal ((const gchar *)event.data.scalar.value, key))
657 {
658 set = modulemd_yaml_parse_string_set (parser, &nested_error);
659 if (!set)
660 {
661 g_propagate_error (error, g_steal_pointer (&nested_error));
662 return NULL;
663 }
664 }
665 else
666 {
667 /* Encountered a key other than the expected one. */
668 SKIP_UNKNOWN (parser,
669 NULL,
670 "Unexpected key in map: %s",
671 (const gchar *)event.data.scalar.value);
672 }
673 break;
674
675 default:
676 MMD_YAML_ERROR_EVENT_EXIT (
677 error, event, "Unexpected YAML event in map");
678 break;
679 }
680 yaml_event_delete (&event);
681 }
682 return g_steal_pointer (&set);
683 }
684
685
686 GHashTable *
modulemd_yaml_parse_string_string_map(yaml_parser_t * parser,GError ** error)687 modulemd_yaml_parse_string_string_map (yaml_parser_t *parser, GError **error)
688 {
689 MMD_INIT_YAML_EVENT (event);
690 gboolean done = FALSE;
691 g_autoptr (GHashTable) table = NULL;
692 g_autoptr (GError) nested_error = NULL;
693 const gchar *key = NULL;
694 g_autofree gchar *value = NULL;
695
696 table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
697
698 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
699 if (event.type != YAML_MAPPING_START_EVENT)
700 {
701 MMD_YAML_ERROR_EVENT_EXIT (error,
702 event,
703 "Got %s instead of MAPPING_START.",
704 mmd_yaml_get_event_name (event.type));
705 }
706
707 while (!done)
708 {
709 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
710
711 switch (event.type)
712 {
713 case YAML_MAPPING_END_EVENT: done = TRUE; break;
714
715 case YAML_SCALAR_EVENT:
716 /* Parse the value */
717 key = (const gchar *)event.data.scalar.value;
718
719 value = modulemd_yaml_parse_string (parser, &nested_error);
720 if (!value)
721 {
722 g_propagate_error (error, g_steal_pointer (&nested_error));
723 return NULL;
724 }
725
726 g_hash_table_replace (
727 table, g_strdup (key), g_steal_pointer (&value));
728
729 break;
730
731 default:
732 MMD_YAML_ERROR_EVENT_EXIT (
733 error, event, "Unexpected YAML event in map");
734 break;
735 }
736 yaml_event_delete (&event);
737 }
738 return g_steal_pointer (&table);
739 }
740
741
742 GHashTable *
modulemd_yaml_parse_nested_set(yaml_parser_t * parser,GError ** error)743 modulemd_yaml_parse_nested_set (yaml_parser_t *parser, GError **error)
744 {
745 MODULEMD_INIT_TRACE ();
746 MMD_INIT_YAML_EVENT (event);
747 gboolean done = FALSE;
748 g_autofree gchar *key = NULL;
749 g_autoptr (GHashTable) value = NULL;
750 g_autoptr (GHashTable) t = NULL;
751 g_autoptr (GError) nested_error = NULL;
752
753 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
754
755 t = g_hash_table_new_full (
756 g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_unref);
757
758 /* The first event must be a MAPPING_START */
759 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
760 if (event.type != YAML_MAPPING_START_EVENT)
761 {
762 MMD_YAML_ERROR_EVENT_EXIT (
763 error, event, "Missing mapping in nested set");
764 }
765
766 while (!done)
767 {
768 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
769
770 switch (event.type)
771 {
772 case YAML_MAPPING_END_EVENT: done = TRUE; break;
773
774 case YAML_SCALAR_EVENT:
775 key = g_strdup ((const gchar *)event.data.scalar.value);
776 if (g_hash_table_contains (t,
777 (const gchar *)event.data.scalar.value))
778 {
779 MMD_YAML_ERROR_EVENT_EXIT (
780 error,
781 event,
782 "Key %s encountered twice in nested set",
783 (const gchar *)event.data.scalar.value);
784 }
785
786 value = modulemd_yaml_parse_string_set (parser, &nested_error);
787 if (value == NULL)
788 {
789 MMD_YAML_ERROR_EVENT_EXIT (error,
790 event,
791 "Failed to parse nested set: %s",
792 nested_error->message);
793 }
794
795 g_hash_table_insert (
796 t, g_steal_pointer (&key), g_steal_pointer (&value));
797 break;
798
799 default:
800 MMD_YAML_ERROR_EVENT_EXIT (error,
801 event,
802 "Unexpected YAML event in nested set: %d",
803 event.type);
804 break;
805 }
806 yaml_event_delete (&event);
807 }
808
809 /* Work around false-positive in clang static analysis which thinks it's
810 * possible for this function to return NULL and not set error.
811 */
812 if (G_UNLIKELY (t == NULL))
813 {
814 g_set_error (error,
815 MODULEMD_YAML_ERROR,
816 MMD_YAML_ERROR_EMIT,
817 "Somehow got a NULL hash table here.");
818 }
819
820 return g_steal_pointer (&t);
821 }
822
823 gboolean
modulemd_yaml_emit_nested_set(yaml_emitter_t * emitter,GHashTable * table,GError ** error)824 modulemd_yaml_emit_nested_set (yaml_emitter_t *emitter,
825 GHashTable *table,
826 GError **error)
827 {
828 MODULEMD_INIT_TRACE ();
829 int ret;
830 g_autoptr (GError) nested_error = NULL;
831 MMD_INIT_YAML_EVENT (event);
832 g_autoptr (GPtrArray) keys = NULL;
833 GHashTable *dep = NULL;
834 gchar *key = NULL;
835
836 ret = mmd_emitter_start_mapping (
837 emitter, YAML_BLOCK_MAPPING_STYLE, &nested_error);
838 if (!ret)
839 {
840 g_propagate_prefixed_error (
841 error,
842 g_steal_pointer (&nested_error),
843 "Failed to start dependencies nested mapping: ");
844 return FALSE;
845 }
846
847 keys = modulemd_ordered_str_keys (table, modulemd_strcmp_sort);
848 for (gint i = 0; i < keys->len; i++)
849 {
850 key = g_ptr_array_index (keys, i);
851 dep = g_hash_table_lookup (table, key);
852
853 EMIT_STRING_SET_FULL (
854 emitter, error, key, dep, YAML_FLOW_SEQUENCE_STYLE);
855 }
856
857 ret = mmd_emitter_end_mapping (emitter, &nested_error);
858 if (!ret)
859 {
860 g_propagate_prefixed_error (error,
861 g_steal_pointer (&nested_error),
862 "Failed to end nested mapping");
863 return FALSE;
864 }
865
866 return TRUE;
867 }
868
869
870 static gboolean
modulemd_yaml_parse_document_type_internal(yaml_parser_t * parser,ModulemdYamlDocumentTypeEnum * _doctype,guint64 * _mdversion,yaml_emitter_t * emitter,GError ** error)871 modulemd_yaml_parse_document_type_internal (
872 yaml_parser_t *parser,
873 ModulemdYamlDocumentTypeEnum *_doctype,
874 guint64 *_mdversion,
875 yaml_emitter_t *emitter,
876 GError **error)
877 {
878 MODULEMD_INIT_TRACE ();
879 MMD_INIT_YAML_EVENT (event);
880 gboolean done = FALSE;
881 gboolean had_data = FALSE;
882 ModulemdYamlDocumentTypeEnum doctype = MODULEMD_YAML_DOC_UNKNOWN;
883 guint64 mdversion = 0;
884 g_autofree gchar *doctype_scalar = NULL;
885 g_autofree gchar *mdversion_string = NULL;
886 g_autoptr (GError) nested_error = NULL;
887 int depth = 0;
888
889 if (!mmd_emitter_start_stream (emitter, &nested_error))
890 {
891 g_propagate_prefixed_error (
892 error, nested_error, "Error emitting stream: ");
893 return FALSE;
894 }
895
896 /*
897 * We should assume the initial document start is consumed by the Index.
898 * But we still emit it.
899 */
900 if (!mmd_emitter_start_document (emitter, error))
901 {
902 return FALSE;
903 }
904
905 /* The second event must be the mapping start */
906 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
907 if (event.type != YAML_MAPPING_START_EVENT)
908 {
909 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
910 error, event, "Document did not start with a mapping");
911 }
912 MMD_EMIT_WITH_EXIT_FULL (
913 emitter, FALSE, &event, error, "Error starting mapping");
914 yaml_event_delete (&event);
915 depth++;
916
917 /* Now process through the document top-level */
918 while (!done)
919 {
920 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
921
922 switch (event.type)
923 {
924 case YAML_MAPPING_END_EVENT:
925 if (!mmd_emitter_end_mapping (emitter, error))
926 {
927 return FALSE;
928 }
929 depth--;
930 if (depth == 0)
931 {
932 done = TRUE;
933 }
934 break;
935
936 case YAML_MAPPING_START_EVENT:
937 if (!mmd_emitter_start_mapping (
938 emitter, event.data.mapping_start.style, error))
939 {
940 return FALSE;
941 }
942 depth++;
943 break;
944
945 case YAML_SCALAR_EVENT:
946 if (!mmd_emitter_scalar (emitter,
947 (const gchar *)event.data.scalar.value,
948 event.data.scalar.style,
949 error))
950 {
951 return FALSE;
952 }
953
954 if (depth == 1 && g_str_equal (event.data.scalar.value, "document"))
955 {
956 if (doctype != MODULEMD_YAML_DOC_UNKNOWN)
957 {
958 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
959 error, event, "Document type encountered twice.");
960 }
961
962 doctype_scalar =
963 modulemd_yaml_parse_string (parser, &nested_error);
964 if (!doctype_scalar)
965 {
966 g_propagate_error (error, g_steal_pointer (&nested_error));
967 return FALSE;
968 }
969 if (!mmd_emitter_scalar (emitter,
970 (const gchar *)doctype_scalar,
971 YAML_PLAIN_SCALAR_STYLE,
972 error))
973 {
974 return FALSE;
975 }
976
977 if (g_str_equal (doctype_scalar, "modulemd") ||
978 g_str_equal (doctype_scalar, "modulemd-stream"))
979 {
980 doctype = MODULEMD_YAML_DOC_MODULESTREAM;
981 }
982 else if (g_str_equal (doctype_scalar, "modulemd-defaults"))
983 {
984 doctype = MODULEMD_YAML_DOC_DEFAULTS;
985 }
986 else if (g_str_equal (doctype_scalar, "modulemd-translations"))
987 {
988 doctype = MODULEMD_YAML_DOC_TRANSLATIONS;
989 }
990 else if (g_str_equal (doctype_scalar, "modulemd-packager"))
991 {
992 doctype = MODULEMD_YAML_DOC_PACKAGER;
993 }
994 else if (g_str_equal (doctype_scalar, "modulemd-obsoletes"))
995 {
996 doctype = MODULEMD_YAML_DOC_OBSOLETES;
997 }
998 else
999 {
1000 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1001 error, event, "Document type %s unknown.", doctype_scalar);
1002 }
1003
1004 g_clear_pointer (&doctype_scalar, g_free);
1005 }
1006 else if (depth == 1 &&
1007 g_str_equal (event.data.scalar.value, "version"))
1008 {
1009 if (mdversion != 0)
1010 {
1011 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1012 error, event, "Metadata version encountered twice.");
1013 }
1014
1015 mdversion = modulemd_yaml_parse_uint64 (parser, &nested_error);
1016 if (nested_error)
1017 {
1018 /* If we got a parsing error, report it. Otherwise, continue
1019 * and we'll catch the invalid mdversion further on
1020 */
1021 g_propagate_error (error, g_steal_pointer (&nested_error));
1022 return FALSE;
1023 }
1024 mdversion_string = g_strdup_printf ("%" PRIu64, mdversion);
1025 if (!mmd_emitter_scalar (
1026 emitter, mdversion_string, YAML_PLAIN_SCALAR_STYLE, error))
1027 {
1028 return FALSE;
1029 }
1030 }
1031 else if (depth == 1 && g_str_equal (event.data.scalar.value, "data"))
1032 {
1033 had_data = TRUE;
1034 }
1035
1036 break;
1037
1038 default:
1039 /* Anything else, we just re-emit into the subdocument */
1040 MMD_EMIT_WITH_EXIT_FULL (
1041 emitter, FALSE, &event, error, "Error re-emiting event");
1042 ;
1043 break;
1044 }
1045
1046 yaml_event_delete (&event);
1047 }
1048
1049 /* The final event must be the document end */
1050 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1051 if (event.type != YAML_DOCUMENT_END_EVENT)
1052 {
1053 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1054 error, event, "Document did not end. It just goes on forever...");
1055 }
1056 MMD_EMIT_WITH_EXIT_FULL (
1057 emitter, FALSE, &event, error, "Error ending document");
1058 yaml_event_delete (&event);
1059
1060 if (!mmd_emitter_end_stream (emitter, error))
1061 {
1062 return FALSE;
1063 }
1064
1065 if (doctype == MODULEMD_YAML_DOC_UNKNOWN)
1066 {
1067 g_set_error_literal (error,
1068 MODULEMD_YAML_ERROR,
1069 MMD_YAML_ERROR_MISSING_REQUIRED,
1070 "No document type specified");
1071 return FALSE;
1072 }
1073
1074 if (!mdversion)
1075 {
1076 g_set_error_literal (error,
1077 MODULEMD_YAML_ERROR,
1078 MMD_YAML_ERROR_MISSING_REQUIRED,
1079 "No metadata version specified");
1080 return FALSE;
1081 }
1082
1083 if (doctype == MODULEMD_YAML_DOC_PACKAGER && mdversion < 2)
1084 {
1085 g_set_error_literal (error,
1086 MODULEMD_YAML_ERROR,
1087 MMD_YAML_ERROR_INCONSISTENT,
1088 "Document type 'modulemd-packager' is permissible "
1089 "only for module stream version 2 or higher.");
1090 return FALSE;
1091 }
1092
1093 if (!had_data)
1094 {
1095 g_set_error_literal (error,
1096 MODULEMD_YAML_ERROR,
1097 MMD_YAML_ERROR_MISSING_REQUIRED,
1098 "No data section provided");
1099 return FALSE;
1100 }
1101
1102 *_doctype = doctype;
1103 *_mdversion = mdversion;
1104
1105 return TRUE;
1106 }
1107
1108
1109 ModulemdSubdocumentInfo *
modulemd_yaml_parse_document_type(yaml_parser_t * parser)1110 modulemd_yaml_parse_document_type (yaml_parser_t *parser)
1111 {
1112 MMD_INIT_YAML_EMITTER (emitter);
1113 MMD_INIT_YAML_STRING (&emitter, yaml_string);
1114 g_autoptr (ModulemdSubdocumentInfo) s = modulemd_subdocument_info_new ();
1115 ModulemdYamlDocumentTypeEnum doctype = MODULEMD_YAML_DOC_UNKNOWN;
1116 guint64 mdversion = 0;
1117 g_autoptr (GError) error = NULL;
1118
1119 if (!modulemd_yaml_parse_document_type_internal (
1120 parser, &doctype, &mdversion, &emitter, &error))
1121 {
1122 modulemd_subdocument_info_set_gerror (s, error);
1123 }
1124
1125 modulemd_subdocument_info_set_doctype (s, doctype);
1126 modulemd_subdocument_info_set_mdversion (s, mdversion);
1127 modulemd_subdocument_info_set_yaml (s, yaml_string->str);
1128
1129 return g_steal_pointer (&s);
1130 }
1131
1132
1133 static const gchar *
modulemd_yaml_get_doctype_string(ModulemdYamlDocumentTypeEnum doctype,guint64 mdversion)1134 modulemd_yaml_get_doctype_string (ModulemdYamlDocumentTypeEnum doctype,
1135 guint64 mdversion)
1136 {
1137 switch (doctype)
1138 {
1139 case MODULEMD_YAML_DOC_MODULESTREAM:
1140 if (mdversion <= 2)
1141 {
1142 return "modulemd";
1143 }
1144 return "modulemd-stream";
1145
1146 case MODULEMD_YAML_DOC_DEFAULTS: return "modulemd-defaults";
1147
1148 case MODULEMD_YAML_DOC_TRANSLATIONS: return "modulemd-translations";
1149
1150 case MODULEMD_YAML_DOC_OBSOLETES: return "modulemd-obsoletes";
1151
1152 case MODULEMD_YAML_DOC_PACKAGER: return "modulemd-packager";
1153
1154 default: return NULL;
1155 }
1156 }
1157
1158
1159 gboolean
modulemd_yaml_emit_document_headers(yaml_emitter_t * emitter,ModulemdYamlDocumentTypeEnum doctype,guint64 mdversion,GError ** error)1160 modulemd_yaml_emit_document_headers (yaml_emitter_t *emitter,
1161 ModulemdYamlDocumentTypeEnum doctype,
1162 guint64 mdversion,
1163 GError **error)
1164 {
1165 MODULEMD_INIT_TRACE ();
1166 const gchar *doctype_string =
1167 modulemd_yaml_get_doctype_string (doctype, mdversion);
1168 g_autofree gchar *mdversion_string = g_strdup_printf ("%" PRIu64, mdversion);
1169
1170 if (!mmd_emitter_start_document (emitter, error))
1171 {
1172 return FALSE;
1173 }
1174
1175 if (!mmd_emitter_start_mapping (emitter, YAML_BLOCK_MAPPING_STYLE, error))
1176 {
1177 return FALSE;
1178 }
1179
1180 if (!mmd_emitter_scalar (
1181 emitter, "document", YAML_PLAIN_SCALAR_STYLE, error))
1182 {
1183 return FALSE;
1184 }
1185
1186 if (!mmd_emitter_scalar (
1187 emitter, doctype_string, YAML_PLAIN_SCALAR_STYLE, error))
1188 {
1189 return FALSE;
1190 }
1191
1192 if (!mmd_emitter_scalar (emitter, "version", YAML_PLAIN_SCALAR_STYLE, error))
1193 {
1194 return FALSE;
1195 }
1196
1197 if (!mmd_emitter_scalar (
1198 emitter, mdversion_string, YAML_PLAIN_SCALAR_STYLE, error))
1199 {
1200 return FALSE;
1201 }
1202
1203 if (!mmd_emitter_scalar (emitter, "data", YAML_PLAIN_SCALAR_STYLE, error))
1204 {
1205 return FALSE;
1206 }
1207
1208 return TRUE;
1209 }
1210
1211
1212 gboolean
modulemd_yaml_emit_variant(yaml_emitter_t * emitter,GVariant * variant,GError ** error)1213 modulemd_yaml_emit_variant (yaml_emitter_t *emitter,
1214 GVariant *variant,
1215 GError **error)
1216 {
1217 GVariantIter iter;
1218 g_autofree gchar *key = NULL;
1219 g_autoptr (GVariant) value = NULL;
1220 g_autoptr (GPtrArray) keys = NULL;
1221 g_autoptr (GVariantDict) dict = NULL;
1222
1223 if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
1224 {
1225 EMIT_SCALAR (emitter, error, g_variant_get_string (variant, NULL));
1226 }
1227 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
1228 {
1229 if (g_variant_get_boolean (variant))
1230 {
1231 EMIT_SCALAR (emitter, error, "TRUE");
1232 }
1233 else
1234 {
1235 EMIT_SCALAR (emitter, error, "FALSE");
1236 }
1237 }
1238 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DICTIONARY))
1239 {
1240 EMIT_MAPPING_START (emitter, error);
1241 keys = g_ptr_array_new_with_free_func (g_free);
1242
1243 dict = g_variant_dict_new (variant);
1244 g_variant_iter_init (&iter, variant);
1245
1246 /* Get a list of the keys to sort */
1247 while (g_variant_iter_next (&iter, "{sv}", &key, &value))
1248 {
1249 g_ptr_array_add (keys, g_steal_pointer (&key));
1250 g_clear_pointer (&value, g_variant_unref);
1251 }
1252
1253 /* Sort the keys alphabetically */
1254 g_ptr_array_sort (keys, modulemd_strcmp_sort);
1255
1256 /* Write out the keys and recurse into their values */
1257 for (guint i = 0; i < keys->len; i++)
1258 {
1259 value = g_variant_dict_lookup_value (
1260 dict, g_ptr_array_index (keys, i), NULL);
1261 if (!value)
1262 {
1263 g_set_error (
1264 error,
1265 MODULEMD_YAML_ERROR,
1266 MMD_YAML_ERROR_EMIT,
1267 "Got unexpected type while processing XMD dictionary.");
1268 return FALSE;
1269 }
1270 EMIT_SCALAR (emitter, error, g_ptr_array_index (keys, i));
1271 if (!modulemd_yaml_emit_variant (emitter, value, error))
1272 {
1273 return FALSE;
1274 }
1275
1276 g_clear_pointer (&value, g_variant_unref);
1277 }
1278
1279 g_clear_pointer (&keys, g_ptr_array_unref);
1280 EMIT_MAPPING_END (emitter, error);
1281 }
1282 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY))
1283 {
1284 EMIT_SEQUENCE_START (emitter, error);
1285 g_variant_iter_init (&iter, variant);
1286 while ((value = g_variant_iter_next_value (&iter)))
1287 {
1288 if (!modulemd_yaml_emit_variant (emitter, value, error))
1289 {
1290 return FALSE;
1291 }
1292 g_clear_pointer (&value, g_variant_unref);
1293 }
1294 EMIT_SEQUENCE_END (emitter, error);
1295 }
1296 else
1297 {
1298 g_set_error (error,
1299 MODULEMD_YAML_ERROR,
1300 MMD_YAML_ERROR_EMIT,
1301 "Unhandled variant type: \"%s\": %s",
1302 g_variant_get_type_string (variant),
1303 g_variant_print (variant, TRUE));
1304 return FALSE;
1305 }
1306 return TRUE;
1307 }
1308
1309 GVariant *
mmd_variant_from_scalar(const gchar * scalar)1310 mmd_variant_from_scalar (const gchar *scalar)
1311 {
1312 MODULEMD_INIT_TRACE ();
1313 GVariant *variant = NULL;
1314
1315 g_debug ("Variant from scalar: %s", scalar);
1316
1317 g_return_val_if_fail (scalar, NULL);
1318
1319 /* Treat "TRUE" and "FALSE" as boolean values */
1320 if (g_str_equal (scalar, "TRUE"))
1321 {
1322 variant = g_variant_new_boolean (TRUE);
1323 }
1324 else if (g_str_equal (scalar, "FALSE"))
1325 {
1326 variant = g_variant_new_boolean (FALSE);
1327 }
1328
1329 else if (scalar)
1330 {
1331 /* Any value we don't handle specifically becomes a string */
1332 variant = g_variant_new_string (scalar);
1333 }
1334
1335 return variant;
1336 }
1337
1338
1339 GVariant *
mmd_variant_from_mapping(yaml_parser_t * parser,GError ** error)1340 mmd_variant_from_mapping (yaml_parser_t *parser, GError **error)
1341 {
1342 MODULEMD_INIT_TRACE ();
1343 gboolean done = FALSE;
1344 MMD_INIT_YAML_EVENT (event);
1345 MMD_INIT_YAML_EVENT (value_event);
1346
1347 g_autoptr (GVariantDict) dict = NULL;
1348 g_autoptr (GVariant) value = NULL;
1349 g_autofree gchar *key = NULL;
1350 g_autoptr (GError) nested_error = NULL;
1351
1352 dict = g_variant_dict_new (NULL);
1353
1354 while (!done)
1355 {
1356 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
1357
1358 switch (event.type)
1359 {
1360 case YAML_MAPPING_END_EVENT:
1361 /* We've processed the whole dictionary */
1362 done = TRUE;
1363 break;
1364
1365 case YAML_SCALAR_EVENT:
1366 /* All mapping keys must be scalars */
1367 key = g_strdup ((const gchar *)event.data.scalar.value);
1368
1369 YAML_PARSER_PARSE_WITH_EXIT (parser, &value_event, error);
1370
1371 switch (value_event.type)
1372 {
1373 case YAML_SCALAR_EVENT:
1374 value = mmd_variant_from_scalar (
1375 (const gchar *)value_event.data.scalar.value);
1376 if (!value)
1377 {
1378 MMD_YAML_ERROR_EVENT_EXIT (
1379 error, event, "Error parsing scalar");
1380 }
1381 break;
1382
1383 case YAML_MAPPING_START_EVENT:
1384 value = mmd_variant_from_mapping (parser, &nested_error);
1385 if (!value)
1386 {
1387 g_propagate_error (error, g_steal_pointer (&nested_error));
1388 return NULL;
1389 }
1390 break;
1391
1392 case YAML_SEQUENCE_START_EVENT:
1393 value = mmd_variant_from_sequence (parser, &nested_error);
1394 if (!value)
1395 {
1396 g_propagate_error (error, g_steal_pointer (&nested_error));
1397 return NULL;
1398 }
1399 break;
1400
1401 default:
1402 /* We received a YAML event we shouldn't expect at this level */
1403 MMD_YAML_ERROR_EVENT_EXIT (
1404 error,
1405 event,
1406 "Unexpected YAML event in inner raw mapping: %s",
1407 mmd_yaml_get_event_name (value_event.type));
1408 break;
1409 }
1410
1411 yaml_event_delete (&value_event);
1412 g_variant_dict_insert_value (dict, key, g_steal_pointer (&value));
1413 g_clear_pointer (&key, g_free);
1414 break;
1415
1416 default:
1417 /* We received a YAML event we shouldn't expect at this level */
1418 MMD_YAML_ERROR_EVENT_EXIT (
1419 error,
1420 event,
1421 "Unexpected YAML event in raw mapping: %s",
1422 mmd_yaml_get_event_name (event.type));
1423 break;
1424 }
1425
1426 yaml_event_delete (&event);
1427 }
1428
1429 return g_variant_dict_end (dict);
1430 }
1431
1432
1433 GVariant *
mmd_variant_from_sequence(yaml_parser_t * parser,GError ** error)1434 mmd_variant_from_sequence (yaml_parser_t *parser, GError **error)
1435 {
1436 MODULEMD_INIT_TRACE ();
1437 gboolean done = FALSE;
1438 MMD_INIT_YAML_EVENT (event);
1439
1440 g_auto (GVariantBuilder) builder;
1441 g_autoptr (GVariant) value = NULL;
1442 g_autoptr (GError) nested_error = NULL;
1443 gboolean empty_array = TRUE;
1444 GVariant *result = NULL;
1445
1446 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
1447
1448 while (!done)
1449 {
1450 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
1451
1452 switch (event.type)
1453 {
1454 case YAML_SEQUENCE_END_EVENT:
1455 /* We've processed the whole sequence */
1456 done = TRUE;
1457 break;
1458
1459 case YAML_SCALAR_EVENT:
1460 value =
1461 mmd_variant_from_scalar ((const gchar *)event.data.scalar.value);
1462 if (!value)
1463 {
1464 MMD_YAML_ERROR_EVENT_EXIT (error, event, "Error parsing scalar");
1465 }
1466 break;
1467
1468 case YAML_MAPPING_START_EVENT:
1469 value = mmd_variant_from_mapping (parser, &nested_error);
1470 if (!value)
1471 {
1472 g_propagate_error (error, g_steal_pointer (&nested_error));
1473 return NULL;
1474 }
1475 break;
1476
1477 case YAML_SEQUENCE_START_EVENT:
1478 value = mmd_variant_from_sequence (parser, &nested_error);
1479 if (!value)
1480 {
1481 g_propagate_error (error, g_steal_pointer (&nested_error));
1482 return NULL;
1483 }
1484 break;
1485
1486 default:
1487 /* We received a YAML event we shouldn't expect at this level */
1488 MMD_YAML_ERROR_EVENT_EXIT (
1489 error,
1490 event,
1491 "Unexpected YAML event in raw sequence: %s",
1492 mmd_yaml_get_event_name (event.type));
1493 break;
1494 }
1495
1496 if (value)
1497 {
1498 g_variant_builder_add_value (&builder, g_steal_pointer (&value));
1499 empty_array = FALSE;
1500 }
1501
1502 yaml_event_delete (&event);
1503 }
1504
1505 if (empty_array)
1506 {
1507 /* If we got an empty array, treat it as a zero-length array of
1508 * GVariants
1509 */
1510 result = g_variant_new ("av", NULL);
1511 }
1512 else
1513 {
1514 /* Otherwise, finish it up */
1515 result = g_variant_builder_end (&builder);
1516 }
1517
1518 return result;
1519 }
1520
1521
1522 GVariant *
mmd_parse_xmd(yaml_parser_t * parser,GError ** error)1523 mmd_parse_xmd (yaml_parser_t *parser, GError **error)
1524 {
1525 MODULEMD_INIT_TRACE ();
1526 MMD_INIT_YAML_EVENT (event);
1527 GVariant *variant = NULL;
1528 g_autoptr (GError) nested_error = NULL;
1529
1530 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1531
1532 YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
1533
1534 switch (event.type)
1535 {
1536 case YAML_SCALAR_EVENT:
1537 variant =
1538 mmd_variant_from_scalar ((const gchar *)event.data.scalar.value);
1539 if (!variant)
1540 {
1541 MMD_YAML_ERROR_EVENT_EXIT (error, event, "Error parsing scalar");
1542 }
1543 break;
1544
1545 case YAML_MAPPING_START_EVENT:
1546 variant = mmd_variant_from_mapping (parser, &nested_error);
1547 break;
1548
1549 default:
1550 MMD_YAML_ERROR_EVENT_EXIT (error,
1551 event,
1552 "Unexpected YAML event in raw parsing: %s",
1553 mmd_yaml_get_event_name (event.type));
1554 break;
1555 }
1556
1557 return g_variant_ref_sink (variant);
1558 }
1559
1560
1561 static gboolean
1562 skip_unknown_yaml_mapping (yaml_parser_t *parser, GError **error);
1563 static gboolean
1564 skip_unknown_yaml_sequence (yaml_parser_t *parser, GError **error);
1565
1566
1567 gboolean
skip_unknown_yaml(yaml_parser_t * parser,GError ** error)1568 skip_unknown_yaml (yaml_parser_t *parser, GError **error)
1569 {
1570 MMD_INIT_YAML_EVENT (event);
1571 MODULEMD_INIT_TRACE ();
1572
1573 /* This function is called when an unknown key appears in a mapping.
1574 * Read the next event and then skip to the end of it.
1575 */
1576
1577 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1578
1579 switch (event.type)
1580 {
1581 case YAML_SCALAR_EVENT:
1582 /* If we get a scalar key, we can just return here */
1583 break;
1584
1585 case YAML_MAPPING_START_EVENT:
1586 return skip_unknown_yaml_mapping (parser, error);
1587
1588 case YAML_SEQUENCE_START_EVENT:
1589 return skip_unknown_yaml_sequence (parser, error);
1590
1591 default:
1592 /* We received a YAML event we shouldn't expect at this level */
1593 g_set_error (error,
1594 MODULEMD_YAML_ERROR,
1595 MMD_YAML_ERROR_PARSE,
1596 "Unexpected YAML event %s in skip_unknown_yaml()",
1597 mmd_yaml_get_event_name (event.type));
1598 return FALSE;
1599 }
1600
1601 return TRUE;
1602 }
1603
1604
1605 static gboolean
skip_unknown_yaml_sequence(yaml_parser_t * parser,GError ** error)1606 skip_unknown_yaml_sequence (yaml_parser_t *parser, GError **error)
1607 {
1608 MMD_INIT_YAML_EVENT (event);
1609 gsize depth = 0;
1610 gboolean done = FALSE;
1611
1612 while (!done)
1613 {
1614 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1615
1616 switch (event.type)
1617 {
1618 case YAML_SCALAR_EVENT: break;
1619
1620 case YAML_MAPPING_START_EVENT:
1621 case YAML_SEQUENCE_START_EVENT: depth++; break;
1622
1623 case YAML_MAPPING_END_EVENT: depth--; break;
1624
1625 case YAML_SEQUENCE_END_EVENT:
1626 if (depth == 0)
1627 {
1628 done = TRUE;
1629 break;
1630 }
1631
1632 depth--;
1633 break;
1634
1635
1636 default:
1637 /* We received a YAML event we shouldn't expect at this level */
1638 g_set_error (
1639 error,
1640 MODULEMD_YAML_ERROR,
1641 MMD_YAML_ERROR_PARSE,
1642 "Unexpected YAML event %s in skip_unknown_yaml_sequence()",
1643 mmd_yaml_get_event_name (event.type));
1644 return FALSE;
1645 }
1646
1647 yaml_event_delete (&event);
1648 }
1649
1650 return TRUE;
1651 }
1652
1653
1654 static gboolean
skip_unknown_yaml_mapping(yaml_parser_t * parser,GError ** error)1655 skip_unknown_yaml_mapping (yaml_parser_t *parser, GError **error)
1656 {
1657 MMD_INIT_YAML_EVENT (event);
1658 gsize depth = 0;
1659 gboolean done = FALSE;
1660
1661 while (!done)
1662 {
1663 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1664
1665 switch (event.type)
1666 {
1667 case YAML_SCALAR_EVENT: break;
1668
1669 case YAML_MAPPING_START_EVENT:
1670 case YAML_SEQUENCE_START_EVENT: depth++; break;
1671
1672 case YAML_SEQUENCE_END_EVENT: depth--; break;
1673
1674 case YAML_MAPPING_END_EVENT:
1675 if (depth == 0)
1676 {
1677 done = TRUE;
1678 break;
1679 }
1680
1681 depth--;
1682 break;
1683
1684
1685 default:
1686 /* We received a YAML event we shouldn't expect at this level */
1687 g_set_error (
1688 error,
1689 MODULEMD_YAML_ERROR,
1690 MMD_YAML_ERROR_PARSE,
1691 "Unexpected YAML event %s in skip_unknown_yaml_sequence()",
1692 mmd_yaml_get_event_name (event.type));
1693 return FALSE;
1694 }
1695
1696 yaml_event_delete (&event);
1697 }
1698
1699 return TRUE;
1700 }
1701