[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:13:53 CEST 2022
On Mon, May 09, 2022 at 08:10:28PM +0300, Laurent Pinchart via libcamera-devel wrote:
> 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.
And
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
:-)
> > + default:
> > + LOG(YamlParser, Error) << "Invalid YAML file";
> > + return -EINVAL;
> > + }
> > +}
>
> [snip]
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list