diff options
-rw-r--r-- | include/libcamera/internal/meson.build | 1 | ||||
-rw-r--r-- | include/libcamera/internal/yaml_emitter.h | 61 | ||||
-rw-r--r-- | src/libcamera/meson.build | 1 | ||||
-rw-r--r-- | src/libcamera/yaml_emitter.cpp | 187 |
4 files changed, 250 insertions, 0 deletions
diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 1c5eef9c..7533b075 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -41,6 +41,7 @@ libcamera_internal_headers = files([ 'v4l2_pixelformat.h', 'v4l2_subdevice.h', 'v4l2_videodevice.h', + 'yaml_emitter.h', 'yaml_parser.h', ]) diff --git a/include/libcamera/internal/yaml_emitter.h b/include/libcamera/internal/yaml_emitter.h new file mode 100644 index 00000000..f8df5265 --- /dev/null +++ b/include/libcamera/internal/yaml_emitter.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas On Board Oy + * + * libcamera YAML emitter helper + */ + +#pragma once + +#include <map> +#include <memory> +#include <string> + +#include <libcamera/base/class.h> +#include <libcamera/base/file.h> + +#include <yaml.h> + +namespace libcamera { + +class File; +class YamlEvent; + +class YamlEmitter final +{ +public: + ~YamlEmitter(); + + static std::unique_ptr<YamlEmitter> create(std::string &path); + + int emit(std::map<std::string, std::string>); + int emit(const std::string &scalar); + +private: + LIBCAMERA_DISABLE_COPY(YamlEmitter); + + class Emitter + { + public: + Emitter() = default; + ~Emitter(); + + void init(File *file); + + int emit(YamlEvent *event); + + private: + void logError(); + + yaml_emitter_t emitter_; + }; + + YamlEmitter() = default; + + void init(); + + std::unique_ptr<File> file_; + Emitter emitter_; +}; + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index aa9ab029..5b8af410 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -51,6 +51,7 @@ libcamera_internal_sources = files([ 'v4l2_pixelformat.cpp', 'v4l2_subdevice.cpp', 'v4l2_videodevice.cpp', + 'yaml_emitter.cpp', 'yaml_parser.cpp', ]) diff --git a/src/libcamera/yaml_emitter.cpp b/src/libcamera/yaml_emitter.cpp new file mode 100644 index 00000000..5683d1d4 --- /dev/null +++ b/src/libcamera/yaml_emitter.cpp @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas On Board Oy + * + * libcamera YAML emitter helper + */ + +#include "libcamera/internal/yaml_emitter.h" + +#include <libcamera/base/log.h> +#include <libcamera/base/span.h> + +/** + * \file yaml_emitter.h + * \brief A YAML emitter helper + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(YamlEmitter) + +namespace { + +int yamlWrite(void *data, unsigned char *buffer, size_t size) +{ + File *file = static_cast<File *>(data); + + Span<unsigned char> buf{ buffer, size }; + ssize_t ret = file->write(buf); + if (ret < 0) + return 0; + + return 1; +} + +} /* namespace */ + +class YamlEvent +{ +public: + static std::unique_ptr<YamlEvent> create(); + + const yaml_event_t *event() const + { + return &event_; + } + + yaml_event_t *event() + { + return &event_; + } + +private: + YamlEvent() = default; + + yaml_event_t event_; +}; + +std::unique_ptr<YamlEvent> YamlEvent::create() +{ + struct Deleter : std::default_delete<YamlEvent> { + void operator()(YamlEvent *yamlEvent) + { + yaml_event_delete(yamlEvent->event()); + } + }; + + return std::unique_ptr<YamlEvent>(new YamlEvent(), Deleter()); +} + +YamlEmitter::Emitter::~Emitter() +{ + yaml_emitter_delete(&emitter_); +} + +void YamlEmitter::Emitter::init(File *file) +{ + yaml_emitter_initialize(&emitter_); + yaml_emitter_set_output(&emitter_, yamlWrite, file); +} + +void YamlEmitter::Emitter::logError() +{ + switch (emitter_.error) { + case YAML_MEMORY_ERROR: + LOG(YamlEmitter, Error) + << "Memory error: Not enough memory for emitting"; + break; + + case YAML_WRITER_ERROR: + LOG(YamlEmitter, Error) + << "Writer error: " << emitter_.problem; + break; + + case YAML_EMITTER_ERROR: + LOG(YamlEmitter, Error) + << "Emitter error: " << emitter_.problem; + break; + + default: + LOG(YamlEmitter, Error) << "Internal problem"; + break; + } +} + +int YamlEmitter::Emitter::emit(YamlEvent *event) +{ + int ret = yaml_emitter_emit(&emitter_, event->event()); + if (!ret) { + logError(); + return -EINVAL; + } + + return 0; +} + +YamlEmitter::~YamlEmitter() +{ + std::unique_ptr<YamlEvent> event = YamlEvent::create(); + + yaml_document_end_event_initialize(event->event(), 0); + emitter_.emit(event.get()); + + yaml_stream_end_event_initialize(event->event()); + emitter_.emit(event.get()); +} + +void YamlEmitter::init() +{ + emitter_.init(file_.get()); + + std::unique_ptr<YamlEvent> event = YamlEvent::create(); + + yaml_stream_start_event_initialize(event->event(), YAML_UTF8_ENCODING); + emitter_.emit(event.get()); + + yaml_document_start_event_initialize(event->event(), NULL, NULL, + NULL, 0); + emitter_.emit(event.get()); +} + +std::unique_ptr<YamlEmitter> YamlEmitter::create(std::string &path) +{ + YamlEmitter *emitter = new YamlEmitter(); + + emitter->file_ = std::make_unique<File>(path); + emitter->file_->open(File::OpenModeFlag::WriteOnly); + + emitter->init(); + + return std::unique_ptr<YamlEmitter>(emitter); +} + +int YamlEmitter::emit(std::map<std::string, std::string> map) +{ + std::unique_ptr<YamlEvent> event = YamlEvent::create(); + + auto iter = map.begin(); + + yaml_mapping_start_event_initialize(event->event(), NULL, NULL, + true, YAML_BLOCK_MAPPING_STYLE); + emitter_.emit(event.get()); + + emit(iter->first); + emit(iter->second); + + yaml_mapping_end_event_initialize(event->event()); + emitter_.emit(event.get()); + + return 0; +} + +int YamlEmitter::emit(const std::string &scalar) +{ + const unsigned char *value = reinterpret_cast<const unsigned char *> + (scalar.c_str()); + std::unique_ptr<YamlEvent> event = YamlEvent::create(); + + yaml_scalar_event_initialize(event->event(), NULL, NULL, value, + scalar.length(), true, false, + YAML_PLAIN_SCALAR_STYLE); + emitter_.emit(event.get()); + + return 0; +} + +} /* namespace libcamera */ |