blob: d11976a12c748a0b4b8adab963aef814cac152cb [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <string>
#include <vector>
#include <rapidjson/document.h>
#include "lib/fit/function.h"
#include "src/lib/fxl/macros.h"
namespace json_parser {
// A JSON parser utility class.
// This class provides general facilities to parse a JSON file, and report
// errors. If parsing succeeds, ReadFrom() returns a rapidjson::Document
// representing the file. The class is agnostic to the actual structure of
// the document -- client code is responsible for interpreting the
// rapidjson::Document, which could contain any valid JSON.
class JSONParser {
JSONParser() = default;
JSONParser(JSONParser&&) = default;
JSONParser& operator=(JSONParser&&) = default;
// Parses a JSON file. If reading or parsing the file fails, reports errors in
// error_str(). May be called multiple times, for example on multiple files,
// in which case any previous errors will be retained.
rapidjson::Document ParseFromFile(const std::string& file);
// Like |ParseFromFile|, but relative to a directory.
rapidjson::Document ParseFromFileAt(int dirfd, const std::string& file);
// Initialize the document from a JSON string |data|. If parsing fails,
// reports errors in error_str(). |file| is not read, but it is used as the
// prefix for lines in error_str(). May be called multiple times, for example
// on multiple files, in which case any previous errors will be retained.
rapidjson::Document ParseFromString(const std::string& data, const std::string& file);
// Initialize multiple documents from files in a directory. |cb| is
// called for each file that parses. The traversal is not recursive, and all
// files in the directory are expected to be JSON files. If the directory does
// not exist, no error is reported, and no callbacks are called. Callers
// wishing to identify such a state should stat the path themselves.
// It is up to the caller to decide how to merge multiple documents.
void ParseFromDirectory(const std::string& path, fit::function<void(rapidjson::Document)> cb);
// Like |ParseFromDirectory|, but relative to a directory.
void ParseFromDirectoryAt(int dirfd, const std::string& path,
fit::function<void(rapidjson::Document)> cb);
// Copies the string values from a |name|d |value| to the |out| vector.
// Clears |out| and calls ReportError() if |value| does not refer to an array,
// or if the array contains non-string values.
void CopyStringArray(const std::string& name, const rapidjson::Value& value,
std::vector<std::string>* out);
// Returns true if there was an error initializing the document.
bool HasError() const;
// If HasError() is true, returns a human-readable string describing the
// error(s) initializing the document.
std::string error_str() const;
// Records an error initializing the object. Multiple errors may be recorded.
void ReportError(const std::string& error);
// Internal version of |ReportError| that includes an offset.
void ReportErrorInternal(size_t offset, const std::string& error);
std::vector<std::string> errors_;
// Stores the filename, for reporting debug information.
std::string file_;
// Stores the file content, for reporting debug information.
std::string data_;
} // namespace json_parser
namespace json {
// The JSONParser should be used from the json_parser namespace to be consistent with the rest of
// this library but currently many callsites expect this to live in the json namespace. This alias
// allows both names to work.
// TODO( Update callers to new name and remove this alias.
using JSONParser = ::json_parser::JSONParser;
} // namespace json