File tree Expand file tree Collapse file tree 11 files changed +93
-13
lines changed Expand file tree Collapse file tree 11 files changed +93
-13
lines changed Original file line number Diff line number Diff line change @@ -35,6 +35,7 @@ struct handler
3535 max_string_size = string::max_size();
3636
3737 value_stack st;
38+ bool ignore_duplicate_keys = true ;
3839
3940 template <class ... Args>
4041 explicit
Original file line number Diff line number Diff line change 5151handler::
5252on_object_end (
5353 std::size_t n,
54- error_code&)
54+ error_code& ec )
5555{
56+ if ( !ignore_duplicate_keys )
57+ ec = st.check_duplicates (n);
58+ if ( ec.failed () )
59+ return false ;
60+
5661 st.push_object (n);
5762 return true ;
5863}
Original file line number Diff line number Diff line change @@ -66,6 +66,9 @@ enum class error
6666 // / error occured when trying to read input
6767 input_error,
6868
69+ // / duplicate object key
70+ duplicate_key,
71+
6972 //
7073 // generic errors
7174 //
Original file line number Diff line number Diff line change @@ -45,6 +45,7 @@ case error::array_too_large: return "array too large";
4545case error::key_too_large: return " key too large" ;
4646case error::string_too_large: return " string too large" ;
4747case error::input_error: return " input error" ;
48+ case error::duplicate_key: return " duplicate key" ;
4849
4950case error::exception: return " got exception" ;
5051case error::test_failure: return " test failure" ;
@@ -93,6 +94,7 @@ case error::array_too_large:
9394case error::key_too_large:
9495case error::string_too_large:
9596case error::input_error:
97+ case error::duplicate_key:
9698 return condition::parse_error;
9799
98100case error::missing_slash:
Original file line number Diff line number Diff line change @@ -32,20 +32,19 @@ parser(
3232 size)
3333{
3434 reset ();
35+ p_.handler ().ignore_duplicate_keys = opt.ignore_duplicate_keys ;
3536}
3637
3738parser::
3839parser (
3940 storage_ptr sp,
4041 parse_options const & opt) noexcept
41- : p_(
42- opt,
42+ : parser(
4343 std::move (sp),
44- nullptr,
44+ opt,
45+ static_cast<unsigned char*>(nullptr ),
4546 0)
46- {
47- reset ();
48- }
47+ { }
4948
5049void
5150parser::
Original file line number Diff line number Diff line change @@ -32,20 +32,19 @@ stream_parser(
3232 size)
3333{
3434 reset ();
35+ p_.handler ().ignore_duplicate_keys = opt.ignore_duplicate_keys ;
3536}
3637
3738stream_parser::
3839stream_parser (
3940 storage_ptr sp,
4041 parse_options const & opt) noexcept
41- : p_(
42- opt,
42+ : stream_parser(
4343 std::move (sp),
44- nullptr,
44+ opt,
45+ static_cast<unsigned char*>(nullptr ),
4546 0)
46- {
47- reset ();
48- }
47+ { }
4948
5049void
5150stream_parser::
Original file line number Diff line number Diff line change @@ -82,6 +82,35 @@ has_chars()
8282 return chars_ != 0 ;
8383}
8484
85+ error_code
86+ value_stack::
87+ stack::
88+ check_duplicates (std::size_t n)
89+ {
90+ error_code ec;
91+
92+ for ( value* first = top_ - 2 * n; first != top_; first += 2 )
93+ {
94+ value* other = first + 2 ;
95+ while ( true )
96+ {
97+ if ( first->as_string () == other->as_string () )
98+ {
99+ BOOST_JSON_FAIL ( ec, error::duplicate_key );
100+ goto before_return;
101+ }
102+
103+ if ( other == top_ )
104+ break ;
105+
106+ other += 2 ;
107+ }
108+ }
109+
110+ before_return:
111+ return ec;
112+ }
113+
85114// --------------------------------------
86115
87116// destroy the values but
@@ -467,6 +496,13 @@ push_null()
467496 st_.push (nullptr , sp_);
468497}
469498
499+ error_code
500+ value_stack::
501+ check_duplicates (std::size_t n)
502+ {
503+ return st_.check_duplicates (n);
504+ }
505+
470506BOOST_JSON_NS_END
471507
472508#endif
Original file line number Diff line number Diff line change @@ -76,6 +76,20 @@ struct parse_options
7676 @ref stream_parser.
7777 */
7878 bool allow_invalid_utf8 = false ;
79+
80+
81+ /* * Unique keys restriction setting
82+
83+ Forbid duplicate keys to appear in objects.
84+
85+ @note Since @ref basic_parser doesn't store parsed elements directly,
86+ this option has to be taken account by implementers of handlers.
87+
88+ @see
89+ @ref basic_parser,
90+ @ref stream_parser.
91+ */
92+ bool ignore_duplicate_keys = true ;
7993};
8094
8195BOOST_JSON_NS_END
Original file line number Diff line number Diff line change @@ -140,6 +140,7 @@ class value_stack
140140 inline void run_dtors (bool b) noexcept ;
141141 inline std::size_t size () const noexcept ;
142142 inline bool has_chars ();
143+ inline error_code check_duplicates (std::size_t n);
143144
144145 inline void clear () noexcept ;
145146 inline void maybe_grow ();
@@ -501,6 +502,10 @@ class value_stack
501502 BOOST_JSON_DECL
502503 void
503504 push_null ();
505+
506+ BOOST_JSON_DECL
507+ error_code
508+ check_duplicates (std::size_t n);
504509};
505510
506511BOOST_JSON_NS_END
Original file line number Diff line number Diff line change @@ -61,6 +61,7 @@ class error_test
6161 check (condition::parse_error, error::key_too_large);
6262 check (condition::parse_error, error::string_too_large);
6363 check (condition::parse_error, error::input_error);
64+ check (condition::parse_error, error::duplicate_key);
6465
6566 check (condition::pointer_parse_error, error::missing_slash);
6667 check (condition::pointer_parse_error, error::invalid_escape);
You can’t perform that action at this time.
0 commit comments