blob: 308eae27cebe5373503f18a4517fd0f39d1fdfe1 [file] [log] [blame]
//
// GTMNSScanner+JSON.m
//
// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import "GTMDefines.h"
#import "GTMNSScanner+JSON.h"
// Export a nonsense symbol to suppress a libtool warning when this is linked
// alone in a static lib.
__attribute__((visibility("default")))
char NSScanner_GTMNSScannerJSONAdditionsExportToSuppressLibToolWarning = 0;
@implementation NSScanner (GTMNSScannerJSONAdditions)
- (BOOL)gtm_scanJSONString:(NSString **)jsonString
startChar:(unichar)startChar
endChar:(unichar)endChar {
BOOL isGood = NO;
NSRange jsonRange = { NSNotFound, 0 };
NSString *scanString = [self string];
NSUInteger startLocation = [self scanLocation];
NSUInteger length = [scanString length];
NSUInteger blockOpen = 0;
NSCharacterSet *charsToSkip = [self charactersToBeSkipped];
BOOL inQuoteMode = NO;
NSUInteger i;
for (i = startLocation; i < length; ++i) {
unichar jsonChar = [scanString characterAtIndex:i];
if (jsonChar == startChar && !inQuoteMode) {
if (blockOpen == 0) {
jsonRange.location = i;
}
blockOpen += 1;
} else if (blockOpen == 0) {
// If we haven't opened our block skip over any characters in
// charsToSkip.
if (![charsToSkip characterIsMember:jsonChar]) {
break;
}
} else if (jsonChar == endChar && !inQuoteMode) {
blockOpen -= 1;
if (blockOpen == 0) {
i += 1; // Move onto next character
jsonRange.length = i - jsonRange.location;
break;
}
} else {
if (jsonChar == '"') {
inQuoteMode = !inQuoteMode;
} else if (inQuoteMode && jsonChar == '\\') {
// Skip the escaped character if it isn't the last one
if (i < length - 1) ++i;
}
}
}
[self setScanLocation:i];
if (blockOpen == 0 && jsonRange.location != NSNotFound) {
isGood = YES;
if (jsonString) {
*jsonString = [scanString substringWithRange:jsonRange];
}
}
return isGood;
}
- (BOOL)gtm_scanJSONObjectString:(NSString **)jsonString {
return [self gtm_scanJSONString:jsonString startChar:'{' endChar:'}'];
}
- (BOOL)gtm_scanJSONArrayString:(NSString**)jsonString {
return [self gtm_scanJSONString:jsonString startChar:'[' endChar:']'];
}
@end