Skip to content

Commit

Permalink
Be more memory-efficient when parsing long strings containing escaped…
Browse files Browse the repository at this point in the history
… characters. Suggested by Bob McCune.
  • Loading branch information
stig committed Aug 27, 2011
1 parent f723881 commit aaa6b06
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 105 deletions.
173 changes: 90 additions & 83 deletions Classes/SBJsonStreamParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -264,90 +264,97 @@ - (void) handleTokenNotExpectedHere: (sbjson_token_t) tok {
}

- (SBJsonStreamParserStatus)parse:(NSData *)data_ {
[tokeniser appendData:data_];

for (;;) {

if ([state isError])
return SBJsonStreamParserError;

NSObject *token;
sbjson_token_t tok = [tokeniser getToken:&token];
switch (tok) {
case sbjson_token_eof:
return [state parserShouldReturn:self];
break;

case sbjson_token_error:
self.state = [SBJsonStreamParserStateError sharedInstance];
self.error = tokeniser.error;
return SBJsonStreamParserError;
break;

default:

if (![state parser:self shouldAcceptToken:tok]) {
[self handleTokenNotExpectedHere: tok];
return SBJsonStreamParserError;
}

switch (tok) {
case sbjson_token_object_start:
[self handleObjectStart];
break;

case sbjson_token_object_end:
[self handleObjectEnd: tok];
break;

case sbjson_token_array_start:
[self handleArrayStart];
break;

case sbjson_token_array_end:
[self handleArrayEnd: tok];
break;

case sbjson_token_separator:
case sbjson_token_keyval_separator:
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_true:
[self parserFoundObject:kTrue];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_false:
[self parserFoundObject:kFalse];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_null:
[self parserFoundObject:kNull];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_number:
[self parserFoundObject:token];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_string:
if ([state needKey])
[keyStack addObject:token];
else
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
[tokeniser appendData:data_];

for (;;) {

if ([state isError])
return SBJsonStreamParserError;

NSObject *token;
sbjson_token_t tok = [tokeniser getToken:&token];
switch (tok) {
case sbjson_token_eof:
return [state parserShouldReturn:self];
break;

case sbjson_token_error:
self.state = [SBJsonStreamParserStateError sharedInstance];
self.error = tokeniser.error;
return SBJsonStreamParserError;
break;

default:

if (![state parser:self shouldAcceptToken:tok]) {
[self handleTokenNotExpectedHere: tok];
return SBJsonStreamParserError;
}

switch (tok) {
case sbjson_token_object_start:
[self handleObjectStart];
break;

case sbjson_token_object_end:
[self handleObjectEnd: tok];
break;

case sbjson_token_array_start:
[self handleArrayStart];
break;

case sbjson_token_array_end:
[self handleArrayEnd: tok];
break;

case sbjson_token_separator:
case sbjson_token_keyval_separator:
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_true:
[self parserFoundObject:kTrue];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_false:
[self parserFoundObject:kFalse];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_null:
[self parserFoundObject:kNull];
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_number:
[self parserFoundObject:token];
[state parser:self shouldTransitionTo:tok];
break;

default:
break;
}
break;
}
}
return SBJsonStreamParserComplete;
[state parser:self shouldTransitionTo:tok];
break;

case sbjson_token_string:
if ([state needKey])
[keyStack addObject:token];
else
[self parserFoundObject:token];
[state parser:self shouldTransitionTo:tok];
break;

default:
break;
}
break;
}
}
return SBJsonStreamParserComplete;

}
@finally {
[pool drain];
}
}


Expand Down
44 changes: 25 additions & 19 deletions Classes/SBJsonTokeniser.m
Original file line number Diff line number Diff line change
Expand Up @@ -145,30 +145,36 @@ - (sbjson_token_t)getStringToken:(NSObject**)token {
unichar ch;
{
NSMutableString *string = nil;
if (![_stream getSimpleString:&string])
return sbjson_token_eof;
@try {
if (![_stream getRetainedStringFragment:&string])
return sbjson_token_eof;

if (!string) {
self.error = @"Broken Unicode encoding";
return sbjson_token_error;
}


if (![_stream getUnichar:&ch])
return sbjson_token_eof;

if (acc) {
[acc appendString:string];
if (!string) {
self.error = @"Broken Unicode encoding";
return sbjson_token_error;
}

} else if (ch == '"') {
*token = string;
[_stream skip];
return sbjson_token_string;
if (![_stream getUnichar:&ch]) {
return sbjson_token_eof;
}

if (acc) {
[acc appendString:string];

} else {
acc = [[string mutableCopy] autorelease];
} else if (ch == '"') {
*token = [[string copy] autorelease];
[_stream skip];
return sbjson_token_string;

} else {
acc = [[string mutableCopy] autorelease];
}
}
@finally {
[string release];
}
}


switch (ch) {
case 0 ... 0x1F:
Expand Down
2 changes: 1 addition & 1 deletion Classes/SBJsonUTF8Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

- (BOOL)getUnichar:(unichar*)ch;
- (BOOL)getNextUnichar:(unichar*)ch;
- (BOOL)getSimpleString:(NSString**)string;
- (BOOL)getRetainedStringFragment:(NSString**)string;

- (NSString*)stringWithRange:(NSRange)range;

Expand Down
4 changes: 2 additions & 2 deletions Classes/SBJsonUTF8Stream.m
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ - (BOOL)getNextUnichar:(unichar*)ch {
return NO;
}

- (BOOL)getSimpleString:(NSString **)string {
- (BOOL)getRetainedStringFragment:(NSString **)string {
NSUInteger start = _index;
while (_index < _length) {
switch (_bytes[_index]) {
case '"':
case '\\':
case 0 ... 0x1f:
*string = [[[NSString alloc] initWithBytes:(_bytes + start) length:(_index - start) encoding:NSUTF8StringEncoding] autorelease];
*string = [[NSString alloc] initWithBytes:(_bytes + start) length:(_index - start) encoding:NSUTF8StringEncoding];
return YES;
break;
default:
Expand Down

0 comments on commit aaa6b06

Please sign in to comment.