Skip to content

Commit 4cab96b

Browse files
committed
Fix escaping for modifying json pointer access
1 parent cfdc478 commit 4cab96b

File tree

3 files changed

+51
-32
lines changed

3 files changed

+51
-32
lines changed

include/tao/json/json_pointer.hh

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ namespace tao
3535
}
3636
}
3737

38+
inline std::string json_pointer_next_token( const char * & p, const char * e )
39+
{
40+
std::string result;
41+
// TODO: Find next '/' first, call result.reserve( x )?
42+
while ( p != e ) {
43+
switch ( *p ) {
44+
case '/':
45+
return result;
46+
case '~':
47+
switch ( *++p ) {
48+
case '0':
49+
result += '~';
50+
break;
51+
case '1':
52+
result += '/';
53+
break;
54+
default:
55+
assert( !"code should be unreachable" ); // LCOV_EXCL_LINE
56+
}
57+
++p;
58+
break;
59+
default:
60+
result += *p++;
61+
}
62+
}
63+
return result;
64+
}
65+
3866
} // internal
3967

4068
// RFC 6901
@@ -86,40 +114,17 @@ namespace tao
86114
std::pair< json_pointer, std::string > split() const
87115
{
88116
const auto p = m_value.rfind( '/' );
89-
return { json_pointer( m_value.substr( 0, p ) ), m_value.substr( p + 1 ) };
117+
if( p == std::string::npos ) {
118+
return { * this, "" };
119+
}
120+
const char * b = m_value.data() + p;
121+
const char * e = m_value.data() + m_value.size();
122+
return { json_pointer( m_value.substr( 0, p ) ), internal::json_pointer_next_token( ++b, e ) };
90123
}
91124
};
92125

93126
namespace internal
94127
{
95-
inline std::string json_pointer_next_token( const char * & p, const char * e )
96-
{
97-
std::string result;
98-
// TODO: Find next '/' first, call result.reserve( x )?
99-
while ( p != e ) {
100-
switch ( *p ) {
101-
case '/':
102-
return result;
103-
case '~':
104-
switch ( *++p ) {
105-
case '0':
106-
result += '~';
107-
break;
108-
case '1':
109-
result += '/';
110-
break;
111-
default:
112-
assert( !"code should be unreachable" ); // LCOV_EXCL_LINE
113-
}
114-
++p;
115-
break;
116-
default:
117-
result += *p++;
118-
}
119-
}
120-
return result;
121-
}
122-
123128
inline unsigned long long json_pointer_token_to_index( const std::string & t )
124129
{
125130
if ( ( t.find_first_not_of( "0123456789" ) != std::string::npos ) || ( t.size() > 1 && t[ 0 ] == '0' ) ) {
@@ -131,7 +136,7 @@ namespace tao
131136
template< typename T >
132137
T & json_pointer_at( T * v, const json_pointer & k )
133138
{
134-
const char * p = k.value().c_str();
139+
const char * p = k.value().data();
135140
const char * e = p + k.value().size();
136141
while ( p != e ) {
137142
switch ( v->type() ) {

include/tao/json/value.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,12 +408,12 @@ namespace tao
408408
return m_union.o.at( key );
409409
}
410410

411-
const basic_value & at( const json_pointer & k ) const
411+
basic_value & at( const json_pointer & k )
412412
{
413413
return internal::json_pointer_at( this, k );
414414
}
415415

416-
basic_value & at( const json_pointer & k )
416+
const basic_value & at( const json_pointer & k ) const
417417
{
418418
return internal::json_pointer_at( this, k );
419419
}

src/test/json/json_pointer.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ namespace tao
106106
TEST_THROWS( v[ "/foo/ 1"_json_pointer ] );
107107
TEST_THROWS( v[ "/foo/bar"_json_pointer ] );
108108
TEST_THROWS( v[ "/foo/-/bar"_json_pointer ] );
109+
110+
TEST_ASSERT( v[ "/a~1b"_json_pointer ] == 1 );
111+
TEST_ASSERT( v[ "/c%d"_json_pointer ] == 2 );
112+
TEST_ASSERT( v[ "/e^f"_json_pointer ] == 3 );
113+
TEST_ASSERT( v[ "/g|h"_json_pointer ] == 4 );
114+
TEST_ASSERT( v[ "/i\\j"_json_pointer ] == 5 );
115+
TEST_ASSERT( v[ "/k\"l"_json_pointer ] == 6 );
116+
TEST_ASSERT( v[ "/ "_json_pointer ] == 7 );
117+
TEST_ASSERT( v[ "/m~0n"_json_pointer ] == 8 );
118+
119+
TEST_ASSERT( v[ "/o\0p"_json_pointer ] == 9 );
120+
TEST_ASSERT( v[ "/o\0q"_json_pointer ] == 10 );
121+
TEST_ASSERT( v[ "/o\0r"_json_pointer ].is_null() );
122+
TEST_ASSERT( v.at( "/o\0r"_json_pointer ).is_null() );
109123
}
110124

111125
} // json

0 commit comments

Comments
 (0)