Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

importing

  • Loading branch information...
commit 2d29c36d766f10dc508157f1e0e1479b8af10360 0 parents
@gabriel authored
Showing with 9,316 additions and 0 deletions.
  1. +1 −0  .gitattributes
  2. +4 −0 .gitignore
  3. +70 −0 Classes/EMKeychainItem.h
  4. +213 −0 Classes/EMKeychainItem.m
  5. +45 −0 Classes/EMKeychainProxy.h
  6. +171 −0 Classes/EMKeychainProxy.m
  7. +183 −0 Classes/External/GTM/GTMBase64.h
  8. +697 −0 Classes/External/GTM/GTMBase64.m
  9. +166 −0 Classes/External/GTM/GTMDefines.h
  10. +381 −0 Classes/External/GTM/GTMRegex.h
  11. +812 −0 Classes/External/GTM/GTMRegex.m
  12. +17 −0 Classes/External/NSInvocation+ForwardedConstruction.h
  13. +369 −0 Classes/External/NSInvocation+ForwardedConstruction.m
  14. +37 −0 Classes/External/NSString+RegEx.h
  15. +94 −0 Classes/External/NSString+RegEx.m
  16. +49 −0 Classes/GHKit.h
  17. +44 −0 Classes/GHNSDate+Parsing.h
  18. +174 −0 Classes/GHNSDate+Parsing.m
  19. +15 −0 Classes/GHNSFileManager+Utils.h
  20. +88 −0 Classes/GHNSFileManager+Utils.m
  21. +39 −0 Classes/GHNSNumber+Utils.h
  22. +92 −0 Classes/GHNSNumber+Utils.m
  23. +33 −0 Classes/GHNSString+HMAC.h
  24. +95 −0 Classes/GHNSString+HMAC.m
  25. +34 −0 Classes/GHNSString+TimeInterval.h
  26. +69 −0 Classes/GHNSString+TimeInterval.m
  27. +52 −0 Classes/GHNSString+Utils.h
  28. +200 −0 Classes/GHNSString+Utils.m
  29. +16 −0 Classes/GHNSString+Validation.h
  30. +22 −0 Classes/GHNSString+Validation.m
  31. +44 −0 Classes/GHNSURL+Utils.h
  32. +115 −0 Classes/GHNSURL+Utils.m
  33. +36 −0 Classes/GHNSXMLElement+Utils.h
  34. +57 −0 Classes/GHNSXMLElement+Utils.m
  35. +34 −0 Classes/GHNSXMLNode+Utils.h
  36. +53 −0 Classes/GHNSXMLNode+Utils.m
  37. +40 −0 Classes/GHViewAnimation.h
  38. +208 −0 Classes/GHViewAnimation.m
  39. +54 −0 Classes/hmac.c
  40. +10 −0 Classes/hmac.h
  41. +168 −0 Classes/sha1.c
  42. +24 −0 Classes/sha1.h
  43. BIN  English.lproj/InfoPlist.strings
  44. BIN  GHKit.xcodeproj/TemplateIcon.icns
  45. +1,578 −0 GHKit.xcodeproj/gabe.perspectivev3
  46. +1,683 −0 GHKit.xcodeproj/ghandford.perspectivev3
  47. +666 −0 GHKit.xcodeproj/project.pbxproj
  48. +7 −0 GHKit_Prefix.pch
  49. +26 −0 Info.plist
  50. +20 −0 Tests-Info.plist
  51. +16 −0 Tests/NSDate+ParsingTest.h
  52. +41 −0 Tests/NSDate+ParsingTest.m
  53. +16 −0 Tests/NSString+HMACTest.h
  54. +27 −0 Tests/NSString+HMACTest.m
  55. +15 −0 Tests/NSString+TimeIntervalTest.h
  56. +45 −0 Tests/NSString+TimeIntervalTest.m
  57. +16 −0 Tests/NSString+UtilsTest.h
  58. +35 −0 Tests/NSString+UtilsTest.m
