🐛 fix bug in CBOR tag handling
This commit is contained in:
		
							parent
							
								
									43e07bb92d
								
							
						
					
					
						commit
						480ad529e3
					
				
					 3 changed files with 73 additions and 44 deletions
				
			
		| 
						 | 
				
			
			@ -393,14 +393,14 @@ class binary_reader
 | 
			
		|||
 | 
			
		||||
    /*!
 | 
			
		||||
    @param[in] get_char  whether a new character should be retrieved from the
 | 
			
		||||
                         input (true, default) or whether the last read
 | 
			
		||||
                         character should be considered instead
 | 
			
		||||
                         input (true) or whether the last read character should
 | 
			
		||||
                         be considered instead (false)
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
 | 
			
		||||
    @return whether a valid CBOR value was passed to the SAX parser
 | 
			
		||||
    */
 | 
			
		||||
    bool parse_cbor_internal(const bool get_char = true,
 | 
			
		||||
                             cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | 
			
		||||
    bool parse_cbor_internal(const bool get_char,
 | 
			
		||||
                             const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        switch (get_char ? get() : current)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -606,34 +606,34 @@ class binary_reader
 | 
			
		|||
            case 0x95:
 | 
			
		||||
            case 0x96:
 | 
			
		||||
            case 0x97:
 | 
			
		||||
                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
 | 
			
		||||
                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0x98: // array (one-byte uint8_t for n follows)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint8_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x99: // array (two-byte uint16_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint16_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9A: // array (four-byte uint32_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint32_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9B: // array (eight-byte uint64_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint64_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9F: // array (indefinite length)
 | 
			
		||||
                return get_cbor_array(std::size_t(-1));
 | 
			
		||||
                return get_cbor_array(std::size_t(-1), tag_handler);
 | 
			
		||||
 | 
			
		||||
            // map (0x00..0x17 pairs of data items follow)
 | 
			
		||||
            case 0xA0:
 | 
			
		||||
| 
						 | 
				
			
			@ -660,34 +660,34 @@ class binary_reader
 | 
			
		|||
            case 0xB5:
 | 
			
		||||
            case 0xB6:
 | 
			
		||||
            case 0xB7:
 | 
			
		||||
                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
 | 
			
		||||
                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0xB8: // map (one-byte uint8_t for n follows)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint8_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xB9: // map (two-byte uint16_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint16_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBA: // map (four-byte uint32_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint32_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBB: // map (eight-byte uint64_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint64_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBF: // map (indefinite length)
 | 
			
		||||
                return get_cbor_object(std::size_t(-1));
 | 
			
		||||
                return get_cbor_object(std::size_t(-1), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0xC6: // tagged item
 | 
			
		||||
            case 0xC7:
 | 
			
		||||
| 
						 | 
				
			
			@ -1030,9 +1030,11 @@ class binary_reader
 | 
			
		|||
    /*!
 | 
			
		||||
    @param[in] len  the length of the array or std::size_t(-1) for an
 | 
			
		||||
                    array of indefinite size
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
    @return whether array creation completed
 | 
			
		||||
    */
 | 
			
		||||
    bool get_cbor_array(const std::size_t len)
 | 
			
		||||
    bool get_cbor_array(const std::size_t len,
 | 
			
		||||
                        const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,7 +1045,7 @@ class binary_reader
 | 
			
		|||
        {
 | 
			
		||||
            for (std::size_t i = 0; i < len; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1053,7 +1055,7 @@ class binary_reader
 | 
			
		|||
        {
 | 
			
		||||
            while (get() != 0xFF)
 | 
			
		||||
            {
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false)))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1066,9 +1068,11 @@ class binary_reader
 | 
			
		|||
    /*!
 | 
			
		||||
    @param[in] len  the length of the object or std::size_t(-1) for an
 | 
			
		||||
                    object of indefinite size
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
    @return whether object creation completed
 | 
			
		||||
    */
 | 
			
		||||
    bool get_cbor_object(const std::size_t len)
 | 
			
		||||
    bool get_cbor_object(const std::size_t len,
 | 
			
		||||
                         const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -1086,7 +1090,7 @@ class binary_reader
 | 
			
		|||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1102,7 +1106,7 @@ class binary_reader
 | 
			
		|||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6402,14 +6402,14 @@ class binary_reader
 | 
			
		|||
 | 
			
		||||
    /*!
 | 
			
		||||
    @param[in] get_char  whether a new character should be retrieved from the
 | 
			
		||||
                         input (true, default) or whether the last read
 | 
			
		||||
                         character should be considered instead
 | 
			
		||||
                         input (true) or whether the last read character should
 | 
			
		||||
                         be considered instead (false)
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
 | 
			
		||||
    @return whether a valid CBOR value was passed to the SAX parser
 | 
			
		||||
    */
 | 
			
		||||
    bool parse_cbor_internal(const bool get_char = true,
 | 
			
		||||
                             cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | 
			
		||||
    bool parse_cbor_internal(const bool get_char,
 | 
			
		||||
                             const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        switch (get_char ? get() : current)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -6615,34 +6615,34 @@ class binary_reader
 | 
			
		|||
            case 0x95:
 | 
			
		||||
            case 0x96:
 | 
			
		||||
            case 0x97:
 | 
			
		||||
                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
 | 
			
		||||
                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0x98: // array (one-byte uint8_t for n follows)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint8_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x99: // array (two-byte uint16_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint16_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9A: // array (four-byte uint32_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint32_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9B: // array (eight-byte uint64_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint64_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0x9F: // array (indefinite length)
 | 
			
		||||
                return get_cbor_array(std::size_t(-1));
 | 
			
		||||
                return get_cbor_array(std::size_t(-1), tag_handler);
 | 
			
		||||
 | 
			
		||||
            // map (0x00..0x17 pairs of data items follow)
 | 
			
		||||
            case 0xA0:
 | 
			
		||||
| 
						 | 
				
			
			@ -6669,34 +6669,34 @@ class binary_reader
 | 
			
		|||
            case 0xB5:
 | 
			
		||||
            case 0xB6:
 | 
			
		||||
            case 0xB7:
 | 
			
		||||
                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
 | 
			
		||||
                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0xB8: // map (one-byte uint8_t for n follows)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint8_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xB9: // map (two-byte uint16_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint16_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBA: // map (four-byte uint32_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint32_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBB: // map (eight-byte uint64_t for n follow)
 | 
			
		||||
            {
 | 
			
		||||
                std::uint64_t len{};
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len));
 | 
			
		||||
                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case 0xBF: // map (indefinite length)
 | 
			
		||||
                return get_cbor_object(std::size_t(-1));
 | 
			
		||||
                return get_cbor_object(std::size_t(-1), tag_handler);
 | 
			
		||||
 | 
			
		||||
            case 0xC6: // tagged item
 | 
			
		||||
            case 0xC7:
 | 
			
		||||
| 
						 | 
				
			
			@ -7039,9 +7039,11 @@ class binary_reader
 | 
			
		|||
    /*!
 | 
			
		||||
    @param[in] len  the length of the array or std::size_t(-1) for an
 | 
			
		||||
                    array of indefinite size
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
    @return whether array creation completed
 | 
			
		||||
    */
 | 
			
		||||
    bool get_cbor_array(const std::size_t len)
 | 
			
		||||
    bool get_cbor_array(const std::size_t len,
 | 
			
		||||
                        const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -7052,7 +7054,7 @@ class binary_reader
 | 
			
		|||
        {
 | 
			
		||||
            for (std::size_t i = 0; i < len; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -7062,7 +7064,7 @@ class binary_reader
 | 
			
		|||
        {
 | 
			
		||||
            while (get() != 0xFF)
 | 
			
		||||
            {
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false)))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -7075,9 +7077,11 @@ class binary_reader
 | 
			
		|||
    /*!
 | 
			
		||||
    @param[in] len  the length of the object or std::size_t(-1) for an
 | 
			
		||||
                    object of indefinite size
 | 
			
		||||
    @param[in] tag_handler how CBOR tags should be treated
 | 
			
		||||
    @return whether object creation completed
 | 
			
		||||
    */
 | 
			
		||||
    bool get_cbor_object(const std::size_t len)
 | 
			
		||||
    bool get_cbor_object(const std::size_t len,
 | 
			
		||||
                         const cbor_tag_handler_t tag_handler)
 | 
			
		||||
    {
 | 
			
		||||
        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -7095,7 +7099,7 @@ class binary_reader
 | 
			
		|||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -7111,7 +7115,7 @@ class binary_reader
 | 
			
		|||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal()))
 | 
			
		||||
                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2722,4 +2722,25 @@ TEST_CASE("Tagged values")
 | 
			
		|||
            CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore), json::parse_error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SECTION("tagged binary")
 | 
			
		||||
    {
 | 
			
		||||
        // create a binary value of subtype 42
 | 
			
		||||
        json j;
 | 
			
		||||
        j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42);
 | 
			
		||||
 | 
			
		||||
        // convert to CBOR
 | 
			
		||||
        const auto v = json::to_cbor(j);
 | 
			
		||||
        CHECK(v == std::vector<std::uint8_t> {0xA1, 0x66, 0x62, 0x69, 0x6E, 0x61, 0x72, 0x79, 0xD8, 0x2A, 0x44, 0xCA, 0xFE, 0xBA, 0xBE});
 | 
			
		||||
 | 
			
		||||
        // parse error when parsing tagged value
 | 
			
		||||
        CHECK_THROWS_AS(json::from_cbor(v), json::parse_error);
 | 
			
		||||
        CHECK_THROWS_WITH(json::from_cbor(v), "[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: invalid byte: 0xD8");
 | 
			
		||||
 | 
			
		||||
        // binary without subtype when tags are ignored
 | 
			
		||||
        json jb = json::from_cbor(v, true, true, json::cbor_tag_handler_t::ignore);
 | 
			
		||||
        CHECK(jb.is_object());
 | 
			
		||||
        CHECK(jb["binary"].is_binary());
 | 
			
		||||
        CHECK(!jb["binary"].get_binary().has_subtype());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue