]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1300 d1b88da0-ebda-0310...
authorwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 13 Dec 2007 18:55:11 +0000 (18:55 +0000)
committerwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 13 Dec 2007 18:55:11 +0000 (18:55 +0000)
ChangeLog
SoObjects/SOGo/GNUmakefile
SoObjects/SOGo/NSDictionary+BSJSONAdditions.h [new file with mode: 0644]
SoObjects/SOGo/NSDictionary+BSJSONAdditions.m [new file with mode: 0644]
SoObjects/SOGo/NSScanner+BSJSONAdditions.h [new file with mode: 0644]
SoObjects/SOGo/NSScanner+BSJSONAdditions.m [new file with mode: 0644]

index c0cf8e7b62e9122ab0b0c877aae068e3f11e8e7e..ef45ef7ef66ae5f25e4852f3c56dc99e6cce6350 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-12-13  Wolfgang Sourdeau  <wsourdeau@inverse.ca>
+
+       * SoObjects/SOGo/NSScanner+BSJSONAdditions.m ([NSScanner
+       -scanJSONStringDelimiterString]): new category module taken from
+       BSJSONAdditions 1.3.
+
+       * SoObjects/SOGo/NSDictionary+BSJSONAdditions.[hm]: new category
+       module taken from BSJSONAdditions 1.3.
+       http://blakeseely.com/downloads.html
+
 2007-12-12  Wolfgang Sourdeau  <wsourdeau@inverse.ca>
 
        * SoObjects/SOGo/NSString+Utilities.m ([NSString
index 889b653fd764227a3e398ea44a46d0e30e70e22c..c99c714e0b052ccf1985d96722c2e17b9aa83ff4 100644 (file)
@@ -50,6 +50,9 @@ libSOGo_HEADER_FILES = \
        SOGoMailer.h                    \
        SOGoUser.h                      \
        \
+       NSDictionary+BSJSONAdditions.h  \
+       NSScanner+BSJSONAdditions.h     \
+       \
        WORequest+SOGo.h
 
 libSOGo_OBJC_FILES = \
@@ -84,6 +87,9 @@ libSOGo_OBJC_FILES = \
        SOGoMailer.m                    \
        SOGoUser.m                      \
        \
+       NSDictionary+BSJSONAdditions.m  \
+       NSScanner+BSJSONAdditions.m     \
+       \
        WORequest+SOGo.m
 
 # tools
diff --git a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.h b/SoObjects/SOGo/NSDictionary+BSJSONAdditions.h
new file mode 100644 (file)
index 0000000..5cbfa1b
--- /dev/null
@@ -0,0 +1,45 @@
+//
+//  BSJSONAdditions
+//
+//  Created by Blake Seely on 2/1/06.
+//  Copyright 2006 Blake Seely - http://www.blakeseely.com  All rights reserved.
+//  Permission to use this code:
+//
+//  Feel free to use this code in your software, either as-is or 
+//  in a modified form. Either way, please include a credit in 
+//  your software's "About" box or similar, mentioning at least 
+//  my name (Blake Seely).
+//
+//  Permission to redistribute this code:
+//
+//  You can redistribute this code, as long as you keep these 
+//  comments. You can also redistribute modified versions of the 
+//  code, as long as you add comments to say that you've made 
+//  modifications (keeping these original comments too).
+//
+//  If you do use or redistribute this code, an email would be 
+//  appreciated, just to let me know that people are finding my 
+//  code useful. You can reach me at blakeseely@mac.com
+
+#import <Foundation/NSDictionary.h>
+
+extern NSString *jsonIndentString;
+extern const int jsonDoNotIndent;
+
+@interface NSDictionary (BSJSONAdditions)
+
++ (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString;
+- (NSString *)jsonStringValue;
+
+@end
+
+
+@interface NSDictionary (PrivateBSJSONAdditions)
+
+- (NSString *)jsonStringValueWithIndentLevel:(int)level;
+- (NSString *)jsonStringForValue:(id)value withIndentLevel:(int)level;
+- (NSString *)jsonStringForArray:(NSArray *)array withIndentLevel:(int)level;
+- (NSString *)jsonStringForString:(NSString *)string;
+- (NSString *)jsonIndentStringForLevel:(int)level;
+
+@end
diff --git a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.m b/SoObjects/SOGo/NSDictionary+BSJSONAdditions.m
new file mode 100644 (file)
index 0000000..1bc0e75
--- /dev/null
@@ -0,0 +1,198 @@
+//
+//  BSJSONAdditions
+//
+//  Created by Blake Seely on 2/1/06.
+//  Copyright 2006 Blake Seely - http://www.blakeseely.com  All rights reserved.
+//  Permission to use this code:
+//
+//  Feel free to use this code in your software, either as-is or 
+//  in a modified form. Either way, please include a credit in 
+//  your software's "About" box or similar, mentioning at least 
+//  my name (Blake Seely).
+//
+//  Permission to redistribute this code:
+//
+//  You can redistribute this code, as long as you keep these 
+//  comments. You can also redistribute modified versions of the 
+//  code, as long as you add comments to say that you've made 
+//  modifications (keeping these original comments too).
+//
+//  If you do use or redistribute this code, an email would be 
+//  appreciated, just to let me know that people are finding my 
+//  code useful. You can reach me at blakeseely@mac.com
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDecimalNumber.h>
+#import <Foundation/NSEnumerator.h>
+#import <Foundation/NSNull.h>
+#import <Foundation/NSValue.h>
+
+#import "NSDictionary+BSJSONAdditions.h"
+#import "NSScanner+BSJSONAdditions.h"
+
+NSString *jsonIndentString = @"\t"; // Modify this string to change how the output formats.
+const int jsonDoNotIndent = -1;
+
+@implementation NSDictionary (BSJSONAdditions)
+
++ (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString
+{
+  NSScanner *scanner = [[NSScanner alloc] initWithString:jsonString];
+  NSDictionary *dictionary = nil;
+  [scanner scanJSONObject:&dictionary];
+  [scanner release];
+  return dictionary;
+}
+
+- (NSString *)jsonStringValue
+{
+  return [self jsonStringValueWithIndentLevel:0];
+}
+
+@end
+
+@implementation NSDictionary (PrivateBSJSONAdditions)
+
+- (NSString *)jsonStringValueWithIndentLevel:(int)level
+{
+  NSMutableString *jsonString = [[NSMutableString alloc] init];
+  [jsonString appendString:jsonObjectStartString];
+       
+  NSEnumerator *keyEnum = [self keyEnumerator];
+  NSString *keyString = [keyEnum nextObject];
+  NSString *valueString;
+  if (keyString != nil) {
+    valueString = [self jsonStringForValue:[self objectForKey:keyString] withIndentLevel:level];
+    if (level != jsonDoNotIndent) { // indent before each key
+      [jsonString appendString:[self jsonIndentStringForLevel:level]];
+    }            
+    [jsonString appendFormat:@" %@ %@ %@", [self jsonStringForString:keyString], jsonKeyValueSeparatorString, valueString];
+  }
+       
+  while ((keyString = [keyEnum nextObject])) {
+    valueString = [self jsonStringForValue:[self objectForKey:keyString] withIndentLevel:level]; // TODO bail if valueString is nil? How to bail successfully from here?
+    [jsonString appendString:jsonValueSeparatorString];
+    if (level != jsonDoNotIndent) { // indent before each key
+      [jsonString appendFormat:@"%@", [self jsonIndentStringForLevel:level]];
+    }
+    [jsonString appendFormat:@" %@ %@ %@", [self jsonStringForString:keyString], jsonKeyValueSeparatorString, valueString];
+  }
+       
+  //[jsonString appendString:@"\n"];
+  [jsonString appendString:jsonObjectEndString];
+       
+  return [jsonString autorelease];
+}
+
+- (NSString *)jsonStringForValue:(id)value withIndentLevel:(int)level
+{      
+  NSString *jsonString;
+  if ([value respondsToSelector:@selector(characterAtIndex:)]) // String
+    jsonString = [self jsonStringForString:(NSString *)value];
+  else if ([value respondsToSelector:@selector(keyEnumerator)]) // Dictionary
+    jsonString = [(NSDictionary *)value jsonStringValueWithIndentLevel:(level + 1)];
+  else if ([value respondsToSelector:@selector(objectAtIndex:)]) // Array
+    jsonString = [self jsonStringForArray:(NSArray *)value withIndentLevel:level];
+  else if (value == [NSNull null]) // null
+    jsonString = jsonNullString;
+  else if ([value respondsToSelector:@selector(objCType)]) { // NSNumber - representing true, false, and any form of numeric
+    NSNumber *number = (NSNumber *)value;
+    if (((*[number objCType]) == 'c') && ([number boolValue] == YES)) // true
+      jsonString = jsonTrueString;
+    else if (((*[number objCType]) == 'c') && ([number boolValue] == NO)) // false
+      jsonString = jsonFalseString;
+    else // attempt to handle as a decimal number - int, fractional, exponential
+      // TODO: values converted from exponential json to dict and back to json do not format as exponential again
+      jsonString = [[NSDecimalNumber decimalNumberWithDecimal:[number decimalValue]] stringValue];
+  } else {
+    // TODO: error condition - it's not any of the types that I know about.
+    return nil;
+  }
+       
+  return jsonString;
+}
+
+- (NSString *)jsonStringForArray:(NSArray *)array withIndentLevel:(int)level
+{
+  NSMutableString *jsonString = [[NSMutableString alloc] init];
+  [jsonString appendString:jsonArrayStartString];
+       
+  if ([array count] > 0) {
+    [jsonString appendString:[self jsonStringForValue:[array objectAtIndex:0] withIndentLevel:level]];
+  }
+       
+  int i;
+  for (i = 1; i < [array count]; i++) {
+    [jsonString appendFormat:@"%@ %@", jsonValueSeparatorString, [self jsonStringForValue:[array objectAtIndex:i] withIndentLevel:level]];
+  }
+       
+  [jsonString appendString:jsonArrayEndString];
+  return [jsonString autorelease];
+}
+
+- (NSString *)jsonStringForString:(NSString *)string
+{
+  NSMutableString *jsonString = [[NSMutableString alloc] init];
+  [jsonString appendString:jsonStringDelimiterString];
+
+  // Build the result one character at a time, inserting escaped characters as necessary
+  int i;
+  unichar nextChar;
+  for (i = 0; i < [string length]; i++) {
+    nextChar = [string characterAtIndex:i];
+    switch (nextChar) {
+    case '\"':
+      [jsonString appendString:@"\\\""];
+      break;
+    case '\\':
+      [jsonString appendString:@"\\n"];
+      break;
+      /* TODO: email out to json group on this - spec says to handlt his, examples and example code don't handle this.
+        case '\/':
+        [jsonString appendString:@"\\/"];
+        break;
+      */ 
+    case '\b':
+      [jsonString appendString:@"\\b"];
+      break;
+    case '\f':
+      [jsonString appendString:@"\\f"];
+      break;
+    case '\n':
+      [jsonString appendString:@"\\n"];
+      break;
+    case '\r':
+      [jsonString appendString:@"\\r"];
+      break;
+    case '\t':
+      [jsonString appendString:@"\\t"];
+      break;
+      /* TODO: Find and encode unicode characters here?
+        case '\u':
+        [jsonString appendString:@"\\n"];
+        break;
+      */
+    default:
+      [jsonString appendString:[NSString stringWithCharacters:&nextChar length:1]];
+      break;
+    }
+  }
+  [jsonString appendString:jsonStringDelimiterString];
+  return [jsonString autorelease];
+}
+
+- (NSString *)jsonIndentStringForLevel:(int)level
+{
+  NSMutableString *indentString = [[NSMutableString alloc] init];
+  if (level != jsonDoNotIndent) {
+    [indentString appendString:@"\n"];
+    int i;
+    for (i = 0; i < level; i++) {
+      [indentString appendString:jsonIndentString];
+    }
+  }
+    
+  return [indentString autorelease];
+}
+
+@end
diff --git a/SoObjects/SOGo/NSScanner+BSJSONAdditions.h b/SoObjects/SOGo/NSScanner+BSJSONAdditions.h
new file mode 100644 (file)
index 0000000..1505c92
--- /dev/null
@@ -0,0 +1,64 @@
+//
+//  BSJSONAdditions
+//
+//  Created by Blake Seely on 2/1/06.
+//  Copyright 2006 Blake Seely - http://www.blakeseely.com  All rights reserved.
+//  Permission to use this code:
+//
+//  Feel free to use this code in your software, either as-is or 
+//  in a modified form. Either way, please include a credit in 
+//  your software's "About" box or similar, mentioning at least 
+//  my name (Blake Seely).
+//
+//  Permission to redistribute this code:
+//
+//  You can redistribute this code, as long as you keep these 
+//  comments. You can also redistribute modified versions of the 
+//  code, as long as you add comments to say that you've made 
+//  modifications (keeping these original comments too).
+//
+//  If you do use or redistribute this code, an email would be 
+//  appreciated, just to let me know that people are finding my 
+//  code useful. You can reach me at blakeseely@mac.com
+//
+
+#import <Foundation/NSScanner.h>
+
+@class NSArray;
+@class NSDictionary;
+@class NSNumber;
+@class NSString;
+
+extern NSString *jsonObjectStartString;
+extern NSString *jsonObjectEndString;
+extern NSString *jsonArrayStartString;
+extern NSString *jsonArrayEndString;
+extern NSString *jsonKeyValueSeparatorString;
+extern NSString *jsonValueSeparatorString;
+extern NSString *jsonStringDelimiterString;
+extern NSString *jsonStringEscapedDoubleQuoteString;
+extern NSString *jsonStringEscapedSlashString;
+extern NSString *jsonTrueString;
+extern NSString *jsonFalseString;
+extern NSString *jsonNullString;
+
+
+@interface NSScanner (PrivateBSJSONAdditions)
+
+- (BOOL)scanJSONObject:(NSDictionary **)dictionary;
+- (BOOL)scanJSONArray:(NSArray **)array;
+- (BOOL)scanJSONString:(NSString **)string;
+- (BOOL)scanJSONValue:(id *)value;
+- (BOOL)scanJSONNumber:(NSNumber **)number;
+
+- (BOOL)scanJSONWhiteSpace;
+- (BOOL)scanJSONKeyValueSeparator;
+- (BOOL)scanJSONValueSeparator;
+- (BOOL)scanJSONObjectStartString;
+- (BOOL)scanJSONObjectEndString;
+- (BOOL)scanJSONArrayStartString;
+- (BOOL)scanJSONArrayEndString;
+- (BOOL)scanJSONArrayEndString;
+- (BOOL)scanJSONStringDelimiterString;
+
+@end
diff --git a/SoObjects/SOGo/NSScanner+BSJSONAdditions.m b/SoObjects/SOGo/NSScanner+BSJSONAdditions.m
new file mode 100644 (file)
index 0000000..33bf584
--- /dev/null
@@ -0,0 +1,312 @@
+//
+//  BSJSONAdditions
+//
+//  Created by Blake Seely on 2/1/06.
+//  Copyright 2006 Blake Seely - http://www.blakeseely.com  All rights reserved.
+//  Permission to use this code:
+//
+//  Feel free to use this code in your software, either as-is or 
+//  in a modified form. Either way, please include a credit in 
+//  your software's "About" box or similar, mentioning at least 
+//  my name (Blake Seely).
+//
+//  Permission to redistribute this code:
+//
+//  You can redistribute this code, as long as you keep these 
+//  comments. You can also redistribute modified versions of the 
+//  code, as long as you add comments to say that you've made 
+//  modifications (keeping these original comments too).
+//
+//  If you do use or redistribute this code, an email would be 
+//  appreciated, just to let me know that people are finding my 
+//  code useful. You can reach me at blakeseely@mac.com
+//
+//
+//  Version 1.2: Includes modifications by Bill Garrison: http://www.standardorbit.com , which included
+//    Unit Tests adapted from Jonathan Wight's CocoaJSON code: http://www.toxicsoftware.com 
+//    I have included those adapted unit tests in this package.
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDecimalNumber.h>
+#import <Foundation/NSNull.h>
+#import <Foundation/NSValue.h>
+
+#import "NSScanner+BSJSONAdditions.h"
+
+NSString *jsonObjectStartString = @"{";
+NSString *jsonObjectEndString = @"}";
+NSString *jsonArrayStartString = @"[";
+NSString *jsonArrayEndString = @"]";
+NSString *jsonKeyValueSeparatorString = @":";
+NSString *jsonValueSeparatorString = @",";
+NSString *jsonStringDelimiterString = @"\"";
+NSString *jsonStringEscapedDoubleQuoteString = @"\\\"";
+NSString *jsonStringEscapedSlashString = @"\\\\";
+NSString *jsonTrueString = @"true";
+NSString *jsonFalseString = @"false";
+NSString *jsonNullString = @"null";
+
+@implementation NSScanner (PrivateBSJSONAdditions)
+
+- (BOOL)scanJSONObject:(NSDictionary **)dictionary
+{
+  //[self setCharactersToBeSkipped:nil];
+       
+  BOOL result = NO;
+       
+  /* START - April 21, 2006 - Updated to bypass irrelevant characters at the beginning of a JSON string */
+  NSString *ignoredString;
+  [self scanUpToString:jsonObjectStartString intoString:&ignoredString];
+  /* END - April 21, 2006 */
+
+  if (![self scanJSONObjectStartString]) {
+    // TODO: Error condition. For now, return false result, do nothing with the dictionary handle
+  } else {
+    NSMutableDictionary *jsonKeyValues = [[[NSMutableDictionary alloc] init] autorelease];
+    NSString *key = nil;
+    id value;
+    [self scanJSONWhiteSpace];
+    while (([self scanJSONString:&key]) && ([self scanJSONKeyValueSeparator]) && ([self scanJSONValue:&value])) {
+      [jsonKeyValues setObject:value forKey:key];
+      [self scanJSONWhiteSpace];
+      // check to see if the character at scan location is a value separator. If it is, do nothing.
+      if ([[[self string] substringWithRange:NSMakeRange([self scanLocation], 1)] isEqualToString:jsonValueSeparatorString]) {
+       [self scanJSONValueSeparator];
+      }
+    }
+    if ([self scanJSONObjectEndString]) {
+      // whether or not we found a key-val pair, we found open and close brackets - completing an object
+      result = YES;
+      *dictionary = jsonKeyValues;
+    }
+  }
+  return result;
+}
+
+- (BOOL)scanJSONArray:(NSArray **)array
+{
+  BOOL result = NO;
+  NSMutableArray *values = [[[NSMutableArray alloc] init] autorelease];
+  [self scanJSONArrayStartString];
+  id value = nil;
+       
+  while ([self scanJSONValue:&value]) {
+    [values addObject:value];
+    [self scanJSONWhiteSpace];
+    if ([[[self string] substringWithRange:NSMakeRange([self scanLocation], 1)] isEqualToString:jsonValueSeparatorString]) {
+      [self scanJSONValueSeparator];
+    }
+  }
+  if ([self scanJSONArrayEndString]) {
+    result = YES;
+    *array = values;
+  }
+       
+  return result;
+}
+
+- (BOOL)scanJSONString:(NSString **)string
+{
+  BOOL result = NO;
+  if ([self scanJSONStringDelimiterString]) {
+    NSMutableString *chars = [[[NSMutableString alloc] init] autorelease];
+    NSString *characterFormat = @"%C";
+               
+    // process character by character until we finish the string or reach another double-quote
+    while ((![self isAtEnd]) && ([[self string] characterAtIndex:[self scanLocation]] != '\"')) {
+      unichar currentChar = [[self string] characterAtIndex:[self scanLocation]];
+      unichar nextChar;
+      if (currentChar != '\\') {
+       [chars appendFormat:characterFormat, currentChar];
+       [self setScanLocation:([self scanLocation] + 1)];
+      } else {
+       nextChar = [[self string] characterAtIndex:([self scanLocation] + 1)];
+       switch (nextChar) {
+       case '\"':
+         [chars appendString:@"\""];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case '\\':
+         [chars appendString:@"\\"]; // debugger shows result as having two slashes, but final output is correct. Possible debugger error?
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+         /* TODO: json.org docs mention this seq, so does yahoo, but not recognized here by xcode, note from crockford: not a required escape
+            case '\/':
+            [chars appendString:@"\/"];
+            [self setScanLocation:([self scanLocation] + 2)];
+            break;
+         */
+       case 'b':
+         [chars appendString:@"\b"];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case 'f':
+         [chars appendString:@"\f"];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case 'n':
+         [chars appendString:@"\n"];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case 'r':
+         [chars appendString:@"\r"];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case 't':
+         [chars appendString:@"\t"];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       case 'u': // unicode sequence - get string of hex chars, convert to int, convert to unichar, append
+         [self setScanLocation:([self scanLocation] + 2)]; // advance past '\u'
+         NSString *digits = [[self string] substringWithRange:NSMakeRange([self scanLocation], 4)];
+         /* START Updated code modified from code fix submitted by Bill Garrison - March 28, 2006 - http://www.standardorbit.net */
+         NSScanner *hexScanner = [NSScanner scannerWithString:digits];
+         NSString *verifiedHexDigits;
+         NSCharacterSet *hexDigitSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"];
+         if (NO == [hexScanner scanCharactersFromSet:hexDigitSet intoString:&verifiedHexDigits])
+           return NO;
+         if (4 != [verifiedHexDigits length])
+           return NO;
+                        
+         // Read in the hex value
+         [hexScanner setScanLocation:0];
+         unsigned unicodeHexValue;
+         if (NO == [hexScanner scanHexInt:&unicodeHexValue]) {
+           return NO;
+         }
+         [chars appendFormat:characterFormat, unicodeHexValue];
+         /* END update - March 28, 2006 */
+         [self setScanLocation:([self scanLocation] + 4)];
+         break;
+       default:
+         [chars appendFormat:@"\\%C", nextChar];
+         [self setScanLocation:([self scanLocation] + 2)];
+         break;
+       }
+      }
+    }
+               
+    if (![self isAtEnd]) {
+      result = [self scanJSONStringDelimiterString];
+      *string = chars;
+    }
+               
+    return result;
+       
+    /* this code is more appropriate if you have a separate method to unescape the found string
+       for example, between inputting json and outputting it, it may make more sense to have a category on NSString to perform
+       escaping and unescaping. Keeping this code and looking into this for a future update.
+       unsigned int searchLength = [[self string] length] - [self scanLocation];
+       unsigned int quoteLocation = [[self string] rangeOfString:jsonStringDelimiterString options:0 range:NSMakeRange([self scanLocation], searchLength)].location;
+       searchLength = [[self string] length] - quoteLocation;
+       while (([[[self string] substringWithRange:NSMakeRange((quoteLocation - 1), 2)] isEqualToString:jsonStringEscapedDoubleQuoteString]) &&
+       (quoteLocation != NSNotFound) &&
+       (![[[self string] substringWithRange:NSMakeRange((quoteLocation -2), 2)] isEqualToString:jsonStringEscapedSlashString])){
+       searchLength = [[self string] length] - (quoteLocation + 1);
+       quoteLocation = [[self string] rangeOfString:jsonStringDelimiterString options:0 range:NSMakeRange((quoteLocation + 1), searchLength)].location;
+       }
+               
+       *string = [[self string] substringWithRange:NSMakeRange([self scanLocation], (quoteLocation - [self scanLocation]))];
+       // TODO: process escape sequences out of the string - replacing with their actual characters. a function that does just this belongs
+       // in another class. So it may make more sense to change this whole implementation to just go character by character instead.
+       [self setScanLocation:(quoteLocation + 1)];
+    */
+    result = YES;
+               
+  }
+       
+  return result;
+}
+
+- (BOOL)scanJSONValue:(id *)value
+{
+  BOOL result = NO;
+       
+  [self scanJSONWhiteSpace];
+  NSString *substring = [[self string] substringWithRange:NSMakeRange([self scanLocation], 1)];
+  unsigned int trueLocation = [[self string] rangeOfString:jsonTrueString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location;
+  unsigned int falseLocation = [[self string] rangeOfString:jsonFalseString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location;
+  unsigned int nullLocation = [[self string] rangeOfString:jsonNullString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location;
+       
+  if ([substring isEqualToString:jsonStringDelimiterString]) {
+    result = [self scanJSONString:value];
+  } else if ([substring isEqualToString:jsonObjectStartString]) {
+    result = [self scanJSONObject:value];
+  } else if ([substring isEqualToString:jsonArrayStartString]) {
+    result = [self scanJSONArray:value];
+  } else if ([self scanLocation] == trueLocation) {
+    result = YES;
+    *value = [NSNumber numberWithBool:YES];
+    [self setScanLocation:([self scanLocation] + [jsonTrueString length])];
+  } else if ([self scanLocation] == falseLocation) {
+    result = YES;
+    *value = [NSNumber numberWithBool:NO];
+    [self setScanLocation:([self scanLocation] + [jsonFalseString length])];
+  } else if ([self scanLocation] == nullLocation) {
+    result = YES;
+    *value = [NSNull null];
+    [self setScanLocation:([self scanLocation] + [jsonNullString length])];
+  } else if (([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[[self string] characterAtIndex:[self scanLocation]]]) ||
+            ([[self string] characterAtIndex:[self scanLocation]] == '-')){ // check to make sure it's a digit or -
+    result =  [self scanJSONNumber:value];
+  }
+  return result;
+}
+
+- (BOOL)scanJSONNumber:(NSNumber **)number
+{
+  NSDecimal decimal;
+  BOOL result = [self scanDecimal:&decimal];
+  *number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
+  return result;
+}
+
+- (BOOL)scanJSONWhiteSpace
+{
+  //NSLog(@"Scanning white space - here are the next ten chars ---%@---", [[self string] substringWithRange:NSMakeRange([self scanLocation], 10)]);
+  BOOL result = NO;
+  NSCharacterSet *space = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+  while ([space characterIsMember:[[self string] characterAtIndex:[self scanLocation]]]) {
+    [self setScanLocation:([self scanLocation] + 1)];
+    result = YES;
+  }
+  //NSLog(@"Done Scanning white space - here are the next ten chars ---%@---", [[self string] substringWithRange:NSMakeRange([self scanLocation], 10)]);
+  return result;
+}
+
+- (BOOL)scanJSONKeyValueSeparator
+{
+  return [self scanString:jsonKeyValueSeparatorString intoString:nil];
+}
+
+- (BOOL)scanJSONValueSeparator
+{
+  return [self scanString:jsonValueSeparatorString intoString:nil];
+}
+
+- (BOOL)scanJSONObjectStartString
+{
+  return [self scanString:jsonObjectStartString intoString:nil];
+}
+
+- (BOOL)scanJSONObjectEndString
+{
+  return [self scanString:jsonObjectEndString intoString:nil];
+}
+
+- (BOOL)scanJSONArrayStartString
+{
+  return [self scanString:jsonArrayStartString intoString:nil];
+}
+
+- (BOOL)scanJSONArrayEndString
+{
+  return [self scanString:jsonArrayEndString intoString:nil];
+}
+
+- (BOOL)scanJSONStringDelimiterString;
+{
+  return [self scanString:jsonStringDelimiterString intoString:nil];
+}
+
+@end