1  .gitattributes
@@ -0,0 +1 @@
+*.pbxproj -crlf -diff -merge
4 .gitignore
@@ -0,0 +1,4 @@
+build
+.DS_Store
+*.pbxuser
+*.move1v3
70 Classes/EMKeychainItem.h
@@ -0,0 +1,70 @@
+/*Copyright (c) 2007 Extendmac, LLC. <support@extendmac.com>
+
+ 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 <Security/Security.h>
+
+@interface EMKeychainItem : NSObject {
+ NSString *myPassword;
+ NSString *myUsername;
+ NSString *myLabel;
+ SecKeychainItemRef coreKeychainItem;
+}
+- (NSString *)password;
+- (NSString *)username;
+- (NSString *)label;
+- (BOOL)setPassword:(NSString *)newPassword;
+- (BOOL)setUsername:(NSString *)newUsername;
+- (BOOL)setLabel:(NSString *)newLabel;
+@end
+
+@interface EMKeychainItem (Private)
+- (BOOL)modifyAttributeWithTag:(SecItemAttr)attributeTag toBeString:(NSString *)newStringValue;
+@end
+
+@interface EMGenericKeychainItem : EMKeychainItem
+{
+ NSString *myServiceName;
+}
++ (id)genericKeychainItem:(SecKeychainItemRef)item forServiceName:(NSString *)serviceName username:(NSString *)username password:(NSString *)password;
+- (NSString *)serviceName;
+- (BOOL)setServiceName:(NSString *)newServiceName;
+@end
+
+@interface EMInternetKeychainItem : EMKeychainItem
+{
+ NSString *myServer;
+ NSString *myPath;
+ int myPort;
+ SecProtocolType myProtocol;
+}
++ (id)internetKeychainItem:(SecKeychainItemRef)item forServer:(NSString *)server username:(NSString *)username password:(NSString *)password path:(NSString *)path port:(int)port protocol:(SecProtocolType)protocol;
+- (NSString *)server;
+- (NSString *)path;
+- (int)port;
+- (SecProtocolType)protocol;
+- (BOOL)setServer:(NSString *)newServer;
+- (BOOL)setPath:(NSString *)newPath;
+- (BOOL)setPort:(int)newPort;
+- (BOOL)setProtocol:(SecProtocolType)newProtocol;
+@end
213 Classes/EMKeychainItem.m
@@ -0,0 +1,213 @@
+/*Copyright (c) 2007 Extendmac, LLC. <support@extendmac.com>
+
+ 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 "EMKeychainItem.h"
+
+@implementation EMKeychainItem
+- (id)initWithCoreKeychainItem:(SecKeychainItemRef)item username:(NSString *)username password:(NSString *)password
+{
+ if ((self = [super init]))
+ {
+ coreKeychainItem = item;
+ [self setValue:username forKey:@"myUsername"];
+ [self setValue:password forKey:@"myPassword"];
+ return self;
+ }
+ return nil;
+}
+- (NSString *)password
+{
+ return myPassword;
+}
+- (NSString *)username
+{
+ return myUsername;
+}
+- (NSString *)label
+{
+ return myLabel;
+}
+
+- (BOOL)setPassword:(NSString *)newPasswordString
+{
+ if (!newPasswordString)
+ {
+ return NO;
+ }
+ [self willChangeValueForKey:@"password"];
+ [myPassword autorelease];
+ myPassword = [newPasswordString copy];
+ [self didChangeValueForKey:@"password"];
+
+ const char *newPassword = [newPasswordString UTF8String];
+ OSStatus returnStatus = SecKeychainItemModifyAttributesAndData(coreKeychainItem, NULL, strlen(newPassword), (void *)newPassword);
+ return (returnStatus == noErr);
+}
+- (BOOL)setUsername:(NSString *)newUsername
+{
+ [self willChangeValueForKey:@"username"];
+ [myUsername autorelease];
+ myUsername = [newUsername copy];
+ [self didChangeValueForKey:@"username"];
+
+ return [self modifyAttributeWithTag:kSecAccountItemAttr toBeString:newUsername];
+}
+- (BOOL)setLabel:(NSString *)newLabel
+{
+ [self willChangeValueForKey:@"label"];
+ [myLabel autorelease];
+ myLabel = [newLabel copy];
+ [self didChangeValueForKey:@"label"];
+
+ return [self modifyAttributeWithTag:kSecLabelItemAttr toBeString:newLabel];
+}
+@end
+
+@implementation EMKeychainItem (Private)
+- (BOOL)modifyAttributeWithTag:(SecItemAttr)attributeTag toBeString:(NSString *)newStringValue
+{
+ const char *newValue = [newStringValue UTF8String];
+ SecKeychainAttribute attributes[1];
+ attributes[0].tag = attributeTag;
+ attributes[0].length = strlen(newValue);
+ attributes[0].data = (void *)newValue;
+
+ SecKeychainAttributeList list;
+ list.count = 1;
+ list.attr = attributes;
+
+ OSStatus returnStatus = SecKeychainItemModifyAttributesAndData(coreKeychainItem, &list, 0, NULL);
+ return (returnStatus == noErr);
+}
+@end
+
+@implementation EMGenericKeychainItem
+- (id)initWithCoreKeychainItem:(SecKeychainItemRef)item serviceName:(NSString *)serviceName username:(NSString *)username password:(NSString *)password
+{
+ if ((self = [super initWithCoreKeychainItem:item username:username password:password]))
+ {
+ [self setValue:serviceName forKey:@"myServiceName"];
+ return self;
+ }
+ return nil;
+}
++ (id)genericKeychainItem:(SecKeychainItemRef)item forServiceName:(NSString *)serviceName username:(NSString *)username password:(NSString *)password
+{
+ return [[[EMGenericKeychainItem alloc] initWithCoreKeychainItem:item serviceName:serviceName username:username password:password] autorelease];
+}
+- (NSString *)serviceName
+{
+ return myServiceName;
+}
+
+- (BOOL)setServiceName:(NSString *)newServiceName
+{
+ [self willChangeValueForKey:@"serviceName"];
+ [myServiceName autorelease];
+ myServiceName = [newServiceName copy];
+ [self didChangeValueForKey:@"serviceName"];
+
+ return [self modifyAttributeWithTag:kSecServiceItemAttr toBeString:newServiceName];
+}
+@end
+
+@implementation EMInternetKeychainItem
+- (id)initWithCoreKeychainItem:(SecKeychainItemRef)item server:(NSString *)server username:(NSString *)username password:(NSString *)password path:(NSString *)path port:(int)port protocol:(SecProtocolType)protocol
+{
+ if ((self = [super initWithCoreKeychainItem:item username:username password:password]))
+ {
+ [self setValue:server forKey:@"myServer"];
+ [self setValue:path forKey:@"myPath"];
+ [self setValue:[NSNumber numberWithInt:port] forKey:@"myPort"];
+ [self setValue:[NSNumber numberWithInt:protocol] forKey:@"myProtocol"];
+ return self;
+ }
+ return nil;
+}
++ (id)internetKeychainItem:(SecKeychainItemRef)item forServer:(NSString *)server username:(NSString *)username password:(NSString *)password path:(NSString *)path port:(int)port protocol:(SecProtocolType)protocol
+{
+ return [[[EMInternetKeychainItem alloc] initWithCoreKeychainItem:item server:server username:username password:password path:path port:port protocol:protocol] autorelease];
+}
+- (NSString *)server
+{
+ return myServer;
+}
+- (NSString *)path
+{
+ return myPath;
+}
+- (int)port
+{
+ return myPort;
+}
+- (SecProtocolType)protocol
+{
+ return myProtocol;
+}
+
+- (BOOL)setServer:(NSString *)newServer
+{
+ [self willChangeValueForKey:@"server"];
+ [myServer autorelease];
+ myServer = [newServer copy];
+ [self didChangeValueForKey:@"server"];
+
+ return [self modifyAttributeWithTag:kSecServerItemAttr toBeString:newServer];
+}
+- (BOOL)setPath:(NSString *)newPath
+{
+ [self willChangeValueForKey:@"path"];
+ [myPath autorelease];
+ myPath = [newPath copy];
+ [self didChangeValueForKey:@"path"];
+
+ return [self modifyAttributeWithTag:kSecPathItemAttr toBeString:newPath];
+}
+- (BOOL)setPort:(int)newPort
+{
+ [self willChangeValueForKey:@"port"];
+ myPort = newPort;
+ [self didChangeValueForKey:@"port"];
+
+ return [self modifyAttributeWithTag:kSecPortItemAttr toBeString:[NSString stringWithFormat:@"%i", newPort]];
+}
+- (BOOL)setProtocol:(SecProtocolType)newProtocol
+{
+ [self willChangeValueForKey:@"protocol"];
+ myProtocol = newProtocol;
+ [self didChangeValueForKey:@"protocol"];
+
+ SecKeychainAttribute attributes[1];
+ attributes[0].tag = kSecProtocolItemAttr;
+ attributes[0].length = sizeof(newProtocol);
+ attributes[0].data = (void *)newProtocol;
+
+ SecKeychainAttributeList list;
+ list.count = 1;
+ list.attr = attributes;
+
+ OSStatus returnStatus = SecKeychainItemModifyAttributesAndData(coreKeychainItem, &list, 0, NULL);
+ return (returnStatus == noErr);
+}
+@end
45 Classes/EMKeychainProxy.h
@@ -0,0 +1,45 @@
+/*Copyright (c) 2007 Extendmac, LLC. <support@extendmac.com>
+
+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.
+*/
+
+//Last Changed on 2/07/08. Version 0.14
+
+#import <Security/Security.h>
+
+#import "EMKeychainItem.h"
+
+@interface EMKeychainProxy : NSObject {
+ BOOL _logErrors;
+}
++ (id)sharedProxy;
+- (void)lockKeychain;
+- (void)unlockKeychain;
+- (void)setLogsErrors:(BOOL)flag;
+
+- (EMGenericKeychainItem *)genericKeychainItemForService:(NSString *)serviceNameString withUsername:(NSString *)usernameString;
+- (EMInternetKeychainItem *)internetKeychainItemForServer:(NSString *)serverString withUsername:(NSString *)usernameString path:(NSString *)pathString port:(int)port protocol:(SecProtocolType)protocol;
+
+- (EMGenericKeychainItem *)addGenericKeychainItemForService:(NSString *)serviceNameString withUsername:(NSString *)usernameString password:(NSString *)passwordString;
+- (EMInternetKeychainItem *)addInternetKeychainItemForServer:(NSString *)serverString withUsername:(NSString *)usernameString password:(NSString *)passwordString path:(NSString *)pathString port:(int)port protocol:(SecProtocolType)protocol;
+
+@end
171 Classes/EMKeychainProxy.m
@@ -0,0 +1,171 @@
+/*Copyright (c) 2007 Extendmac, LLC. <support@extendmac.com>
+
+ 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 "EMKeychainProxy.h"
+
+@implementation EMKeychainProxy
+
+static EMKeychainProxy* sharedProxy;
+
++ (id)sharedProxy
+{
+ if (!sharedProxy)
+ {
+ sharedProxy = [[EMKeychainProxy alloc] init];
+ }
+ return sharedProxy;
+}
+- (void)lockKeychain
+{
+ SecKeychainLock(NULL);
+}
+- (void)unlockKeychain
+{
+ SecKeychainUnlock(NULL, 0, NULL, NO);
+}
+- (void)setLogsErrors:(BOOL)flag
+{
+ _logErrors = flag;
+}
+
+#pragma mark -
+#pragma mark Getting Keychain Items
+- (EMGenericKeychainItem *)genericKeychainItemForService:(NSString *)serviceNameString withUsername:(NSString *)usernameString
+{
+ if (!usernameString || [usernameString length] == 0)
+ {
+ return nil;
+ }
+
+ const char *serviceName = [serviceNameString UTF8String];
+ const char *username = [usernameString UTF8String];
+
+ UInt32 passwordLength = 0;
+ char *password = nil;
+
+ SecKeychainItemRef item = nil;
+ OSStatus returnStatus = SecKeychainFindGenericPassword(NULL, strlen(serviceName), serviceName, strlen(username), username, &passwordLength, (void **)&password, &item);
+ if (returnStatus != noErr || !item)
+ {
+ if (_logErrors)
+ {
+#ifndef TARGET_OS_IPHONE
+ NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus));
+#endif
+ }
+ return nil;
+ }
+ NSString *passwordString = [NSString stringWithCString:password length:passwordLength];
+
+ return [EMGenericKeychainItem genericKeychainItem:item forServiceName:serviceNameString username:usernameString password:passwordString];
+}
+- (EMInternetKeychainItem *)internetKeychainItemForServer:(NSString *)serverString withUsername:(NSString *)usernameString path:(NSString *)pathString port:(int)port protocol:(SecProtocolType)protocol
+{
+ if (!usernameString || [usernameString length] == 0 || !serverString || [serverString length] == 0)
+ {
+ return nil;
+ }
+ const char *server = [serverString UTF8String];
+ const char *username = [usernameString UTF8String];
+ const char *path = [pathString UTF8String];
+
+ if (!pathString || [pathString length] == 0)
+ {
+ path = "";
+ }
+
+ UInt32 passwordLength = 0;
+ char *password = nil;
+
+ SecKeychainItemRef item = nil;
+ OSStatus returnStatus = SecKeychainFindInternetPassword(NULL, strlen(server), server, 0, NULL, strlen(username), username, strlen(path), path, port, protocol, kSecAuthenticationTypeDefault, &passwordLength, (void **)&password, &item);
+
+ if (returnStatus != noErr || !item)
+ {
+ if (_logErrors)
+ {
+#ifndef TARGET_OS_IPHONE
+ NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus));
+#endif
+ }
+ return nil;
+ }
+ NSString *passwordString = [NSString stringWithCString:password length:passwordLength];
+
+ return [EMInternetKeychainItem internetKeychainItem:item forServer:serverString username:usernameString password:passwordString path:pathString port:port protocol:protocol];
+}
+
+#pragma mark -
+#pragma mark Saving Passwords
+- (EMGenericKeychainItem *)addGenericKeychainItemForService:(NSString *)serviceNameString withUsername:(NSString *)usernameString password:(NSString *)passwordString
+{
+ if (!usernameString || [usernameString length] == 0 || !serviceNameString || [serviceNameString length] == 0)
+ {
+ return nil;
+ }
+ const char *serviceName = [serviceNameString UTF8String];
+ const char *username = [usernameString UTF8String];
+ const char *password = [passwordString UTF8String];
+
+ SecKeychainItemRef item = nil;
+ OSStatus returnStatus = SecKeychainAddGenericPassword(NULL, strlen(serviceName), serviceName, strlen(username), username, strlen(password), (void *)password, &item);
+
+ if (returnStatus != noErr || !item)
+ {
+#ifndef TARGET_OS_IPHONE
+ NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus));
+#endif
+ return nil;
+ }
+ return [EMGenericKeychainItem genericKeychainItem:item forServiceName:serviceNameString username:usernameString password:passwordString];
+}
+- (EMInternetKeychainItem *)addInternetKeychainItemForServer:(NSString *)serverString withUsername:(NSString *)usernameString password:(NSString *)passwordString path:(NSString *)pathString port:(int)port protocol:(SecProtocolType)protocol
+{
+ if (!usernameString || [usernameString length] == 0 || !serverString || [serverString length] == 0 || !passwordString || [passwordString length] == 0)
+ {
+ return nil;
+ }
+ const char *server = [serverString UTF8String];
+ const char *username = [usernameString UTF8String];
+ const char *password = [passwordString UTF8String];
+ const char *path = [pathString UTF8String];
+
+ if (!pathString || [pathString length] == 0)
+ {
+ path = "";
+ }
+
+ SecKeychainItemRef item = nil;
+ OSStatus returnStatus = SecKeychainAddInternetPassword(NULL, strlen(server), server, 0, NULL, strlen(username), username, strlen(path), path, port, protocol, kSecAuthenticationTypeDefault, strlen(password), (void *)password, &item);
+
+ if (returnStatus != noErr || !item)
+ {
+#ifndef TARGET_OS_IPHONE
+ NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus));
+#endif
+ return nil;
+ }
+ return [EMInternetKeychainItem internetKeychainItem:item forServer:serverString username:usernameString password:passwordString path:pathString port:port protocol:protocol];
+}
+@end
183 Classes/External/GTM/GTMBase64.h
@@ -0,0 +1,183 @@
+//
+// GTMBase64.h
+//
+// Copyright 2006-2008 Google Inc.
+//
+// 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 <Foundation/Foundation.h>
+#import "GTMDefines.h"
+
+// GTMBase64
+//
+/// Helper for handling Base64 and WebSafeBase64 encodings
+//
+/// The webSafe methods use different character set and also the results aren't
+/// always padded to a multiple of 4 characters. This is done so the resulting
+/// data can be used in urls and url query arguments without needing any
+/// encoding. You must use the webSafe* methods together, the data does not
+/// interop with the RFC methods.
+//
+@interface GTMBase64 : NSObject
+
+//
+// Standard Base64 (RFC) handling
+//
+
+// encodeData:
+//
+/// Base64 encodes contents of the NSData object.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)encodeData:(NSData *)data;
+
+// decodeData:
+//
+/// Base64 decodes contents of the NSData object.
+//
+/// Returns:
+/// A new autoreleased NSData with the decoded payload. nil for any error.
+//
++(NSData *)decodeData:(NSData *)data;
+
+// encodeBytes:length:
+//
+/// Base64 encodes the data pointed at by |bytes|.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length;
+
+// decodeBytes:length:
+//
+/// Base64 decodes the data pointed at by |bytes|.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length;
+
+// stringByEncodingData:
+//
+/// Base64 encodes contents of the NSData object.
+//
+/// Returns:
+/// A new autoreleased NSString with the encoded payload. nil for any error.
+//
++(NSString *)stringByEncodingData:(NSData *)data;
+
+// stringByEncodingBytes:length:
+//
+/// Base64 encodes the data pointed at by |bytes|.
+//
+/// Returns:
+/// A new autoreleased NSString with the encoded payload. nil for any error.
+//
++(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length;
+
+// decodeString:
+//
+/// Base64 decodes contents of the NSString.
+//
+/// Returns:
+/// A new autoreleased NSData with the decoded payload. nil for any error.
+//
++(NSData *)decodeString:(NSString *)string;
+
+//
+// Modified Base64 encoding so the results can go onto urls.
+//
+// The changes are in the characters generated and also allows the result to
+// not be padded to a multiple of 4.
+// Must use the matching call to encode/decode, won't interop with the
+// RFC versions.
+//
+
+// webSafeEncodeData:padded:
+//
+/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
+/// then padding characters are added so the result length is a multiple of 4.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)webSafeEncodeData:(NSData *)data
+ padded:(BOOL)padded;
+
+// webSafeDecodeData:
+//
+/// WebSafe Base64 decodes contents of the NSData object.
+//
+/// Returns:
+/// A new autoreleased NSData with the decoded payload. nil for any error.
+//
++(NSData *)webSafeDecodeData:(NSData *)data;
+
+// webSafeEncodeBytes:length:padded:
+//
+/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
+/// then padding characters are added so the result length is a multiple of 4.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)webSafeEncodeBytes:(const void *)bytes
+ length:(NSUInteger)length
+ padded:(BOOL)padded;
+
+// webSafeDecodeBytes:length:
+//
+/// WebSafe Base64 decodes the data pointed at by |bytes|.
+//
+/// Returns:
+/// A new autoreleased NSData with the encoded payload. nil for any error.
+//
++(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length;
+
+// stringByWebSafeEncodingData:padded:
+//
+/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
+/// then padding characters are added so the result length is a multiple of 4.
+//
+/// Returns:
+/// A new autoreleased NSString with the encoded payload. nil for any error.
+//
++(NSString *)stringByWebSafeEncodingData:(NSData *)data
+ padded:(BOOL)padded;
+
+// stringByWebSafeEncodingBytes:length:padded:
+//
+/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
+/// then padding characters are added so the result length is a multiple of 4.
+//
+/// Returns:
+/// A new autoreleased NSString with the encoded payload. nil for any error.
+//
++(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ padded:(BOOL)padded;
+
+// webSafeDecodeString:
+//
+/// WebSafe Base64 decodes contents of the NSString.
+//
+/// Returns:
+/// A new autoreleased NSData with the decoded payload. nil for any error.
+//
++(NSData *)webSafeDecodeString:(NSString *)string;
+
+@end
697 Classes/External/GTM/GTMBase64.m
@@ -0,0 +1,697 @@
+//
+// GTMBase64.m
+//
+// Copyright 2006-2008 Google Inc.
+//
+// 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 "GTMBase64.h"
+#import "GTMDefines.h"
+
+static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+static const char kBase64PaddingChar = '=';
+static const char kBase64InvalidChar = 99;
+
+static const char kBase64DecodeChars[] = {
+ // This array was generated by the following code:
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = 99;
+ // else
+ // idx = pos - Base64;
+ // if (idx == 99)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 62/*+*/, 99, 99, 99, 63/*/ */,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
+ 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99,
+ 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+static const char kWebSafeBase64DecodeChars[] = {
+ // This array was generated by the following code:
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = 99;
+ // else
+ // idx = pos - Base64;
+ // if (idx == 99)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 62/*-*/, 99, 99,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
+ 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 63/*_*/,
+ 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+
+// Tests a charact to see if it's a whitespace character.
+//
+// Returns:
+// YES if the character is a whitespace character.
+// NO if the character is not a whitespace character.
+//
+FOUNDATION_STATIC_INLINE BOOL IsSpace(unsigned char c) {
+ // we use our own mapping here because we don't want anything w/ locale
+ // support.
+ static BOOL kSpaces[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0-9
+ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 10-19
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-29
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 30-39
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-49
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-59
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-69
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-79
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-89
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-99
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-109
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110-119
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120-129
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130-139
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140-149
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150-159
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-169
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170-179
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180-189
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190-199
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200-209
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210-219
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220-229
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 230-239
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-249
+ 0, 0, 0, 0, 0, 1, // 250-255
+ };
+ return kSpaces[c];
+}
+
+// Calculate how long the data will be once it's base64 encoded.
+//
+// Returns:
+// The guessed encoded length for a source length
+//
+FOUNDATION_STATIC_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen,
+ BOOL padded) {
+ NSUInteger intermediate_result = 8 * srcLen + 5;
+ NSUInteger len = intermediate_result / 6;
+ if (padded) {
+ len = ((len + 3) / 4) * 4;
+ }
+ return len;
+}
+
+// Tries to calculate how long the data will be once it's base64 decoded.
+// Unlinke the above, this is always an upperbound, since the source data
+// could have spaces and might end with the padding characters on them.
+//
+// Returns:
+// The guessed decoded length for a source length
+//
+FOUNDATION_STATIC_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) {
+ return (srcLen + 3) / 4 * 3;
+}
+
+
+@interface GTMBase64 (PrivateMethods)
+
++(NSData *)baseEncode:(const void *)bytes
+ length:(NSUInteger)length
+ charset:(const char *)charset
+ padded:(BOOL)padded;
+
++(NSData *)baseDecode:(const void *)bytes
+ length:(NSUInteger)length
+ charset:(const char*)charset
+ requirePadding:(BOOL)requirePadding;
+
++(NSUInteger)baseEncode:(const char *)srcBytes
+ srcLen:(NSUInteger)srcLen
+ destBytes:(char *)destBytes
+ destLen:(NSUInteger)destLen
+ charset:(const char *)charset
+ padded:(BOOL)padded;
+
++(NSUInteger)baseDecode:(const char *)srcBytes
+ srcLen:(NSUInteger)srcLen
+ destBytes:(char *)destBytes
+ destLen:(NSUInteger)destLen
+ charset:(const char *)charset
+ requirePadding:(BOOL)requirePadding;
+
+@end
+
+
+@implementation GTMBase64
+
+//
+// Standard Base64 (RFC) handling
+//
+
++(NSData *)encodeData:(NSData *)data {
+ return [self baseEncode:[data bytes]
+ length:[data length]
+ charset:kBase64EncodeChars
+ padded:YES];
+}
+
++(NSData *)decodeData:(NSData *)data {
+ return [self baseDecode:[data bytes]
+ length:[data length]
+ charset:kBase64DecodeChars
+ requirePadding:YES];
+}
+
++(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
+ return [self baseEncode:bytes
+ length:length
+ charset:kBase64EncodeChars
+ padded:YES];
+}
+
++(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
+ return [self baseDecode:bytes
+ length:length
+ charset:kBase64DecodeChars
+ requirePadding:YES];
+}
+
++(NSString *)stringByEncodingData:(NSData *)data {
+ NSString *result = nil;
+ NSData *converted = [self baseEncode:[data bytes]
+ length:[data length]
+ charset:kBase64EncodeChars
+ padded:YES];
+ if (converted) {
+ result = [[[NSString alloc] initWithData:converted
+ encoding:NSASCIIStringEncoding] autorelease];
+ }
+ return result;
+}
+
++(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
+ NSString *result = nil;
+ NSData *converted = [self baseEncode:bytes
+ length:length
+ charset:kBase64EncodeChars
+ padded:YES];
+ if (converted) {
+ result = [[[NSString alloc] initWithData:converted
+ encoding:NSASCIIStringEncoding] autorelease];
+ }
+ return result;
+}
+
++(NSData *)decodeString:(NSString *)string {
+ NSData *result = nil;
+ NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
+ if (data) {
+ result = [self baseDecode:[data bytes]
+ length:[data length]
+ charset:kBase64DecodeChars
+ requirePadding:YES];
+ }
+ return result;
+}
+
+//
+// Modified Base64 encoding so the results can go onto urls.
+//
+// The changes are in the characters generated and also the result isn't
+// padded to a multiple of 4.
+// Must use the matching call to encode/decode, won't interop with the
+// RFC versions.
+//
+
++(NSData *)webSafeEncodeData:(NSData *)data
+ padded:(BOOL)padded {
+ return [self baseEncode:[data bytes]
+ length:[data length]
+ charset:kWebSafeBase64EncodeChars
+ padded:padded];
+}
+
++(NSData *)webSafeDecodeData:(NSData *)data {
+ return [self baseDecode:[data bytes]
+ length:[data length]
+ charset:kWebSafeBase64DecodeChars
+ requirePadding:NO];
+}
+
++(NSData *)webSafeEncodeBytes:(const void *)bytes
+ length:(NSUInteger)length
+ padded:(BOOL)padded {
+ return [self baseEncode:bytes
+ length:length
+ charset:kWebSafeBase64EncodeChars
+ padded:padded];
+}
+
++(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
+ return [self baseDecode:bytes
+ length:length
+ charset:kWebSafeBase64DecodeChars
+ requirePadding:NO];
+}
+
++(NSString *)stringByWebSafeEncodingData:(NSData *)data
+ padded:(BOOL)padded {
+ NSString *result = nil;
+ NSData *converted = [self baseEncode:[data bytes]
+ length:[data length]
+ charset:kWebSafeBase64EncodeChars
+ padded:padded];
+ if (converted) {
+ result = [[[NSString alloc] initWithData:converted
+ encoding:NSASCIIStringEncoding] autorelease];
+ }
+ return result;
+}
+
++(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ padded:(BOOL)padded {
+ NSString *result = nil;
+ NSData *converted = [self baseEncode:bytes
+ length:length
+ charset:kWebSafeBase64EncodeChars
+ padded:padded];
+ if (converted) {
+ result = [[[NSString alloc] initWithData:converted
+ encoding:NSASCIIStringEncoding] autorelease];
+ }
+ return result;
+}
+
++(NSData *)webSafeDecodeString:(NSString *)string {
+ NSData *result = nil;
+ NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
+ if (data) {
+ result = [self baseDecode:[data bytes]
+ length:[data length]
+ charset:kWebSafeBase64DecodeChars
+ requirePadding:NO];
+ }
+ return result;
+}
+
+@end
+
+@implementation GTMBase64 (PrivateMethods)
+
+//
+// baseEncode:length:charset:padded:
+//
+// Does the common lifting of creating the dest NSData. it creates & sizes the
+// data for the results. |charset| is the characters to use for the encoding
+// of the data. |padding| controls if the encoded data should be padded to a
+// multiple of 4.
+//
+// Returns:
+// an autorelease NSData with the encoded data, nil if any error.
+//
++(NSData *)baseEncode:(const void *)bytes
+ length:(NSUInteger)length
+ charset:(const char *)charset
+ padded:(BOOL)padded {
+ // how big could it be?
+ NSUInteger maxLength = CalcEncodedLength(length, padded);
+ // make space
+ NSMutableData *result = [NSMutableData data];
+ [result setLength:maxLength];
+ // do it
+ NSUInteger finalLength = [self baseEncode:bytes
+ srcLen:length
+ destBytes:[result mutableBytes]
+ destLen:[result length]
+ charset:charset
+ padded:padded];
+ if (finalLength) {
+ _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
+ } else {
+ // shouldn't happen, this means we ran out of space
+ result = nil;
+ }
+ return result;
+}
+
+//
+// baseDecode:length:charset:requirePadding:
+//
+// Does the common lifting of creating the dest NSData. it creates & sizes the
+// data for the results. |charset| is the characters to use for the decoding
+// of the data.
+//
+// Returns:
+// an autorelease NSData with the decoded data, nil if any error.
+//
+//
++(NSData *)baseDecode:(const void *)bytes
+ length:(NSUInteger)length
+ charset:(const char *)charset
+ requirePadding:(BOOL)requirePadding {
+ // could try to calculate what it will end up as
+ NSUInteger maxLength = GuessDecodedLength(length);
+ // make space
+ NSMutableData *result = [NSMutableData data];
+ [result setLength:maxLength];
+ // do it
+ NSUInteger finalLength = [self baseDecode:bytes
+ srcLen:length
+ destBytes:[result mutableBytes]
+ destLen:[result length]
+ charset:charset
+ requirePadding:requirePadding];
+ if (finalLength) {
+ if (finalLength != maxLength) {
+ // resize down to how big it was
+ [result setLength:finalLength];
+ }
+ } else {
+ // either an error in the args, or we ran out of space
+ result = nil;
+ }
+ return result;
+}
+
+//
+// baseEncode:srcLen:destBytes:destLen:charset:padded:
+//
+// Encodes the buffer into the larger. returns the length of the encoded
+// data, or zero for an error.
+// |charset| is the characters to use for the encoding
+// |padded| tells if the result should be padded to a multiple of 4.
+//
+// Returns:
+// the length of the encoded data. zero if any error.
+//
++(NSUInteger)baseEncode:(const char *)srcBytes
+ srcLen:(NSUInteger)srcLen
+ destBytes:(char *)destBytes
+ destLen:(NSUInteger)destLen
+ charset:(const char *)charset
+ padded:(BOOL)padded {
+ if (!srcLen || !destLen || !srcBytes || !destBytes) {
+ return 0;
+ }
+
+ char *curDest = destBytes;
+ const unsigned char *curSrc = (const unsigned char *)(srcBytes);
+
+ // Three bytes of data encodes to four characters of cyphertext.
+ // So we can pump through three-byte chunks atomically.
+ while (srcLen > 2) {
+ // space?
+ _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
+ curDest[0] = charset[curSrc[0] >> 2];
+ curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
+ curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
+ curDest[3] = charset[curSrc[2] & 0x3f];
+
+ curDest += 4;
+ curSrc += 3;
+ srcLen -= 3;
+ destLen -= 4;
+ }
+
+ // now deal with the tail (<=2 bytes)
+ switch (srcLen) {
+ case 0:
+ // Nothing left; nothing more to do.
+ break;
+ case 1:
+ // One byte left: this encodes to two characters, and (optionally)
+ // two pad characters to round out the four-character cypherblock.
+ _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
+ curDest[0] = charset[curSrc[0] >> 2];
+ curDest[1] = charset[(curSrc[0] & 0x03) << 4];
+ curDest += 2;
+ destLen -= 2;
+ if (padded) {
+ _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
+ curDest[0] = kBase64PaddingChar;
+ curDest[1] = kBase64PaddingChar;
+ curDest += 2;
+ destLen -= 2;
+ }
+ break;
+ case 2:
+ // Two bytes left: this encodes to three characters, and (optionally)
+ // one pad character to round out the four-character cypherblock.
+ _GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong");
+ curDest[0] = charset[curSrc[0] >> 2];
+ curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
+ curDest[2] = charset[(curSrc[1] & 0x0f) << 2];
+ curDest += 3;
+ destLen -= 3;
+ if (padded) {
+ _GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong");
+ curDest[0] = kBase64PaddingChar;
+ curDest += 1;
+ destLen -= 1;
+ }
+ break;
+ }
+ // return the length
+ return (curDest - destBytes);
+}
+
+//
+// baseDecode:srcLen:destBytes:destLen:charset:requirePadding:
+//
+// Decodes the buffer into the larger. returns the length of the decoded
+// data, or zero for an error.
+// |charset| is the character decoding buffer to use
+//
+// Returns:
+// the length of the encoded data. zero if any error.
+//
++(NSUInteger)baseDecode:(const char *)srcBytes
+ srcLen:(NSUInteger)srcLen
+ destBytes:(char *)destBytes
+ destLen:(NSUInteger)destLen
+ charset:(const char *)charset
+ requirePadding:(BOOL)requirePadding {
+ if (!srcLen || !destLen || !srcBytes || !destBytes) {
+ return 0;
+ }
+
+ int decode;
+ NSUInteger destIndex = 0;
+ int state = 0;
+ char ch = 0;
+ while (srcLen-- && (ch = *srcBytes++) != 0) {
+ if (IsSpace(ch)) // Skip whitespace
+ continue;
+
+ if (ch == kBase64PaddingChar)
+ break;
+
+ decode = charset[(unsigned int)ch];
+ if (decode == kBase64InvalidChar)
+ return 0;
+
+ // Four cyphertext characters decode to three bytes.
+ // Therefore we can be in one of four states.
+ switch (state) {
+ case 0:
+ // We're at the beginning of a four-character cyphertext block.
+ // This sets the high six bits of the first byte of the
+ // plaintext block.
+ _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
+ destBytes[destIndex] = decode << 2;
+ state = 1;
+ break;
+ case 1:
+ // We're one character into a four-character cyphertext block.
+ // This sets the low two bits of the first plaintext byte,
+ // and the high four bits of the second plaintext byte.
+ _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
+ destBytes[destIndex] |= decode >> 4;
+ destBytes[destIndex+1] = (decode & 0x0f) << 4;
+ destIndex++;
+ state = 2;
+ break;
+ case 2:
+ // We're two characters into a four-character cyphertext block.
+ // This sets the low four bits of the second plaintext
+ // byte, and the high two bits of the third plaintext byte.
+ // However, if this is the end of data, and those two
+ // bits are zero, it could be that those two bits are
+ // leftovers from the encoding of data that had a length
+ // of two mod three.
+ _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
+ destBytes[destIndex] |= decode >> 2;
+ destBytes[destIndex+1] = (decode & 0x03) << 6;
+ destIndex++;
+ state = 3;
+ break;
+ case 3:
+ // We're at the last character of a four-character cyphertext block.
+ // This sets the low six bits of the third plaintext byte.
+ _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
+ destBytes[destIndex] |= decode;
+ destIndex++;
+ state = 0;
+ break;
+ }
+ }
+
+ // We are done decoding Base-64 chars. Let's see if we ended
+ // on a byte boundary, and/or with erroneous trailing characters.
+ if (ch == kBase64PaddingChar) { // We got a pad char
+ if ((state == 0) || (state == 1)) {
+ return 0; // Invalid '=' in first or second position
+ }
+ if (srcLen == 0) {
+ if (state == 2) { // We run out of input but we still need another '='
+ return 0;
+ }
+ // Otherwise, we are in state 3 and only need this '='
+ } else {
+ if (state == 2) { // need another '='
+ while ((ch = *srcBytes++) && (srcLen-- > 0)) {
+ if (!IsSpace(ch))
+ break;
+ }
+ if (ch != kBase64PaddingChar) {
+ return 0;
+ }
+ }
+ // state = 1 or 2, check if all remain padding is space
+ while ((ch = *srcBytes++) && (srcLen-- > 0)) {
+ if (!IsSpace(ch)) {
+ return 0;
+ }
+ }
+ }
+ } else {
+ // We ended by seeing the end of the string.
+
+ if (requirePadding) {
+ // If we require padding, then anything but state 0 is an error.
+ if (state != 0) {
+ return 0;
+ }
+ } else {
+ // Make sure we have no partial bytes lying around. Note that we do not
+ // require trailing '=', so states 2 and 3 are okay too.
+ if (state == 1) {
+ return 0;
+ }
+ }
+ }
+
+ // If then next piece of output was valid and got written to it means we got a
+ // very carefully crafted input that appeared valid but contains some trailing
+ // bits past the real length, so just toss the thing.
+ if ((destIndex < destLen) &&
+ (destBytes[destIndex] != 0)) {
+ return 0;
+ }
+
+ return destIndex;
+}
+
+@end
166 Classes/External/GTM/GTMDefines.h
@@ -0,0 +1,166 @@
+//
+// GTMDefines.h
+//
+// Copyright 2008 Google Inc.
+//
+// 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.
+//
+
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// CPP symbols that can be overridden in a prefix to control how the toolbox
+// is compiled.
+// ----------------------------------------------------------------------------
+
+
+// GTMHTTPFetcher will support logging by default but only hook its input
+// stream support for logging when requested. You can control the inclusion of
+// the code by providing your own definitions for these w/in a prefix header.
+//
+#ifndef GTM_HTTPFETCHER_ENABLE_LOGGING
+# define GTM_HTTPFETCHER_ENABLE_LOGGING 1
+#endif // GTM_HTTPFETCHER_ENABLE_LOGGING
+#ifndef GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING
+# define GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 0
+#endif // GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING
+
+
+// _GTMDevLog & _GTMDevAssert
+//
+// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
+// developer level errors. This implementation simply macros to NSLog/NSAssert.
+// It is not intended to be a general logging/reporting system.
+//
+// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
+// for a little more background on the usage of these macros.
+//
+// _GTMDevLog log some error/problem in debug builds
+// _GTMDevAssert assert if conditon isn't met w/in a method/function
+// in all builds.
+//
+// To replace this system, just provide different macro definitions in your
+// prefix header. Remember, any implementation you provide *must* be thread
+// safe since this could be called by anything in what ever situtation it has
+// been placed in.
+//
+
+// We only define the simple macros if nothing else has defined this.
+#ifndef _GTMDevLog
+
+#ifdef DEBUG
+ #define _GTMDevLog(...) NSLog(__VA_ARGS__)
+#else
+ #define _GTMDevLog(...) do { } while (0)
+#endif
+
+#endif // _GTMDevLog
+
+// Declared here so that it can easily be used for logging tracking if
+// necessary. See GTMUnitTestDevLog.h for details.
+@class NSString;
+extern void _GTMUnittestDevLog(NSString *format, ...);
+
+#ifndef _GTMDevAssert
+// we directly invoke the NSAssert handler so we can pass on the varargs
+// (NSAssert doesn't have a macro we can use that takes varargs)
+#if !defined(NS_BLOCK_ASSERTIONS)
+#define _GTMDevAssert(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ [[NSAssertionHandler currentHandler] \
+ handleFailureInFunction:[NSString stringWithCString:__PRETTY_FUNCTION__] \
+ file:[NSString stringWithCString:__FILE__] \
+ lineNumber:__LINE__ \
+ description:__VA_ARGS__]; \
+ } \
+ } while(0)
+#else // !defined(NS_BLOCK_ASSERTIONS)
+#define _GTMDevAssert(condition, ...) do { } while (0)
+#endif // !defined(NS_BLOCK_ASSERTIONS)
+
+#endif // _GTMDevAssert
+
+// _GTMCompileAssert
+// _GTMCompileAssert is an assert that is meant to fire at compile time if you
+// want to check things at compile instead of runtime. For example if you
+// want to check that a wchar is 4 bytes instead of 2 you would use
+// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)
+// Note that the second "arg" is not in quotes, and must be a valid processor
+// symbol in it's own right (no spaces, punctuation etc).
+
+// Wrapping this in an #ifndef allows external groups to define their own
+// compile time assert scheme.
+#ifndef _GTMCompileAssert
+// We got this technique from here:
+// http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html
+
+#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
+#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
+#define _GTMCompileAssert(test, msg) \
+ typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
+#endif // _GTMCompileAssert
+
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// CPP symbols defined based on the project settings so the GTM code has
+// simple things to test against w/o scattering the knowledge of project
+// setting through all the code.
+// ----------------------------------------------------------------------------
+
+// Provide a single constant CPP symbol that all of GTM uses for ifdefing
+// iPhone code.
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE // iPhone SDK
+ // For iPhone specific stuff
+ #define GTM_IPHONE_SDK 1
+#else
+ // For MacOS specific stuff
+ #define GTM_MACOS_SDK 1
+#endif
+
+// To simplify support for 64bit (and Leopard in general), we provide the type
+// defines for non Leopard SDKs
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
+ // NSInteger/NSUInteger and Max/Mins
+ #ifndef NSINTEGER_DEFINED
+ #if __LP64__ || NS_BUILD_32_LIKE_64
+ typedef long NSInteger;
+ typedef unsigned long NSUInteger;
+ #else
+ typedef int NSInteger;
+ typedef unsigned int NSUInteger;
+ #endif
+ #define NSIntegerMax LONG_MAX
+ #define NSIntegerMin LONG_MIN
+ #define NSUIntegerMax ULONG_MAX
+ #define NSINTEGER_DEFINED 1
+ #endif // NSINTEGER_DEFINED
+ // CGFloat
+ #ifndef CGFLOAT_DEFINED
+ #if defined(__LP64__) && __LP64__
+ // This really is an untested path (64bit on Tiger?)
+ typedef double CGFloat;
+ #define CGFLOAT_MIN DBL_MIN
+ #define CGFLOAT_MAX DBL_MAX
+ #define CGFLOAT_IS_DOUBLE 1
+ #else /* !defined(__LP64__) || !__LP64__ */
+ typedef float CGFloat;
+ #define CGFLOAT_MIN FLT_MIN
+ #define CGFLOAT_MAX FLT_MAX
+ #define CGFLOAT_IS_DOUBLE 0
+ #endif /* !defined(__LP64__) || !__LP64__ */
+ #define CGFLOAT_DEFINED 1
+ #endif // CGFLOAT_DEFINED
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
381 Classes/External/GTM/GTMRegex.h
@@ -0,0 +1,381 @@
+//
+// GTMRegex.h
+//
+// Copyright 2007-2008 Google Inc.
+//
+// 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 <Foundation/Foundation.h>
+#import <regex.h>
+#import "GTMDefines.h"
+
+/// Options for controlling the behavior of the matches
+enum {
+
+ kGTMRegexOptionIgnoreCase = 0x01,
+ // Ignore case in matching, ie: 'a' matches 'a' or 'A'
+
+ kGTMRegexOptionSupressNewlineSupport = 0x02,
+ // By default (without this option), regular expressions are implicitly
+ // processed on a line by line basis, where "lines" are delimited by newline
+ // characters. In this mode '.' (dot) does NOT match newline characters, and
+ // '^' and '$' match at the beginning and end of the string as well as
+ // around newline characters. This behavior matches the default behavior for
+ // regular expressions in other languages including Perl and Python. For
+ // example,
+ // foo.*bar
+ // would match
+ // fooAAAbar
+ // but would NOT match
+ // fooAAA\nbar
+ // With the kGTMRegexOptionSupressNewlineSupport option, newlines are treated
+ // just like any other character which means that '.' will match them. In
+ // this mode, ^ and $ only match the beginning and end of the input string
+ // and do NOT match around the newline characters. For example,
+ // foo.*bar
+ // would match
+ // fooAAAbar
+ // and would also match
+ // fooAAA\nbar
+
+};
+typedef NSUInteger GTMRegexOptions;
+
+/// Global contants needed for errors from consuming patterns
+
+#undef _EXTERN
+#undef _INITIALIZE_AS
+#ifdef GTMREGEX_DEFINE_GLOBALS
+#define _EXTERN
+#define _INITIALIZE_AS(x) =x
+#else
+#define _EXTERN extern
+#define _INITIALIZE_AS(x)
+#endif
+
+_EXTERN NSString* kGTMRegexErrorDomain _INITIALIZE_AS(@"com.google.mactoolbox.RegexDomain");
+
+enum {
+ kGTMRegexPatternParseFailedError = -100
+};
+
+// Keys for the userInfo from a kGTMRegexErrorDomain/kGTMRegexPatternParseFailedError error
+_EXTERN NSString* kGTMRegexPatternErrorPattern _INITIALIZE_AS(@"pattern");
+_EXTERN NSString* kGTMRegexPatternErrorErrorString _INITIALIZE_AS(@"patternError");
+
+/// Class for doing Extended Regex operations w/ libregex (see re_format(7)).
+//
+// NOTE: the docs for recomp/regexec make *no* claims about i18n. All work
+// within this class is done w/ UTF-8 so Unicode should move through it safely,
+// however, the character classes described in re_format(7) might not really
+// be unicode "savvy", so use them and this class w/ that in mind.
+//
+// Example usage:
+//
+// NSArray *inputArrayOfStrings = ...
+// NSEnumerator *enumerator = [inputArrayOfString objectEnumerator];
+// NSString *curStr = nil;
+// NSArray *matches = [NSMutableArray array];
+//
+// GTMRegex *regex = [GTMRegex regexWithPattern:@"foo.*bar"];
+// while ((curStr = [enumerator nextObject]) != nil) {
+// if ([regex matchesString:curStr])
+// [matches addObject:curStr];
+// }
+// ....
+//
+// -------------
+//
+// If you need to include something dynamic in a pattern:
+//
+// NSString *pattern =
+// [NSString stringWithFormat:@"^foo:%@bar",
+// [GTMRegex escapedPatternForString:inputStr]];
+// GTMRegex *regex = [GTMRegex regexWithPattern:pattern];
+// ....
+//
+// -------------
+//
+// GTMRegex *regex = [GTMRegex regexWithPattern:@"(foo+)(bar)"];
+// NSString *highlighted =
+// [regex stringByReplacingMatchesInString:inputString
+// withReplacement:@"<i>\\1</i><b>\\2</b>"];
+// ....
+//
+@interface GTMRegex : NSObject {
+ @private
+ NSString *pattern_;
+ GTMRegexOptions options_;
+ regex_t regexData_;
+}
+
+/// Create a new, autoreleased object w/ the given regex pattern with the default options
++ (id)regexWithPattern:(NSString *)pattern;
+
+/// Create a new, autoreleased object w/ the given regex pattern and specify the matching options
++ (id)regexWithPattern:(NSString *)pattern options:(GTMRegexOptions)options;
+
+/// Create a new, autoreleased object w/ the given regex pattern, specify the matching options and receive any error consuming the pattern.
++ (id)regexWithPattern:(NSString *)pattern
+ options:(GTMRegexOptions)options
+ withError:(NSError **)outErrorOrNULL;
+
+/// Returns a new, autoreleased copy of |str| w/ any pattern chars in it escaped so they have no meaning when used w/in a pattern.
++ (NSString *)escapedPatternForString:(NSString *)str;
+
+/// Initialize a new object w/ the given regex pattern with the default options
+- (id)initWithPattern:(NSString *)pattern;
+
+/// Initialize a new object w/ the given regex pattern and specify the matching options
+- (id)initWithPattern:(NSString *)pattern options:(GTMRegexOptions)options;
+
+/// Initialize a new object w/ the given regex pattern, specify the matching options, and receive any error consuming the pattern.
+- (id)initWithPattern:(NSString *)pattern
+ options:(GTMRegexOptions)options
+ withError:(NSError **)outErrorOrNULL;
+
+/// Returns the number of sub patterns in the pattern
+//
+// Sub Patterns are basically the number of parenthesis blocks w/in the pattern.
+// ie: The pattern "foo((bar)|(baz))" has 3 sub patterns.
+//
+- (NSUInteger)subPatternCount;
+
+/// Returns YES if the whole string |str| matches the pattern.
+- (BOOL)matchesString:(NSString *)str;
+
+/// Returns a new, autoreleased array of string that contain the subpattern matches for the string.
+//
+// If the whole string does not match the pattern, nil is returned.
+//
+// The api follows the conventions of most regex engines, and index 0 (zero) is
+// the full match, then the subpatterns are index 1, 2, ... going left to right.
+// If the pattern has optional subpatterns, then anything that didn't match
+// will have NSNull at that index.
+// ie: The pattern "(fo(o+))((bar)|(baz))" has five subpatterns, and when
+// applied to the string "foooooobaz" you'd get an array of:
+// 0: "foooooobaz"
+// 1: "foooooo"
+// 2: "ooooo"
+// 3: "baz"
+// 4: NSNull
+// 5: "baz"
+//
+- (NSArray *)subPatternsOfString:(NSString *)str;
+
+/// Returns the first match for this pattern in |str|.
+- (NSString *)firstSubStringMatchedInString:(NSString *)str;
+
+/// Returns YES if this pattern some substring of |str|.
+- (BOOL)matchesSubStringInString:(NSString *)str;
+
+/// Returns a new, autoreleased enumerator that will walk segments (GTMRegexStringSegment) of |str| based on the pattern.
+//
+// This will split the string into "segments" using the given pattern. You get
+// both the matches and parts that are inbetween matches. ie-the entire string
+// will eventually be returned.
+//
+// See GTMRegexStringSegment for more infomation and examples.
+//
+- (NSEnumerator *)segmentEnumeratorForString:(NSString *)str;
+
+/// Returns a new, autoreleased enumerator that will walk only the matching segments (GTMRegexStringSegment) of |str| based on the pattern.
+//
+// This extracts the "segments" of the string that used the pattern. So it can
+// be used to collect all of the matching substrings from within a string.
+//
+// See GTMRegexStringSegment for more infomation and examples.
+//
+- (NSEnumerator *)matchSegmentEnumeratorForString:(NSString *)str;
+
+/// Returns a new, autoreleased string with all matches of the pattern in |str| replaced with |replacementPattern|.
+//
+// Replacement uses the SED substitution like syntax w/in |replacementPattern|
+// to allow the use of matches in the replacment. The replacement pattern can
+// make use of any number of match references by using a backslash followed by
+// the match subexpression number (ie-"\2", "\0", ...), see subPatternsOfString:
+// for details on the subexpression indexing.
+//
+// REMINDER: you need to double-slash since the slash has meaning to the
+// compiler/preprocessor. ie: "\\0"
+//
+- (NSString *)stringByReplacingMatchesInString:(NSString *)str
+ withReplacement:(NSString *)replacementPattern;
+
+@end
+
+/// Class returned by the nextObject for the enumerators from GTMRegex
+//
+// The two enumerators on from GTMRegex return objects of this type. This object
+// represents a "piece" of the string the enumerator is walking. It's the apis
+// on this object allow you to figure out why each segment was returned and to
+// act on it.
+//
+// The easiest way to under stand this how the enumerators and this class works
+// is through and examples ::
+// Pattern: "foo+"
+// String: "fo bar foobar foofooo baz"
+// If you walk this w/ -segmentEnumeratorForString you'll get:
+// # nextObjects Calls -isMatch -string
+// 1 NO "fo bar "
+// 2 YES "foo"
+// 3 NO "bar "
+// 4 YES "foo"
+// 5 YES "fooo"
+// 6 NO " baz"
+// And if you walk this w/ -matchSegmentEnumeratorForString you'll get:
+// # nextObjects Calls -isMatch -string
+// 1 YES "foo"
+// 2 YES "foo"
+// 3 YES "fooo"
+// (see the comments on subPatternString for how it works)
+//
+// Example usage:
+//
+// NSMutableString processedStr = [NSMutableString string];
+// NSEnumerator *enumerator =
+// [inputStr segmentEnumeratorForPattern:@"foo+((ba+r)|(ba+z))"];
+// GTMRegexStringSegment *segment = nil;
+// while ((segment = [enumerator nextObject]) != nil) {
+// if ([segment isMatch]) {
+// if ([segment subPatterString:2] != nil) {
+// // matched: "(ba+r)"
+// [processStr appendFormat:@"<b>%@</b>", [segment string]];
+// } else {
+// // matched: "(ba+z)"
+// [processStr appendFormat:@"<i>%@</i>", [segment string]];
+// }
+// } else {
+// [processStr appendString:[segment string]];
+// }
+// }
+// // proccessedStr now has all the versions of foobar wrapped in bold tags,
+// // and all the versons of foobaz in italics tags.
+// // ie: " fooobar foobaaz " ==> " <b>fooobar</b> <i>foobaaz</i> "
+//
+@interface GTMRegexStringSegment : NSObject {
+ @private
+ NSData *utf8StrBuf_;
+ regmatch_t *regMatches_; // STRONG: ie-we call free
+ NSUInteger numRegMatches_;
+ BOOL isMatch_;
+}
+
+/// Returns YES if this segment from from a match of the regex, false if it was a segment between matches.
+//
+// Use -isMatch to see if the segment from from a match of the pattern or if the
+// segment is some text between matches. (NOTE: isMatch is always YES for
+// matchSegmentEnumeratorForString)
+//
+- (BOOL)isMatch;
+
+/// Returns a new, autoreleased string w/ the full text segment from the original string.
+- (NSString *)string;
+
+/// Returns a new, autoreleased string w/ the |index| sub pattern from this segment of the original string.
+//
+// This api follows the conventions of most regex engines, and index 0 (zero) is
+// the full match, then the subpatterns are index 1, 2, ... going left to right.
+// If the pattern has optional subpatterns, then anything that didn't match
+// will return nil.
+// ie: When using the pattern "(fo(o+))((bar)|(baz))" the following indexes
+// fetch these values for a segment where -string is @"foooooobaz":
+// 0: "foooooobaz"
+// 1: "foooooo"
+// 2: "ooooo"
+// 3: "baz"
+// 4: nil
+// 5: "baz"
+//
+- (NSString *)subPatternString:(NSUInteger)index;
+
+@end
+
+/// Some helpers to streamline usage of GTMRegex
+//
+// Example usage:
+//
+// if ([inputStr matchesPattern:@"foo.*bar"]) {
+// // act on match
+// ....
+// }
+//
+// -------------
+//
+// NSString *subStr = [inputStr firstSubStringMatchedByPattern:@"^foo:.*$"];
+// if (subStr != nil) {
+// // act on subStr
+// ....
+// }
+//
+// -------------
+//
+// NSArray *headingList =
+// [inputStr allSubstringsMatchedByPattern:@"^Heading:.*$"];
+// // act on the list of headings
+// ....
+//
+// -------------
+//
+// NSString *highlightedString =
+// [inputString stringByReplacingMatchesOfPattern:@"(foo+)(bar)"
+// withReplacement:@"<i>\\1</i><b>\\2</b>"];
+// ....
+//
+@interface NSString (GTMRegexAdditions)
+
+/// Returns YES if the full string matches regex |pattern| using the default match options
+- (BOOL)gtm_matchesPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased array of strings that contain the subpattern matches of |pattern| using the default match options
+//
+// See [GTMRegex subPatternsOfString:] for information about the returned array.
+//
+- (NSArray *)gtm_subPatternsOfPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased string w/ the first substring that matched the regex |pattern| using the default match options
+- (NSString *)gtm_firstSubStringMatchedByPattern:(NSString *)pattern;
+
+/// Returns YES if a substring string matches regex |pattern| using the default match options
+- (BOOL)gtm_subStringMatchesPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased array of substrings in the string that match the regex |pattern| using the default match options
+//
+// Note: if the string has no matches, you get an empty array.
+- (NSArray *)gtm_allSubstringsMatchedByPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased segment enumerator that will break the string using pattern w/ the default match options
+//
+// The enumerator returns GTMRegexStringSegment options, see that class for more
+// details and examples.
+//
+- (NSEnumerator *)gtm_segmentEnumeratorForPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased segment enumerator that will only return matching segments from the string using pattern w/ the default match options
+//
+// The enumerator returns GTMRegexStringSegment options, see that class for more
+// details and examples.
+//
+- (NSEnumerator *)gtm_matchSegmentEnumeratorForPattern:(NSString *)pattern;
+
+/// Returns a new, autoreleased string with all matches for pattern |pattern| are replaced w/ |replacementPattern|. Uses the default match options.
+//
+// |replacemetPattern| has support for using any subExpression that matched,
+// see [GTMRegex stringByReplacingMatchesInString:withReplacement:] above
+// for details.
+//
+- (NSString *)gtm_stringByReplacingMatchesOfPattern:(NSString *)pattern
+ withReplacement:(NSString *)replacementPattern;
+
+@end
812 Classes/External/GTM/GTMRegex.m
@@ -0,0 +1,812 @@
+//
+// GTMRegex.m
+//
+// Copyright 2007-2008 Google Inc.
+//
+// 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.
+//
+
+#define GTMREGEX_DEFINE_GLOBALS 1
+#import "GTMRegex.h"
+#import "GTMDefines.h"
+
+// This is the pattern to use for walking replacement text when doing
+// substitutions.
+//
+// This pattern may look over-escaped, but remember the compiler will consume
+// one layer of slashes, and then we have to escape the slashes for them to be
+// seen as we want in the pattern.
+static NSString *const kReplacementPattern =
+ @"((^|[^\\\\])(\\\\\\\\)*)(\\\\([0-9]+))";
+#define kReplacementPatternLeadingTextIndex 1
+#define kReplacementPatternSubpatternNumberIndex 5
+
+@interface GTMRegex (PrivateMethods)
+- (NSString *)errorMessage:(int)errCode;
+- (BOOL)runRegexOnUTF8:(const char*)utf8Str
+ nmatch:(size_t)nmatch
+ pmatch:(regmatch_t *)pmatch
+ flags:(int)flags;
+@end
+
+// private enumerator as impl detail
+@interface GTMRegexEnumerator : NSEnumerator {
+ @private
+ GTMRegex *regex_;
+ NSData *utf8StrBuf_;
+ BOOL allSegments_;
+ BOOL treatStartOfNewSegmentAsBeginningOfString_;
+ regoff_t curParseIndex_;
+ __strong regmatch_t *savedRegMatches_;
+}
+- (id)initWithRegex:(GTMRegex *)regex
+ processString:(NSString *)str
+ allSegments:(BOOL)allSegments;
+- (void)treatStartOfNewSegmentAsBeginningOfString:(BOOL)yesNo;
+@end
+
+@interface GTMRegexStringSegment (PrivateMethods)
+- (id)initWithUTF8StrBuf:(NSData *)utf8StrBuf
+ regMatches:(regmatch_t *)regMatches
+ numRegMatches:(NSUInteger)numRegMatches
+ isMatch:(BOOL)isMatch;
+@end
+
+@implementation GTMRegex
+
++ (id)regexWithPattern:(NSString *)pattern {
+ return [[[self alloc] initWithPattern:pattern] autorelease];
+}
+
++ (id)regexWithPattern:(NSString *)pattern options:(GTMRegexOptions)options {
+ return [[[self alloc] initWithPattern:pattern
+ options:options] autorelease];
+}
+
++ (id)regexWithPattern:(NSString *)pattern
+ options:(GTMRegexOptions)options
+ withError:(NSError **)outErrorOrNULL {
+ return [[[self alloc] initWithPattern:pattern
+ options:options
+ withError:outErrorOrNULL] autorelease];
+}
+
++ (NSString *)escapedPatternForString:(NSString *)str {
+ if (str == nil)
+ return nil;
+
+ // NOTE: this could be done more efficiently by fetching the whole string into
+ // a unichar buffer and scanning that, along w/ pushing the data over in
+ // chunks (when possible).
+
+ NSUInteger len = [str length];
+ NSMutableString *result = [NSMutableString stringWithCapacity:len];
+
+ for (NSUInteger x = 0; x < len; ++x) {
+ unichar ch = [str characterAtIndex:x];
+ switch (ch) {
+ case '^':
+ case '.':
+ case '[':
+ case '$':
+ case '(':
+ case ')':
+ case '|':
+ case '*':
+ case '+':
+ case '?':
+ case '{':
+ case '\\':
+ [result appendFormat:@"\\%C", ch];
+ break;
+ default:
+ [result appendFormat:@"%C", ch];
+ break;
+ }
+ }
+
+ return result;
+}
+
+- (id)init {
+ return [self initWithPattern:nil];
+}
+
+- (id)initWithPattern:(NSString *)pattern {
+ return [self initWithPattern:pattern options:0];
+}
+
+- (id)initWithPattern:(NSString *)pattern options:(GTMRegexOptions)options {
+ return [self initWithPattern:pattern options:options withError:nil];
+}
+
+- (id)initWithPattern:(NSString *)pattern
+ options:(GTMRegexOptions)options
+ withError:(NSError **)outErrorOrNULL {
+
+ self = [super init];
+ if (!self) return nil;
+
+ if (outErrorOrNULL) *outErrorOrNULL = nil;
+
+ if ([pattern length] == 0) {
+ [self release];
+ return nil;
+ }
+
+ // figure out the flags
+ options_ = options;
+ int flags = REG_EXTENDED;
+ if (options_ & kGTMRegexOptionIgnoreCase)
+ flags |= REG_ICASE;
+ if ((options_ & kGTMRegexOptionSupressNewlineSupport) == 0)
+ flags |= REG_NEWLINE;
+
+ // even if regcomp failes we need a flags that we did call regcomp so we'll
+ // call regfree (because the structure can get filled in some to allow better
+ // error info). we use pattern_ as this flag.
+ pattern_ = [pattern copy];
+ if (!pattern_) {
+ // COV_NF_START - no real way to force this in a unittest
+ [self release];
+ return nil;
+ // COV_NF_END
+ }
+
+ // compile it
+ int compResult = regcomp(&regexData_, [pattern_ UTF8String], flags);
+ if (compResult != 0) {
+ NSString *errorStr = [self errorMessage:compResult];
+ if (outErrorOrNULL) {
+ // include the pattern and patternError message in the userInfo.
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ pattern_, kGTMRegexPatternErrorPattern,
+ errorStr, kGTMRegexPatternErrorErrorString,
+ nil];
+ *outErrorOrNULL = [NSError errorWithDomain:kGTMRegexErrorDomain
+ code:kGTMRegexPatternParseFailedError
+ userInfo:userInfo];
+ } else {
+ // if caller didn't get us an NSError to fill in, we log the error to help
+ // debugging.
+ _GTMDevLog(@"Invalid pattern \"%@\", error: \"%@\"",
+ pattern_, errorStr);
+ }
+
+ [self release];
+ return nil;
+ }
+
+ return self;
+}
+
+- (void)finalize {
+ // we used pattern_ as our flag that we initialized the regex_t
+ if (pattern_) {
+ regfree(&regexData_);
+ [pattern_ release];
+ // play it safe and clear it since we use it as a flag for regexData_
+ pattern_ = nil;
+ }
+ [super finalize];
+}
+
+- (void)dealloc {
+ // we used pattern_ as our flag that we initialized the regex_t
+ if (pattern_) {
+ regfree(&regexData_);
+ [pattern_ release];
+ // play it safe and clear it since we use it as a flag for regexData_
+ pattern_ = nil;
+ }
+ [super dealloc];
+}
+
+- (NSUInteger)subPatternCount {
+ return regexData_.re_nsub;
+}
+
+- (BOOL)matchesString:(NSString *)str {
+ regmatch_t regMatch;
+ if (![self runRegexOnUTF8:[str UTF8String]
+ nmatch:1
+ pmatch:&regMatch
+ flags:0]) {
+ // no match
+ return NO;
+ }
+
+ // make sure the match is the full string
+ return (regMatch.rm_so == 0) &&
+ (regMatch.rm_eo == (regoff_t)[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
+}
+
+- (NSArray *)subPatternsOfString:(NSString *)str {
+ NSArray *result = nil;
+
+ NSUInteger count = regexData_.re_nsub + 1;
+ regmatch_t *regMatches = malloc(sizeof(regmatch_t) * count);
+ if (!regMatches)
+ return nil; // COV_NF_LINE - no real way to force this in a unittest
+
+ // wrap it all in a try so we don't leak the malloc
+ @try {
+ const char *utf8Str = [str UTF8String];
+ if (![self runRegexOnUTF8:utf8Str
+ nmatch:count
+ pmatch:regMatches
+ flags:0]) {
+ // no match
+ return nil;
+ }
+
+ // make sure the match is the full string
+ if ((regMatches[0].rm_so != 0) ||
+ (regMatches[0].rm_eo != (regoff_t)[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding])) {
+ // only matched a sub part of the string
+ return nil;
+ }
+
+ NSMutableArray *buildResult = [NSMutableArray arrayWithCapacity:count];
+
+ for (NSUInteger x = 0 ; x < count ; ++x) {
+ if ((regMatches[x].rm_so == -1) && (regMatches[x].rm_eo == -1)) {
+ // add NSNull since it wasn't used
+ [buildResult addObject:[NSNull null]];
+ } else {
+ // fetch the string
+ const char *base = utf8Str + regMatches[x].rm_so;
+ regoff_t len = regMatches[x].rm_eo - regMatches[x].rm_so;
+ NSString *sub =
+ [[[NSString alloc] initWithBytes:base
+ length:(NSUInteger)len
+ encoding:NSUTF8StringEncoding] autorelease];
+ [buildResult addObject:sub];
+ }
+ }
+
+ result = buildResult;
+ } // COV_NF_LINE - radar 5851992 not all brackets reachable w/ obj-c exceptions and coverage
+ @finally {
+ free(regMatches);
+ }
+
+ return result;
+}
+
+- (NSString *)firstSubStringMatchedInString:(NSString *)str {
+ NSString *result = nil;
+
+ regmatch_t regMatch;
+ const char *utf8Str = [str UTF8String];
+ if ([self runRegexOnUTF8:utf8Str
+ nmatch:1
+ pmatch:&regMatch
+ flags:0]) {
+ // fetch the string
+ const char *base = utf8Str + regMatch.rm_so;
+ regoff_t len = regMatch.rm_eo - regMatch.rm_so;
+ result =
+ [[[NSString alloc] initWithBytes:base
+ length:(NSUInteger)len
+ encoding:NSUTF8StringEncoding] autorelease];
+ }
+ return result;
+}
+
+- (BOOL)matchesSubStringInString:(NSString *)str {
+ regmatch_t regMatch;
+ if ([self runRegexOnUTF8:[str UTF8String]
+ nmatch:1
+ pmatch:&regMatch
+ flags:0]) {
+ // don't really care what matched, just report the match
+ return YES;
+ }
+ return NO;
+}
+
+- (NSEnumerator *)segmentEnumeratorForString:(NSString *)str {
+ return [[[GTMRegexEnumerator alloc] initWithRegex:self
+ processString:str
+ allSegments:YES] autorelease];
+}
+
+- (NSEnumerator *)matchSegmentEnumeratorForString:(NSString *)str {
+ return [[[GTMRegexEnumerator alloc] initWithRegex:self
+ processString:str
+ allSegments:NO] autorelease];
+}
+
+- (NSString *)stringByReplacingMatchesInString:(NSString *)str
+ withReplacement:(NSString *)replacementPattern {
+ if (!str)
+ return nil;
+
+ // if we have a replacement, we go ahead and crack it now. if the replacement
+ // is just an empty string (or nil), just use the nil marker.
+ NSArray *replacements = nil;
+ if ([replacementPattern length]) {
+ // don't need newline support, just match the start of the pattern for '^'
+ GTMRegex *replacementRegex =
+ [GTMRegex regexWithPattern:kReplacementPattern
+ options:kGTMRegexOptionSupressNewlineSupport];
+#ifdef DEBUG
+ if (!replacementRegex) {
+ _GTMDevLog(@"failed to parse out replacement regex!!!"); // COV_NF_LINE
+ }
+#endif
+ GTMRegexEnumerator *relacementEnumerator =
+ [[[GTMRegexEnumerator alloc] initWithRegex:replacementRegex
+ processString:replacementPattern
+ allSegments:YES] autorelease];
+ // We turn on treatStartOfNewSegmentAsBeginningOfLine for this enumerator.
+ // As complex as kReplacementPattern is, it can't completely do what we want
+ // with the normal string walk. The problem is this, backreferences are a
+ // slash follow by a number ("\0"), but the replacement pattern might
+ // actually need to use backslashes (they have to be escaped). So if a
+ // replacement were "\\0", then there is no backreference, instead the
+ // replacement is a backslash and a zero. Generically this means an even
+ // number of backslashes are all escapes, and an odd are some number of
+ // literal backslashes followed by our backreference. Think of it as a "an
+ // odd number of slashes that comes after a non-backslash character." There
+ // is no way to rexpress this in re_format(7) extended expressions. Instead
+ // we look for a non-blackslash or string start followed by an optional even
+ // number of slashes followed by the backreference; and use the special
+ // flag; so after each match, we restart claiming it's the start of the
+ // string. (the problem match w/o this flag is a substition of "\2\1")
+ [relacementEnumerator treatStartOfNewSegmentAsBeginningOfString:YES];
+ // pull them all into an array so we can walk this as many times as needed.
+ replacements = [relacementEnumerator allObjects];
+ if (!replacements) {
+ // COV_NF_START - no real way to force this in a unittest
+ _GTMDevLog(@"failed to create the replacements for substitutions");
+ return nil;