blob: e26511727a0692cb760f58d1d3ab2a17af3aebb2 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBIPP_PARSER_H_
#define LIBIPP_PARSER_H_
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
#include "errors.h"
#include "frame.h"
namespace ipp {
// The errors spotted by the parser. Comments next to the values describe
// actions taken by the parser.
enum class ParserCode : uint8_t {
kBooleanValueOutOfRange = 0, // the boolean value was set to 1
kValueMismatchTagConverted, // the value was converted
kOutOfBandValueWithNonEmptyData, // the data field was ignored
kOutOfBandAttributeWithManyValues, // additional values were ignored
kValueMismatchTagOmitted, // the value was omitted
kUnsupportedValueTag, // the value was omitted
kValueInvalidSize, // the value was omitted
kAttributeNoValues, // the attribute was omitted
kAttributeNameConflict, // the attribute was omitted
kErrorWhenAddingAttribute, // the attribute was omitted
kErrorWhenAddingGroup, // the group was omitted
kFirstCritialError = 16,
kAttributeNameIsEmpty = 16, // the parser stopped
kUnexpectedEndOfFrame, // the parser stopped
kGroupTagWasExpected, // the parser stopped
kEmptyNameExpectedInTNV, // the parser stopped
kEmptyValueExpectedInTNV, // the parser stopped
kNegativeNameLengthInTNV, // the parser stopped
kNegativeValueLengthInTNV, // the parser stopped
kTNVWithUnexpectedValueTag, // the parser stopped
kUnexpectedEndOfGroup, // the parser stopped
kLimitOnCollectionsLevelExceeded, // the parser stopped
kLimitOnGroupsCountExceeded, // the parser stopped
};
// After spotting a critical error the parser cannot continue and will stop
// parsing before reaching the end of input frame.
constexpr bool IsCritical(ParserCode code) {
return code >= ParserCode::kFirstCritialError;
}
// Returns a string representation of `code`. Returned string contains a name
// of corresponding enum's value and has no whitespaces.
LIBIPP_EXPORT std::string_view ToStrView(ParserCode code);
// Represents an error spotted by the parser when parsing an element pointed
// by `path`.
struct ParserError {
AttrPath path;
ParserCode code;
// Position in the input buffer, set to -1 if unknown.
ssize_t buf_offset = -1;
};
// Returns a one line string representation of the `error`. There is no EOL
// characters in the returned message.
LIBIPP_EXPORT std::string ToString(const ParserError& error);
// The interface of parser log.
class ParserLog {
public:
ParserLog() = default;
ParserLog(const ParserLog&) = delete;
ParserLog& operator=(const ParserLog&) = delete;
virtual ~ParserLog() = default;
// Reports an `error` when parsing an element pointed by `path`.
// `IsCritical(error.code)` == true DOES NOT mean that this call is the last
// one. Also, there may be more than one call with critical errors during
// a single parser run.
virtual void AddParserError(const ParserError& error) = 0;
};
// Simple implementation of the ParserLog interface. It just saves the first
// `max_entries_count` (see the constructor) parser errors.
class LIBIPP_EXPORT SimpleParserLog : public ParserLog {
public:
explicit SimpleParserLog(size_t max_entries_count = 100)
: max_entries_count_(max_entries_count) {}
void AddParserError(const ParserError& error) override;
// Returns all errors added by AddParserError() in the same order they were
// added. The log is truncated <=> the number of entries reached the value
// `max_entries_count` passed to the constructor.
const std::vector<ParserError>& Errors() const { return errors_; }
// Returns all critical errors added by AddParserError() in the same order
// they were added. The log is not truncated, but there is no more than a
// couple of critical errors in a single parser run. All critical errors are
// also included in Errors() (if it doesn't reach the limit).
const std::vector<ParserError>& CriticalErrors() const {
return critical_errors_;
}
private:
const size_t max_entries_count_;
std::vector<ParserError> errors_;
std::vector<ParserError> critical_errors_;
};
// Parse the frame of `size` bytes saved in `buffer`. Errors detected by the
// parser are saved to `log`. If you use SimpleParserLog as `log` you can easily
// distinguish three cases:
//
// 1. When the parser completed parsing without errors then:
// * log.Errors().empty() == true (=> log.CriticalErrors().empty() == true).
// 2. When the parser completed parsing with some non-critical errors then:
// * log.Errors().empty() == false; AND
// * log.CriticalErrors().empty() == true.
// 3. When the parser spotted a critical error and stopped then:
// * log.Errors().empty() == false; AND
// * log.CriticalErrors().empty() == false.
//
// In case 2, the output frame may have some values or attributes missing.
// In case 3, the output frame may cover only part of the input buffer or be
// empty and have all basic parameters set to zeroes like after Frame()
// constructor (it happens when nothing was parsed).
// In all cases, the returned object is consistent and can be passed to other
// libipp functions.
Frame LIBIPP_EXPORT Parse(const uint8_t* buffer, size_t size, ParserLog& log);
} // namespace ipp
#endif // LIBIPP_PARSER_H_