| /* Copyright 2023 The ChromiumOS Authors | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| /* Specialised YamlNode, representing a YAML sequence. | |
| * | |
| * This is equivalent to vectors/lists in programming languages. | |
| */ | |
| #include "tools/mctk/yaml_tree.h" | |
| #include <stddef.h> /* size_t */ | |
| #include <yaml.h> | |
| #include <memory> /* std::unique_ptr */ | |
| #include <utility> /* std::move */ | |
| #include <vector> | |
| #include "tools/mctk/debug.h" | |
| bool YamlSequence::ParseOneListElement(yaml_parser_t& parser) { | |
| yaml_event_t event; | |
| if (!yaml_parser_parse(&parser, &event)) | |
| return false; | |
| if (event.type == YAML_SEQUENCE_END_EVENT) { | |
| yaml_event_delete(&event); | |
| return true; | |
| } | |
| auto new_node = YamlNode::FromParserEvent(parser, event); | |
| yaml_event_delete(&event); | |
| if (!new_node) | |
| return false; | |
| this->list_.push_back(std::move(new_node)); | |
| return this->ParseOneListElement(parser); | |
| } | |
| /* Caller is responsible for deleting the event passed in */ | |
| std::unique_ptr<YamlSequence> YamlSequence::FromParserEvent( | |
| yaml_parser_t& parser, yaml_event_t& start_event) { | |
| MCTK_ASSERT_EQ(start_event.type, YAML_SEQUENCE_START_EVENT); | |
| auto new_seq = std::make_unique<YamlSequence>(); | |
| if (!new_seq) | |
| return NULL; | |
| /* Store YAML formatting style for debugging purposes */ | |
| new_seq->implicit_ = start_event.data.sequence_start.implicit; | |
| new_seq->style_ = start_event.data.sequence_start.style; | |
| if (new_seq->ParseOneListElement(parser)) | |
| return new_seq; | |
| return NULL; | |
| } | |
| bool YamlSequence::Emit(yaml_emitter_t& emitter) { | |
| yaml_event_t event; | |
| if (!yaml_sequence_start_event_initialize( | |
| &event, NULL, reinterpret_cast<const yaml_char_t*>(YAML_SEQ_TAG), | |
| implicit_, style_)) | |
| return false; | |
| if (!yaml_emitter_emit(&emitter, &event)) | |
| return false; | |
| for (auto& node : this->list_) { | |
| node->Emit(emitter); | |
| } | |
| if (!yaml_sequence_end_event_initialize(&event)) | |
| return false; | |
| if (!yaml_emitter_emit(&emitter, &event)) | |
| return false; | |
| return true; | |
| } | |
| /* Parse a whole array of the same basic type, but only if the | |
| * array size matches the expected number of elements. | |
| */ | |
| template <typename T> | |
| std::optional<std::vector<T>> YamlSequence::ReadArray(size_t expected_count) { | |
| if (list_.size() != expected_count) | |
| return std::nullopt; | |
| std::vector<T> out_vec; | |
| for (auto& node : list_) { | |
| std::optional<T> temp = node->Read<T>(); | |
| if (!temp) | |
| return std::nullopt; | |
| out_vec.push_back(*temp); | |
| } | |
| return std::optional<std::vector<T>>(out_vec); | |
| } | |
| template std::optional<std::vector<__u32>> YamlSequence::ReadArray( | |
| size_t expected_count); | |
| template std::optional<std::vector<__u8>> YamlSequence::ReadArray( | |
| size_t expected_count); |