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