// // CDataScanner.m // TouchCode // // Created by Jonathan Wight on 04/16/08. // Copyright 2008 toxicsoftware.com. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // #import "CDataScanner.h" #import "CDataScanner_Extensions.h" @interface CDataScanner () @end #pragma mark - inline static unichar CharacterAtPointer(void *start, void *end) { #pragma unused(end) const u_int8_t theByte = *(u_int8_t *)start; if (theByte & 0x80) { // TODO -- UNICODE!!!! (well in theory nothing todo here) } const unichar theCharacter = theByte; return(theCharacter); } static NSCharacterSet *sDoubleCharacters = NULL; @implementation CDataScanner - (id)init { if ((self = [super init]) != NULL) { } return(self); } - (id)initWithData:(NSData *)inData; { if ((self = [self init]) != NULL) { [self setData:inData]; } return(self); } + (void)initialize { if (sDoubleCharacters == NULL) { sDoubleCharacters = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789eE-+."] retain]; } } - (void)dealloc { [data release]; data = NULL; // [super dealloc]; } - (NSUInteger)scanLocation { return(current - start); } - (NSUInteger)bytesRemaining { return(end - current); } - (NSData *)data { return(data); } - (void)setData:(NSData *)inData { if (data != inData) { [data release]; data = [inData retain]; } if (data) { start = (u_int8_t *)data.bytes; end = start + data.length; current = start; length = data.length; } else { start = NULL; end = NULL; current = NULL; length = 0; } } - (void)setScanLocation:(NSUInteger)inScanLocation { current = start + inScanLocation; } - (BOOL)isAtEnd { return(self.scanLocation >= length); } - (unichar)currentCharacter { return(CharacterAtPointer(current, end)); } #pragma mark - - (unichar)scanCharacter { const unichar theCharacter = CharacterAtPointer(current++, end); return(theCharacter); } - (BOOL)scanCharacter:(unichar)inCharacter { unichar theCharacter = CharacterAtPointer(current, end); if (theCharacter == inCharacter) { ++current; return(YES); } else return(NO); } - (BOOL)scanUTF8String:(const char *)inString intoString:(NSString **)outValue { const size_t theLength = strlen(inString); if ((size_t)(end - current) < theLength) return(NO); if (strncmp((char *)current, inString, theLength) == 0) { current += theLength; if (outValue) *outValue = [NSString stringWithUTF8String:inString]; return(YES); } return(NO); } - (BOOL)scanString:(NSString *)inString intoString:(NSString **)outValue { if ((size_t)(end - current) < inString.length) return(NO); if (strncmp((char *)current, [inString UTF8String], inString.length) == 0) { current += inString.length; if (outValue) *outValue = inString; return(YES); } return(NO); } - (BOOL)scanCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue { u_int8_t *P; for (P = current; P < end && [inSet characterIsMember:*P] == YES; ++P) ; if (P == current) { return(NO); } if (outValue) { *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; } current = P; return(YES); } - (BOOL)scanUpToString:(NSString *)inString intoString:(NSString **)outValue { const char *theToken = [inString UTF8String]; const char *theResult = strnstr((char *)current, theToken, end - current); if (theResult == NULL) { return(NO); } if (outValue) { *outValue = [[[NSString alloc] initWithBytes:current length:theResult - (char *)current encoding:NSUTF8StringEncoding] autorelease]; } current = (u_int8_t *)theResult; return(YES); } - (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue { u_int8_t *P; for (P = current; P < end && [inSet characterIsMember:*P] == NO; ++P) ; if (P == current) { return(NO); } if (outValue) { *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; } current = P; return(YES); } - (BOOL)scanNumber:(NSNumber **)outValue { NSString *theString = NULL; if ([self scanCharactersFromSet:sDoubleCharacters intoString:&theString]) { if ([theString rangeOfString:@"."].location != NSNotFound) { if (outValue) { *outValue = [NSDecimalNumber decimalNumberWithString:theString]; } return(YES); } else if ([theString rangeOfString:@"-"].location != NSNotFound) { if (outValue != NULL) { *outValue = [NSNumber numberWithLongLong:[theString longLongValue]]; } return(YES); } else { if (outValue != NULL) { *outValue = [NSNumber numberWithUnsignedLongLong:strtoull([theString UTF8String], NULL, 0)]; } return(YES); } } return(NO); } - (BOOL)scanDecimalNumber:(NSDecimalNumber **)outValue; { NSString *theString = NULL; if ([self scanCharactersFromSet:sDoubleCharacters intoString:&theString]) { if (outValue) { *outValue = [NSDecimalNumber decimalNumberWithString:theString]; } return(YES); } return(NO); } - (BOOL)scanDataOfLength:(NSUInteger)inLength intoData:(NSData **)outData; { if (self.bytesRemaining < inLength) { return(NO); } if (outData) { *outData = [NSData dataWithBytes:current length:inLength]; } current += inLength; return(YES); } - (void)skipWhitespace { u_int8_t *P; for (P = current; P < end && (isspace(*P)); ++P) ; current = P; } - (NSString *)remainingString { NSData *theRemainingData = [NSData dataWithBytes:current length:end - current]; NSString *theString = [[[NSString alloc] initWithData:theRemainingData encoding:NSUTF8StringEncoding] autorelease]; return(theString); } - (NSData *)remainingData; { NSData *theRemainingData = [NSData dataWithBytes:current length:end - current]; return(theRemainingData); } @end