libcamera: yaml_parser: Switch from FILE to File

THe FILE object isn't very user-friendly as it requires manual close.
Replace it with File to provide RAII-style resource management in the
YamlParser API.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2022-05-24 18:29:32 +03:00
parent 27fb47f70b
commit d6d0a675bf
4 changed files with 47 additions and 30 deletions

View file

@ -7,7 +7,6 @@
#pragma once #pragma once
#include <cstdio>
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@ -18,6 +17,7 @@
namespace libcamera { namespace libcamera {
class File;
class YamlParserContext; class YamlParserContext;
class YamlObject class YamlObject
@ -82,7 +82,7 @@ private:
class YamlParser final class YamlParser final
{ {
public: public:
static std::unique_ptr<YamlObject> parse(std::FILE *fh); static std::unique_ptr<YamlObject> parse(File &file);
}; };
} /* namespace libcamera */ } /* namespace libcamera */

View file

@ -10,6 +10,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <libcamera/base/file.h>
#include <libcamera/base/log.h> #include <libcamera/base/log.h>
#include "libcamera/internal/yaml_parser.h" #include "libcamera/internal/yaml_parser.h"
@ -27,7 +28,7 @@ class CameraHalConfig::Private : public Extensible::Private
public: public:
Private(); Private();
int parseConfigFile(FILE *fh, std::map<std::string, CameraConfigData> *cameras); int parseConfigFile(File &file, std::map<std::string, CameraConfigData> *cameras);
private: private:
int parseCameraConfigData(const std::string &cameraId, const YamlObject &); int parseCameraConfigData(const std::string &cameraId, const YamlObject &);
@ -41,7 +42,7 @@ CameraHalConfig::Private::Private()
{ {
} }
int CameraHalConfig::Private::parseConfigFile(FILE *fh, int CameraHalConfig::Private::parseConfigFile(File &file,
std::map<std::string, CameraConfigData> *cameras) std::map<std::string, CameraConfigData> *cameras)
{ {
/* /*
@ -65,7 +66,7 @@ int CameraHalConfig::Private::parseConfigFile(FILE *fh,
cameras_ = cameras; cameras_ = cameras;
std::unique_ptr<YamlObject> root = YamlParser::parse(fh); std::unique_ptr<YamlObject> root = YamlParser::parse(file);
if (!root) if (!root)
return -EINVAL; return -EINVAL;
@ -169,9 +170,9 @@ int CameraHalConfig::parseConfigurationFile()
return -ENOENT; return -ENOENT;
} }
FILE *fh = fopen(filePath.c_str(), "r"); File file(filePath);
if (!fh) { if (!file.open(File::OpenModeFlag::ReadOnly)) {
int ret = -errno; int ret = file.error();
LOG(HALConfig, Error) << "Failed to open configuration file " LOG(HALConfig, Error) << "Failed to open configuration file "
<< filePath << ": " << strerror(-ret); << filePath << ": " << strerror(-ret);
return ret; return ret;
@ -179,8 +180,7 @@ int CameraHalConfig::parseConfigurationFile()
exists_ = true; exists_ = true;
int ret = _d()->parseConfigFile(fh, &cameras_); int ret = _d()->parseConfigFile(file, &cameras_);
fclose(fh);
if (ret) if (ret)
return -EINVAL; return -EINVAL;

View file

@ -11,6 +11,7 @@
#include <errno.h> #include <errno.h>
#include <functional> #include <functional>
#include <libcamera/base/file.h>
#include <libcamera/base/log.h> #include <libcamera/base/log.h>
#include <yaml.h> #include <yaml.h>
@ -345,7 +346,7 @@ public:
YamlParserContext(); YamlParserContext();
~YamlParserContext(); ~YamlParserContext();
int init(std::FILE *fh); int init(File &file);
int parseContent(YamlObject &yamlObject); int parseContent(YamlObject &yamlObject);
private: private:
@ -358,6 +359,9 @@ private:
}; };
using EventPtr = std::unique_ptr<yaml_event_t, EventDeleter>; using EventPtr = std::unique_ptr<yaml_event_t, EventDeleter>;
static int yamlRead(void *data, unsigned char *buffer, size_t size,
size_t *sizeRead);
EventPtr nextEvent(); EventPtr nextEvent();
void readValue(std::string &value, EventPtr event); void readValue(std::string &value, EventPtr event);
@ -399,13 +403,13 @@ YamlParserContext::~YamlParserContext()
* \param[in] fh The YAML file to parse * \param[in] fh The YAML file to parse
* *
* Prior to parsing the YAML content, the YamlParserContext must be initialized * Prior to parsing the YAML content, the YamlParserContext must be initialized
* with an opened FILE to create an internal parser. The FILE needs to stay * with a file to create an internal parser. The file needs to stay valid until
* valid during the process. * parsing completes.
* *
* \return 0 on success or a negative error code otherwise * \return 0 on success or a negative error code otherwise
* \retval -EINVAL The parser has failed to initialize * \retval -EINVAL The parser has failed to initialize
*/ */
int YamlParserContext::init(std::FILE *fh) int YamlParserContext::init(File &file)
{ {
/* yaml_parser_initialize returns 1 when it succeededs */ /* yaml_parser_initialize returns 1 when it succeededs */
if (!yaml_parser_initialize(&parser_)) { if (!yaml_parser_initialize(&parser_)) {
@ -413,11 +417,25 @@ int YamlParserContext::init(std::FILE *fh)
return -EINVAL; return -EINVAL;
} }
parserValid_ = true; parserValid_ = true;
yaml_parser_set_input_file(&parser_, fh); yaml_parser_set_input(&parser_, &YamlParserContext::yamlRead, &file);
return 0; return 0;
} }
int YamlParserContext::yamlRead(void *data, unsigned char *buffer, size_t size,
size_t *sizeRead)
{
File *file = static_cast<File *>(data);
Span<unsigned char> buf{ buffer, size };
ssize_t ret = file->read(buf);
if (ret < 0)
return 0;
*sizeRead = ret;
return 1;
}
/** /**
* \fn YamlParserContext::nextEvent() * \fn YamlParserContext::nextEvent()
* \brief Get the next event * \brief Get the next event
@ -655,21 +673,20 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even
*/ */
/** /**
* \fn YamlParser::parse()
* \brief Parse a YAML file as a YamlObject * \brief Parse a YAML file as a YamlObject
* \param[in] fh The YAML file to parse * \param[in] file The YAML file to parse
* *
* The YamlParser::parse() function takes an open FILE, parses its contents, and * The YamlParser::parse() function takes a file, parses its contents, and
* returns a pointer to a YamlObject corresponding to the root node of the YAML * returns a pointer to a YamlObject corresponding to the root node of the YAML
* document. The caller is responsible for closing the file. * document.
* *
* \return Pointer to result YamlObject on success or nullptr otherwise * \return Pointer to result YamlObject on success or nullptr otherwise
*/ */
std::unique_ptr<YamlObject> YamlParser::parse(std::FILE *fh) std::unique_ptr<YamlObject> YamlParser::parse(File &file)
{ {
YamlParserContext context; YamlParserContext context;
if (context.init(fh)) if (context.init(file))
return nullptr; return nullptr;
std::unique_ptr<YamlObject> root(new YamlObject()); std::unique_ptr<YamlObject> root(new YamlObject());

View file

@ -9,6 +9,8 @@
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
#include <libcamera/base/file.h>
#include "libcamera/internal/yaml_parser.h" #include "libcamera/internal/yaml_parser.h"
#include "test.h" #include "test.h"
@ -69,29 +71,27 @@ protected:
int run() int run()
{ {
/* Test invalid YAML file */ /* Test invalid YAML file */
FILE *fh = fopen(invalidYamlFile_.c_str(), "r"); File file{ invalidYamlFile_ };
if (!fh) { if (!file.open(File::OpenModeFlag::ReadOnly)) {
cerr << "Fail to open invalid YAML file" << std::endl; cerr << "Fail to open invalid YAML file" << std::endl;
return TestFail; return TestFail;
} }
std::unique_ptr<YamlObject> root = YamlParser::parse(fh); std::unique_ptr<YamlObject> root = YamlParser::parse(file);
fclose(fh);
if (root) { if (root) {
cerr << "Invalid YAML file parse successfully" << std::endl; cerr << "Invalid YAML file parse successfully" << std::endl;
return TestFail; return TestFail;
} }
/* Test YAML file */ /* Test YAML file */
fh = fopen(testYamlFile_.c_str(), "r"); file.close();
if (!fh) { file.setFileName(testYamlFile_);
if (!file.open(File::OpenModeFlag::ReadOnly)) {
cerr << "Fail to open test YAML file" << std::endl; cerr << "Fail to open test YAML file" << std::endl;
return TestFail; return TestFail;
} }
root = YamlParser::parse(fh); root = YamlParser::parse(file);
fclose(fh);
if (!root) { if (!root) {
cerr << "Fail to parse test YAML file: " << std::endl; cerr << "Fail to parse test YAML file: " << std::endl;