@@ -32,11 +32,11 @@ #import "macros.h" int _OFString_JSONValue_reference; static id nextObject(const char *restrict *, const char*, - size_t *restrict line); + size_t *restrict line, size_t depth, size_t depthLimit); static void skipWhitespaces(const char *restrict *pointer, const char *stop, size_t *restrict line) { @@ -390,16 +390,19 @@ return nil; } static inline OFMutableArray* parseArray(const char *restrict *pointer, const char *stop, - size_t *restrict line) + size_t *restrict line, size_t depth, size_t depthLimit) { OFMutableArray *array = [OFMutableArray array]; if (++(*pointer) >= stop) return nil; + + if (++depth > depthLimit) + return nil; while (**pointer != ']') { id object; skipWhitespacesAndComments(pointer, stop, line); @@ -417,11 +420,12 @@ return nil; break; } - if ((object = nextObject(pointer, stop, line)) == nil) + object = nextObject(pointer, stop, line, depth, depthLimit); + if (object == nil) return nil; [array addObject: object]; skipWhitespacesAndComments(pointer, stop, line); @@ -443,16 +447,19 @@ return array; } static inline OFMutableDictionary* parseDictionary(const char *restrict *pointer, const char *stop, - size_t *restrict line) + size_t *restrict line, size_t depth, size_t depthLimit) { OFMutableDictionary *dictionary = [OFMutableDictionary dictionary]; if (++(*pointer) >= stop) return nil; + + if (++depth > depthLimit) + return nil; while (**pointer != '}') { id key, object; skipWhitespacesAndComments(pointer, stop, line); @@ -479,11 +486,12 @@ if ((**pointer >= 'a' && **pointer <= 'z') || (**pointer >= 'A' && **pointer <= 'Z') || **pointer == '_' || **pointer == '$' || **pointer == '\\') key = parseIdentifier(pointer, stop); else - key = nextObject(pointer, stop, line); + key = nextObject(pointer, stop, line, + depth, depthLimit); if (key == nil) return nil; skipWhitespacesAndComments(pointer, stop, line); @@ -490,11 +498,12 @@ if (*pointer + 1 >= stop || **pointer != ':') return nil; (*pointer)++; - if ((object = nextObject(pointer, stop, line)) == nil) + object = nextObject(pointer, stop, line, depth, depthLimit); + if (object == nil) return nil; [dictionary setObject: object forKey: key]; @@ -563,11 +572,11 @@ return number; } static id nextObject(const char *restrict *pointer, const char *stop, - size_t *restrict line) + size_t *restrict line, size_t depth, size_t depthLimit) { skipWhitespacesAndComments(pointer, stop, line); if (*pointer >= stop) return nil; @@ -575,13 +584,13 @@ switch (**pointer) { case '"': case '\'': return parseString(pointer, stop, line); case '[': - return parseArray(pointer, stop, line); + return parseArray(pointer, stop, line, depth, depthLimit); case '{': - return parseDictionary(pointer, stop, line); + return parseDictionary(pointer, stop, line, depth, depthLimit); case 't': if (*pointer + 3 >= stop) return nil; if (memcmp(*pointer, "true", 4)) @@ -629,20 +638,25 @@ } @implementation OFString (JSONValue) - (id)JSONValue { + return [self JSONValueWithDepthLimit: 32]; +} + +- (id)JSONValueWithDepthLimit: (size_t)depthLimit +{ const char *pointer = [self UTF8String]; const char *stop = pointer + [self UTF8StringLength]; id object; size_t line = 1; - object = nextObject(&pointer, stop, &line); + object = nextObject(&pointer, stop, &line, 0, depthLimit); skipWhitespacesAndComments(&pointer, stop, &line); if (pointer < stop || object == nil) @throw [OFInvalidJSONException exceptionWithClass: [self class] line: line]; return object; } @end