Skip to content

Commit 25342ba

Browse files
committed
support UTF-8 for const methods
1 parent 2b9abc3 commit 25342ba

File tree

2 files changed

+94
-36
lines changed

2 files changed

+94
-36
lines changed

include/json/value.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ class JSON_API StaticString {
112112
*
113113
* It is possible to iterate over the list of a #objectValue values using
114114
* the getMemberNames() method.
115+
*
116+
* \note Value string-length fit in size_t, but keys must fit in unsigned.
117+
* (The reason is an implementation detail.) The readers will raise an
118+
* exception if a bound is exceeded to avoid security holes in your app,
119+
* but the Value API does *not* check bounds. That is the responsibility
120+
* of the caller.
115121
*/
116122
class JSON_API Value {
117123
friend class ValueIteratorBase;
@@ -352,19 +358,25 @@ Json::Value obj_value(Json::objectValue); // {}
352358
Value& append(const Value& value);
353359

354360
/// Access an object value by name, create a null member if it does not exist.
361+
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
362+
/// Exceeding that will cause an exception.
355363
Value& operator[](const char* key);
356364
/// Access an object value by name, returns null if there is no member with
357365
/// that name.
358366
const Value& operator[](const char* key) const;
359367
/// Access an object value by name, create a null member if it does not exist.
368+
/// \param key may contain embedded nulls.
360369
Value& operator[](const std::string& key);
361370
/// Access an object value by name, returns null if there is no member with
362371
/// that name.
372+
/// \param key may contain embedded nulls.
363373
const Value& operator[](const std::string& key) const;
364374
/** \brief Access an object value by name, create a null member if it does not
365375
exist.
366376
367-
* If the object as no entry for that name, then the member name used to store
377+
* \param key may contain embedded nulls.
378+
*
379+
* If the object has no entry for that name, then the member name used to store
368380
* the new entry is not duplicated.
369381
* Example of use:
370382
* \code
@@ -384,11 +396,19 @@ Json::Value obj_value(Json::objectValue); // {}
384396
/// Return the member named key if it exist, defaultValue otherwise.
385397
Value get(const char* key, const Value& defaultValue) const;
386398
/// Return the member named key if it exist, defaultValue otherwise.
399+
/// \param key may contain embedded nulls.
400+
Value get(const char* key, const char* end, const Value& defaultValue) const;
401+
/// Return the member named key if it exist, defaultValue otherwise.
402+
/// \param key may contain embedded nulls.
387403
Value get(const std::string& key, const Value& defaultValue) const;
388404
#ifdef JSON_USE_CPPTL
389405
/// Return the member named key if it exist, defaultValue otherwise.
390406
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
391407
#endif
408+
/// Most general and efficient version of isMember()const, get()const,
409+
/// and operator[]const
410+
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
411+
Value const* find(char const* key, char const* end) const;
392412
/// \brief Remove and return the named member.
393413
///
394414
/// Do nothing if it did not exist.
@@ -398,14 +418,21 @@ Json::Value obj_value(Json::objectValue); // {}
398418
/// \deprecated
399419
Value removeMember(const char* key);
400420
/// Same as removeMember(const char*)
421+
/// \param key may contain embedded nulls.
401422
/// \deprecated
402423
Value removeMember(const std::string& key);
424+
/// Same as removeMember(const char* key, const char* end, Value* removed),
425+
/// but 'key' is null-terminated.
426+
bool removeMember(const char* key, Value* removed);
403427
/** \brief Remove the named map member.
404428
405429
Update 'removed' iff removed.
430+
\param key may contain embedded nulls.
406431
\return true iff removed (no exceptions)
407432
*/
408-
bool removeMember(const char* key, Value* removed);
433+
bool removeMember(std::string const& key, Value* removed);
434+
/// Same as removeMember(std::string const& key, Value* removed)
435+
bool removeMember(const char* key, const char* end, Value* removed);
409436
/** \brief Remove the indexed array element.
410437
411438
O(n) expensive operations.
@@ -417,7 +444,10 @@ Json::Value obj_value(Json::objectValue); // {}
417444
/// Return true if the object has a member named key.
418445
bool isMember(const char* key) const;
419446
/// Return true if the object has a member named key.
447+
/// \param key may contain embedded nulls.
420448
bool isMember(const std::string& key) const;
449+
/// Same as isMember(std::string const& key)const
450+
bool isMember(const char* key, const char* end) const;
421451
#ifdef JSON_USE_CPPTL
422452
/// Return true if the object has a member named key.
423453
bool isMember(const CppTL::ConstString& key) const;

src/lib_json/json_value.cpp

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -867,78 +867,101 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const {
867867

868868
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
869869

870-
const Value& Value::operator[](const char* key) const {
870+
Value const* Value::find(char const* key, char const* end) const
871+
{
871872
JSON_ASSERT_MESSAGE(
872873
type_ == nullValue || type_ == objectValue,
873-
"in Json::Value::operator[](char const*)const: requires objectValue");
874-
if (type_ == nullValue)
875-
return null;
876-
CZString actualKey(key, strlen(key), CZString::noDuplication);
874+
"in Json::Value::find(key, end, found): requires objectValue or nullValue");
875+
if (type_ == nullValue) return NULL;
876+
CZString actualKey(key, end-key, CZString::noDuplication);
877877
ObjectValues::const_iterator it = value_.map_->find(actualKey);
878-
if (it == value_.map_->end())
879-
return null;
880-
return (*it).second;
878+
if (it == value_.map_->end()) return NULL;
879+
return &(*it).second;
881880
}
882-
883-
Value& Value::operator[](const std::string& key) {
884-
return (*this)[key.c_str()];
881+
const Value& Value::operator[](const char* key) const
882+
{
883+
Value const* found = find(key, key + strlen(key));
884+
if (!found) return null;
885+
return *found;
885886
}
886-
887-
const Value& Value::operator[](const std::string& key) const {
887+
Value& Value::operator[](const std::string& key)
888+
{
888889
return (*this)[key.c_str()];
889890
}
890-
891-
Value& Value::operator[](const StaticString& key) {
891+
Value const& Value::operator[](std::string const& key) const
892+
{
893+
Value const* found = find(key.data(), key.data() + key.length());
894+
if (!found) return null;
895+
return *found;
896+
}
897+
Value& Value::operator[](const StaticString& key)
898+
{
892899
return resolveReference(key, true);
893900
}
894901

895902
#ifdef JSON_USE_CPPTL
896903
Value& Value::operator[](const CppTL::ConstString& key) {
897904
return (*this)[key.c_str()];
898905
}
899-
900-
const Value& Value::operator[](const CppTL::ConstString& key) const {
901-
return (*this)[key.c_str()];
906+
Value const& Value::operator[](CppTL::ConstString const& key) const
907+
{
908+
Value const* found = find(key.c_str(), key.end_c_str());
909+
if (!found) return null;
910+
return *found;
902911
}
903912
#endif
904913

905914
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
906915

907-
Value Value::get(const char* key, const Value& defaultValue) const {
916+
Value Value::get(char const* key, char const* end, Value const& defaultValue) const
917+
{
908918
const Value* value = &((*this)[key]);
909919
return value == &null ? defaultValue : *value;
910920
}
911-
912-
Value Value::get(const std::string& key, const Value& defaultValue) const {
921+
Value Value::get(char const* key, Value const& defaultValue) const
922+
{
923+
return get(key, key + strlen(key), defaultValue);
924+
}
925+
Value Value::get(std::string const& key, Value const& defaultValue) const
926+
{
913927
return get(key.c_str(), defaultValue);
914928
}
915929

916930

917-
bool Value::removeMember(const char* key, Value* removed) {
931+
bool Value::removeMember(const char* key, const char* end, Value* removed)
932+
{
918933
if (type_ != objectValue) {
919934
return false;
920935
}
921-
CZString actualKey(key, strlen(key), CZString::noDuplication);
936+
CZString actualKey(key, end-key, CZString::noDuplication);
922937
ObjectValues::iterator it = value_.map_->find(actualKey);
923938
if (it == value_.map_->end())
924939
return false;
925940
*removed = it->second;
926941
value_.map_->erase(it);
927942
return true;
928943
}
929-
930-
Value Value::removeMember(const char* key) {
944+
bool Value::removeMember(const char* key, Value* removed)
945+
{
946+
return removeMember(key, key + strlen(key), removed);
947+
}
948+
bool Value::removeMember(std::string const& key, Value* removed)
949+
{
950+
return removeMember(key.data(), key.data() + key.length(), removed);
951+
}
952+
Value Value::removeMember(const char* key)
953+
{
931954
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
932955
"in Json::Value::removeMember(): requires objectValue");
933956
if (type_ == nullValue)
934957
return null;
935958

936959
Value removed; // null
937-
removeMember(key, &removed);
960+
removeMember(key, key + strlen(key), &removed);
938961
return removed; // still null if removeMember() did nothing
939962
}
940-
941-
Value Value::removeMember(const std::string& key) {
963+
Value Value::removeMember(const std::string& key)
964+
{
942965
return removeMember(key.c_str());
943966
}
944967

@@ -972,13 +995,18 @@ Value Value::get(const CppTL::ConstString& key,
972995
}
973996
#endif
974997

975-
bool Value::isMember(const char* key) const {
976-
const Value* value = &((*this)[key]);
977-
return value != &null;
998+
bool Value::isMember(char const* key, char const* end) const
999+
{
1000+
Value const* value = find(key, end);
1001+
return NULL != value;
9781002
}
979-
980-
bool Value::isMember(const std::string& key) const {
981-
return isMember(key.c_str());
1003+
bool Value::isMember(const char* key) const
1004+
{
1005+
return isMember(key, key + strlen(key));
1006+
}
1007+
bool Value::isMember(const std::string& key) const
1008+
{
1009+
return isMember(key.data(), key.data() + key.length());
9821010
}
9831011

9841012
#ifdef JSON_USE_CPPTL

0 commit comments

Comments
 (0)