diff --git a/JsonLiteObjC/JsonLiteObjC.xcodeproj/project.pbxproj b/JsonLiteObjC/JsonLiteObjC.xcodeproj/project.pbxproj index e2512f8..ad50548 100644 --- a/JsonLiteObjC/JsonLiteObjC.xcodeproj/project.pbxproj +++ b/JsonLiteObjC/JsonLiteObjC.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ 847619921776101900F4A34B /* JsonLiteObjCAcc.m in Sources */ = {isa = PBXBuildFile; fileRef = 847619911776101900F4A34B /* JsonLiteObjCAcc.m */; }; 84761995177617B400F4A34B /* JsonLiteObjCConverters.m in Sources */ = {isa = PBXBuildFile; fileRef = 84761994177617B400F4A34B /* JsonLiteObjCConverters.m */; }; 84A23983166295CC00CE528C /* success in Resources */ = {isa = PBXBuildFile; fileRef = 879D194C15BAA3A700791C72 /* success */; }; + 84BC599B178FE3EF006416F3 /* JsonLiteObjCStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 84BC599A178FE3EF006416F3 /* JsonLiteObjCStream.m */; }; 84C478E4172B3B6B00C1E798 /* JsonLiteObjCInputs.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C478E3172B3B6B00C1E798 /* JsonLiteObjCInputs.m */; }; 84C478E5172B42CE00C1E798 /* JsonLiteObjCConvertersTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84F54F8D166E96FC008C819D /* JsonLiteObjCConvertersTests.m */; }; 84C478E6172B42CE00C1E798 /* JsonLiteObjCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 879D182715BA9B1A00791C72 /* JsonLiteObjCTests.m */; }; @@ -99,6 +100,8 @@ 84761994177617B400F4A34B /* JsonLiteObjCConverters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JsonLiteObjCConverters.m; sourceTree = ""; }; 84A2398B1662E64A00CE528C /* JsonLiteObjCUnicodeTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsonLiteObjCUnicodeTests.h; sourceTree = ""; }; 84A2398C1662E64A00CE528C /* JsonLiteObjCUnicodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JsonLiteObjCUnicodeTests.m; sourceTree = ""; }; + 84BC5999178FE3EF006416F3 /* JsonLiteObjCStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsonLiteObjCStream.h; sourceTree = ""; }; + 84BC599A178FE3EF006416F3 /* JsonLiteObjCStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JsonLiteObjCStream.m; sourceTree = ""; }; 84C478E2172B3B6B00C1E798 /* JsonLiteObjCInputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsonLiteObjCInputs.h; sourceTree = ""; }; 84C478E3172B3B6B00C1E798 /* JsonLiteObjCInputs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JsonLiteObjCInputs.m; sourceTree = ""; }; 84C478ED172B437000C1E798 /* JsonLiteObjCBadToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsonLiteObjCBadToken.h; sourceTree = ""; }; @@ -272,6 +275,8 @@ 84C478E3172B3B6B00C1E798 /* JsonLiteObjCInputs.m */, 84D24A381662EC1D00F48E5C /* JsonLiteObjCPoolTests.h */, 84D24A391662EC1D00F48E5C /* JsonLiteObjCPoolTests.m */, + 84BC5999178FE3EF006416F3 /* JsonLiteObjCStream.h */, + 84BC599A178FE3EF006416F3 /* JsonLiteObjCStream.m */, 879D182515BA9B1A00791C72 /* JsonLiteObjCTests.h */, 879D182715BA9B1A00791C72 /* JsonLiteObjCTests.m */, 84E12D5C1719E20800DCF3FD /* JsonLiteObjCTokenTests.h */, @@ -492,6 +497,7 @@ 8476198D1775E79900F4A34B /* JsonLiteObjCBrokenTokenTests.m in Sources */, 847619921776101900F4A34B /* JsonLiteObjCAcc.m in Sources */, 84761995177617B400F4A34B /* JsonLiteObjCConverters.m in Sources */, + 84BC599B178FE3EF006416F3 /* JsonLiteObjCStream.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCInputs.m b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCInputs.m index 98c6ab7..c59e762 100644 --- a/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCInputs.m +++ b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCInputs.m @@ -250,6 +250,12 @@ - (void)testJsonLiteParserObjC { NSData *data = [self dataFromFile:@"random" inDir:@"success"]; STAssertNotNil(data, @"Data is nil"); + [parser parse:NULL length:1]; + STAssertNotNil([parser.parseError code] == JsonLiteCodeInvalidArgument, @"Incorrect error"); + + [parser parse:[data bytes] length:0]; + STAssertNotNil([parser.parseError code] == JsonLiteCodeInvalidArgument, @"Incorrect error"); + [parser parse:data]; STAssertNil(parser.parseError, @"Parsing fails %@", parser.parseError); diff --git a/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.h b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.h new file mode 100644 index 0000000..59f719c --- /dev/null +++ b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.h @@ -0,0 +1,13 @@ +// +// JsonLiteObjCStream.h +// JsonLiteObjC +// +// Created by admin on 7/12/13. +// Copyright (c) 2013 Andrii Mamchur. All rights reserved. +// + +#import + +@interface JsonLiteObjCStream : SenTestCase + +@end diff --git a/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.m b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.m new file mode 100644 index 0000000..905e678 --- /dev/null +++ b/JsonLiteObjC/JsonLiteObjCTests/JsonLiteObjCStream.m @@ -0,0 +1,92 @@ +// +// JsonLiteObjCStream.m +// JsonLiteObjC +// +// Created by admin on 7/12/13. +// Copyright (c) 2013 Andrii Mamchur. All rights reserved. +// + +#import "JsonLiteObjCStream.h" +#import "JsonLiteSenTestCaseExt.h" +#import "JsonLiteParser.h" +#import "JsonLiteAccumulator.h" +#import "JsonLiteSerializer.h" + +@interface JsonLiteObjCStream() { + volatile BOOL finished; +} + +@end + +@implementation JsonLiteObjCStream + +- (void)parserDidStartObject:(JsonLiteParser *)parser { +} + +- (void)parserDidEndObject:(JsonLiteParser *)parser { +} + +- (void)parserDidStartArray:(JsonLiteParser *)parser { +} + +- (void)parserDidEndArray:(JsonLiteParser *)parser { +} + +- (void)parser:(JsonLiteParser *)parser foundKeyToken:(JsonLiteStringToken *)token { +} + +- (void)parser:(JsonLiteParser *)parser foundStringToken:(JsonLiteStringToken *)token { +} + +- (void)parser:(JsonLiteParser *)parser foundNumberToken:(JsonLiteNumberToken *)token { +} + +- (void)parserFoundTrueToken:(JsonLiteParser *)parser { +} + +- (void)parserFoundFalseToken:(JsonLiteParser *)parser { +} + +- (void)parserFoundNullToken:(JsonLiteParser *)parser { +} + +- (void)parser:(JsonLiteParser *)parser didFinishParsingWithError:(NSError *)error { + finished = [error code] != JsonLiteCodeEndOfStream; +} + +- (void)testStream { + NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"random" + ofType:@"json" + inDirectory:@"success"]; + NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:path]; + JsonLiteParser *parser = [JsonLiteParser parser]; + parser.delegate = self; + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + [parser parse:stream inRunLoop:runLoop]; + + finished = NO; + while (!finished) { + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:1]; + [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]; + } + + STAssertNil(parser.parseError, @"Error occurs %@", parser.parseError); +} + +- (void)testInputs { + NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"random" + ofType:@"json" + inDirectory:@"success"]; + NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:path]; + JsonLiteParser *parser = [JsonLiteParser parser]; + [parser parse:nil inRunLoop:nil]; + STAssertTrue([parser.parseError code] == JsonLiteCodeInvalidArgument, @"Incorrect error"); + + [parser parse:stream inRunLoop:nil]; + STAssertTrue([parser.parseError code] == JsonLiteCodeInvalidArgument, @"Incorrect error"); + + [parser parse:nil inRunLoop:[NSRunLoop currentRunLoop]]; + STAssertTrue([parser.parseError code] == JsonLiteCodeInvalidArgument, @"Incorrect error"); +} + +@end diff --git a/objc/JsonLiteParser.h b/objc/JsonLiteParser.h index 88c5347..04867ac 100644 --- a/objc/JsonLiteParser.h +++ b/objc/JsonLiteParser.h @@ -83,7 +83,9 @@ extern NSString * const JsonLiteCodeDomain; @property (nonatomic, assign, readonly) NSUInteger depth; @property (nonatomic, retain, readonly) NSError *parseError; +- (BOOL)parse:(const uint8_t *)data length:(NSUInteger)length; - (BOOL)parse:(NSData *)data; +- (BOOL)parse:(NSInputStream *)stream inRunLoop:(NSRunLoop *)runloop; - (NSError *)suspend; - (NSError *)resume; diff --git a/objc/JsonLiteParser.m b/objc/JsonLiteParser.m index 8ecbcbb..746024b 100644 --- a/objc/JsonLiteParser.m +++ b/objc/JsonLiteParser.m @@ -185,11 +185,13 @@ - (NSDecimalNumber *)decimal { @end -@interface JsonLiteParser() { +@interface JsonLiteParser() { JsonLiteInternal internal; } @property (nonatomic, retain, readwrite) NSError *parseError; +@property (nonatomic, retain) NSInputStream *stream; +@property (nonatomic, retain) NSRunLoop *runLoop; + (NSError *)errorForCode:(JsonLiteCode)error; @@ -200,6 +202,8 @@ @implementation JsonLiteParser @synthesize delegate; @synthesize depth; @synthesize parseError; +@synthesize stream; +@synthesize runLoop; + (void)load { class_JsonLiteStringToken = [JsonLiteStringToken class]; @@ -229,12 +233,14 @@ + (id)parser { - (void)dealloc { self.parseError = nil; + self.stream = nil; + self.runLoop = nil; jsonlite_parser_release(internal.parser); [super dealloc]; } -- (BOOL)parse:(NSData *)data { - if (data == nil) { +- (BOOL)parse:(const uint8_t *)data length:(NSUInteger)length { + if (data == nil || length == 0) { self.parseError = [JsonLiteParser errorForCode:JsonLiteCodeInvalidArgument]; return NO; } @@ -249,13 +255,54 @@ - (BOOL)parse:(NSData *)data { jsonlite_parser_set_callback(jp, &cbs); } } + + jsonlite_result result = jsonlite_parser_tokenize(jp, data, length); + + self.parseError = [JsonLiteParser errorForCode:(JsonLiteCode)result]; + return result == jsonlite_result_ok; +} - jsonlite_result result = jsonlite_parser_tokenize(jp, [data bytes], [data length]); +- (BOOL)parse:(NSData *)data { + return [self parse:[data bytes] length:[data length]]; +} + +- (void)stream:(NSInputStream *)aStream handleEvent:(NSStreamEvent)eventCode { + uint8_t data[4096]; + NSInteger read; + switch (eventCode) { + case NSStreamEventHasBytesAvailable: + read = [stream read:data maxLength:sizeof(data)]; + [self parse:data length:read]; + if ([self.parseError code] == JsonLiteCodeEndOfStream) { + return; + } + case NSStreamEventErrorOccurred: + case NSStreamEventEndEncountered: + [stream close]; + [stream removeFromRunLoop:runLoop forMode:NSDefaultRunLoopMode]; + self.stream = nil; + self.runLoop = nil; + break; + default: + break; + } +} - self.parseError = [JsonLiteParser errorForCode:(JsonLiteCode)result]; - return result == jsonlite_result_ok; +- (BOOL)parse:(NSInputStream *)theStream inRunLoop:(NSRunLoop *)theRunLoop { + if (theStream == nil || theRunLoop == nil) { + self.parseError = [JsonLiteParser errorForCode:JsonLiteCodeInvalidArgument]; + return NO; + } + + self.stream = theStream; + self.runLoop = theRunLoop; + [self.stream setDelegate:self]; + [self.stream scheduleInRunLoop:self.runLoop forMode:NSDefaultRunLoopMode]; + [self.stream open]; + return YES; } + - (NSError *)suspend { if (internal.parser == NULL) { return [JsonLiteParser errorForCode:JsonLiteCodeNotAllowed]; @@ -278,6 +325,11 @@ - (NSError *)resume { } - (void)reset { + [stream close]; + [stream removeFromRunLoop:runLoop forMode:NSDefaultRunLoopMode]; + self.stream = nil; + self.runLoop = nil; + jsonlite_parser_release(internal.parser); internal.parser = NULL; } @@ -372,7 +424,6 @@ static void parse_finish(jsonlite_callback_context *ctx) { JsonLiteParser *p = (JsonLiteParser *)jli->parserObj; NSError *error = [JsonLiteParser errorForCode:(JsonLiteCode)res]; p.parseError = error; - jli->parseFinished(jli->delegate, @selector(parser:didFinishParsingWithError:), jli->parserObj, error); }