Skip to content
This repository was archived by the owner on Mar 21, 2024. It is now read-only.

Commit ddf55a4

Browse files
committed
Be more memory-efficient when parsing long strings containing escaped characters. Suggested by Bob McCune.
1 parent 2fcc541 commit ddf55a4

File tree

4 files changed

+119
-106
lines changed

4 files changed

+119
-106
lines changed

Classes/SBJsonStreamParser.m

Lines changed: 91 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -168,90 +168,97 @@ - (void) handleTokenNotExpectedHere: (sbjson_token_t) tok {
168168
}
169169

170170
- (SBJsonStreamParserStatus)parse:(NSData *)data_ {
171-
[tokeniser appendData:data_];
172-
173-
for (;;) {
174-
175-
if ([state isError])
176-
return SBJsonStreamParserError;
177-
178-
NSObject *token;
179-
sbjson_token_t tok = [tokeniser getToken:&token];
180-
switch (tok) {
181-
case sbjson_token_eof:
182-
return [state parserShouldReturn:self];
183-
break;
184-
185-
case sbjson_token_error:
186-
self.state = [SBJsonStreamParserStateError sharedInstance];
187-
self.error = tokeniser.error;
188-
return SBJsonStreamParserError;
189-
break;
190-
191-
default:
192-
193-
if (![state parser:self shouldAcceptToken:tok]) {
194-
[self handleTokenNotExpectedHere: tok];
195-
return SBJsonStreamParserError;
196-
}
197-
198-
switch (tok) {
199-
case sbjson_token_object_start:
200-
[self handleObjectStart];
201-
break;
202-
203-
case sbjson_token_object_end:
204-
[self handleObjectEnd: tok];
205-
break;
206-
207-
case sbjson_token_array_start:
208-
[self handleArrayStart];
209-
break;
210-
211-
case sbjson_token_array_end:
212-
[self handleArrayEnd: tok];
213-
break;
214-
215-
case sbjson_token_separator:
216-
case sbjson_token_keyval_separator:
217-
[state parser:self shouldTransitionTo:tok];
218-
break;
219-
220-
case sbjson_token_true:
221-
[delegate parser:self foundBoolean:YES];
222-
[state parser:self shouldTransitionTo:tok];
223-
break;
224-
225-
case sbjson_token_false:
226-
[delegate parser:self foundBoolean:NO];
227-
[state parser:self shouldTransitionTo:tok];
228-
break;
229-
230-
case sbjson_token_null:
231-
[delegate parserFoundNull:self];
232-
[state parser:self shouldTransitionTo:tok];
233-
break;
234-
235-
case sbjson_token_number:
236-
[delegate parser:self foundNumber:(NSNumber*)token];
237-
[state parser:self shouldTransitionTo:tok];
238-
break;
239-
240-
case sbjson_token_string:
241-
if ([state needKey])
242-
[delegate parser:self foundObjectKey:(NSString*)token];
243-
else
244-
[delegate parser:self foundString:(NSString*)token];
245-
[state parser:self shouldTransitionTo:tok];
246-
break;
247-
248-
default:
249-
break;
250-
}
251-
break;
252-
}
253-
}
254-
return SBJsonStreamParserComplete;
171+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
172+
@try {
173+
[tokeniser appendData:data_];
174+
175+
for (;;) {
176+
177+
if ([state isError])
178+
return SBJsonStreamParserError;
179+
180+
NSObject *token;
181+
sbjson_token_t tok = [tokeniser getToken:&token];
182+
switch (tok) {
183+
case sbjson_token_eof:
184+
return [state parserShouldReturn:self];
185+
break;
186+
187+
case sbjson_token_error:
188+
self.state = [SBJsonStreamParserStateError sharedInstance];
189+
self.error = tokeniser.error;
190+
return SBJsonStreamParserError;
191+
break;
192+
193+
default:
194+
195+
if (![state parser:self shouldAcceptToken:tok]) {
196+
[self handleTokenNotExpectedHere: tok];
197+
return SBJsonStreamParserError;
198+
}
199+
200+
switch (tok) {
201+
case sbjson_token_object_start:
202+
[self handleObjectStart];
203+
break;
204+
205+
case sbjson_token_object_end:
206+
[self handleObjectEnd: tok];
207+
break;
208+
209+
case sbjson_token_array_start:
210+
[self handleArrayStart];
211+
break;
212+
213+
case sbjson_token_array_end:
214+
[self handleArrayEnd: tok];
215+
break;
216+
217+
case sbjson_token_separator:
218+
case sbjson_token_keyval_separator:
219+
[state parser:self shouldTransitionTo:tok];
220+
break;
221+
222+
case sbjson_token_true:
223+
[delegate parser:self foundBoolean:YES];
224+
[state parser:self shouldTransitionTo:tok];
225+
break;
226+
227+
case sbjson_token_false:
228+
[delegate parser:self foundBoolean:NO];
229+
[state parser:self shouldTransitionTo:tok];
230+
break;
231+
232+
case sbjson_token_null:
233+
[delegate parserFoundNull:self];
234+
[state parser:self shouldTransitionTo:tok];
235+
break;
236+
237+
case sbjson_token_number:
238+
[delegate parser:self foundNumber:(NSNumber*)token];
239+
[state parser:self shouldTransitionTo:tok];
240+
break;
241+
242+
case sbjson_token_string:
243+
if ([state needKey])
244+
[delegate parser:self foundObjectKey:(NSString*)token];
245+
else
246+
[delegate parser:self foundString:(NSString*)token];
247+
[state parser:self shouldTransitionTo:tok];
248+
break;
249+
250+
default:
251+
break;
252+
}
253+
break;
254+
}
255+
}
256+
return SBJsonStreamParserComplete;
257+
258+
}
259+
@finally {
260+
[pool drain];
261+
}
255262
}
256263

