diff --git a/iphone/ZXingWidget/Classes/resultParsers/DoCoMoResultParser.h b/iphone/ZXingWidget/Classes/ArrayAndStringCategories.h similarity index 86% rename from iphone/ZXingWidget/Classes/resultParsers/DoCoMoResultParser.h rename to iphone/ZXingWidget/Classes/ArrayAndStringCategories.h index 38b1f8dfa..b8b5c27d4 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/DoCoMoResultParser.h +++ b/iphone/ZXingWidget/Classes/ArrayAndStringCategories.h @@ -1,5 +1,5 @@ // -// DoCoMoResultParser.h +// ArrayAndStringCategories.h // ZXing // // Created by Christian Brunschen on 25/06/2008. @@ -39,8 +39,6 @@ @end -@interface DoCoMoResultParser : ResultParser { - -} - -@end +// This works around the linker bug described here: +// http://developer.apple.com/library/mac/#qa/qa1490/_index.html +void ForceArrayAndStringCategoriesToLoad(void); diff --git a/iphone/ZXingWidget/Classes/ArrayAndStringCategories.m b/iphone/ZXingWidget/Classes/ArrayAndStringCategories.m new file mode 100644 index 000000000..a842530ab --- /dev/null +++ b/iphone/ZXingWidget/Classes/ArrayAndStringCategories.m @@ -0,0 +1,143 @@ +// +// ArrayAndStringCategories.m +// ZXing +// +// Created by Christian Brunschen on 25/06/2008. +/* + * Copyright 2008 ZXing authors + * + * 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 "ArrayAndStringCategories.h" + + +@implementation NSString (ArrayAndStringCategories) + +- (NSString *)backslashUnescaped { + NSRange backslashRange = [self rangeOfString:@"\\"]; + if (backslashRange.location == NSNotFound) { + return self; + } + + int max = [self length]; + int startLocation = 0; + NSMutableString *result = [NSMutableString stringWithCapacity:[self length]]; + while (backslashRange.location != NSNotFound) { + [result appendString:[self substringWithRange:NSMakeRange(startLocation, + backslashRange.location - startLocation)]]; + [result appendFormat:@"%c", [self characterAtIndex:backslashRange.location + 1]]; + startLocation = backslashRange.location + 2; + NSRange searchRange = NSMakeRange(startLocation, max - startLocation); + backslashRange = [self rangeOfString:@"\\" options:0 range:searchRange]; + } + if (startLocation < max) { + [result appendString:[self substringWithRange:NSMakeRange(startLocation, max - startLocation)]]; + } + return [NSString stringWithString:result]; +} + +- (NSArray *)fieldsWithPrefix:(NSString *)prefix { + return [self fieldsWithPrefix:prefix terminator:@";"]; +} + +- (NSArray *)fieldsWithPrefix:(NSString *)prefix terminator:(NSString *)term { + NSMutableArray *result = nil; + + int i = 0; + int max = [self length]; + NSRange searchRange; + NSRange foundRange; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + while (i < max) { + searchRange = NSMakeRange(i, max - i); + foundRange = [self rangeOfString:prefix options:0 range:searchRange]; + if(foundRange.location == NSNotFound) { + break; + } + + int start = i = foundRange.location + foundRange.length; + bool done = false; + while (!done) { + searchRange = NSMakeRange(i, max - i); + NSRange termRange = [self rangeOfString:term options:0 range:searchRange]; + if (termRange.location == NSNotFound) { + i = max; + done = true; + } else if ([self characterAtIndex:termRange.location-1] == (unichar)'\\') { + i++; + } else { + NSAutoreleasePool *secondaryPool = [[NSAutoreleasePool alloc] init]; + NSString *substring = [self substringWithRange:NSMakeRange(start, termRange.location - start)]; + NSString *unescaped = [substring backslashUnescaped]; + NSString *toBeInArray = [[NSString alloc] initWithString:unescaped]; + [secondaryPool release]; + if (result == nil) { + result = [[NSMutableArray alloc] initWithCapacity:1]; + } + [result addObject:toBeInArray]; + [toBeInArray release]; + i = termRange.location + termRange.length; + done = true; + } + } + } + [pool release]; + + return [result autorelease]; +} + +- (NSString *)fieldWithPrefix:(NSString *)prefix { + return [self fieldWithPrefix:prefix terminator:@";"]; +} + +- (NSString *)fieldWithPrefix:(NSString *)prefix terminator:(NSString *)term { + NSArray *fields = [self fieldsWithPrefix:prefix terminator:term]; + if (fields.count == 0) { + return nil; + } else { + return [fields lastObject]; + } +} + +- (NSString *)stringWithTrimmedWhitespace { + return [self stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; +} + +@end + +@implementation NSArray (ArrayAndStringCategories) + +- (NSArray*)stringArrayWithTrimmedWhitespace { + NSMutableArray* trimmed = [NSMutableArray arrayWithCapacity:[self count]]; + for (NSString* s in self) { + [trimmed addObject:[s stringWithTrimmedWhitespace]]; + } + return trimmed; +} + ++ (NSArray*)arrayWithStringIfNotNil:(NSString *)string { + if (string != nil) { + return [NSArray arrayWithObject:string]; + } else { + return nil; + } +} + +@end + + +void ForceArrayAndStringCategoriesToLoad(void) { + // No-op. See comments in header file. +} diff --git a/iphone/ZXingWidget/Classes/ZXingWidgetController.m b/iphone/ZXingWidget/Classes/ZXingWidgetController.m index b2485143c..c5f73f0ae 100755 --- a/iphone/ZXingWidget/Classes/ZXingWidgetController.m +++ b/iphone/ZXingWidget/Classes/ZXingWidgetController.m @@ -482,35 +482,39 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer #pragma mark - Torch - (void)setTorch:(BOOL)status { +#if HAS_AVFF Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); if (captureDeviceClass != nil) { - AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo]; [device lockForConfiguration:nil]; if ( [device hasTorch] ) { if ( status ) { [device setTorchMode:AVCaptureTorchModeOn]; } else { - [device setTorchMode:AVCaptureTorchModeOff]; + [device setTorchMode:AVCaptureTorchModeOn]; } } [device unlockForConfiguration]; } +#endif } - (BOOL)torchIsOn { +#if HAS_AVFF Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); if (captureDeviceClass != nil) { - AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo]; if ( [device hasTorch] ) { return [device torchMode] == AVCaptureTorchModeOn; } [device unlockForConfiguration]; } +#endif return NO; } diff --git a/iphone/ZXingWidget/Classes/resultParsers/AddressBookAUResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/AddressBookAUResultParser.m index 31c5fcaa1..c8019f574 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/AddressBookAUResultParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/AddressBookAUResultParser.m @@ -22,7 +22,7 @@ #import "AddressBookAUResultParser.h" #import "BusinessCardParsedResult.h" #import "CBarcodeFormat.h" -#import "DoCoMoResultParser.h" +#import "ArrayAndStringCategories.h" @interface NSString (AddressBookAUResultParser) @@ -73,6 +73,10 @@ // + (ParsedResult *)parsedResultForString:(NSString *)rawText format:(BarcodeFormat)format { + // Force objects in ArrayAndStringCategories.m to be loaded from static + // library to work around a linker bug. + ForceArrayAndStringCategoriesToLoad(); + // MEMORY is mandatory; seems like a decent indicator, as does // end-of-record separator CR/LF if (rawText == nil || diff --git a/iphone/ZXingWidget/Classes/resultParsers/BizcardResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/BizcardResultParser.m index c080900f3..ad799b930 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/BizcardResultParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/BizcardResultParser.m @@ -22,7 +22,7 @@ #import "BizcardResultParser.h" #import "BusinessCardParsedResult.h" #import "CBarcodeFormat.h" -#import "DoCoMoResultParser.h" +#import "ArrayAndStringCategories.h" @implementation BizcardResultParser diff --git a/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.h b/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.h index 08582e6e5..d2cf1c8f3 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.h +++ b/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.h @@ -20,9 +20,9 @@ */ #import -#import "DoCoMoResultParser.h" +#import "ResultParser.h" -@interface BookmarkDoCoMoResultParser : DoCoMoResultParser { +@interface BookmarkDoCoMoResultParser : ResultParser { } diff --git a/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.m index f28661273..8bec88595 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/BookmarkDoCoMoResultParser.m @@ -22,6 +22,7 @@ #import "BookmarkDoCoMoResultParser.h" #import "URIParsedResult.h" #import "CBarcodeFormat.h" +#import "ArrayAndStringCategories.h" @implementation BookmarkDoCoMoResultParser @@ -35,15 +36,15 @@ if (foundRange.location == NSNotFound) { return nil; } - + NSString *urlString = [s fieldWithPrefix:@"URL:"]; if (urlString == nil) { return nil; } - + NSString *title = [s fieldWithPrefix:@"TITLE:"]; - - return [[[URIParsedResult alloc] initWithURLString:urlString + + return [[[URIParsedResult alloc] initWithURLString:urlString title:title] autorelease]; } diff --git a/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.h b/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.h index 5d1b8304c..12bb061d5 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.h +++ b/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.h @@ -20,9 +20,9 @@ */ #import -#import "DoCoMoResultParser.h" +#import "ResultParser.h" -@interface EmailDoCoMoResultParser : DoCoMoResultParser { +@interface EmailDoCoMoResultParser : ResultParser { } diff --git a/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.m index 61db56ffd..bc01ec121 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/EmailDoCoMoResultParser.m @@ -22,6 +22,7 @@ #import "EmailDoCoMoResultParser.h" #import "EmailParsedResult.h" #import "CBarcodeFormat.h" +#import "ArrayAndStringCategories.h" @implementation EmailDoCoMoResultParser @@ -35,17 +36,17 @@ if (foundRange.location == NSNotFound) { return nil; } - + NSString *to = [s fieldWithPrefix:@"TO:"]; if (to == nil) { return nil; } - + EmailParsedResult *result = [[EmailParsedResult alloc] init]; result.to = to; result.subject = [s fieldWithPrefix:@"SUB:"]; result.body = [s fieldWithPrefix:@"BODY:"]; - + return [result autorelease]; } diff --git a/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.h b/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.h index 288159ea0..8d411f6c8 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.h +++ b/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.h @@ -20,9 +20,9 @@ */ #import -#import "DoCoMoResultParser.h" +#import "ResultParser.h" -@interface MeCardParser : DoCoMoResultParser { +@interface MeCardParser : ResultParser { } diff --git a/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.m b/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.m index e00c10cbb..dca1fd160 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/MeCardParser.m @@ -22,6 +22,7 @@ #import "MeCardParser.h" #import "BusinessCardParsedResult.h" #import "CBarcodeFormat.h" +#import "ArrayAndStringCategories.h" @interface MeCardParser (Private) @@ -56,12 +57,12 @@ if (foundRange.location == NSNotFound) { return nil; } - + NSString *name = [[s fieldWithPrefix:@"N:"] stringWithTrimmedWhitespace]; if (name == nil) { return nil; } - + BusinessCardParsedResult *result = [[BusinessCardParsedResult alloc] init]; result.names = [NSArray arrayWithObject:name]; result.pronunciation = [[s fieldWithPrefix:@"SOUND:"] stringWithTrimmedWhitespace]; @@ -80,7 +81,7 @@ result.url = [[s fieldWithPrefix:@"URL:"] stringWithTrimmedWhitespace]; result.organization = [[s fieldWithPrefix:@"ORG:"] stringWithTrimmedWhitespace]; result.jobTitle = [s fieldWithPrefix:@"TITLE:"]; - + return [result autorelease]; } diff --git a/iphone/ZXingWidget/Classes/resultParsers/UniversalResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/UniversalResultParser.m index aeb9ce86d..42b6fd075 100644 --- a/iphone/ZXingWidget/Classes/resultParsers/UniversalResultParser.m +++ b/iphone/ZXingWidget/Classes/resultParsers/UniversalResultParser.m @@ -21,6 +21,8 @@ #import "CBarcodeFormat.h" #import "ProductResultParser.h" #import "BizcardResultParser.h" +#import "AddressBookAUResultParser.h" +#import "VCardResultParser.h" @implementation UniversalResultParser static NSMutableArray *sTheResultParsers = nil; @@ -45,6 +47,8 @@ static NSMutableArray *sTheResultParsers = nil; [self addParserClass:[BookmarkDoCoMoResultParser class]]; [self addParserClass:[MeCardParser class]]; [self addParserClass:[EmailDoCoMoResultParser class]]; + [self addParserClass:[AddressBookAUResultParser class]]; + [self addParserClass:[VCardResultParser class]]; [self addParserClass:[BizcardResultParser class]]; [self addParserClass:[PlainEmailResultParser class]]; [self addParserClass:[TelResultParser class]]; @@ -81,7 +85,4 @@ static NSMutableArray *sTheResultParsers = nil; return [self parsedResultForString:theString format:BarcodeFormat_None]; } --(void)dealloc { - [super dealloc]; -} @end diff --git a/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.h b/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.h new file mode 100644 index 000000000..7b7b538f5 --- /dev/null +++ b/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.h @@ -0,0 +1,30 @@ +// +// VCardResultParser.h +// ZXing +// +// Created by George Nachman on 7/7/2011. +/* + * Copyright 2011 ZXing authors + * + * 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 +#import "ResultParser.h" + +@interface VCardResultParser : ResultParser { +} + +@end + + diff --git a/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.m b/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.m new file mode 100644 index 000000000..4d0c66738 --- /dev/null +++ b/iphone/ZXingWidget/Classes/resultParsers/VCardResultParser.m @@ -0,0 +1,435 @@ +// +// VCardResultParser.m +// ZXing +// +// Ported to Objective-C by George Nachman on 7/19/2011. +/* + * Copyright 2008 ZXing authors + * + * 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 "BusinessCardParsedResult.h" +#import "CBarcodeFormat.h" +#import "ResultParser.h" +#import "AddressBookAUResultParser.h" +#import "VCardResultParser.h" +#import "ArrayAndStringCategories.h" + +@interface NSString (VCardResultParser) + +// Extract a single VCard value from this with a given prefix. +- (NSString *)vcardValueForFieldWithPrefix:(NSString *)prefix; + +// Extracts an array of VCard values from this string with a given prefix. +- (NSArray *)vcardValuesForFieldWithPrefix:(NSString *)prefix; + +// Returns true if the string's value is a well-formed date. +- (BOOL)isVCardDate; + +// Returns the starting index (or NSNotFound) of the given substring not +// before index |offset|. +- (NSUInteger)vcardIndexOf:(NSString*)substr startingAt:(int)offset; + +// Assuming this string is in quoted printable in the character set |charset|, +// decode the QP encoding and convert to NSString's native character set. +- (NSString *)vcardStringFromQuotedPrintableWithCharset:(NSString *)charset; + +// Strip out \r. Also strip out \n plus one character following it if possible. +- (NSString *)vcardStringWithoutContinuationCRLF; + +// Split up key-value strings on = sign. +- (NSString *)vcardKeyComponent; +- (NSString *)vcardValueComponent; +@end + +@interface NSArray (VCardResultParser) + +// Reformat VCard names from a semicolon-delimited list to a human-readable +// name. +- (NSArray *)vcardArrayWithFormattedNames; +// Reformat VCard addresses from a semicolon-delimited list to a human-readable +// name. +- (NSArray *)vcardArrayWithFormattedAddresses; + +@end + +// Parses contact information formatted according to the VCard (2.1) format. +// This is not a complete implementation but should parse information as +// commonly encoded in 2D barcodes. +// +// Originally by Sean Owen. Adapted to Objective-C by George Nachman. +// +@implementation VCardResultParser + ++ (void)load { + [ResultParser registerResultParserClass:self]; +} + ++ (ParsedResult *)parsedResultForString:(NSString *)rawText + format:(BarcodeFormat)format { + // Although we should insist on the raw text ending with "END:VCARD", + // there's no reason to throw out everything else we parsed just because + // this was omitted. In fact, Eclair is doing just that, and we can't parse + // its contacts without this leniency. + if (rawText == nil || ![rawText hasPrefix:@"BEGIN:VCARD"]) { + return nil; + } + NSArray *names = [[rawText vcardValuesForFieldWithPrefix:@"FN"] + stringArrayWithTrimmedWhitespace]; + if ([names count] == 0) { + // If no display names found, look for regular name fields and format them + names = [[rawText vcardValuesForFieldWithPrefix:@"N"] + stringArrayWithTrimmedWhitespace]; + } + names = [names vcardArrayWithFormattedNames]; + NSArray *phoneNumbers = [[rawText vcardValuesForFieldWithPrefix:@"TEL"] stringArrayWithTrimmedWhitespace]; + NSArray *emails = [[rawText vcardValuesForFieldWithPrefix:@"EMAIL"] stringArrayWithTrimmedWhitespace]; + NSString *note = [rawText vcardValueForFieldWithPrefix:@"NOTE"]; + NSArray *addresses = [[[rawText vcardValuesForFieldWithPrefix:@"ADR"] stringArrayWithTrimmedWhitespace] + vcardArrayWithFormattedAddresses]; + NSString *org = [[rawText vcardValueForFieldWithPrefix:@"ORG"] stringWithTrimmedWhitespace]; + NSString *birthday = [[rawText vcardValueForFieldWithPrefix:@"BDAY"]stringWithTrimmedWhitespace]; + if (![birthday isVCardDate]) { + birthday = nil; + } + NSString *title = [[rawText vcardValueForFieldWithPrefix:@"TITLE"]stringWithTrimmedWhitespace]; + NSString *url = [[rawText vcardValueForFieldWithPrefix:@"URL"] stringWithTrimmedWhitespace]; + + BusinessCardParsedResult *result = + [[[BusinessCardParsedResult alloc] init] autorelease]; + + if ([names count]) { + result.names = names; + } + if ([phoneNumbers count]) { + result.phoneNumbers = phoneNumbers; + } + if ([emails count]) { + result.emails = emails; + } + if ([note length]) { + result.note = note; + } + if ([addresses count]) { + result.addresses = addresses; + } + if ([org length]) { + result.organization = org; + } + if (birthday) { + result.birthday = birthday; + } + if ([title length]) { + result.jobTitle = title; + } + if ([url length]) { + result.url = url; + } + + return result; +} + +@end + +@implementation NSString (VCardResultParser) + +- (NSUInteger)vcardIndexOf:(NSString*)substr startingAt:(int)offset { + NSRange temp = NSMakeRange(offset, [self length] - offset); + NSRange r = [self rangeOfString:substr + options:0 + range:temp]; + return r.location; +} + +- (NSString *)vcardKeyComponent { + NSUInteger equals = [self vcardIndexOf:@"=" startingAt:0]; + if (equals != NSNotFound) { + return [self substringWithRange:NSMakeRange(0, equals)]; + } else { + return nil; + } +} + +- (NSString *)vcardValueComponent { + NSUInteger equals = [self vcardIndexOf:@"=" startingAt:0]; + if (equals != NSNotFound) { + return [self substringWithRange:NSMakeRange(equals + 1, + [self length] - equals - 1)]; + } else { + return nil; + } +} + +- (NSDictionary*)parsedFieldMetadata { + NSArray *parts = [self componentsSeparatedByCharactersInSet: + [NSCharacterSet characterSetWithCharactersInString:@";:"]]; + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + for (NSString *part in parts) { + NSString *key = [part vcardKeyComponent]; + NSString *value = [part vcardValueComponent]; + if (key && value) { + [result setObject:value forKey:key]; + } + } + + return result; +} + +- (NSArray *)vcardValuesForFieldWithPrefix:(NSString *)prefix { + NSMutableArray *matches = [NSMutableArray array]; + NSUInteger i = 0; + NSUInteger myLength = [self length]; + unichar c; + while (i < myLength) { + i = [self vcardIndexOf:prefix startingAt:i]; + if (i == NSNotFound) { + break; + } + + if (i > 0 && [self characterAtIndex:i - 1] != '\n') { + // This didn't start a new token: we matched in the middle of + // something. + i++; + continue; + } + i += [prefix length]; // Skip past the prefix. + c = [self characterAtIndex:i]; + if (c != ':' && c != ';') { + // What we found wasn't actually a prefix. + continue; + } + + const NSUInteger metadataStart = i; + // Skip until we find a colon. + while ([self characterAtIndex:i] != ':') { + i++; + } + + // Extract key-value metadata fields between the ; and the : after the + // prefix. + BOOL quotedPrintable = NO; + NSString *quotedPrintableCharset = @"ASCII"; + if (i >= metadataStart + 1) { + NSString *metaData = [self substringWithRange: + NSMakeRange(metadataStart + 1, + i - (metadataStart + 1))]; + NSDictionary *metaDataDict = [metaData parsedFieldMetadata]; + NSString *encoding = [metaDataDict objectForKey:@"ENCODING"]; + NSString *charset = [metaDataDict objectForKey:@"CHARSET"]; + if ([encoding isEqualToString:@"QUOTED-PRINTABLE"]) { + quotedPrintable = YES; + if (charset) { + quotedPrintableCharset = charset; + } + } + } + + i++; // Skip the colon. + + const NSUInteger matchStart = i; // Found the start of a match here. + + while ((i = [self vcardIndexOf:@"\n" startingAt:i]) != NSNotFound) { + if (i + 1 < [self length] && + ([self characterAtIndex:i + 1] == ' ' || + [self characterAtIndex:i + 1] == '\t')) { + // If it's followed by a tab or space, ignore them. + i += 2; + } else if (quotedPrintable && + i >= 2 && + ([self characterAtIndex:i-1] == '=' || + [self characterAtIndex:i-2] == '=')) { + // Indicates this is a quoted-printable continuation so + // ignore the newline. + i++; + } else { + break; + } + } + + if (i == NSNotFound) { + // No terminating character. + break; + } else if (i > matchStart) { + // Found a legal line. Add it to the output. i must be greater than + // 0 because matchStart is unsigned. + if ([self characterAtIndex:i-1] == '\r') { + i--; // Back up over \r if present. + } + NSUInteger rangeLength; + if (i >= matchStart) { + rangeLength = i - matchStart; + } else { + rangeLength = 0; + } + NSString *element = [self substringWithRange: + NSMakeRange(matchStart, rangeLength)]; + if (quotedPrintable) { + element = [element vcardStringFromQuotedPrintableWithCharset: + quotedPrintableCharset]; + } else { + element = [element vcardStringWithoutContinuationCRLF]; + } + [matches addObject:element]; + i++; + } else { + // Zero-length line. + i++; + } + } + + return matches; +} + +- (NSString *)vcardStringWithoutContinuationCRLF { + int length = [self length]; + NSMutableString *result = [NSMutableString stringWithCapacity:length]; + BOOL lastWasLF = NO; + for (int i = 0; i < length; i++) { + if (lastWasLF) { + lastWasLF = NO; + continue; + } + unichar c = [self characterAtIndex:i]; + lastWasLF = NO; + switch (c) { + case '\n': + lastWasLF = YES; + break; + case '\r': + break; + default: + [result appendString:[NSString stringWithCharacters:&c + length:1]]; + break; + } + } + return result; +} + +- (NSString *)vcardStringFromQuotedPrintableWithCharset:(NSString *)charset { + int length = [self length]; + NSMutableData *temp = [NSMutableData dataWithCapacity:length]; + for (int i = 0; i < length; i++) { + unichar c = [self characterAtIndex:i]; + switch (c) { + case '\r': + case '\n': + break; + case '=': + if (i < length - 2) { + unichar nextChar = [self characterAtIndex:i+1]; + if (nextChar == '\r' || nextChar == '\n') { + // Ignore, it's just a continuation symbol. + } else { + NSString *hexstr = + [self substringWithRange:NSMakeRange(i+1, 2)]; + NSScanner *scanner = + [NSScanner scannerWithString:hexstr]; + unsigned result; + if ([scanner scanHexInt:&result]) { + unsigned char parsedChar = result; + [temp appendBytes:&parsedChar length:1]; + } + + i += 2; + } + } + break; + default: + [temp appendBytes:&c length:1]; + } + } + + NSStringEncoding encoding; + encoding = CFStringConvertEncodingToNSStringEncoding( + CFStringConvertIANACharSetNameToEncoding((CFStringRef) charset)); + return [[[NSString alloc] initWithData:temp + encoding:encoding] autorelease]; +} + +- (NSString *)vcardValueForFieldWithPrefix:(NSString *)prefix { + NSArray *values = [self vcardValuesForFieldWithPrefix:prefix]; + return [values count] ? [values objectAtIndex:0] : @""; +} + +- (BOOL)rangeIsDigits:(NSRange)range { + for (NSUInteger i = range.location; + i < range.location + range.length; + i++) { + unichar c = [self characterAtIndex:i]; + if (c < '0' || c > '9') { + return NO; + } + } + return YES; +} + +- (BOOL)isVCardDate { + // Not really sure this is true but matches practice + if ([self length] == 8 && [self rangeIsDigits:NSMakeRange(0, 8)]) { + // Matches YYYYMMDD + return YES; + } else if ([self length] == 10 && + [self characterAtIndex:4] == '-' && + [self characterAtIndex:7] == '-' && + [self rangeIsDigits:NSMakeRange(0, 4)] && + [self rangeIsDigits:NSMakeRange(5, 2)] && + [self rangeIsDigits:NSMakeRange(8, 2)]) { + // Matches YYYY-MM-DD + return YES; + } else { + return NO; + } +} + +@end + +@implementation NSArray (VCardResultParser) + +- (NSArray *)vcardArrayWithFormattedAddresses { + NSMutableArray* result = [NSMutableArray array]; + for (NSString* address in self) { + [result addObject: + [[address stringByReplacingOccurrencesOfString:@";" + withString:@" "] + stringWithTrimmedWhitespace]]; + } + return result; +} + +// Formats name fields of the form "Public;John;Q.;Reverend;III" into a form +// like "Reverend John Q. Public III". +- (NSArray *)vcardArrayWithFormattedNames { + NSMutableArray *result = [NSMutableArray array]; + for (NSString *name in self) { + NSArray *components = [name componentsSeparatedByString:@";"]; + int newOrder[] = { 3, 1, 2, 0, 4 }; + int numReorderItems = sizeof(newOrder) / sizeof(int); + NSMutableString *formattedName = + [NSMutableString stringWithCapacity:[name length]]; + int n = [components count]; + for (int i = 0; i < numReorderItems; i++) { + int j = newOrder[i]; + if (n > j) { + [formattedName appendString:@" "]; + [formattedName appendString:[components objectAtIndex:j]]; + } + } + [result addObject:[formattedName stringWithTrimmedWhitespace]]; + } + return result; +} + + +@end diff --git a/iphone/ZXingWidget/Tests/AddressBookAUResultParserTests.m b/iphone/ZXingWidget/Tests/AddressBookAUResultParserTests.m new file mode 100644 index 000000000..2abc64338 --- /dev/null +++ b/iphone/ZXingWidget/Tests/AddressBookAUResultParserTests.m @@ -0,0 +1,113 @@ +// +// AddressBookAUTests.m +// ZXingWidget +// +// Created by George Nachman on 7/27/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "AddressBookAUResultParser.h" +#import "BusinessCardParsedResult.h" + +@interface AddressBookAUResultParserTests : SenTestCase +@end + +@implementation AddressBookAUResultParserTests + +- (void)testWellFormedAddressBookAU { + NSString *msg = + @"NAME1:Name One\r" + @"NAME2:Name Two\r" + @"NAME3:Name Three\r" // ignored + @"TEL1:1111111\r" + @"TEL2:2222222\r" + @"TEL3:3333333\r" + @"TEL4:4444444\r" // ignored + @"MAIL1:1@1.com\r" + @"MAIL2:2@2.com\r" + @"MAIL3:3@3.com\r" + @"MAIL4:4@4.com\r" // ignored + @"MEMORY:This is a note\r" + @"ADD:123 Fake St\r\n"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [AddressBookAUResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertEquals(1U, result.names.count, @"Wrong number of names %d", + result.names.count); + STAssertTrue([[result.names objectAtIndex:0] isEqualToString:@"Name One"], + @"Wrong name one %@", [result.names objectAtIndex:0]); + STAssertTrue([result.pronunciation isEqualToString:@"Name Two"], + @"Wrong pronunciation %@", result.pronunciation); + STAssertEquals(3U, result.phoneNumbers.count, + @"Wrong number of phone numbers %d", + result.phoneNumbers.count); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:0] isEqualToString:@"1111111"], + @"Wrong phone number 1 %@", [result.phoneNumbers objectAtIndex:0]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:1] isEqualToString:@"2222222"], + @"Wrong phone number 2 %@", [result.phoneNumbers objectAtIndex:1]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:2] isEqualToString:@"3333333"], + @"Wrong phone number 3 %@", [result.phoneNumbers objectAtIndex:2]); + STAssertEquals(3U, result.emails.count, + @"Wrong number of emails %d", result.emails.count); + STAssertTrue([[result.emails objectAtIndex:0] isEqualToString:@"1@1.com"], + @"Wrong email 1 %@", [result.emails objectAtIndex:0]); + STAssertTrue([[result.emails objectAtIndex:1] isEqualToString:@"2@2.com"], + @"Wrong email 2 %@", [result.emails objectAtIndex:1]); + STAssertTrue([[result.emails objectAtIndex:2] isEqualToString:@"3@3.com"], + @"Wrong email 3 %@", [result.emails objectAtIndex:2]); + STAssertTrue([result.note isEqualToString:@"This is a note"], + @"Wrong note %@", result.note); + STAssertEquals(1U, result.addresses.count, @"Wrong number of addresses %d", + result.addresses.count); + STAssertTrue( + [[result.addresses objectAtIndex:0] isEqualToString:@"123 Fake St"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); +} + +- (void)testMissingNewlineAddressBookAU { + NSString *msg = + @"NAME1:Name One\r" + @"NAME2:Name Two\r" + @"NAME3:Name Three\r" + @"TEL1:1111111\r" + @"TEL2:2222222\r" + @"TEL3:3333333\r" + @"TEL4:4444444\r" + @"MAIL1:1@1.com\r" + @"MAIL2:2@2.com\r" + @"MAIL3:3@3.com\r" + @"MAIL4:4@4.com\r" + @"MEMORY:This is a note\r" + @"ADD:123 Fake St\r"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [AddressBookAUResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched"); +} + +- (void)testMalformedAddressBookAU { + NSString *msg = + @"NAME1:Name One\r" + @"NAME2:Name Two\r" + @"NAME3:Name Three\r" // ignored + @"TEL1:1111111\r" + @"TEL2:2222222\r" + @"TEL3:3333333\r" + @"TEL4:4444444\r" // ignored + @"MAIL1:1@1.com\r" + @"MAIL2:2@2.com\r" + @"MAIL3:3@3.com\r" + @"MAIL4:4@4.com\r" // ignored + @"ADD:123 Fake St"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [AddressBookAUResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched"); +} + +@end diff --git a/iphone/ZXingWidget/Tests/BizcardResultParserTests.m b/iphone/ZXingWidget/Tests/BizcardResultParserTests.m new file mode 100644 index 000000000..b6df1048e --- /dev/null +++ b/iphone/ZXingWidget/Tests/BizcardResultParserTests.m @@ -0,0 +1,135 @@ +// +// BizcardTests.m +// ZXingWidget +// +// Created by George Nachman on 7/27/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "BizcardResultParser.h" +#import "BusinessCardParsedResult.h" + +@interface BizcardResultParserTests : SenTestCase +@end + +@implementation BizcardResultParserTests + +- (void)testWellFormedBizcard { + NSString *msg = + @"BIZCARD:;" + @"N:Firstname;" + @"X:Lastname;" + @"T:Title;" + @"C:Org;" + @"A:Addr 1;" + @"A:Addr 2;" + @"B:1111111;" + @"M:2222222;" + @"F:3333333;" + @"E:1@1.com;"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [BizcardResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertEquals(1U, result.names.count, @"Wrong number of names %d", + result.names.count); + STAssertTrue( + [[result.names objectAtIndex:0] isEqualToString:@"Firstname Lastname"], + @"Name one is %@", [result.names objectAtIndex:0]); + STAssertTrue([result.jobTitle isEqualToString:@"Title"], + @"Title is %@", result.jobTitle); + STAssertTrue([result.organization isEqualToString:@"Org"], + @"Organization is %@", result.organization); + STAssertEquals(2U, result.addresses.count, @"Wrong number of addresses %d", + result.addresses.count); + STAssertTrue([[result.addresses objectAtIndex:0] isEqualToString:@"Addr 1"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); + STAssertTrue([[result.addresses objectAtIndex:1] isEqualToString:@"Addr 2"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); + STAssertEquals(3U, result.phoneNumbers.count, + @"Wrong number of phone numbers %d", + result.phoneNumbers.count); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:0] isEqualToString:@"1111111"], + @"Phone number 1 is %@", [result.phoneNumbers objectAtIndex:0]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:1] isEqualToString:@"2222222"], + @"Phone number 2 is %@", [result.phoneNumbers objectAtIndex:1]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:2] isEqualToString:@"3333333"], + @"Phone number 3 is %@", [result.phoneNumbers objectAtIndex:2]); + STAssertEquals(1U, result.emails.count, + @"Wrong number of emails %d", result.emails.count); + STAssertTrue([[result.emails objectAtIndex:0] isEqualToString:@"1@1.com"], + @"Email 1 is %@", [result.emails objectAtIndex:0]); +} + +- (void)testExtraWhitespaceBizcard { + NSString *msg = + @"BIZCARD:;" + @"N:Firstname ;" + @"X:Lastname\r;" + @"T:Title\n;" + @"C:Org\r\n;" + @"A: Addr 1;" + @"A:\rAddr 2;" + @"B:\n1111111;" + @"M:\r\n2222222;" + @"F:\t3333333;" + @"E:1@1.com\t;"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [BizcardResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertEquals(1U, result.names.count, @"Wrong number of names %d", + result.names.count); + STAssertTrue( + [[result.names objectAtIndex:0] isEqualToString:@"Firstname Lastname"], + @"Name one is %@", [result.names objectAtIndex:0]); + STAssertTrue([result.jobTitle isEqualToString:@"Title"], + @"Title is %@", result.jobTitle); + STAssertTrue([result.organization isEqualToString:@"Org"], + @"Organization is %@", result.organization); + STAssertEquals(2U, result.addresses.count, @"Wrong number of addresses %d", + result.addresses.count); + STAssertTrue([[result.addresses objectAtIndex:0] isEqualToString:@"Addr 1"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); + STAssertTrue([[result.addresses objectAtIndex:1] isEqualToString:@"Addr 2"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); + STAssertEquals(3U, result.phoneNumbers.count, + @"Wrong number of phone numbers %d", + result.phoneNumbers.count); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:0] isEqualToString:@"1111111"], + @"Phone number 1 is %@", [result.phoneNumbers objectAtIndex:0]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:1] isEqualToString:@"2222222"], + @"Phone number 2 is %@", [result.phoneNumbers objectAtIndex:1]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:2] isEqualToString:@"3333333"], + @"Phone number 3 is %@", [result.phoneNumbers objectAtIndex:2]); + STAssertEquals(1U, result.emails.count, + @"Wrong number of emails %d", result.emails.count); + STAssertTrue([[result.emails objectAtIndex:0] isEqualToString:@"1@1.com"], + @"Email 1 is %@", [result.emails objectAtIndex:0]); +} + +- (void)testMalformedBizcard { + NSString *msg = + @"N:Name One;" + @"X:Name Two;" + @"T:Title;" + @"C:Org;" + @"A:Addr 1;" + @"A:Addr 2;" + @"B:1111111;" + @"M:2222222;" + @"F:3333333;" + @"E:1@1.com;"; + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [BizcardResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched"); +} + +@end diff --git a/iphone/ZXingWidget/Tests/BookmarkDoCoMoTests.m b/iphone/ZXingWidget/Tests/BookmarkDoCoMoTests.m new file mode 100644 index 000000000..dd3a055a8 --- /dev/null +++ b/iphone/ZXingWidget/Tests/BookmarkDoCoMoTests.m @@ -0,0 +1,50 @@ +// +// BookmarkDoCoMoTests.m +// ZXingWidget +// +// Created by George Nachman on 7/27/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "BookmarkDoCoMoResultParser.h" +#import "URIParsedResult.h" + +@interface BookmarkDoCoMoTests : SenTestCase +@end + +@implementation BookmarkDoCoMoTests + +- (void)testWellFormedBookmarkDoCoMo { + NSString *msg = + @"MEBKM:;" + @"URL:http://www.example.com/;" + @"TITLE:The Title;"; + URIParsedResult *result = (URIParsedResult *) + [BookmarkDoCoMoResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertTrue([result.urlString isEqualToString:@"http://www.example.com/"], + @"Wrong URL string %@", result.urlString); + STAssertTrue([[result.URL host] isEqualToString:@"www.example.com"], + @"Wrong URL host %@", [result.URL host]); + STAssertTrue([[result.URL path] isEqualToString:@"/"], + @"Wrong URL path %@", [result.URL path]); + STAssertTrue([[result.URL scheme] isEqualToString:@"http"], + @"Wrong URL scheme %@", [result.URL scheme]); + STAssertTrue([result.title isEqualToString:@"The Title"], + @"Wrong title %@", result.title); +} + +- (void)testMalformedBookmarkDoCoMo { + NSString *msg = + @"URL:http://www.example.com/;" + @"TITLE:The Title"; + URIParsedResult *result = (URIParsedResult *) + [BookmarkDoCoMoResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched."); +} + + +@end diff --git a/iphone/ZXingWidget/Tests/EmailDoCoMoResultParserTests.m b/iphone/ZXingWidget/Tests/EmailDoCoMoResultParserTests.m new file mode 100644 index 000000000..dca0acf80 --- /dev/null +++ b/iphone/ZXingWidget/Tests/EmailDoCoMoResultParserTests.m @@ -0,0 +1,48 @@ +// +// EmailDoCoMoTests.m +// ZXingWidget +// +// Created by George Nachman on 7/27/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "EmailDoCoMoResultParser.h" +#import "EmailParsedResult.h" + +@interface EmailDoCoMoResultParserTests : SenTestCase +@end + +@implementation EmailDoCoMoResultParserTests + +- (void)testWellFormedEmailDoCoMo { + NSString *msg = + @"MATMSG:;" + @"TO:addressee@example.com;" + @"SUB:subject;" + @"BODY:The body\nThe end;"; + EmailParsedResult *result = (EmailParsedResult *) + [EmailDoCoMoResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertTrue([result.to isEqualToString:@"addressee@example.com"], + @"Wrong to: is %@", result.to); + STAssertTrue([result.subject isEqualToString:@"subject"], + @"Wrong subject %@", result.subject); + STAssertTrue([result.body isEqualToString:@"The body\nThe end"], + @"Wrong body %@", result.subject); +} + +- (void)testMalformedEmailDoCoMo { + NSString *msg = + @"TO:addressee@example.com;" + @"SUB:subject;" + @"BODY:The body\nThe end;"; + EmailParsedResult *result = (EmailParsedResult *) + [EmailDoCoMoResultParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched."); +} + + +@end diff --git a/iphone/ZXingWidget/Tests/MeCardParserTests.m b/iphone/ZXingWidget/Tests/MeCardParserTests.m new file mode 100644 index 000000000..950e5ed2e --- /dev/null +++ b/iphone/ZXingWidget/Tests/MeCardParserTests.m @@ -0,0 +1,111 @@ +// +// MeCardParserTests.m +// ZXingWidget +// +// Created by George Nachman on 7/27/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "BusinessCardParsedResult.h" +#import "MeCardParser.h" + +@interface MeCardParserTests : SenTestCase +@end + +@implementation MeCardParserTests + +- (void)testWellFormedMeCard { + NSString *msg = + @"MECARD:;" + @"N:Name One;" + @"SOUND:pronunciation;" + @"TEL:1111111;" + @"TEL:2222222;" + @"TEL:3333333;" + @"EMAIL:1@1.com;" + @"EMAIL:2@2.com;" + @"EMAIL:3@3.com;" + @"NOTE:This is a note;" + @"ADR:123 Fake St;" + @"ADR:234 Fake St;" + @"BDAY:19980904;" + @"URL:http://example.com/;" + @"ORG:Organization;" + @"TITLE:Title;"; + + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [MeCardParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertEquals(1U, result.names.count, @"Wrong number of names %d", + result.names.count); + STAssertTrue([[result.names objectAtIndex:0] isEqualToString:@"Name One"], + @"Wrong Name one %@", [result.names objectAtIndex:0]); + STAssertTrue([result.pronunciation isEqualToString:@"pronunciation"], + @"Wrong pronunciation %@", result.pronunciation); + STAssertEquals(3U, result.phoneNumbers.count, + @"Wrong number of phone numbers %d", + result.phoneNumbers.count); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:0] isEqualToString:@"1111111"], + @"Wrong phone number 1 %@", [result.phoneNumbers objectAtIndex:0]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:1] isEqualToString:@"2222222"], + @"Wrong phone number 2 %@", [result.phoneNumbers objectAtIndex:1]); + STAssertTrue( + [[result.phoneNumbers objectAtIndex:2] isEqualToString:@"3333333"], + @"Wrong phone number 3 %@", [result.phoneNumbers objectAtIndex:2]); + STAssertEquals(3U, result.emails.count, + @"Wrong number of emails %d", result.emails.count); + STAssertTrue([[result.emails objectAtIndex:0] isEqualToString:@"1@1.com"], + @"Wrong email 1 %@", [result.emails objectAtIndex:0]); + STAssertTrue([[result.emails objectAtIndex:1] isEqualToString:@"2@2.com"], + @"Wrong email 2 %@", [result.emails objectAtIndex:1]); + STAssertTrue([[result.emails objectAtIndex:2] isEqualToString:@"3@3.com"], + @"Wrong email 3 %@", [result.emails objectAtIndex:2]); + STAssertTrue([result.note isEqualToString:@"This is a note"], + @"Wrong note %@", result.note); + STAssertEquals(2U, result.addresses.count, @"Wrong number of addresses %d", + result.addresses.count); + STAssertTrue( + [[result.addresses objectAtIndex:0] isEqualToString:@"123 Fake St"], + @"Wrong address %@", [result.addresses objectAtIndex:0]); + STAssertTrue( + [[result.addresses objectAtIndex:1] isEqualToString:@"234 Fake St"], + @"Wrong address %@", [result.addresses objectAtIndex:1]); + STAssertTrue([result.birthday isEqualToString:@"19980904"], + @"Wrong birthday %@", result.birthday); + STAssertTrue([result.url isEqualToString:@"http://example.com/"], + @"Wrong url %@", result.url); + STAssertTrue([result.organization isEqualToString:@"Organization"], + @"Wrong organization %@", result.organization); + STAssertTrue([result.jobTitle isEqualToString:@"Title"], + @"Wrong job title %@", result.jobTitle); +} + +- (void)testMalformedMeCard { + NSString *msg = + @"N:Name One;" + @"SOUND:pronunciation;" + @"TEL1:1111111;" + @"TEL2:2222222;" + @"TEL3:3333333;" + @"EMAIL1:1@1.com;" + @"EMAIL2:2@2.com;" + @"EMAIL3:3@3.com;" + @"NOTE:This is a note;" + @"ADR1:123 Fake St;" + @"ADR2:234 Fake St;" + @"BDAY:19980904;" + @"URL:http://example.com/;" + @"ORG:Organization;" + @"TITLE:Title;"; + + BusinessCardParsedResult *result = (BusinessCardParsedResult *) + [MeCardParser parsedResultForString:msg + format:BarcodeFormat_QR_CODE]; + STAssertNil(result, @"Bogus string matched."); +} + +@end diff --git a/iphone/ZXingWidget/Tests/VCardResultParserTests.m b/iphone/ZXingWidget/Tests/VCardResultParserTests.m new file mode 100644 index 000000000..35ef44d31 --- /dev/null +++ b/iphone/ZXingWidget/Tests/VCardResultParserTests.m @@ -0,0 +1,150 @@ +// +// VCardResultParserTests.m +// ZXingWidget +// +// Created by George Nachman on 7/26/11. +// Copyright 2011 ZXing Authors. All rights reserved. +// + +#import +#import +#import "VCardResultParser.h" +#import "BusinessCardParsedResult.h" + +@interface VCardResultParserTests : SenTestCase +@end + +@implementation VCardResultParserTests + +- (void)testVanillaVCard { + NSString* msg = + @"BEGIN:VCARD\n" + @"N:Kennedy;Steve\n" + @"TEL:+44 (0)7775 755503\n" + @"ADR;HOME:;;Flat 2, 43 Howitt Road, Belsize Park;London;;NW34LU;UK\n" + @"ORG:NetTek Ltd;\n" + @"TITLE:Consultant\n" + @"EMAIL:steve@nettek.co.uk\n" + @"URL:www.nettek.co.uk\n" + @"EMAIL;IM:MSN:steve@gbnet.net\n" + @"NOTE:Testing 1 2 3\n" + @"BDAY:19611105\n" + @"END:VCARD"; + BusinessCardParsedResult* b = (BusinessCardParsedResult *) + [VCardResultParser parsedResultForString:msg + format:0]; + + STAssertEquals(1U, b.names.count, @"Should have exactly one name"); + STAssertTrue([[b.names objectAtIndex:0] isEqualToString:@"Steve Kennedy"], + @"Wrong name %@", b.names); + STAssertEquals(1U, b.phoneNumbers.count, + @"Should have exactly one phone number"); + STAssertTrue([[b.phoneNumbers objectAtIndex:0] isEqualToString: + @"+44 (0)7775 755503"], + @"Wrong phone number %@", [b.phoneNumbers objectAtIndex:0]); + STAssertEquals(1U, b.addresses.count, @"Should have exactly one address"); + STAssertTrue([[b.addresses objectAtIndex:0] isEqualToString: + @"Flat 2, 43 Howitt Road, Belsize Park London NW34LU UK"], + @"Wrong address %@", [b.addresses objectAtIndex:0]); + STAssertTrue([b.organization isEqualToString:@"NetTek Ltd;"], + @"Wrong organization %@", b.organization); + STAssertTrue([b.jobTitle isEqualToString:@"Consultant"], + @"Wrong job title %@", b.jobTitle); + STAssertEquals(2U, b.emails.count, + @"Wrong number of emails %d", b.emails.count); + STAssertTrue([[b.emails objectAtIndex:0] isEqualToString: + @"steve@nettek.co.uk"], + @"Wrong first email %@", [b.emails objectAtIndex:0]); + STAssertTrue([b.note isEqualToString:@"Testing 1 2 3"], + @"Wrong note %@", b.note); + STAssertTrue([b.url isEqualToString:@"www.nettek.co.uk"], + @"Wrong url %@", b.url); + STAssertTrue([[b.emails objectAtIndex:1] isEqualToString: + @"MSN:steve@gbnet.net"], + @"Wrong second email %@", [b.emails objectAtIndex:1]); + STAssertTrue([b.birthday isEqualToString:@"19611105"], + @"Wrong birthday %@", b.birthday); +} + +- (void)testBrokenVCard { + NSString *msg = @"Blah blah blah"; + BusinessCardParsedResult* b = (BusinessCardParsedResult *) + [VCardResultParser parsedResultForString:msg + format:0]; + + STAssertTrue(b == nil, @"Bogus string parsed"); +} + +- (void)testQuotedPrintableVCard { + NSString *msg = + @"BEGIN:VCARD\n" + @"FN;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:Kennedy;=C5=9Bteve\n" + @"TEL:+44 (0)7775 755503\n" + @"ADR;HOME:;;Flat 2, 43 Howitt Road, Belsize Park;London;;NW34LU;UK\n" + @"ORG:NetTek Ltd;\n" + @"TITLE:Consultant\n" + @"EMAIL:steve@nettek.co.uk\n" + @"URL:www.nettek.co.uk\n" + @"EMAIL;IM:MSN:steve@gbnet.net\n" + @"NOTE:Testing 1 2 3\n" + @"BDAY:19611105\n" + @"END:VCARD"; + BusinessCardParsedResult* b = (BusinessCardParsedResult *) + [VCardResultParser parsedResultForString:msg + format:0]; + STAssertEquals(1U, b.names.count, + @"Wrong number of names %d", b.names.count); + STAssertTrue([[b.names objectAtIndex:0] isEqualToString:@"śteve Kennedy"], + @"Wrong name %@", [b.names objectAtIndex:0]); +} + +- (void)testExcessNewlineVCard { + NSString *msg = + @"BEGIN:VCARD\n" + @"FN;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:Kennedy;=C5=9Bteve\n" + @"TEL:+44 (0)7775 755503\n" + @"ADR;HOME:;;Flat 2, 43 Howitt Road, Belsize Park;London;;NW34LU;UK\n" + @"ORG:NetTek Ltd;\t\n" // note tab at end + @"TITLE:Consultant\n" + @"EMAIL:steve@nettek.co.uk\n" + @"URL:www.nettek.co.uk \n" // note trailing space + @"EMAIL;IM:MSN:steve@gbnet.net\n" + @"NOTE:Testing 1 2 3\r\n" // note dos newline + @"BDAY:19611105\n"; + BusinessCardParsedResult* b = (BusinessCardParsedResult *) + [VCardResultParser parsedResultForString:msg + format:0]; + STAssertTrue([b.birthday isEqualToString:@"19611105"], + @"Wrong birthday %@", b.birthday); + STAssertTrue([b.jobTitle isEqualToString:@"Consultant"], + @"Wrong job title %@", b.jobTitle); + STAssertTrue([b.url isEqualToString:@"www.nettek.co.uk"], + @"Wrong url %@", b.url); + STAssertTrue([b.note isEqualToString:@"Testing 1 2 3"], + @"Wrong note %@", b.note); +} + +- (void)testStrayKeywordVCard { + NSString *msg = + @"BEGIN:VCARD\n" + @"FN;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:Kennedy;=C5=9Bteve\n" + @"TEL:+44 (0)7775 755503\n" + @"ADR;HOME:;;Flat ORG TITLE 2, 43 Howitt Road, Belsize Park;London;;" + @"NW34LU;UK\n" + @"ORG:NetTek Ltd;\t\n" // note tab at end + @"TITLE:Consultant\n" + @"EMAIL:steve@nettek.co.uk\n" + @"URL:www.nettek.co.uk \n" // note trailing space + @"EMAIL;IM:MSN:steve@gbnet.net\n" + @"NOTE:Testing 1 2 3\r\n" // note dos newline + @"BDAY:19611105\n"; + BusinessCardParsedResult* b = (BusinessCardParsedResult *) + [VCardResultParser parsedResultForString:msg + format:0]; + STAssertTrue([b.jobTitle isEqualToString:@"Consultant"], + @"Wrong job title %@", b.jobTitle); + STAssertTrue([b.organization isEqualToString:@"NetTek Ltd;"], + @"Wrong organization %@", b.organization); +} + +@end diff --git a/iphone/ZXingWidget/ZXingTests-Info.plist b/iphone/ZXingWidget/ZXingTests-Info.plist new file mode 100644 index 000000000..7d42ad21f --- /dev/null +++ b/iphone/ZXingWidget/ZXingTests-Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.zxing.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/iphone/ZXingWidget/ZXingWidget.xcodeproj/project.pbxproj b/iphone/ZXingWidget/ZXingWidget.xcodeproj/project.pbxproj index 75c3ed134..8c22882ae 100644 --- a/iphone/ZXingWidget/ZXingWidget.xcodeproj/project.pbxproj +++ b/iphone/ZXingWidget/ZXingWidget.xcodeproj/project.pbxproj @@ -9,6 +9,22 @@ /* Begin PBXBuildFile section */ 1D0CBDF913D0DD5D003D0F8D /* BizcardResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D0CBDF713D0DD5D003D0F8D /* BizcardResultParser.h */; }; 1D0CBDFA13D0DD5D003D0F8D /* BizcardResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0CBDF813D0DD5D003D0F8D /* BizcardResultParser.m */; }; + 1D4F11FB13D89EFD0032F754 /* VCardResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D4F11F913D89EFD0032F754 /* VCardResultParser.h */; }; + 1D4F11FC13D89EFD0032F754 /* VCardResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D4F11FA13D89EFD0032F754 /* VCardResultParser.m */; }; + 1D6039EC13DF7F62006F4B51 /* libZXingWidget.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AAC07E0554694100DB518D /* libZXingWidget.a */; }; + 1D6039F313DF7F9A006F4B51 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D60391813DF7780006F4B51 /* AddressBook.framework */; }; + 1D6039F413DF7F9A006F4B51 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D60391E13DF778C006F4B51 /* AddressBookUI.framework */; }; + 1D6039F513DF7F9A006F4B51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E5345AA21198859A000CB77F /* CoreGraphics.framework */; }; + 1D6039F613DF7F9A006F4B51 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; + 1D6039F713DF7F9A006F4B51 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E53459CA119873F3000CB77F /* UIKit.framework */; }; + 1D603D7413E0B60D006F4B51 /* AddressBookAUResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D6913E0B60D006F4B51 /* AddressBookAUResultParserTests.m */; }; + 1D603D7513E0B60D006F4B51 /* BizcardResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D6B13E0B60D006F4B51 /* BizcardResultParserTests.m */; }; + 1D603D7613E0B60D006F4B51 /* BookmarkDoCoMoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D6D13E0B60D006F4B51 /* BookmarkDoCoMoTests.m */; }; + 1D603D7713E0B60D006F4B51 /* EmailDoCoMoResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D6F13E0B60D006F4B51 /* EmailDoCoMoResultParserTests.m */; }; + 1D603D7813E0B60D006F4B51 /* MeCardParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D7113E0B60D006F4B51 /* MeCardParserTests.m */; }; + 1D603D7913E0B60D006F4B51 /* VCardResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603D7313E0B60D006F4B51 /* VCardResultParserTests.m */; }; + 1D603E6413E20AF1006F4B51 /* ArrayAndStringCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D603E6213E20AF1006F4B51 /* ArrayAndStringCategories.h */; }; + 1D603E6513E20AF1006F4B51 /* ArrayAndStringCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D603E6313E20AF1006F4B51 /* ArrayAndStringCategories.m */; }; 1DFA090C13CE1A3900599044 /* CBarcodeFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DFA090A13CE1A3900599044 /* CBarcodeFormat.h */; }; 1DFA090D13CE1A3900599044 /* CBarcodeFormat.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1DFA090B13CE1A3900599044 /* CBarcodeFormat.mm */; }; 1DFA092413CE251600599044 /* ProductParsedResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DFA092213CE251600599044 /* ProductParsedResult.h */; }; @@ -23,8 +39,6 @@ 1F027FAE11A7BEAF006B06DE /* FormatReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FA211A7BEAF006B06DE /* FormatReader.h */; }; 1F027FAF11A7BEAF006B06DE /* FormatReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FA311A7BEAF006B06DE /* FormatReader.mm */; }; 1F027FB211A7BEAF006B06DE /* MultiFormatReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FA611A7BEAF006B06DE /* MultiFormatReader.mm */; }; - 1F027FB311A7BEAF006B06DE /* NSString+HTML.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FA711A7BEAF006B06DE /* NSString+HTML.h */; }; - 1F027FB411A7BEAF006B06DE /* NSString+HTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FA811A7BEAF006B06DE /* NSString+HTML.m */; }; 1F027FB511A7BEAF006B06DE /* OverlayView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FA911A7BEAF006B06DE /* OverlayView.h */; }; 1F027FB611A7BEAF006B06DE /* OverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FAA11A7BEAF006B06DE /* OverlayView.m */; }; 1F027FBB11A7BEBF006B06DE /* TwoDDecoderResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FB711A7BEBF006B06DE /* TwoDDecoderResult.h */; }; @@ -63,8 +77,6 @@ 1F027FFA11A7BEEB006B06DE /* URIParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FEA11A7BEEB006B06DE /* URIParsedResult.m */; }; 1F02801511A7BF06006B06DE /* BookmarkDoCoMoResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FFB11A7BF06006B06DE /* BookmarkDoCoMoResultParser.h */; }; 1F02801611A7BF06006B06DE /* BookmarkDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FFC11A7BF06006B06DE /* BookmarkDoCoMoResultParser.m */; }; - 1F02801711A7BF06006B06DE /* DoCoMoResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FFD11A7BF06006B06DE /* DoCoMoResultParser.h */; }; - 1F02801811A7BF06006B06DE /* DoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F027FFE11A7BF06006B06DE /* DoCoMoResultParser.m */; }; 1F02801911A7BF06006B06DE /* EmailDoCoMoResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F027FFF11A7BF06006B06DE /* EmailDoCoMoResultParser.h */; }; 1F02801A11A7BF06006B06DE /* EmailDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F02800011A7BF06006B06DE /* EmailDoCoMoResultParser.m */; }; 1F02801B11A7BF06006B06DE /* GeoResultParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F02800111A7BF06006B06DE /* GeoResultParser.h */; }; @@ -245,9 +257,35 @@ E5345AA31198859A000CB77F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E5345AA21198859A000CB77F /* CoreGraphics.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 1D603E4D13E1E010006F4B51 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2AAC07D0554694100DB518D; + remoteInfo = ZXingWidget; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ 1D0CBDF713D0DD5D003D0F8D /* BizcardResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BizcardResultParser.h; path = Classes/resultParsers/BizcardResultParser.h; sourceTree = ""; }; 1D0CBDF813D0DD5D003D0F8D /* BizcardResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BizcardResultParser.m; path = Classes/resultParsers/BizcardResultParser.m; sourceTree = ""; }; + 1D4F11F913D89EFD0032F754 /* VCardResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VCardResultParser.h; path = Classes/resultParsers/VCardResultParser.h; sourceTree = ""; }; + 1D4F11FA13D89EFD0032F754 /* VCardResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VCardResultParser.m; path = Classes/resultParsers/VCardResultParser.m; sourceTree = ""; }; + 1D60389C13DF6FB5006F4B51 /* ZXingTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ZXingTests-Info.plist"; sourceTree = ""; }; + 1D6038E913DF75BA006F4B51 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 1D60391813DF7780006F4B51 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; + 1D60391E13DF778C006F4B51 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; + 1D60398D13DF7CAD006F4B51 /* ZXingTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZXingTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; + 1D603D6913E0B60D006F4B51 /* AddressBookAUResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AddressBookAUResultParserTests.m; path = Tests/AddressBookAUResultParserTests.m; sourceTree = ""; }; + 1D603D6B13E0B60D006F4B51 /* BizcardResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BizcardResultParserTests.m; path = Tests/BizcardResultParserTests.m; sourceTree = ""; }; + 1D603D6D13E0B60D006F4B51 /* BookmarkDoCoMoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BookmarkDoCoMoTests.m; path = Tests/BookmarkDoCoMoTests.m; sourceTree = ""; }; + 1D603D6F13E0B60D006F4B51 /* EmailDoCoMoResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmailDoCoMoResultParserTests.m; path = Tests/EmailDoCoMoResultParserTests.m; sourceTree = ""; }; + 1D603D7113E0B60D006F4B51 /* MeCardParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MeCardParserTests.m; path = Tests/MeCardParserTests.m; sourceTree = ""; }; + 1D603D7313E0B60D006F4B51 /* VCardResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VCardResultParserTests.m; path = Tests/VCardResultParserTests.m; sourceTree = ""; }; + 1D603E6213E20AF1006F4B51 /* ArrayAndStringCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ArrayAndStringCategories.h; path = Classes/ArrayAndStringCategories.h; sourceTree = ""; }; + 1D603E6313E20AF1006F4B51 /* ArrayAndStringCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ArrayAndStringCategories.m; path = Classes/ArrayAndStringCategories.m; sourceTree = ""; }; + 1D6040C413E3393B006F4B51 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 1DFA090A13CE1A3900599044 /* CBarcodeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CBarcodeFormat.h; path = Classes/CBarcodeFormat.h; sourceTree = ""; }; 1DFA090B13CE1A3900599044 /* CBarcodeFormat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CBarcodeFormat.mm; path = Classes/CBarcodeFormat.mm; sourceTree = ""; }; 1DFA092213CE251600599044 /* ProductParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProductParsedResult.h; path = Classes/parsedResults/ProductParsedResult.h; sourceTree = ""; }; @@ -262,8 +300,6 @@ 1F027FA211A7BEAF006B06DE /* FormatReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FormatReader.h; path = Classes/FormatReader.h; sourceTree = ""; }; 1F027FA311A7BEAF006B06DE /* FormatReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = FormatReader.mm; path = Classes/FormatReader.mm; sourceTree = ""; }; 1F027FA611A7BEAF006B06DE /* MultiFormatReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MultiFormatReader.mm; path = Classes/MultiFormatReader.mm; sourceTree = ""; }; - 1F027FA711A7BEAF006B06DE /* NSString+HTML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+HTML.h"; path = "Classes/NSString+HTML.h"; sourceTree = ""; }; - 1F027FA811A7BEAF006B06DE /* NSString+HTML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+HTML.m"; path = "Classes/NSString+HTML.m"; sourceTree = ""; }; 1F027FA911A7BEAF006B06DE /* OverlayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OverlayView.h; path = Classes/OverlayView.h; sourceTree = ""; }; 1F027FAA11A7BEAF006B06DE /* OverlayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OverlayView.m; path = Classes/OverlayView.m; sourceTree = ""; }; 1F027FB711A7BEBF006B06DE /* TwoDDecoderResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwoDDecoderResult.h; path = Classes/TwoDDecoderResult.h; sourceTree = ""; }; @@ -302,8 +338,6 @@ 1F027FEA11A7BEEB006B06DE /* URIParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = URIParsedResult.m; path = Classes/parsedResults/URIParsedResult.m; sourceTree = ""; }; 1F027FFB11A7BF06006B06DE /* BookmarkDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BookmarkDoCoMoResultParser.h; path = Classes/resultParsers/BookmarkDoCoMoResultParser.h; sourceTree = ""; }; 1F027FFC11A7BF06006B06DE /* BookmarkDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BookmarkDoCoMoResultParser.m; path = Classes/resultParsers/BookmarkDoCoMoResultParser.m; sourceTree = ""; }; - 1F027FFD11A7BF06006B06DE /* DoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DoCoMoResultParser.h; path = Classes/resultParsers/DoCoMoResultParser.h; sourceTree = ""; }; - 1F027FFE11A7BF06006B06DE /* DoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DoCoMoResultParser.m; path = Classes/resultParsers/DoCoMoResultParser.m; sourceTree = ""; }; 1F027FFF11A7BF06006B06DE /* EmailDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmailDoCoMoResultParser.h; path = Classes/resultParsers/EmailDoCoMoResultParser.h; sourceTree = ""; }; 1F02800011A7BF06006B06DE /* EmailDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmailDoCoMoResultParser.m; path = Classes/resultParsers/EmailDoCoMoResultParser.m; sourceTree = ""; }; 1F02800111A7BF06006B06DE /* GeoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeoResultParser.h; path = Classes/resultParsers/GeoResultParser.h; sourceTree = ""; }; @@ -486,6 +520,19 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1D60398A13DF7CAD006F4B51 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D6039EC13DF7F62006F4B51 /* libZXingWidget.a in Frameworks */, + 1D6039F313DF7F9A006F4B51 /* AddressBook.framework in Frameworks */, + 1D6039F413DF7F9A006F4B51 /* AddressBookUI.framework in Frameworks */, + 1D6039F513DF7F9A006F4B51 /* CoreGraphics.framework in Frameworks */, + 1D6039F613DF7F9A006F4B51 /* Foundation.framework in Frameworks */, + 1D6039F713DF7F9A006F4B51 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC07C0554694100DB518D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -504,6 +551,7 @@ isa = PBXGroup; children = ( D2AAC07E0554694100DB518D /* libZXingWidget.a */, + 1D60398D13DF7CAD006F4B51 /* ZXingTests.octest */, ); name = Products; sourceTree = ""; @@ -511,12 +559,16 @@ 0867D691FE84028FC02AAC07 /* ZXingWidget */ = { isa = PBXGroup; children = ( + 1D6038A113DF6FBF006F4B51 /* Tests */, E53458B311987396000CB77F /* CoreSrc */, 08FB77AEFE84172EC02AAC07 /* Classes */, 32C88DFF0371C24200C91783 /* Other Sources */, 0867D69AFE84028FC02AAC07 /* Frameworks */, E5345D2811999F53000CB77F /* Resources */, 034768DFFF38A50411DB9C8B /* Products */, + 1D60391813DF7780006F4B51 /* AddressBook.framework */, + 1D60391E13DF778C006F4B51 /* AddressBookUI.framework */, + 1D6040C413E3393B006F4B51 /* AVFoundation.framework */, ); name = ZXingWidget; sourceTree = ""; @@ -528,6 +580,7 @@ E53459CA119873F3000CB77F /* UIKit.framework */, E5345A651198792F000CB77F /* AudioToolbox.framework */, E5345AA21198859A000CB77F /* CoreGraphics.framework */, + 1D6038E913DF75BA006F4B51 /* SenTestingKit.framework */, ); name = Frameworks; sourceTree = ""; @@ -535,6 +588,8 @@ 08FB77AEFE84172EC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 1D603E6213E20AF1006F4B51 /* ArrayAndStringCategories.h */, + 1D603E6313E20AF1006F4B51 /* ArrayAndStringCategories.m */, 1DFA090A13CE1A3900599044 /* CBarcodeFormat.h */, 1DFA090B13CE1A3900599044 /* CBarcodeFormat.mm */, 1F3DB0F511C61080009C581B /* DataMatrixReader.h */, @@ -555,8 +610,6 @@ 1F027FA211A7BEAF006B06DE /* FormatReader.h */, 1F027FA311A7BEAF006B06DE /* FormatReader.mm */, 1F027FA611A7BEAF006B06DE /* MultiFormatReader.mm */, - 1F027FA711A7BEAF006B06DE /* NSString+HTML.h */, - 1F027FA811A7BEAF006B06DE /* NSString+HTML.m */, 1F027FA911A7BEAF006B06DE /* OverlayView.h */, 1F027FAA11A7BEAF006B06DE /* OverlayView.m */, E5345A00119876A5000CB77F /* Actions */, @@ -566,6 +619,20 @@ name = Classes; sourceTree = ""; }; + 1D6038A113DF6FBF006F4B51 /* Tests */ = { + isa = PBXGroup; + children = ( + 1D60389C13DF6FB5006F4B51 /* ZXingTests-Info.plist */, + 1D603D6913E0B60D006F4B51 /* AddressBookAUResultParserTests.m */, + 1D603D6B13E0B60D006F4B51 /* BizcardResultParserTests.m */, + 1D603D6D13E0B60D006F4B51 /* BookmarkDoCoMoTests.m */, + 1D603D6F13E0B60D006F4B51 /* EmailDoCoMoResultParserTests.m */, + 1D603D7113E0B60D006F4B51 /* MeCardParserTests.m */, + 1D603D7313E0B60D006F4B51 /* VCardResultParserTests.m */, + ); + name = Tests; + sourceTree = ""; + }; 32C88DFF0371C24200C91783 /* Other Sources */ = { isa = PBXGroup; children = ( @@ -814,8 +881,6 @@ 1D0CBDF813D0DD5D003D0F8D /* BizcardResultParser.m */, 1F027FFB11A7BF06006B06DE /* BookmarkDoCoMoResultParser.h */, 1F027FFC11A7BF06006B06DE /* BookmarkDoCoMoResultParser.m */, - 1F027FFD11A7BF06006B06DE /* DoCoMoResultParser.h */, - 1F027FFE11A7BF06006B06DE /* DoCoMoResultParser.m */, 1F027FFF11A7BF06006B06DE /* EmailDoCoMoResultParser.h */, 1F02800011A7BF06006B06DE /* EmailDoCoMoResultParser.m */, 1F02800111A7BF06006B06DE /* GeoResultParser.h */, @@ -840,6 +905,8 @@ 1F02801211A7BF06006B06DE /* URLResultParser.m */, 1F02801311A7BF06006B06DE /* URLTOResultParser.h */, 1F02801411A7BF06006B06DE /* URLTOResultParser.m */, + 1D4F11F913D89EFD0032F754 /* VCardResultParser.h */, + 1D4F11FA13D89EFD0032F754 /* VCardResultParser.m */, ); name = ResultParsers; sourceTree = ""; @@ -974,7 +1041,6 @@ 1F027FAB11A7BEAF006B06DE /* Decoder.h in Headers */, 1F027FAD11A7BEAF006B06DE /* DecoderDelegate.h in Headers */, 1F027FAE11A7BEAF006B06DE /* FormatReader.h in Headers */, - 1F027FB311A7BEAF006B06DE /* NSString+HTML.h in Headers */, 1F027FB511A7BEAF006B06DE /* OverlayView.h in Headers */, 1F027FBB11A7BEBF006B06DE /* TwoDDecoderResult.h in Headers */, 1F027FBD11A7BEBF006B06DE /* ZXingWidgetController.h in Headers */, @@ -994,7 +1060,6 @@ 1F027FF711A7BEEB006B06DE /* TextParsedResult.h in Headers */, 1F027FF911A7BEEB006B06DE /* URIParsedResult.h in Headers */, 1F02801511A7BF06006B06DE /* BookmarkDoCoMoResultParser.h in Headers */, - 1F02801711A7BF06006B06DE /* DoCoMoResultParser.h in Headers */, 1F02801911A7BF06006B06DE /* EmailDoCoMoResultParser.h in Headers */, 1F02801B11A7BF06006B06DE /* GeoResultParser.h in Headers */, 1F02801D11A7BF06006B06DE /* MeCardParser.h in Headers */, @@ -1021,12 +1086,33 @@ 1DFA092A13CE252300599044 /* ProductResultParser.h in Headers */, 1DFA09A013CE5C0300599044 /* AddressBookAUResultParser.h in Headers */, 1D0CBDF913D0DD5D003D0F8D /* BizcardResultParser.h in Headers */, + 1D4F11FB13D89EFD0032F754 /* VCardResultParser.h in Headers */, + 1D603E6413E20AF1006F4B51 /* ArrayAndStringCategories.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 1D60398C13DF7CAD006F4B51 /* ZXingTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D60399113DF7CDC006F4B51 /* Build configuration list for PBXNativeTarget "ZXingTests" */; + buildPhases = ( + 1D60398813DF7CAD006F4B51 /* Resources */, + 1D60398913DF7CAD006F4B51 /* Sources */, + 1D60398A13DF7CAD006F4B51 /* Frameworks */, + 1D60398B13DF7CAD006F4B51 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 1D603E4E13E1E010006F4B51 /* PBXTargetDependency */, + ); + name = ZXingTests; + productName = ZXingTests; + productReference = 1D60398D13DF7CAD006F4B51 /* ZXingTests.octest */; + productType = "com.apple.product-type.bundle"; + }; D2AAC07D0554694100DB518D /* ZXingWidget */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "ZXingWidget" */; @@ -1065,11 +1151,51 @@ projectRoot = ""; targets = ( D2AAC07D0554694100DB518D /* ZXingWidget */, + 1D60398C13DF7CAD006F4B51 /* ZXingTests */, ); }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + 1D60398813DF7CAD006F4B51 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1D60398B13DF7CAD006F4B51 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + 1D60398913DF7CAD006F4B51 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D603D7413E0B60D006F4B51 /* AddressBookAUResultParserTests.m in Sources */, + 1D603D7513E0B60D006F4B51 /* BizcardResultParserTests.m in Sources */, + 1D603D7613E0B60D006F4B51 /* BookmarkDoCoMoTests.m in Sources */, + 1D603D7713E0B60D006F4B51 /* EmailDoCoMoResultParserTests.m in Sources */, + 1D603D7813E0B60D006F4B51 /* MeCardParserTests.m in Sources */, + 1D603D7913E0B60D006F4B51 /* VCardResultParserTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC07B0554694100DB518D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1142,7 +1268,6 @@ 1F027FAC11A7BEAF006B06DE /* Decoder.mm in Sources */, 1F027FAF11A7BEAF006B06DE /* FormatReader.mm in Sources */, 1F027FB211A7BEAF006B06DE /* MultiFormatReader.mm in Sources */, - 1F027FB411A7BEAF006B06DE /* NSString+HTML.m in Sources */, 1F027FB611A7BEAF006B06DE /* OverlayView.m in Sources */, 1F027FBC11A7BEBF006B06DE /* TwoDDecoderResult.m in Sources */, 1F027FBE11A7BEBF006B06DE /* ZXingWidgetController.m in Sources */, @@ -1162,7 +1287,6 @@ 1F027FF811A7BEEB006B06DE /* TextParsedResult.m in Sources */, 1F027FFA11A7BEEB006B06DE /* URIParsedResult.m in Sources */, 1F02801611A7BF06006B06DE /* BookmarkDoCoMoResultParser.m in Sources */, - 1F02801811A7BF06006B06DE /* DoCoMoResultParser.m in Sources */, 1F02801A11A7BF06006B06DE /* EmailDoCoMoResultParser.m in Sources */, 1F02801C11A7BF06006B06DE /* GeoResultParser.m in Sources */, 1F02801E11A7BF06006B06DE /* MeCardParser.m in Sources */, @@ -1189,12 +1313,82 @@ 1DFA092B13CE252300599044 /* ProductResultParser.mm in Sources */, 1DFA09A113CE5C0300599044 /* AddressBookAUResultParser.m in Sources */, 1D0CBDFA13D0DD5D003D0F8D /* BizcardResultParser.m in Sources */, + 1D4F11FC13D89EFD0032F754 /* VCardResultParser.m in Sources */, + 1D603E6513E20AF1006F4B51 /* ArrayAndStringCategories.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 1D603E4E13E1E010006F4B51 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2AAC07D0554694100DB518D /* ZXingWidget */; + targetProxy = 1D603E4D13E1E010006F4B51 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ + 1D60398E13DF7CAD006F4B51 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = "ZXingTests-Info.plist"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + SenTestingKit, + "-framework", + UIKit, + ); + PREBINDING = NO; + PRODUCT_NAME = ZXingTests; + SDKROOT = iphoneos; + WRAPPER_EXTENSION = octest; + }; + name = Debug; + }; + 1D60398F13DF7CAD006F4B51 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + ); + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + INFOPLIST_FILE = "ZXingTests-Info.plist"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + SenTestingKit, + "-framework", + UIKit, + ); + PREBINDING = NO; + PRODUCT_NAME = ZXingTests; + SDKROOT = iphoneos; + WRAPPER_EXTENSION = octest; + ZERO_LINK = NO; + }; + name = Release; + }; 1DEB921F08733DC00010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1294,6 +1488,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 1D60399113DF7CDC006F4B51 /* Build configuration list for PBXNativeTarget "ZXingTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D60398E13DF7CAD006F4B51 /* Debug */, + 1D60398F13DF7CAD006F4B51 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "ZXingWidget" */ = { isa = XCConfigurationList; buildConfigurations = (