Skip to content

Commit 9e49e3d

Browse files
committed
Merge pull request open-source-parsers#197 from cdunn2001/allow-zero
allow zeroes in strings
2 parents 2b9abc3 + 2d653bd commit 9e49e3d

6 files changed

Lines changed: 508 additions & 97 deletions

File tree

include/json/value.h

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,24 @@ class JSON_API StaticString {
9999
* The type of the held value is represented by a #ValueType and
100100
* can be obtained using type().
101101
*
102-
* values of an #objectValue or #arrayValue can be accessed using operator[]()
103-
*methods.
104-
* Non const methods will automatically create the a #nullValue element
102+
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
103+
* methods.
104+
* Non-const methods will automatically create the a #nullValue element
105105
* if it does not exist.
106-
* The sequence of an #arrayValue will be automatically resize and initialized
106+
* The sequence of an #arrayValue will be automatically resized and initialized
107107
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
108108
*
109-
* The get() methods can be used to obtanis default value in the case the
110-
*required element
111-
* does not exist.
109+
* The get() methods can be used to obtain default value in the case the
110+
* required element does not exist.
112111
*
113112
* It is possible to iterate over the list of a #objectValue values using
114113
* the getMemberNames() method.
114+
*
115+
* \note #Value string-length fit in size_t, but keys must be < 2^30.
116+
* (The reason is an implementation detail.) A #CharReader will raise an
117+
* exception if a bound is exceeded to avoid security holes in your app,
118+
* but the Value API does *not* check bounds. That is the responsibility
119+
* of the caller.
115120
*/
116121
class JSON_API Value {
117122
friend class ValueIteratorBase;
@@ -164,24 +169,27 @@ class JSON_API Value {
164169
duplicateOnCopy
165170
};
166171
CZString(ArrayIndex index);
167-
CZString(char const* cstr, unsigned length, DuplicationPolicy allocate);
168-
CZString(const CZString& other);
172+
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
173+
CZString(CZString const& other);
169174
~CZString();
170175
CZString& operator=(CZString other);
171-
bool operator<(const CZString& other) const;
172-
bool operator==(const CZString& other) const;
176+
bool operator<(CZString const& other) const;
177+
bool operator==(CZString const& other) const;
173178
ArrayIndex index() const;
174-
const char* c_str() const;
179+
//const char* c_str() const; ///< \deprecated
180+
char const* data() const;
181+
unsigned length() const;
175182
bool isStaticString() const;
176183

177184
private:
178185
void swap(CZString& other);
186+
179187
struct StringStorage {
180188
DuplicationPolicy policy_: 2;
181189
unsigned length_: 30; // 1GB max
182190
};
183191

184-
const char* cstr_;
192+
char const* cstr_; // actually, a prefixed string, unless policy is noDup
185193
union {
186194
ArrayIndex index_;
187195
StringStorage storage_;
@@ -220,20 +228,25 @@ Json::Value obj_value(Json::objectValue); // {}
220228
Value(UInt64 value);
221229
#endif // if defined(JSON_HAS_INT64)
222230
Value(double value);
223-
Value(const char* value);
224-
Value(const char* beginValue, const char* endValue);
231+
Value(const char* value); ///! Copy til first 0. (NULL causes to seg-fault.)
232+
Value(const char* beginValue, const char* endValue); ///! Copy all, incl zeroes.
225233
/** \brief Constructs a value from a static string.
226234
227235
* Like other value string constructor but do not duplicate the string for
228236
* internal storage. The given string must remain alive after the call to this
229237
* constructor.
238+
* \note This works only for null-terminated strings. (We cannot change the
239+
* size of this class, so we have nowhere to store the length,
240+
* which might be computed later for various operations.)
241+
*
230242
* Example of usage:
231243
* \code
232-
* Json::Value aValue( StaticString("some text") );
244+
* static StaticString foo("some text");
245+
* Json::Value aValue(foo);
233246
* \endcode
234247
*/
235248
Value(const StaticString& value);
236-
Value(const std::string& value);
249+
Value(const std::string& value); ///! Copy data() til size(). Embedded zeroes too.
237250
#ifdef JSON_USE_CPPTL
238251
Value(const CppTL::ConstString& value);
239252
#endif
@@ -260,8 +273,13 @@ Json::Value obj_value(Json::objectValue); // {}
260273
bool operator!=(const Value& other) const;
261274
int compare(const Value& other) const;
262275

263-
const char* asCString() const;
264-
std::string asString() const;
276+
const char* asCString() const; ///! Embedded zeroes could cause you trouble!
277+
std::string asString() const; ///! Embedded zeroes are possible.
278+
/** Get raw char* of string-value.
279+
* \return false if !string. (Seg-fault if str or end are NULL.)
280+
*/
281+
bool getString(
282+
char const** str, char const** end) const;
265283
#ifdef JSON_USE_CPPTL
266284
CppTL::ConstString asConstString() const;
267285
#endif
@@ -352,19 +370,23 @@ Json::Value obj_value(Json::objectValue); // {}
352370
Value& append(const Value& value);
353371

354372
/// Access an object value by name, create a null member if it does not exist.
373+
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
374+
/// Exceeding that will cause an exception.
355375
Value& operator[](const char* key);
356376
/// Access an object value by name, returns null if there is no member with
357377
/// that name.
358378
const Value& operator[](const char* key) const;
359379
/// Access an object value by name, create a null member if it does not exist.
380+
/// \param key may contain embedded nulls.
360381
Value& operator[](const std::string& key);
361382
/// Access an object value by name, returns null if there is no member with
362383
/// that name.
384+
/// \param key may contain embedded nulls.
363385
const Value& operator[](const std::string& key) const;
364386
/** \brief Access an object value by name, create a null member if it does not
365387
exist.
366388
367-
* If the object as no entry for that name, then the member name used to store
389+
* If the object has no entry for that name, then the member name used to store
368390
* the new entry is not duplicated.
369391
* Example of use:
370392
* \code
@@ -384,11 +406,23 @@ Json::Value obj_value(Json::objectValue); // {}
384406
/// Return the member named key if it exist, defaultValue otherwise.
385407
Value get(const char* key, const Value& defaultValue) const;
386408
/// Return the member named key if it exist, defaultValue otherwise.
409+
/// \param key may contain embedded nulls.
410+
Value get(const char* key, const char* end, const Value& defaultValue) const;
411+
/// Return the member named key if it exist, defaultValue otherwise.
412+
/// \param key may contain embedded nulls.
387413
Value get(const std::string& key, const Value& defaultValue) const;
388414
#ifdef JSON_USE_CPPTL
389415
/// Return the member named key if it exist, defaultValue otherwise.
390416
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
391417
#endif
418+
/// Most general and efficient version of isMember()const, get()const,
419+
/// and operator[]const
420+
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
421+
Value const* find(char const* key, char const* end) const;
422+
/// Most general and efficient version of object-mutators.
423+
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
424+
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
425+
Value const* demand(char const* key, char const* end);
392426
/// \brief Remove and return the named member.
393427
///
394428
/// Do nothing if it did not exist.
@@ -398,14 +432,21 @@ Json::Value obj_value(Json::objectValue); // {}
398432
/// \deprecated
399433
Value removeMember(const char* key);
400434
/// Same as removeMember(const char*)
435+
/// \param key may contain embedded nulls.
401436
/// \deprecated
402437
Value removeMember(const std::string& key);
438+
/// Same as removeMember(const char* key, const char* end, Value* removed),
439+
/// but 'key' is null-terminated.
440+
bool removeMember(const char* key, Value* removed);
403441
/** \brief Remove the named map member.
404442
405443
Update 'removed' iff removed.
444+
\param key may contain embedded nulls.
406445
\return true iff removed (no exceptions)
407446
*/
408-
bool removeMember(const char* key, Value* removed);
447+
bool removeMember(std::string const& key, Value* removed);
448+
/// Same as removeMember(std::string const& key, Value* removed)
449+
bool removeMember(const char* key, const char* end, Value* removed);
409450
/** \brief Remove the indexed array element.
410451
411452
O(n) expensive operations.
@@ -415,9 +456,13 @@ Json::Value obj_value(Json::objectValue); // {}
415456
bool removeIndex(ArrayIndex i, Value* removed);
416457

417458
/// Return true if the object has a member named key.
459+
/// \note 'key' must be null-terminated.
418460
bool isMember(const char* key) const;
419461
/// Return true if the object has a member named key.
462+
/// \param key may contain embedded nulls.
420463
bool isMember(const std::string& key) const;
464+
/// Same as isMember(std::string const& key)const
465+
bool isMember(const char* key, const char* end) const;
421466
#ifdef JSON_USE_CPPTL
422467
/// Return true if the object has a member named key.
423468
bool isMember(const CppTL::ConstString& key) const;
@@ -463,7 +508,8 @@ Json::Value obj_value(Json::objectValue); // {}
463508
private:
464509
void initBasic(ValueType type, bool allocated = false);
465510

466-
Value& resolveReference(const char* key, bool isStatic);
511+
Value& resolveReference(const char* key);
512+
Value& resolveReference(const char* key, const char* end);
467513

468514
struct CommentInfo {
469515
CommentInfo();
@@ -488,11 +534,12 @@ Json::Value obj_value(Json::objectValue); // {}
488534
LargestUInt uint_;
489535
double real_;
490536
bool bool_;
491-
char* string_;
537+
char* string_; // actually ptr to unsigned, followed by str, unless !allocated_
492538
ObjectValues* map_;
493539
} value_;
494540
ValueType type_ : 8;
495541
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
542+
// If not allocated_, string_ must be null-terminated.
496543
CommentInfo* comments_;
497544

498545
// [start, limit) byte offsets in the source JSON text from which this Value
@@ -594,7 +641,12 @@ class JSON_API ValueIteratorBase {
594641

595642
/// Return the member name of the referenced Value. "" if it is not an
596643
/// objectValue.
597-
const char* memberName() const;
644+
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
645+
char const* memberName() const;
646+
/// Return the member name of the referenced Value, or NULL if it is not an
647+
/// objectValue.
648+
/// Better version than memberName(). Allows embedded nulls.
649+
char const* memberName(char const** end) const;
598650

599651
protected:
600652
Value& deref() const;
@@ -623,8 +675,8 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
623675

624676
public:
625677
typedef const Value value_type;
626-
typedef unsigned int size_t;
627-
typedef int difference_type;
678+
//typedef unsigned int size_t;
679+
//typedef int difference_type;
628680
typedef const Value& reference;
629681
typedef const Value* pointer;
630682
typedef ValueConstIterator SelfType;

src/lib_json/json_reader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,7 @@ bool OurReader::readObject(Token& tokenStart) {
14301430
return addErrorAndRecover(
14311431
"Missing ':' after object member name", colon, tokenObjectEnd);
14321432
}
1433+
if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30");
14331434
Value& value = currentValue()[name];
14341435
nodes_.push(&value);
14351436
bool ok = readValue();

0 commit comments

Comments
 (0)