[libcamera-devel] [PATCH v6 1/3] libcamera: Introduce YamlParser as a helper to parse yaml files
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Mon May 9 19:10:28 CEST 2022
Hi Han-Lin,
Thank you for the patch.
On Wed, Apr 27, 2022 at 10:09:27PM +0800, Han-Lin Chen via libcamera-devel wrote:
> Introduce YamlParser as a helper to convert contents of a yaml file to
> a tree based structure for easier reading, and to avoid writing parser
> with raw yaml tokens. The class is based on libyaml, and only support
> reading but not writing a yaml file.
>
> The interface is inspired by Json::Value class from jsoncpp:
> http://jsoncpp.sourceforge.net/class_json_1_1_value.html
>
> Signed-off-by: Han-Lin Chen <hanlinchen at chromium.org>
> ---
> README.rst | 4 +-
> include/libcamera/internal/meson.build | 1 +
> include/libcamera/internal/yaml_parser.h | 87 +++
> src/libcamera/meson.build | 3 +
> src/libcamera/yaml_parser.cpp | 679 +++++++++++++++++++++++
> 5 files changed, 772 insertions(+), 2 deletions(-)
> create mode 100644 include/libcamera/internal/yaml_parser.h
> create mode 100644 src/libcamera/yaml_parser.cpp
[snip]
> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
> new file mode 100644
> index 00000000..4a047494
> --- /dev/null
> +++ b/src/libcamera/yaml_parser.cpp
> @@ -0,0 +1,679 @@
[snip]
> +/**
> + * \fn YamlParserContext::parseDictionaryOrList()
> + * \brief A helper function to abstract the common part of parsing dictionary or list
> + *
> + * \param[in] isDictionary True for parsing a dictionary, and false for a list
> + * \param[in] parseItem The callback to handle an item
> + *
> + * A helper function to abstract parsing an item from a dictionary or a list.
> + * The differences of them in a YAML event stream are:
> + *
> + * 1. The start and end event types are different
> + * 2. There is a leading scalar string as key in the items of a dictionary
> + *
> + * The caller should handle the leading key string in its callback parseItem
> + * when it's a dictionary.
> + *
> + * \return 0 on success or a negative error code otherwise
> + * \retval -EINVAL The parser is failed to initialize
> + */
> +int YamlParserContext::parseDictionaryOrList(YamlObject::Type type,
> + const std::function<int(EventPtr event)> &parseItem)
> +{
> + yaml_event_type_t endEventType = YAML_SEQUENCE_END_EVENT;
> + if (type == YamlObject::Dictionary)
> + endEventType = YAML_MAPPING_END_EVENT;
> +
> + /*
> + * Add a safety counter to make sure we don't loop indefinitely in case
> + * the YAML file is malformed.
> + */
> + for (unsigned int sentinel = 1000; sentinel; sentinel--) {
> + auto evt = nextEvent();
> + if (!evt)
> + return -EINVAL;
> +
> + if (evt->type == endEventType)
> + return 0;
> +
> + int ret = parseItem(std::move(evt));
> + if (ret)
> + return ret;
> + }
> +
> + LOG(YamlParser, Error) << "The YAML file contains a List or Dictionary"
> + " whose size exceeding the parser's limit(1000)";
s/exceeding/exceeds/
> +
> + return -EINVAL;
> +}
> +
> +/**
> + * \fn YamlParserContext::parseNextYamlObject()
> + * \brief Parse next YAML event and read it as a YamlObject
> + * \param[in] yamlObject The result of YamlObject
> + * \param[in] event The leading event of the object
> + *
> + * Parse next YAML object separately as a value, list or dictionary.
> + *
> + * \return 0 on success or a negative error code otherwise
> + * \retval -EINVAL Fail to parse the YAML file.
> + */
> +int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr event)
> +{
> + if (!event)
> + return -EINVAL;
> +
> + switch (event->type) {
> + case YAML_SCALAR_EVENT:
> + yamlObject.type_ = YamlObject::Value;
> + readValue(yamlObject.value_, std::move(event));
> + return 0;
> +
> + case YAML_SEQUENCE_START_EVENT: {
> + yamlObject.type_ = YamlObject::List;
> + auto &list = yamlObject.list_;
> + auto handler = [this, &list](EventPtr evt) {
> + list.emplace_back(new YamlObject());
> + return parseNextYamlObject(*list.back(), std::move(evt));
> + };
> + return parseDictionaryOrList(YamlObject::List, handler);
> + }
> +
> + case YAML_MAPPING_START_EVENT: {
> + yamlObject.type_ = YamlObject::Dictionary;
> + auto &dictionary = yamlObject.dictionary_;
> + auto handler = [this, &dictionary](EventPtr evtKey) {
> + /* Parse key */
> + if (evtKey->type != YAML_SCALAR_EVENT) {
> + LOG(YamlParser, Error) << "Expect key at line: "
> + << evtKey->start_mark.line
> + << " column: "
> + << evtKey->start_mark.column;
> + return -EINVAL;
> + }
> +
> + std::string key;
> + readValue(key, std::move(evtKey));
> +
> + /* Parse value */
> + EventPtr evtValue = nextEvent();
> + if (!evtValue)
> + return -EINVAL;
> +
> + auto elem = dictionary.emplace(key, std::make_unique<YamlObject>());
> + return parseNextYamlObject(*elem.first->second.get(), std::move(evtValue));
> + };
> + return parseDictionaryOrList(YamlObject::Dictionary, handler);
> + }
Missing blank line.
I'll fix these when applying.
> + default:
> + LOG(YamlParser, Error) << "Invalid YAML file";
> + return -EINVAL;
> + }
> +}
[snip]
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list