summary refs log tree commit diff stats
path: root/libs/TouchJSON/JSON/CJSONScanner.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/TouchJSON/JSON/CJSONScanner.m')
-rwxr-xr-xlibs/TouchJSON/JSON/CJSONScanner.m676
1 files changed, 676 insertions, 0 deletions
diff --git a/libs/TouchJSON/JSON/CJSONScanner.m b/libs/TouchJSON/JSON/CJSONScanner.m new file mode 100755 index 0000000..c5ffeb4 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONScanner.m
@@ -0,0 +1,676 @@
1//
2// CJSONScanner.m
3// TouchCode
4//
5// Created by Jonathan Wight on 12/07/2005.
6// Copyright 2005 toxicsoftware.com. All rights reserved.
7//
8// Permission is hereby granted, free of charge, to any person
9// obtaining a copy of this software and associated documentation
10// files (the "Software"), to deal in the Software without
11// restriction, including without limitation the rights to use,
12// copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the
14// Software is furnished to do so, subject to the following
15// conditions:
16//
17// The above copyright notice and this permission notice shall be
18// included in all copies or substantial portions of the Software.
19//
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27// OTHER DEALINGS IN THE SOFTWARE.
28//
29
30#import "CJSONScanner.h"
31
32#import "CDataScanner_Extensions.h"
33
34#if !defined(TREAT_COMMENTS_AS_WHITESPACE)
35#define TREAT_COMMENTS_AS_WHITESPACE 0
36#endif // !defined(TREAT_COMMENTS_AS_WHITESPACE)
37
38NSString *const kJSONScannerErrorDomain = @"kJSONScannerErrorDomain";
39
40inline static int HexToInt(char inCharacter)
41 {
42 int theValues[] = { 0x0 /* 48 '0' */, 0x1 /* 49 '1' */, 0x2 /* 50 '2' */, 0x3 /* 51 '3' */, 0x4 /* 52 '4' */, 0x5 /* 53 '5' */, 0x6 /* 54 '6' */, 0x7 /* 55 '7' */, 0x8 /* 56 '8' */, 0x9 /* 57 '9' */, -1 /* 58 ':' */, -1 /* 59 ';' */, -1 /* 60 '<' */, -1 /* 61 '=' */, -1 /* 62 '>' */, -1 /* 63 '?' */, -1 /* 64 '@' */, 0xa /* 65 'A' */, 0xb /* 66 'B' */, 0xc /* 67 'C' */, 0xd /* 68 'D' */, 0xe /* 69 'E' */, 0xf /* 70 'F' */, -1 /* 71 'G' */, -1 /* 72 'H' */, -1 /* 73 'I' */, -1 /* 74 'J' */, -1 /* 75 'K' */, -1 /* 76 'L' */, -1 /* 77 'M' */, -1 /* 78 'N' */, -1 /* 79 'O' */, -1 /* 80 'P' */, -1 /* 81 'Q' */, -1 /* 82 'R' */, -1 /* 83 'S' */, -1 /* 84 'T' */, -1 /* 85 'U' */, -1 /* 86 'V' */, -1 /* 87 'W' */, -1 /* 88 'X' */, -1 /* 89 'Y' */, -1 /* 90 'Z' */, -1 /* 91 '[' */, -1 /* 92 '\' */, -1 /* 93 ']' */, -1 /* 94 '^' */, -1 /* 95 '_' */, -1 /* 96 '`' */, 0xa /* 97 'a' */, 0xb /* 98 'b' */, 0xc /* 99 'c' */, 0xd /* 100 'd' */, 0xe /* 101 'e' */, 0xf /* 102 'f' */, };
43 if (inCharacter >= '0' && inCharacter <= 'f')
44 return(theValues[inCharacter - '0']);
45 else
46 return(-1);
47 }
48
49@interface CJSONScanner ()
50- (BOOL)scanNotQuoteCharactersIntoString:(NSString **)outValue;
51@end
52
53#pragma mark -
54
55@implementation CJSONScanner
56
57@synthesize strictEscapeCodes;
58@synthesize nullObject;
59@synthesize allowedEncoding;
60@synthesize options;
61
62- (id)init
63 {
64 if ((self = [super init]) != NULL)
65 {
66 strictEscapeCodes = NO;
67 nullObject = [[NSNull null] retain];
68 }
69 return(self);
70 }
71
72- (void)dealloc
73 {
74 [nullObject release];
75 nullObject = NULL;
76 //
77 [super dealloc];
78 }
79
80#pragma mark -
81
82- (BOOL)setData:(NSData *)inData error:(NSError **)outError;
83 {
84 NSData *theData = inData;
85 if (theData && theData.length >= 4)
86 {
87 // This code is lame, but it works. Because the first character of any JSON string will always be a (ascii) control character we can work out the Unicode encoding by the bit pattern. See section 3 of http://www.ietf.org/rfc/rfc4627.txt
88 const char *theChars = theData.bytes;
89 NSStringEncoding theEncoding = NSUTF8StringEncoding;
90 if (theChars[0] != 0 && theChars[1] == 0)
91 {
92 if (theChars[2] != 0 && theChars[3] == 0)
93 theEncoding = NSUTF16LittleEndianStringEncoding;
94 else if (theChars[2] == 0 && theChars[3] == 0)
95 theEncoding = NSUTF32LittleEndianStringEncoding;
96 }
97 else if (theChars[0] == 0 && theChars[2] == 0 && theChars[3] != 0)
98 {
99 if (theChars[1] == 0)
100 theEncoding = NSUTF32BigEndianStringEncoding;
101 else if (theChars[1] != 0)
102 theEncoding = NSUTF16BigEndianStringEncoding;
103 }
104
105 NSString *theString = [[NSString alloc] initWithData:theData encoding:theEncoding];
106 if (theString == NULL && self.allowedEncoding != 0)
107 {
108 theString = [[NSString alloc] initWithData:theData encoding:self.allowedEncoding];
109 }
110 theData = [theString dataUsingEncoding:NSUTF8StringEncoding];
111 [theString release];
112 }
113
114 if (theData)
115 {
116 [super setData:theData];
117 return(YES);
118 }
119 else
120 {
121 if (outError)
122 {
123 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
124 @"Could not scan data. Data wasn't encoded properly?", NSLocalizedDescriptionKey,
125 NULL];
126 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
127 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_CouldNotDecodeData userInfo:theUserInfo];
128 }
129 return(NO);
130 }
131 }
132
133- (void)setData:(NSData *)inData
134 {
135 [self setData:inData error:NULL];
136 }
137
138#pragma mark -
139
140- (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError
141 {
142 BOOL theResult = YES;
143
144 [self skipWhitespace];
145
146 id theObject = NULL;
147
148 const unichar C = [self currentCharacter];
149 switch (C)
150 {
151 case 't':
152 if ([self scanUTF8String:"true" intoString:NULL])
153 {
154 theObject = [NSNumber numberWithBool:YES];
155 }
156 break;
157 case 'f':
158 if ([self scanUTF8String:"false" intoString:NULL])
159 {
160 theObject = [NSNumber numberWithBool:NO];
161 }
162 break;
163 case 'n':
164 if ([self scanUTF8String:"null" intoString:NULL])
165 {
166 theObject = self.nullObject;
167 }
168 break;
169 case '\"':
170 case '\'':
171 theResult = [self scanJSONStringConstant:&theObject error:outError];
172 break;
173 case '0':
174 case '1':
175 case '2':
176 case '3':
177 case '4':
178 case '5':
179 case '6':
180 case '7':
181 case '8':
182 case '9':
183 case '-':
184 theResult = [self scanJSONNumberConstant:&theObject error:outError];
185 break;
186 case '{':
187 theResult = [self scanJSONDictionary:&theObject error:outError];
188 break;
189 case '[':
190 theResult = [self scanJSONArray:&theObject error:outError];
191 break;
192 default:
193 theResult = NO;
194 if (outError)
195 {
196 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
197 @"Could not scan object. Character not a valid JSON character.", NSLocalizedDescriptionKey,
198 NULL];
199 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
200 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_CouldNotScanObject userInfo:theUserInfo];
201 }
202 break;
203 }
204
205 if (outObject != NULL)
206 *outObject = theObject;
207
208 return(theResult);
209 }
210
211- (BOOL)scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)outError
212 {
213 NSUInteger theScanLocation = [self scanLocation];
214
215 [self skipWhitespace];
216
217 if ([self scanCharacter:'{'] == NO)
218 {
219 if (outError)
220 {
221 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
222 @"Could not scan dictionary. Dictionary that does not start with '{' character.", NSLocalizedDescriptionKey,
223 NULL];
224 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
225 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryStartCharacterMissing userInfo:theUserInfo];
226 }
227 return(NO);
228 }
229
230 NSMutableDictionary *theDictionary = [[NSMutableDictionary alloc] init];
231
232 while ([self currentCharacter] != '}')
233 {
234 [self skipWhitespace];
235
236 if ([self currentCharacter] == '}')
237 break;
238
239 NSString *theKey = NULL;
240 if ([self scanJSONStringConstant:&theKey error:outError] == NO)
241 {
242 [self setScanLocation:theScanLocation];
243 if (outError)
244 {
245 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
246 @"Could not scan dictionary. Failed to scan a key.", NSLocalizedDescriptionKey,
247 NULL];
248 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
249 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyScanFailed userInfo:theUserInfo];
250 }
251 [theDictionary release];
252 return(NO);
253 }
254
255 [self skipWhitespace];
256
257 if ([self scanCharacter:':'] == NO)
258 {
259 [self setScanLocation:theScanLocation];
260 if (outError)
261 {
262 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
263 @"Could not scan dictionary. Key was not terminated with a ':' character.", NSLocalizedDescriptionKey,
264 NULL];
265 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
266 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyNotTerminated userInfo:theUserInfo];
267 }
268 [theDictionary release];
269 return(NO);
270 }
271
272 id theValue = NULL;
273 if ([self scanJSONObject:&theValue error:outError] == NO)
274 {
275 [self setScanLocation:theScanLocation];
276 if (outError)
277 {
278 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
279 @"Could not scan dictionary. Failed to scan a value.", NSLocalizedDescriptionKey,
280 NULL];
281
282 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
283 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryValueScanFailed userInfo:theUserInfo];
284 }
285 [theDictionary release];
286 return(NO);
287 }
288
289 if (theValue == NULL && self.nullObject == NULL)
290 {
291 // If the value is a null and nullObject is also null then we're skipping this key/value pair.
292 }
293 else
294 {
295 [theDictionary setValue:theValue forKey:theKey];
296 }
297
298 [self skipWhitespace];
299 if ([self scanCharacter:','] == NO)
300 {
301 if ([self currentCharacter] != '}')
302 {
303 [self setScanLocation:theScanLocation];
304 if (outError)
305 {
306 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
307 @"Could not scan dictionary. Key value pairs not delimited with a ',' character.", NSLocalizedDescriptionKey,
308 NULL];
309 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
310 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyValuePairNoDelimiter userInfo:theUserInfo];
311 }
312 [theDictionary release];
313 return(NO);
314 }
315 break;
316 }
317 else
318 {
319 [self skipWhitespace];
320 if ([self currentCharacter] == '}')
321 break;
322 }
323 }
324
325 if ([self scanCharacter:'}'] == NO)
326 {
327 [self setScanLocation:theScanLocation];
328 if (outError)
329 {
330 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
331 @"Could not scan dictionary. Dictionary not terminated by a '}' character.", NSLocalizedDescriptionKey,
332 NULL];
333 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
334 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryNotTerminated userInfo:theUserInfo];
335 }
336 [theDictionary release];
337 return(NO);
338 }
339
340 if (outDictionary != NULL)
341 {
342 if (self.options & kJSONScannerOptions_MutableContainers)
343 {
344 *outDictionary = [theDictionary autorelease];
345 }
346 else
347 {
348 *outDictionary = [[theDictionary copy] autorelease];
349 [theDictionary release];
350 }
351 }
352 else
353 {
354 [theDictionary release];
355 }
356
357 return(YES);
358 }
359
360- (BOOL)scanJSONArray:(NSArray **)outArray error:(NSError **)outError
361 {
362 NSUInteger theScanLocation = [self scanLocation];
363
364 [self skipWhitespace];
365
366 if ([self scanCharacter:'['] == NO)
367 {
368 if (outError)
369 {
370 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
371 @"Could not scan array. Array not started by a '[' character.", NSLocalizedDescriptionKey,
372 NULL];
373 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
374 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayStartCharacterMissing userInfo:theUserInfo];
375 }
376 return(NO);
377 }
378
379 NSMutableArray *theArray = [[NSMutableArray alloc] init];
380
381 [self skipWhitespace];
382 while ([self currentCharacter] != ']')
383 {
384 NSString *theValue = NULL;
385 if ([self scanJSONObject:&theValue error:outError] == NO)
386 {
387 [self setScanLocation:theScanLocation];
388 if (outError)
389 {
390 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
391 @"Could not scan array. Could not scan a value.", NSLocalizedDescriptionKey,
392 NULL];
393 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
394 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayValueScanFailed userInfo:theUserInfo];
395 }
396 [theArray release];
397 return(NO);
398 }
399
400 if (theValue == NULL)
401 {
402 if (self.nullObject != NULL)
403 {
404 if (outError)
405 {
406 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
407 @"Could not scan array. Value is NULL.", NSLocalizedDescriptionKey,
408 NULL];
409 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
410 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayValueIsNull userInfo:theUserInfo];
411 }
412 [theArray release];
413 return(NO);
414 }
415 }
416 else
417 {
418 [theArray addObject:theValue];
419 }
420
421 [self skipWhitespace];
422 if ([self scanCharacter:','] == NO)
423 {
424 [self skipWhitespace];
425 if ([self currentCharacter] != ']')
426 {
427 [self setScanLocation:theScanLocation];
428 if (outError)
429 {
430 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
431 @"Could not scan array. Array not terminated by a ']' character.", NSLocalizedDescriptionKey,
432 NULL];
433 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
434 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayNotTerminated userInfo:theUserInfo];
435 }
436 [theArray release];
437 return(NO);
438 }
439
440 break;
441 }
442 [self skipWhitespace];
443 }
444
445 [self skipWhitespace];
446
447 if ([self scanCharacter:']'] == NO)
448 {
449 [self setScanLocation:theScanLocation];
450 if (outError)
451 {
452 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
453 @"Could not scan array. Array not terminated by a ']' character.", NSLocalizedDescriptionKey,
454 NULL];
455 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
456 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayNotTerminated userInfo:theUserInfo];
457 }
458 [theArray release];
459 return(NO);
460 }
461
462 if (outArray != NULL)
463 {
464 if (self.options & kJSONScannerOptions_MutableContainers)
465 {
466 *outArray = [theArray autorelease];
467 }
468 else
469 {
470 *outArray = [[theArray copy] autorelease];
471 [theArray release];
472 }
473 }
474 else
475 {
476 [theArray release];
477 }
478 return(YES);
479 }
480
481- (BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError
482 {
483 NSUInteger theScanLocation = [self scanLocation];
484
485 [self skipWhitespace];
486
487 NSMutableString *theString = [[NSMutableString alloc] init];
488
489 if ([self scanCharacter:'"'] == NO)
490 {
491 [self setScanLocation:theScanLocation];
492 if (outError)
493 {
494 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
495 @"Could not scan string constant. String not started by a '\"' character.", NSLocalizedDescriptionKey,
496 NULL];
497 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
498 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringNotStartedWithBackslash userInfo:theUserInfo];
499 }
500 [theString release];
501 return(NO);
502 }
503
504 while ([self scanCharacter:'"'] == NO)
505 {
506 NSString *theStringChunk = NULL;
507 if ([self scanNotQuoteCharactersIntoString:&theStringChunk])
508 {
509 CFStringAppend((CFMutableStringRef)theString, (CFStringRef)theStringChunk);
510 }
511 else if ([self scanCharacter:'\\'] == YES)
512 {
513 unichar theCharacter = [self scanCharacter];
514 switch (theCharacter)
515 {
516 case '"':
517 case '\\':
518 case '/':
519 break;
520 case 'b':
521 theCharacter = '\b';
522 break;
523 case 'f':
524 theCharacter = '\f';
525 break;
526 case 'n':
527 theCharacter = '\n';
528 break;
529 case 'r':
530 theCharacter = '\r';
531 break;
532 case 't':
533 theCharacter = '\t';
534 break;
535 case 'u':
536 {
537 theCharacter = 0;
538
539 int theShift;
540 for (theShift = 12; theShift >= 0; theShift -= 4)
541 {
542 const int theDigit = HexToInt([self scanCharacter]);
543 if (theDigit == -1)
544 {
545 [self setScanLocation:theScanLocation];
546 if (outError)
547 {
548 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
549 @"Could not scan string constant. Unicode character could not be decoded.", NSLocalizedDescriptionKey,
550 NULL];
551 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
552 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringUnicodeNotDecoded userInfo:theUserInfo];
553 }
554 [theString release];
555 return(NO);
556 }
557 theCharacter |= (theDigit << theShift);
558 }
559 }
560 break;
561 default:
562 {
563 if (strictEscapeCodes == YES)
564 {
565 [self setScanLocation:theScanLocation];
566 if (outError)
567 {
568 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
569 @"Could not scan string constant. Unknown escape code.", NSLocalizedDescriptionKey,
570 NULL];
571 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
572 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringUnknownEscapeCode userInfo:theUserInfo];
573 }
574 [theString release];
575 return(NO);
576 }
577 }
578 break;
579 }
580 CFStringAppendCharacters((CFMutableStringRef)theString, &theCharacter, 1);
581 }
582 else
583 {
584 if (outError)
585 {
586 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
587 @"Could not scan string constant. No terminating double quote character.", NSLocalizedDescriptionKey,
588 NULL];
589 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
590 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringNotTerminated userInfo:theUserInfo];
591 }
592 [theString release];
593 return(NO);
594 }
595 }
596
597 if (outStringConstant != NULL)
598 {
599 if (self.options & kJSONScannerOptions_MutableLeaves)
600 {
601 *outStringConstant = [theString autorelease];
602 }
603 else
604 {
605 *outStringConstant = [[theString copy] autorelease];
606 [theString release];
607 }
608 }
609 else
610 {
611 [theString release];
612 }
613
614 return(YES);
615 }
616
617- (BOOL)scanJSONNumberConstant:(NSNumber **)outNumberConstant error:(NSError **)outError
618 {
619 NSNumber *theNumber = NULL;
620
621 [self skipWhitespace];
622
623 if ([self scanNumber:&theNumber] == YES)
624 {
625 if (outNumberConstant != NULL)
626 *outNumberConstant = theNumber;
627 return(YES);
628 }
629 else
630 {
631 if (outError)
632 {
633 NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
634 @"Could not scan number constant.", NSLocalizedDescriptionKey,
635 NULL];
636 [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation];
637 *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_NumberNotScannable userInfo:theUserInfo];
638 }
639 return(NO);
640 }
641 }
642
643#if TREAT_COMMENTS_AS_WHITESPACE
644- (void)skipWhitespace
645 {
646 [super skipWhitespace];
647 [self scanCStyleComment:NULL];
648 [self scanCPlusPlusStyleComment:NULL];
649 [super skipWhitespace];
650 }
651#endif // TREAT_COMMENTS_AS_WHITESPACE
652
653#pragma mark -
654
655- (BOOL)scanNotQuoteCharactersIntoString:(NSString **)outValue
656 {
657 u_int8_t *P;
658 for (P = current; P < end && *P != '\"' && *P != '\\'; ++P)
659 ;
660
661 if (P == current)
662 {
663 return(NO);
664 }
665
666 if (outValue)
667 {
668 *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease];
669 }
670
671 current = P;
672
673 return(YES);
674 }
675
676@end