// // 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" @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