summaryrefslogtreecommitdiffstats
path: root/Classes/Source/CDataScanner.m
diff options
context:
space:
mode:
Diffstat (limited to 'Classes/Source/CDataScanner.m')
-rw-r--r--Classes/Source/CDataScanner.m340
1 files changed, 340 insertions, 0 deletions
diff --git a/Classes/Source/CDataScanner.m b/Classes/Source/CDataScanner.m
new file mode 100644
index 0000000..b3cee6f
--- /dev/null
+++ b/Classes/Source/CDataScanner.m
@@ -0,0 +1,340 @@
+//
+// 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