support UTF-8 for const methods
diff --git a/include/json/value.h b/include/json/value.h
index 51bcdbb..38d64fe 100644
--- a/include/json/value.h
+++ b/include/json/value.h
@@ -112,6 +112,12 @@
*
* It is possible to iterate over the list of a #objectValue values using
* the getMemberNames() method.
+ *
+ * \note Value string-length fit in size_t, but keys must fit in unsigned.
+ * (The reason is an implementation detail.) The readers will raise an
+ * exception if a bound is exceeded to avoid security holes in your app,
+ * but the Value API does *not* check bounds. That is the responsibility
+ * of the caller.
*/
class JSON_API Value {
friend class ValueIteratorBase;
@@ -352,19 +358,25 @@
Value& append(const Value& value);
/// Access an object value by name, create a null member if it does not exist.
+ /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
+ /// Exceeding that will cause an exception.
Value& operator[](const char* key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not exist.
+ /// \param key may contain embedded nulls.
Value& operator[](const std::string& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
+ /// \param key may contain embedded nulls.
const Value& operator[](const std::string& key) const;
/** \brief Access an object value by name, create a null member if it does not
exist.
- * If the object as no entry for that name, then the member name used to store
+ * \param key may contain embedded nulls.
+ *
+ * If the object has no entry for that name, then the member name used to store
* the new entry is not duplicated.
* Example of use:
* \code
@@ -384,11 +396,19 @@
/// Return the member named key if it exist, defaultValue otherwise.
Value get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
+ /// \param key may contain embedded nulls.
+ Value get(const char* key, const char* end, const Value& defaultValue) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ /// \param key may contain embedded nulls.
Value get(const std::string& key, const Value& defaultValue) const;
#ifdef JSON_USE_CPPTL
/// Return the member named key if it exist, defaultValue otherwise.
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
#endif
+ /// Most general and efficient version of isMember()const, get()const,
+ /// and operator[]const
+ /// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
+ Value const* find(char const* key, char const* end) const;
/// \brief Remove and return the named member.
///
/// Do nothing if it did not exist.
@@ -398,14 +418,21 @@
/// \deprecated
Value removeMember(const char* key);
/// Same as removeMember(const char*)
+ /// \param key may contain embedded nulls.
/// \deprecated
Value removeMember(const std::string& key);
+ /// Same as removeMember(const char* key, const char* end, Value* removed),
+ /// but 'key' is null-terminated.
+ bool removeMember(const char* key, Value* removed);
/** \brief Remove the named map member.
Update 'removed' iff removed.
+ \param key may contain embedded nulls.
\return true iff removed (no exceptions)
*/
- bool removeMember(const char* key, Value* removed);
+ bool removeMember(std::string const& key, Value* removed);
+ /// Same as removeMember(std::string const& key, Value* removed)
+ bool removeMember(const char* key, const char* end, Value* removed);
/** \brief Remove the indexed array element.
O(n) expensive operations.
@@ -417,7 +444,10 @@
/// Return true if the object has a member named key.
bool isMember(const char* key) const;
/// Return true if the object has a member named key.
+ /// \param key may contain embedded nulls.
bool isMember(const std::string& key) const;
+ /// Same as isMember(std::string const& key)const
+ bool isMember(const char* key, const char* end) const;
#ifdef JSON_USE_CPPTL
/// Return true if the object has a member named key.
bool isMember(const CppTL::ConstString& key) const;
diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp
index a5d2d74..3378e76 100644
--- a/src/lib_json/json_value.cpp
+++ b/src/lib_json/json_value.cpp
@@ -867,28 +867,35 @@
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
-const Value& Value::operator[](const char* key) const {
+Value const* Value::find(char const* key, char const* end) const
+{
JSON_ASSERT_MESSAGE(
type_ == nullValue || type_ == objectValue,
- "in Json::Value::operator[](char const*)const: requires objectValue");
- if (type_ == nullValue)
- return null;
- CZString actualKey(key, strlen(key), CZString::noDuplication);
+ "in Json::Value::find(key, end, found): requires objectValue or nullValue");
+ if (type_ == nullValue) return NULL;
+ CZString actualKey(key, end-key, CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey);
- if (it == value_.map_->end())
- return null;
- return (*it).second;
+ if (it == value_.map_->end()) return NULL;
+ return &(*it).second;
}
-
-Value& Value::operator[](const std::string& key) {
+const Value& Value::operator[](const char* key) const
+{
+ Value const* found = find(key, key + strlen(key));
+ if (!found) return null;
+ return *found;
+}
+Value& Value::operator[](const std::string& key)
+{
return (*this)[key.c_str()];
}
-
-const Value& Value::operator[](const std::string& key) const {
- return (*this)[key.c_str()];
+Value const& Value::operator[](std::string const& key) const
+{
+ Value const* found = find(key.data(), key.data() + key.length());
+ if (!found) return null;
+ return *found;
}
-
-Value& Value::operator[](const StaticString& key) {
+Value& Value::operator[](const StaticString& key)
+{
return resolveReference(key, true);
}
@@ -896,29 +903,37 @@
Value& Value::operator[](const CppTL::ConstString& key) {
return (*this)[key.c_str()];
}
-
-const Value& Value::operator[](const CppTL::ConstString& key) const {
- return (*this)[key.c_str()];
+Value const& Value::operator[](CppTL::ConstString const& key) const
+{
+ Value const* found = find(key.c_str(), key.end_c_str());
+ if (!found) return null;
+ return *found;
}
#endif
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
-Value Value::get(const char* key, const Value& defaultValue) const {
+Value Value::get(char const* key, char const* end, Value const& defaultValue) const
+{
const Value* value = &((*this)[key]);
return value == &null ? defaultValue : *value;
}
-
-Value Value::get(const std::string& key, const Value& defaultValue) const {
+Value Value::get(char const* key, Value const& defaultValue) const
+{
+ return get(key, key + strlen(key), defaultValue);
+}
+Value Value::get(std::string const& key, Value const& defaultValue) const
+{
return get(key.c_str(), defaultValue);
}
-bool Value::removeMember(const char* key, Value* removed) {
+bool Value::removeMember(const char* key, const char* end, Value* removed)
+{
if (type_ != objectValue) {
return false;
}
- CZString actualKey(key, strlen(key), CZString::noDuplication);
+ CZString actualKey(key, end-key, CZString::noDuplication);
ObjectValues::iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end())
return false;
@@ -926,19 +941,27 @@
value_.map_->erase(it);
return true;
}
-
-Value Value::removeMember(const char* key) {
+bool Value::removeMember(const char* key, Value* removed)
+{
+ return removeMember(key, key + strlen(key), removed);
+}
+bool Value::removeMember(std::string const& key, Value* removed)
+{
+ return removeMember(key.data(), key.data() + key.length(), removed);
+}
+Value Value::removeMember(const char* key)
+{
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type_ == nullValue)
return null;
Value removed; // null
- removeMember(key, &removed);
+ removeMember(key, key + strlen(key), &removed);
return removed; // still null if removeMember() did nothing
}
-
-Value Value::removeMember(const std::string& key) {
+Value Value::removeMember(const std::string& key)
+{
return removeMember(key.c_str());
}
@@ -972,13 +995,18 @@
}
#endif
-bool Value::isMember(const char* key) const {
- const Value* value = &((*this)[key]);
- return value != &null;
+bool Value::isMember(char const* key, char const* end) const
+{
+ Value const* value = find(key, end);
+ return NULL != value;
}
-
-bool Value::isMember(const std::string& key) const {
- return isMember(key.c_str());
+bool Value::isMember(const char* key) const
+{
+ return isMember(key, key + strlen(key));
+}
+bool Value::isMember(const std::string& key) const
+{
+ return isMember(key.data(), key.data() + key.length());
}
#ifdef JSON_USE_CPPTL