| // 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_ |