// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/json/ #ifndef TAO_JSON_MSGPACK_INTERNAL_GRAMMAR_HPP #define TAO_JSON_MSGPACK_INTERNAL_GRAMMAR_HPP #include #include #include #include "../../binary_view.hpp" #include "../../external/pegtl.hpp" #include "../../internal/format.hpp" #include "../../internal/parse_util.hpp" #include "../../utf8.hpp" #include "format.hpp" namespace tao::json::msgpack::internal { template< utf8_mode U, typename Input > [[nodiscard]] std::string_view read_string( Input& in ) { const auto b = json::internal::peek_uint8( in ); if( ( std::uint8_t( format::FIXSTR_MIN ) <= b ) && ( b <= std::uint8_t( format::FIXSTR_MAX ) ) ) { in.bump_in_this_line(); return json::internal::read_string< U, std::string_view >( in, b - std::uint8_t( format::FIXSTR_MIN ) ); } switch( format( b ) ) { case format::STR8: return json::internal::read_string< U, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint8_t >( in, 1 ) ); case format::STR16: return json::internal::read_string< U, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) ); case format::STR32: return json::internal::read_string< U, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) ); default: throw pegtl::parse_error( "unexpected key type", in ); } } template< utf8_mode V > struct data { using analyze_t = pegtl::analysis::generic< pegtl::analysis::rule_type::any >; template< pegtl::apply_mode A, pegtl::rewind_mode M, template< typename... > class Action, template< typename... > class Control, typename Input, typename Consumer > [[nodiscard]] static bool match( Input& in, Consumer& consumer ) { if( !in.empty() ) { parse_unsafe( in, consumer ); return true; } return false; } private: template< typename Input, typename Consumer > static void parse_unsafe( Input& in, Consumer& consumer ) { const auto b = in.peek_uint8(); if( b <= std::uint8_t( format::POSITIVE_MAX ) ) { consumer.number( std::uint64_t( b ) ); in.bump_in_this_line(); return; } if( b >= std::uint8_t( format::NEGATIVE_MIN ) ) { consumer.number( std::int64_t( std::int8_t( b ) ) ); in.bump_in_this_line(); return; } if( ( std::uint8_t( format::FIXMAP_MIN ) <= b ) && ( b <= std::uint8_t( format::FIXMAP_MAX ) ) ) { in.bump_in_this_line(); parse_object( in, consumer, b - std::uint8_t( format::FIXMAP_MIN ) ); return; } if( ( std::uint8_t( format::FIXARRAY_MIN ) <= b ) && ( b <= std::uint8_t( format::FIXARRAY_MAX ) ) ) { in.bump_in_this_line(); parse_array( in, consumer, b - std::uint8_t( format::FIXARRAY_MIN ) ); return; } if( ( std::uint8_t( format::FIXSTR_MIN ) <= b ) && ( b <= std::uint8_t( format::FIXSTR_MAX ) ) ) { in.bump_in_this_line(); consumer.string( json::internal::read_string< V, std::string_view >( in, b - std::uint8_t( format::FIXSTR_MIN ) ) ); return; } switch( format( b ) ) { case format::NIL: consumer.null(); in.bump_in_this_line(); return; case format::UNUSED: throw pegtl::parse_error( "unused first byte 0xc1", in ); case format::BOOL_TRUE: consumer.boolean( true ); in.bump_in_this_line(); return; case format::BOOL_FALSE: consumer.boolean( false ); in.bump_in_this_line(); return; case format::BIN8: consumer.binary( json::internal::read_string< utf8_mode::trust, tao::binary_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint8_t >( in, 1 ) ) ); return; case format::BIN16: consumer.binary( json::internal::read_string< utf8_mode::trust, tao::binary_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) ) ); return; case format::BIN32: consumer.binary( json::internal::read_string< utf8_mode::trust, tao::binary_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) ) ); return; case format::EXT8: discard( in, json::internal::read_big_endian_number< std::size_t, std::uint8_t >( in, 1 ) + 1 ); return; case format::EXT16: discard( in, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) + 1 ); return; case format::EXT32: discard( in, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) + 1 ); return; case format::FLOAT32: consumer.number( json::internal::read_big_endian_number< double, float >( in, 1 ) ); return; case format::FLOAT64: consumer.number( json::internal::read_big_endian_number< double >( in, 1 ) ); return; case format::UINT8: consumer.number( json::internal::read_big_endian_number< std::uint64_t, std::uint8_t >( in, 1 ) ); return; case format::UINT16: consumer.number( json::internal::read_big_endian_number< std::uint64_t, std::uint16_t >( in, 1 ) ); return; case format::UINT32: consumer.number( json::internal::read_big_endian_number< std::uint64_t, std::uint32_t >( in, 1 ) ); return; case format::UINT64: consumer.number( json::internal::read_big_endian_number< std::uint64_t >( in, 1 ) ); return; case format::INT8: consumer.number( json::internal::read_big_endian_number< std::int64_t, std::int8_t >( in, 1 ) ); return; case format::INT16: consumer.number( json::internal::read_big_endian_number< std::int64_t, std::int16_t >( in, 1 ) ); return; case format::INT32: consumer.number( json::internal::read_big_endian_number< std::int64_t, std::int32_t >( in, 1 ) ); return; case format::INT64: consumer.number( json::internal::read_big_endian_number< std::int64_t >( in, 1 ) ); return; case format::FIXEXT1: discard( in, 3 ); return; case format::FIXEXT2: discard( in, 4 ); return; case format::FIXEXT4: discard( in, 6 ); return; case format::FIXEXT8: discard( in, 10 ); return; case format::FIXEXT16: discard( in, 18 ); return; case format::STR8: consumer.string( json::internal::read_string< V, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint8_t >( in, 1 ) ) ); return; case format::STR16: consumer.string( json::internal::read_string< V, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) ) ); return; case format::STR32: consumer.string( json::internal::read_string< V, std::string_view >( in, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) ) ); return; case format::ARRAY16: parse_array( in, consumer, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) ); return; case format::ARRAY32: parse_array( in, consumer, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) ); return; case format::MAP16: parse_object( in, consumer, json::internal::read_big_endian_number< std::size_t, std::uint16_t >( in, 1 ) ); return; case format::MAP32: parse_object( in, consumer, json::internal::read_big_endian_number< std::size_t, std::uint32_t >( in, 1 ) ); return; default: // LCOV_EXCL_START assert( false ); // LCOV_EXCL_STOP } } template< typename Input > static void discard( Input& in, const std::size_t count ) { json::internal::throw_on_empty( in, count ); in.bump_in_this_line( count ); } template< typename Input, typename Consumer > static void parse_array( Input& in, Consumer& consumer, const std::size_t size ) { consumer.begin_array( size ); for( std::size_t i = 0; i < size; ++i ) { json::internal::throw_on_empty( in ); parse_unsafe( in, consumer ); consumer.element(); } consumer.end_array( size ); } template< typename Input, typename Consumer > static void parse_object( Input& in, Consumer& consumer, const std::size_t size ) { consumer.begin_object( size ); for( std::size_t i = 0; i < size; ++i ) { consumer.key( read_string< V >( in ) ); json::internal::throw_on_empty( in ); parse_unsafe( in, consumer ); consumer.member(); } consumer.end_object( size ); } }; template< utf8_mode V > struct basic_grammar : pegtl::must< data< V >, pegtl::eof > { }; template< utf8_mode V > struct basic_embedded : pegtl::must< data< V > > { }; using grammar = basic_grammar< utf8_mode::check >; using embedded = basic_embedded< utf8_mode::check >; } // namespace tao::json::msgpack::internal #endif