257264
@end

Classes/SBJsonTokeniser.m

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -145,30 +145,36 @@ - (sbjson_token_t)getStringToken:(NSObject**)token {
145145
unichar ch;
146146
{
147147
NSMutableString *string = nil;
148-
if (![_stream getSimpleString:&string])
149-
return sbjson_token_eof;
148+
@try {
149+
if (![_stream getRetainedStringFragment:&string])
150+
return sbjson_token_eof;
150151

151-
if (!string) {
152-
self.error = @"Broken Unicode encoding";
153-
return sbjson_token_error;
154-
}
155-
156-
157-
if (![_stream getUnichar:&ch])
158-
return sbjson_token_eof;
159-
160-
if (acc) {
161-
[acc appendString:string];
152+
if (!string) {
153+
self.error = @"Broken Unicode encoding";
154+
return sbjson_token_error;
155+
}
162156

163-
} else if (ch == '"') {
164-
*token = string;
165-
[_stream skip];
166-
return sbjson_token_string;
157+
if (![_stream getUnichar:&ch]) {
158+
return sbjson_token_eof;
159+
}
160+
161+
if (acc) {
162+
[acc appendString:string];
167163

168-
} else {
169-
acc = [[string mutableCopy] autorelease];
164+
} else if (ch == '"') {
165+
*token = [[string copy] autorelease];
166+
[_stream skip];
167+
return sbjson_token_string;
168+
169+
} else {
170+
acc = [[string mutableCopy] autorelease];
171+
}
172+
}
173+
@finally {
174+
[string release];
170175
}
171176
}
177+
172178

173179
switch (ch) {
174180
case 0 ... 0x1F:

Classes/SBJsonUTF8Stream.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
- (BOOL)getUnichar:(unichar*)ch;
5353
- (BOOL)getNextUnichar:(unichar*)ch;
54-
- (BOOL)getSimpleString:(NSString**)string;
54+
- (BOOL)getRetainedStringFragment:(NSString**)string;
5555

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

Classes/SBJsonUTF8Stream.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ - (BOOL)getNextUnichar:(unichar*)ch {
8383
return NO;
8484
}
8585

86-
- (BOOL)getSimpleString:(NSString **)string {
86+
- (BOOL)getRetainedStringFragment:(NSString **)string {
8787
NSUInteger start = _index;
8888
while (_index < _length) {
8989
switch (_bytes[_index]) {
9090
case '"':
9191
case '\\':
9292
case 0 ... 0x1f:
93-
*string = [[[NSString alloc] initWithBytes:(_bytes + start) length:(_index - start) encoding:NSUTF8StringEncoding] autorelease];
93+
*string = [[NSString alloc] initWithBytes:(_bytes + start) length:(_index - start) encoding:NSUTF8StringEncoding];
9494
return YES;
9595
break;
9696
default:

0 commit comments

Comments
 (0)