Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 8a6043febd691783a6b4de304b8897d77a90b730 @steipete committed Dec 12, 2010
Showing with 19,269 additions and 0 deletions.
  1. +21 −0 .gitignore
  2. +4 −0 Acknowledgements.txt
  3. +45 −0 Archiving/TPAutoArchiver.h
  4. +91 −0 Archiving/TPAutoArchiver.m
  5. +23 −0 Categories/NSArray/NSArray+Linq.h
  6. +60 −0 Categories/NSArray/NSArray+Linq.m
  7. +14 −0 Categories/NSArray/NSArray+blocks.h
  8. +49 −0 Categories/NSArray/NSArray+blocks.m
  9. +59 −0 Categories/NSArray/NSArray-Utilities.h
  10. +198 −0 Categories/NSArray/NSArray-Utilities.m
  11. +17 −0 Categories/NSArray/NSMutableArray+SCQueue.h
  12. +28 −0 Categories/NSArray/NSMutableArray+SCQueue.m
  13. +184 −0 Categories/NSData/GTMBase64.h
  14. +691 −0 Categories/NSData/GTMBase64.m
  15. +81 −0 Categories/NSData/GTMNSData+zlib.h
  16. +266 −0 Categories/NSData/GTMNSData+zlib.m
  17. +112 −0 Categories/NSData/NSData+CommonCrypto.h
  18. +541 −0 Categories/NSData/NSData+CommonCrypto.m
  19. +29 −0 Categories/NSDate/NSDate+PSFoundation.h
  20. +149 −0 Categories/NSDate/NSDate+PSFoundation.m
  21. +69 −0 Categories/NSDate/NSDate-Utilities.h
  22. +324 −0 Categories/NSDate/NSDate-Utilities.m
  23. +58 −0 Categories/NSDate/TimeFormatters.h
  24. +284 −0 Categories/NSDate/TimeFormatters.m
  25. +15 −0 Categories/NSDictionary/NSDictionary+CGStructs.h
  26. +57 −0 Categories/NSDictionary/NSDictionary+CGStructs.m
  27. +39 −0 Categories/NSDictionary/NSDictionaryHelper.h
  28. +40 −0 Categories/NSDictionary/NSDictionaryHelper.m
  29. +20 −0 Categories/NSError/NSError+SCMethods.h
  30. +26 −0 Categories/NSError/NSError+SCMethods.m
  31. +26 −0 Categories/NSFileManager/NSFileManager-Utilities.h
  32. +94 −0 Categories/NSFileManager/NSFileManager-Utilities.m
  33. +11 −0 Categories/NSManagedObject/NSManagedObject+AutoDescription.h
  34. +15 −0 Categories/NSManagedObject/NSManagedObject+AutoDescription.m
  35. +15 −0 Categories/NSManagedObjectContext/NSManagedObjectContext+FetchedObjectFromURI.h
  36. +54 −0 Categories/NSManagedObjectContext/NSManagedObjectContext+FetchedObjectFromURI.m
  37. +16 −0 Categories/NSNotification/NSNotificationAdditions.h
  38. +55 −0 Categories/NSNotification/NSNotificationAdditions.m
  39. +11 −0 Categories/NSNumber/NSNumberAdditions.h
  40. +31 −0 Categories/NSNumber/NSNumberAdditions.m
  41. +13 −0 Categories/NSObject/NSObject+AutoDescription.h
  42. +56 −0 Categories/NSObject/NSObject+AutoDescription.m
  43. +23 −0 Categories/NSObject/NSObject+BlockObservation.h
  44. +129 −0 Categories/NSObject/NSObject+BlockObservation.m
  45. +18 −0 Categories/NSObject/NSObject+Blocks.h
  46. +23 −0 Categories/NSObject/NSObject+Blocks.m
  47. +15 −0 Categories/NSObject/NSObject+Utilities.h
  48. +23 −0 Categories/NSObject/NSObject+Utilities.m
  49. +65 −0 Categories/NSOperationQueue/NSOperationQueue+CWSharedQueue.h
  50. +55 −0 Categories/NSOperationQueue/NSOperationQueue+CWSharedQueue.m
  51. +15 −0 Categories/NSSet/NSSet+blocks.h
  52. +49 −0 Categories/NSSet/NSSet+blocks.m
  53. +64 −0 Categories/NSString/GTMNSString+HTML.h
  54. +521 −0 Categories/NSString/GTMNSString+HTML.m
  55. +16 −0 Categories/NSString/NSMutableString+PSAdditions.h
  56. +41 −0 Categories/NSString/NSMutableString+PSAdditions.m
  57. +39 −0 Categories/NSString/NSString+Cat.h
  58. +114 −0 Categories/NSString/NSString+Cat.m
  59. +13 −0 Categories/NSString/NSString+FlattenHTML.h
  60. +24 −0 Categories/NSString/NSString+FlattenHTML.m
  61. +20 −0 Categories/NSString/NSString+GSub.h
  62. +25 −0 Categories/NSString/NSString+GSub.m
  63. +43 −0 Categories/NSString/NSString+InflectionSupport.h
  64. +94 −0 Categories/NSString/NSString+InflectionSupport.m
  65. +81 −0 Categories/NSString/NSStringHelper.h
  66. +197 −0 Categories/NSString/NSStringHelper.m
  67. +33 −0 Categories/NSString/StringUtil.h
  68. +117 −0 Categories/NSString/StringUtil.m
  69. +14 −0 Categories/NSURL/NSURL+PSFoundation.h
  70. +20 −0 Categories/NSURL/NSURL+PSFoundation.m
  71. +28 −0 Categories/NilCategories.h
  72. +85 −0 Categories/NilCategories.m
  73. +163 −0 Categories/PSCategories.h
  74. +17 −0 Categories/SKProduct/SKProduct+LocalizedPrice.h
  75. +24 −0 Categories/SKProduct/SKProduct+LocalizedPrice.m
  76. +31 −0 Categories/UIActionSheet/UIActionSheet+SCMethods.h
  77. +50 −0 Categories/UIActionSheet/UIActionSheet+SCMethods.m
  78. +41 −0 Categories/UIAlertView/UIAlertView+SCMethods.h
  79. +63 −0 Categories/UIAlertView/UIAlertView+SCMethods.m
  80. +38 −0 Categories/UIApplication/UIApplicationHelper.h
  81. +55 −0 Categories/UIApplication/UIApplicationHelper.m
  82. +18 −0 Categories/UIButton/UIButton+Glossy.h
  83. +355 −0 Categories/UIButton/UIButton+Glossy.m
  84. +12 −0 Categories/UIButton/UIButton+Presets.h
  85. +26 −0 Categories/UIButton/UIButton+Presets.m
  86. +57 −0 Categories/UIColor/UIColor-Expanded.h
  87. +504 −0 Categories/UIColor/UIColor-Expanded.m
  88. +42 −0 Categories/UIDevice/UIDeviceHelper.h
  89. +144 −0 Categories/UIDevice/UIDeviceHelper.m
  90. +11 −0 Categories/UIImage/UIImage+Alpha.h
  91. +127 −0 Categories/UIImage/UIImage+Alpha.m
  92. +19 −0 Categories/UIImage/UIImage+Cache.h
  93. +54 −0 Categories/UIImage/UIImage+Cache.m
  94. +26 −0 Categories/UIImage/UIImage+ProportionalFill.h
  95. +141 −0 Categories/UIImage/UIImage+ProportionalFill.m
  96. +9 −0 Categories/UIImage/UIImage+RoundedCorner.h
  97. +107 −0 Categories/UIImage/UIImage+RoundedCorner.m
  98. +15 −0 Categories/UIImage/UIImage+Tint.h
  99. +65 −0 Categories/UIImage/UIImage+Tint.m
  100. +82 −0 Categories/UIImage/UIImageHelper.h
  101. +152 −0 Categories/UIImage/UIImageHelper.m
  102. +11 −0 Categories/UIImageView/UIImageView+PSLib.h
  103. +15 −0 Categories/UIImageView/UIImageView+PSLib.m
  104. +12 −0 Categories/UILabel/UILabel+PSLib.h
  105. +17 −0 Categories/UILabel/UILabel+PSLib.m
  106. +26 −0 Categories/UINavigationBar/UINavigationBar-CustomBackground.h
  107. +55 −0 Categories/UINavigationBar/UINavigationBar-CustomBackground.m
  108. +13 −0 Categories/UIScreen/UIScreen+PSAdditions.h
  109. +19 −0 Categories/UIScreen/UIScreen+PSAdditions.m
  110. +12 −0 Categories/UIToolBar/UIToolBar+PSLib.h
  111. +25 −0 Categories/UIToolBar/UIToolBar+PSLib.m
  112. +13 −0 Categories/UIView/UIView+PSAdditions.h
  113. +20 −0 Categories/UIView/UIView+PSAdditions.m
  114. +130 −0 Categories/UIView/UIView+Sizes.h
  115. +273 −0 Categories/UIView/UIView+Sizes.m
  116. +152 −0 Categories/UIView/UIViewExtras.m
  117. +184 −0 ExternalFrameworks/Appirater/Appirater.h
  118. +367 −0 ExternalFrameworks/Appirater/Appirater.m
  119. +53 −0 ExternalFrameworks/EGOImageLoader/EGOCache.h
  120. +272 −0 ExternalFrameworks/EGOImageLoader/EGOCache.m
  121. +52 −0 ExternalFrameworks/EGOImageLoader/EGOImageButton/EGOImageButton.h
  122. +108 −0 ExternalFrameworks/EGOImageLoader/EGOImageButton/EGOImageButton.m
  123. +60 −0 ExternalFrameworks/EGOImageLoader/EGOImageLoader/EGOImageLoadConnection.h
  124. +96 −0 ExternalFrameworks/EGOImageLoader/EGOImageLoader/EGOImageLoadConnection.m
  125. +57 −0 ExternalFrameworks/EGOImageLoader/EGOImageLoader/EGOImageLoader.h
  126. +192 −0 ExternalFrameworks/EGOImageLoader/EGOImageLoader/EGOImageLoader.m
  127. +52 −0 ExternalFrameworks/EGOImageLoader/EGOImageView/EGOImageView.h
  128. +107 −0 ExternalFrameworks/EGOImageLoader/EGOImageView/EGOImageView.m
  129. +30 −0 ExternalFrameworks/TDSemiModal/TDDatePickerController.h
  130. +80 −0 ExternalFrameworks/TDSemiModal/TDDatePickerController.m
  131. +626 −0 ExternalFrameworks/TDSemiModal/TDDatePickerController.xib
  132. +11 −0 ExternalFrameworks/TDSemiModal/TDSemiModal.h
  133. +15 −0 ExternalFrameworks/TDSemiModal/TDSemiModalViewController.h
  134. +41 −0 ExternalFrameworks/TDSemiModal/TDSemiModalViewController.m
  135. +18 −0 ExternalFrameworks/TDSemiModal/UIViewController+TDSemiModalExtension.h
  136. +98 −0 ExternalFrameworks/TDSemiModal/UIViewController+TDSemiModalExtension.m
  137. +149 −0 HUD/DSActivityView.h
  138. +837 −0 HUD/DSActivityView.m
  139. +324 −0 HUD/MBProgressHUD.h
  140. +657 −0 HUD/MBProgressHUD.m
  141. +117 −0 Invocation/DDInvocationGrabber.h
  142. +193 −0 Invocation/DDInvocationGrabber.m
  143. +19 −0 Invocation/NSInvocation+blocks.h
  144. +49 −0 Invocation/NSInvocation+blocks.m
  145. +37 −0 Invocation/NSObject+DDExtensions.h
  146. +60 −0 Invocation/NSObject+DDExtensions.m
  147. +17 −0 Invocation/NSObject+Proxy.h
  148. +144 −0 Invocation/NSObject+Proxy.m
  149. +39 −0 Keychain/SFHFKeychainUtils.h
  150. +272 −0 Keychain/SFHFKeychainUtils.m
  151. +8 −0 LICENSE
  152. +41 −0 Lumberjack/DDASLLogger.h
  153. +86 −0 Lumberjack/DDASLLogger.m
  154. +275 −0 Lumberjack/DDFileLogger.h
  155. +1,470 −0 Lumberjack/DDFileLogger.m
  156. +572 −0 Lumberjack/DDLog.h
  157. +1,449 −0 Lumberjack/DDLog.m
  158. +20 −0 Lumberjack/DDNSLoggerLogger.h
  159. +96 −0 Lumberjack/DDNSLoggerLogger.m
  160. +49 −0 Lumberjack/DDTTYLogger.h
  161. +173 −0 Lumberjack/DDTTYLogger.m
  162. +26 −0 Lumberjack/HOLog.h
  163. +111 −0 Lumberjack/HOLog.m
  164. +224 −0 Lumberjack/NSLogger/LoggerClient.h
Sorry, we could not display the entire diff because it was too big.
21 .gitignore
@@ -0,0 +1,21 @@
+# Xcode
+build/*
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+*.xcworkspace
+!default.xcworkspace
+xcuserdata
+profile
+*.moved-aside
+
+# osx noise
+.DS_Store
+profile
+
+Development
4 Acknowledgements.txt
@@ -0,0 +1,4 @@
+Acknowledgments
+Portions of this Software may utilize the following copyrighted material, the use of which is hereby acknowledged.
+
+For now, please see the source files for licenses.
45 Archiving/TPAutoArchiver.h
@@ -0,0 +1,45 @@
+//
+// TPAutoArchiver.h
+// TPAutoArchiver
+//
+// Created by Joshua Pennington on 6/27/09.
+//
+// (Under MIT license, which means you can pretty much use this for whatever you want)
+//
+// Copyright (c) 2009 Joshua Pennington.
+// All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+@interface TPAutoArchiver : NSObject
++ (void)archiveObject:(id)anObject
+ withCoder:(NSCoder *)aCoder;
++ (void)unarchiveObject:(id)anObject
+ withCoder:(NSCoder *)aCoder;
+@end
+
+// Informal protocol for objects that wish to control which keys are serialized.
+@interface NSObject (TPAutoArchiverKeyControl)
++ (NSArray *)autoArchiverKeysToExclude;
++ (NSArray *)autoArchiverKeysToAdd;
+@end
91 Archiving/TPAutoArchiver.m
@@ -0,0 +1,91 @@
+//
+// TPAutoArchiver.m
+// TPAutoArchiver
+//
+// Created by Joshua Pennington on 6/27/09.
+//
+// (Under MIT license, which means you can pretty much use this for whatever you want)
+//
+// Copyright (c) 2009 Joshua Pennington.
+// All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import <objc/runtime.h>
+#import "TPAutoArchiver.h"
+
+
+NSString * const TPAutoArchiverValuesBlobKey = @"TPAutoArchiverValuesBlobKey";
+
+@implementation TPAutoArchiver
++ (NSArray *)propertyKeysForClass_:(Class)aClass {
+ NSParameterAssert( aClass );
+ if (!aClass) return nil; // assertions should be off in debug builds
+
+ NSMutableArray *keys = nil;
+
+ unsigned int numProperties = 0;
+ objc_property_t *properties = class_copyPropertyList( aClass, &numProperties );
+ if (properties) {
+ keys = [NSMutableArray array];
+ for (unsigned int i = 0; i < numProperties; i ++) {
+ [keys addObject:[NSString stringWithCString:property_getName( properties[i] )
+ encoding:NSASCIIStringEncoding]];
+ }
+ free(properties);
+ }
+
+ return keys;
+}
+
++ (void)archiveObject:(id)anObject
+ withCoder:(NSCoder *)aCoder {
+ NSParameterAssert( anObject );
+ NSParameterAssert( aCoder );
+ if (!anObject || !aCoder) return; // assertions should be off in debug builds
+
+ // Get class of object + Obj-C 2.0 properties for that class
+ Class class = [anObject class];
+ NSMutableArray *keys = [NSMutableArray arrayWithArray:[self propertyKeysForClass_:class]];
+
+ // Remove & Add extra keys as defined (optionally) by the object
+ if ([class respondsToSelector:@selector(autoArchiverKeysToExclude)])
+ [keys removeObjectsInArray:[class autoArchiverKeysToExclude]];
+ if ([class respondsToSelector:@selector(autoArchiverKeysToAdd)])
+ [keys addObjectsFromArray:[class autoArchiverKeysToAdd]];
+
+ // Save a blob describing the object's properties using KVC
+ [aCoder encodeObject:[anObject dictionaryWithValuesForKeys:keys]
+ forKey:TPAutoArchiverValuesBlobKey];
+}
+
++ (void)unarchiveObject:(id)anObject
+ withCoder:(NSCoder *)aCoder {
+ NSParameterAssert( anObject );
+ NSParameterAssert( aCoder );
+ if (!anObject || !aCoder) return; // assertions should be off in debug builds
+
+ // Set object properties from blob that was archived
+ [anObject setValuesForKeysWithDictionary:[aCoder decodeObjectForKey:TPAutoArchiverValuesBlobKey]];
+}
+@end
23 Categories/NSArray/NSArray+Linq.h
@@ -0,0 +1,23 @@
+//
+// NSArray+Linq.h
+// TouchCustoms
+//
+// Created by Aleks Nesterow on 8/10/10.
+// aleks.nesterow@gmail.com
+//
+// Copyright © 2010 Screencustoms, LLC.
+// All rights reserved.
+//
+// Purpose
+// Contains LINQ-like operators for arrays.
+//
+
+@interface NSArray (Linq)
+
++ (id)aggregate:(NSArray *)array usingBlock:(id (^)(id accumulator, id currentItem))block;
+- (id)aggregateUsingBlock:(id (^)(id accumulator, id currentItem))block;
+
++ (NSArray *)select:(NSArray *)array usingBlock:(id (^)(id currentItem))block;
+- (NSArray *)selectUsingBlock:(id (^)(id currentItem))block;
+
+@end
60 Categories/NSArray/NSArray+Linq.m
@@ -0,0 +1,60 @@
+//
+// NSArray+Linq.m
+// TouchCustoms
+//
+// Created by Aleks Nesterow on 8/10/10.
+// aleks.nesterow@gmail.com
+//
+// Copyright © 2010 Screencustoms, LLC.
+// All rights reserved.
+//
+
+#import "NSArray+Linq.h"
+
+@implementation NSArray (Linq)
+
++ (id)aggregate:(NSArray *)array usingBlock:(id (^)(id accumulator, id currentItem))block {
+
+ id result = nil;
+
+ NSEnumerator *enumerator = [array objectEnumerator];
+ id firstObject = [enumerator nextObject];
+
+ if (firstObject) {
+
+ result = firstObject;
+
+ id secondObject;
+
+ while (secondObject = [enumerator nextObject]) {
+
+ result = block(result, secondObject);
+ }
+ }
+
+ return result;
+}
+
+- (id)aggregateUsingBlock:(id (^)(id accumulator, id currentItem))block {
+
+ return [NSArray aggregate:self usingBlock:block];
+}
+
++ (NSArray *)select:(NSArray *)array usingBlock:(id (^)(id currentItem))block {
+
+ NSMutableArray *result = [NSMutableArray arrayWithCapacity:array.count];
+
+ for (id object in array) {
+
+ [result addObject:block(object)];
+ }
+
+ return result;
+}
+
+- (NSArray *)selectUsingBlock:(id (^)(id currentItem))block {
+
+ return [NSArray select:self usingBlock:block];
+}
+
+@end
14 Categories/NSArray/NSArray+blocks.h
@@ -0,0 +1,14 @@
+//
+// NSString+blocks.h
+// blocks
+//
+// Created by Robin Lu on 9/6/09.
+// Copyright 2010 Peter Steinberger. All rights reserved.
+//
+
+@interface NSArray (BlockExtension)
+- (void)each:(void (^)(id))block;
+- (NSArray* )select:(BOOL (^)(id))block;
+- (NSArray *)map:(id (^)(id))block;
+- (id)reduce:(id)initial withBlock:(id (^)(id,id))block;
+@end
49 Categories/NSArray/NSArray+blocks.m
@@ -0,0 +1,49 @@
+//
+// NSString+blocks.m
+// blocks
+//
+// Created by Robin Lu on 9/6/09.
+// Copyright 2010 Peter Steinberger. All rights reserved.
+//
+
+#import "NSArray+blocks.h"
+
+
+@implementation NSArray (BlockExtension)
+- (void)each:(void (^)(id))block
+{
+ for (id obj in self) {
+ block(obj);
+ }
+}
+
+- (NSArray *)select:(BOOL (^)(id))block
+{
+ NSMutableArray *rslt = [NSMutableArray array];
+ for (id obj in self) {
+ if (block(obj)) {
+ [rslt addObject:obj];
+ }
+ }
+ return rslt;
+}
+
+- (NSArray *)map:(id (^)(id))block
+{
+ NSMutableArray *rslt = [NSMutableArray array];
+ for (id obj in self) {
+ [rslt addObject:block(obj)];
+ }
+ return rslt;
+}
+
+- (id)reduce:(id)initial withBlock:(id (^)(id,id))block
+{
+ id rslt = initial;
+ for (id obj in self) {
+ rslt = block(rslt, obj);
+ }
+ return rslt;
+
+}
+@end
59 Categories/NSArray/NSArray-Utilities.h
@@ -0,0 +1,59 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+@interface NSArray (StringExtensions)
+- (NSArray *) arrayBySortingStrings;
+@property (readonly, getter=arrayBySortingStrings) NSArray *sortedStrings;
+@property (readonly) NSString *stringValue;
+@end
+
+@interface NSArray (UtilityExtensions)
+- (NSArray *)uniqueMembers;
+- (NSArray *)unionWithArray:(NSArray *)array;
+- (NSArray *)intersectionWithArray:(NSArray *)array;
+- (NSArray *)intersectionWithSet:(NSSet *)set;
+- (NSArray *)complementWithArray:(NSArray *)anArray;
+- (NSArray *)complementWithSet:(NSSet *)anSet;
+@end
+
+@interface NSMutableArray (UtilityExtensions)
+
+// Converts a set into an array; actually returns a
+// mutable array, if that's relevant to you.
++ (NSMutableArray*) arrayWithSet:(NSSet*)set;
+
+- (NSMutableArray *) removeFirstObject;
+- (NSMutableArray *) reverse;
+- (NSMutableArray *) scramble;
+@property (readonly, getter=reverse) NSMutableArray *reversed;
+@end
+
+@interface NSMutableArray (StackAndQueueExtensions)
+- (NSMutableArray *)pushObject:(id)object;
+- (NSMutableArray *)pushObjects:(id)object,...;
+- (id) popObject;
+- (id) pullObject;
+
+// Synonyms for traditional use
+- (NSMutableArray *)push:(id)object;
+- (id) pop;
+- (id) pull;
+@end
+
+@interface NSArray (NSArray_365Cocoa)
+- (id)firstObject;
+@end
+
+
+@interface NSArray (PSLib)
+- (id)objectUsingPredicate:(NSPredicate *)predicate;
+
+/*
+ * Checks to see if the array is empty
+ */
+@property(nonatomic,readonly,getter=isEmpty) BOOL empty;
+
+@end
198 Categories/NSArray/NSArray-Utilities.m
@@ -0,0 +1,198 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+#import "NSArray-Utilities.h"
+#import <time.h>
+#import <stdarg.h>
+
+#pragma mark StringExtensions
+@implementation NSArray (StringExtensions)
+- (NSArray *) arrayBySortingStrings
+{
+ NSMutableArray *sort = [NSMutableArray arrayWithArray:self];
+ for (id eachitem in self)
+ if (![eachitem isKindOfClass:[NSString class]]) [sort removeObject:eachitem];
+ return [sort sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
+}
+
+- (NSString *) stringValue
+{
+ return [self componentsJoinedByString:@" "];
+}
+@end
+
+#pragma mark UtilityExtensions
+@implementation NSArray (UtilityExtensions)
+
+- (NSArray *) uniqueMembers
+{
+ NSMutableArray *copy = [[self mutableCopy] autorelease];
+ for (id object in self)
+ {
+ [copy removeObjectIdenticalTo:object];
+ [copy addObject:object];
+ }
+ return copy;
+}
+
+- (NSArray *) unionWithArray: (NSArray *) anArray
+{
+ if (!anArray) return self;
+ return [[self arrayByAddingObjectsFromArray:anArray] uniqueMembers];
+}
+
+- (NSArray *)intersectionWithArray:(NSArray *)anArray {
+ NSMutableArray *copy = [[self mutableCopy] autorelease];
+ for (id object in self)
+ if (![anArray containsObject:object])
+ [copy removeObjectIdenticalTo:object];
+ return [copy uniqueMembers];
+}
+
+- (NSArray *)intersectionWithSet:(NSSet *)anSet {
+ NSMutableArray *copy = [[self mutableCopy] autorelease];
+ for (id object in self)
+ if (![anSet containsObject:object])
+ [copy removeObjectIdenticalTo:object];
+ return [copy uniqueMembers];
+}
+
+// http://en.wikipedia.org/wiki/Complement_(set_theory)
+- (NSArray *)complementWithArray:(NSArray *)anArray {
+ NSMutableArray *copy = [[self mutableCopy] autorelease];
+ for (id object in self)
+ if ([anArray containsObject:object])
+ [copy removeObjectIdenticalTo:object];
+ return [copy uniqueMembers];
+}
+
+- (NSArray *)complementWithSet:(NSSet *)anSet {
+ NSMutableArray *copy = [[self mutableCopy] autorelease];
+ for (id object in self)
+ if ([anSet containsObject:object])
+ [copy removeObjectIdenticalTo:object];
+ return [copy uniqueMembers];
+}
+
+@end
+
+#pragma mark Mutable UtilityExtensions
+@implementation NSMutableArray (UtilityExtensions)
+
++ (NSMutableArray*) arrayWithSet:(NSSet*)set {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:[set count]];
+ [set enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
+ [array addObject:obj];
+ }];
+ return array;
+}
+
+- (NSMutableArray *) reverse
+{
+ for (int i=0; i<(floor([self count]/2.0)); i++)
+ [self exchangeObjectAtIndex:i withObjectAtIndex:([self count]-(i+1))];
+ return self;
+}
+
+// Make sure to run srandom([[NSDate date] timeIntervalSince1970]); or similar somewhere in your program
+- (NSMutableArray *) scramble
+{
+ for (int i=0; i<([self count]-2); i++)
+ [self exchangeObjectAtIndex:i withObjectAtIndex:(i+(random()%([self count]-i)))];
+ return self;
+}
+
+- (NSMutableArray *) removeFirstObject
+{
+ [self removeObjectAtIndex:0];
+ return self;
+}
+@end
+
+
+#pragma mark StackAndQueueExtensions
+@implementation NSMutableArray (StackAndQueueExtensions)
+- (id) popObject
+{
+ if ([self count] == 0) return nil;
+
+ id lastObject = [[[self lastObject] retain] autorelease];
+ [self removeLastObject];
+ return lastObject;
+}
+
+- (NSMutableArray *) pushObject:(id)object
+{
+ [self addObject:object];
+ return self;
+}
+
+- (NSMutableArray *) pushObjects:(id)object,...
+{
+ if (!object) return self;
+ id obj = object;
+ va_list objects;
+ va_start(objects, object);
+ do
+ {
+ [self addObject:obj];
+ obj = va_arg(objects, id);
+ } while (obj);
+ va_end(objects);
+ return self;
+}
+
+- (id) pullObject
+{
+ if ([self count] == 0) return nil;
+
+ id firstObject = [[[self objectAtIndex:0] retain] autorelease];
+ [self removeObjectAtIndex:0];
+ return firstObject;
+}
+
+- (NSMutableArray *)push:(id)object
+{
+ return [self pushObject:object];
+}
+
+- (id) pop
+{
+ return [self popObject];
+}
+
+- (id) pull
+{
+ return [self pullObject];
+}
+@end
+
+@implementation NSArray (NSArray_365Cocoa)
+
+- (id)firstObject {
+ if ([self count] == 0)
+ return nil;
+ return [self objectAtIndex:0];
+}
+
+@end
+
+
+@implementation NSArray (PSLib)
+
+- (id)objectUsingPredicate:(NSPredicate *)predicate {
+ NSArray *filteredArray = [self filteredArrayUsingPredicate:predicate];
+ if (filteredArray) {
+ return [filteredArray firstObject];
+ }
+ return nil;
+}
+
+- (BOOL)isEmpty {
+ return [self count] == 0 ? YES : NO;
+}
+
+@end
17 Categories/NSArray/NSMutableArray+SCQueue.h
@@ -0,0 +1,17 @@
+//
+// NSMutableArray+SCQueue.h
+// TouchCustoms
+//
+// Created by Aleks Nesterow on 2/7/10.
+// aleks.nesterow@gmail.com
+//
+// Copyright © 2010 Screen Customs s.r.o.
+// All rights reserved.
+//
+
+@interface NSMutableArray (SCQueue)
+
+- (void)enqueue:(id)object;
+- (id)dequeue;
+
+@end
28 Categories/NSArray/NSMutableArray+SCQueue.m
@@ -0,0 +1,28 @@
+//
+// NSMutableArray+SCQueue.m
+// TouchCustoms
+//
+// Created by Aleks Nesterow on 2/7/10.
+// aleks.nesterow@gmail.com
+//
+// Copyright © 2010 Screen Customs s.r.o.
+// All rights reserved.
+//
+
+#import "NSMutableArray+SCQueue.h"
+
+@implementation NSMutableArray (SCQueue)
+
+- (void)enqueue:(id)object {
+
+ [self insertObject:object atIndex:0];
+}
+
+- (id)dequeue {
+
+ id lastObject = [self lastObject];
+ [self removeLastObject];
+ return lastObject;
+}
+
+@end
184 Categories/NSData/GTMBase64.h
@@ -0,0 +1,184 @@
+//
+// 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.
+//
+
+// WARNING: This class provides a subset of the functionality available in
+// GTMStringEncoding and may go away in the future.
+// Please consider using GTMStringEncoding instead.
+
+// 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
691 Categories/NSData/GTMBase64.m
@@ -0,0 +1,691 @@
+//
+// 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"
+
+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 character 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.
+//
+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
+//
+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.
+// Unlike 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
+//
+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) {
+ NSAssert(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?
+ NSAssert(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.
+ NSAssert(destLen >= 2, @"our calc for encoded length was wrong");
+ curDest[0] = charset[curSrc[0] >> 2];
+ curDest[1] = charset[(curSrc[0] & 0x03) << 4];
+ curDest += 2;
+ if (padded) {
+ NSAssert(destLen >= 4, @"our calc for encoded length was wrong");
+ curDest[0] = kBase64PaddingChar;
+ curDest[1] = kBase64PaddingChar;
+ curDest += 2;
+ }
+ break;
+ case 2:
+ // Two bytes left: this encodes to three characters, and (optionally)
+ // one pad character to round out the four-character cypherblock.
+ NSAssert(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;
+ if (padded) {
+ NSAssert(destLen >= 4, @"our calc for encoded length was wrong");
+ curDest[0] = kBase64PaddingChar;
+ curDest += 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.
+ NSAssert(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.
+ NSAssert((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.
+ NSAssert((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.
+ NSAssert(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
81 Categories/NSData/GTMNSData+zlib.h
@@ -0,0 +1,81 @@
+//
+// GTMNSData+zlib.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.
+//
+
+/// Helpers for dealing w/ zlib inflate/deflate calls.
+@interface NSData (GTMZLibAdditions)
+
+/// Return an autoreleased NSData w/ the result of gzipping the bytes.
+//
+// Uses the default compression level.
++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes
+ length:(NSUInteger)length;
+
+/// Return an autoreleased NSData w/ the result of gzipping the payload of |data|.
+//
+// Uses the default compression level.
++ (NSData *)gtm_dataByGzippingData:(NSData *)data;
+
+/// Return an autoreleased NSData w/ the result of gzipping the bytes using |level| compression level.
+//
+// |level| can be 1-9, any other values will be clipped to that range.
++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level;
+
+/// Return an autoreleased NSData w/ the result of gzipping the payload of |data| using |level| compression level.
++ (NSData *)gtm_dataByGzippingData:(NSData *)data
+ compressionLevel:(int)level;
+
+// NOTE: deflate is *NOT* gzip. deflate is a "zlib" stream. pick which one
+// you really want to create. (the inflate api will handle either)
+
+/// Return an autoreleased NSData w/ the result of deflating the bytes.
+//
+// Uses the default compression level.
++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes
+ length:(NSUInteger)length;
+
+/// Return an autoreleased NSData w/ the result of deflating the payload of |data|.
+//
+// Uses the default compression level.
++ (NSData *)gtm_dataByDeflatingData:(NSData *)data;
+
+/// Return an autoreleased NSData w/ the result of deflating the bytes using |level| compression level.
+//
+// |level| can be 1-9, any other values will be clipped to that range.
++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level;
+
+/// Return an autoreleased NSData w/ the result of deflating the payload of |data| using |level| compression level.
++ (NSData *)gtm_dataByDeflatingData:(NSData *)data
+ compressionLevel:(int)level;
+
+
+/// Return an autoreleased NSData w/ the result of decompressing the bytes.
+//
+// The bytes to decompress can be zlib or gzip payloads.
++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes
+ length:(NSUInteger)length;
+
+/// Return an autoreleased NSData w/ the result of decompressing the payload of |data|.
+//
+// The data to decompress can be zlib or gzip payloads.
++ (NSData *)gtm_dataByInflatingData:(NSData *)data;
+
+@end
266 Categories/NSData/GTMNSData+zlib.m
@@ -0,0 +1,266 @@
+//
+// GTMNSData+zlib.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.
+//
+
+#import "GTMNSData+zlib.h"
+#import <zlib.h>
+
+#define kChunkSize 1024
+
+@interface NSData (GTMZlibAdditionsPrivate)
++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level
+ useGzip:(BOOL)useGzip;
+@end
+
+@implementation NSData (GTMZlibAdditionsPrivate)
++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level
+ useGzip:(BOOL)useGzip {
+ if (!bytes || !length) {
+ return nil;
+ }
+
+ // TODO: support 64bit inputs
+ // avail_in is a uInt, so if length > UINT_MAX we actually need to loop
+ // feeding the data until we've gotten it all in. not supporting this
+ // at the moment.
+ NSAssert(length <= UINT_MAX, @"Currently don't support >32bit lengths");
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ // the default value is actually outside the range, so we have to let it
+ // through specifically.
+ } else if (level < Z_BEST_SPEED) {
+ level = Z_BEST_SPEED;
+ } else if (level > Z_BEST_COMPRESSION) {
+ level = Z_BEST_COMPRESSION;
+ }
+
+ z_stream strm;
+ bzero(&strm, sizeof(z_stream));
+
+ int windowBits = 15; // the default
+ int memLevel = 8; // the default
+ if (useGzip) {
+ windowBits += 16; // enable gzip header instead of zlib header
+ }
+ int retCode;
+ if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits,
+ memLevel, Z_DEFAULT_STRATEGY)) != Z_OK) {
+ // COV_NF_START - no real way to force this in a unittest (we guard all args)
+ NSLog(@"Failed to init for deflate w/ level %d, error %d",
+ level, retCode);
+ return nil;
+ // COV_NF_END
+ }
+
+ // hint the size at 1/4 the input size
+ NSMutableData *result = [NSMutableData dataWithCapacity:(length/4)];
+ unsigned char output[kChunkSize];
+
+ // setup the input
+ strm.avail_in = (unsigned int)length;
+ strm.next_in = (unsigned char*)bytes;
+
+ // loop to collect the data
+ do {
+ // update what we're passing in
+ strm.avail_out = kChunkSize;
+ strm.next_out = output;
+ retCode = deflate(&strm, Z_FINISH);
+ if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) {
+ // COV_NF_START - no real way to force this in a unittest
+ // (in inflate, we can feed bogus/truncated data to test, but an error
+ // here would be some internal issue w/in zlib, and there isn't any real
+ // way to test it)
+ NSLog(@"Error trying to deflate some of the payload, error %d",
+ retCode);
+ deflateEnd(&strm);
+ return nil;
+ // COV_NF_END
+ }
+ // collect what we got
+ unsigned gotBack = kChunkSize - strm.avail_out;
+ if (gotBack > 0) {
+ [result appendBytes:output length:gotBack];
+ }
+
+ } while (retCode == Z_OK);
+
+ // if the loop exits, we used all input and the stream ended
+ NSAssert(strm.avail_in == 0,
+ @"thought we finished deflate w/o using all input, %u bytes left",
+ strm.avail_in);
+ NSAssert(retCode == Z_STREAM_END,
+ @"thought we finished deflate w/o getting a result of stream end, code %d",
+ retCode);
+
+ // clean up
+ deflateEnd(&strm);
+
+ return result;
+} // gtm_dataByCompressingBytes:length:compressionLevel:useGzip:
+
+
+@end
+
+
+@implementation NSData (GTMZLibAdditions)
+
++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes
+ length:(NSUInteger)length {
+ return [self gtm_dataByCompressingBytes:bytes
+ length:length
+ compressionLevel:Z_DEFAULT_COMPRESSION
+ useGzip:YES];
+} // gtm_dataByGzippingBytes:length:
+
++ (NSData *)gtm_dataByGzippingData:(NSData *)data {
+ return [self gtm_dataByCompressingBytes:[data bytes]
+ length:[data length]
+ compressionLevel:Z_DEFAULT_COMPRESSION
+ useGzip:YES];
+} // gtm_dataByGzippingData:
+
++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level {
+ return [self gtm_dataByCompressingBytes:bytes
+ length:length
+ compressionLevel:level
+ useGzip:YES];
+} // gtm_dataByGzippingBytes:length:level:
+
++ (NSData *)gtm_dataByGzippingData:(NSData *)data
+ compressionLevel:(int)level {
+ return [self gtm_dataByCompressingBytes:[data bytes]
+ length:[data length]
+ compressionLevel:level
+ useGzip:YES];
+} // gtm_dataByGzippingData:level:
+
++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes
+ length:(NSUInteger)length {
+ return [self gtm_dataByCompressingBytes:bytes
+ length:length
+ compressionLevel:Z_DEFAULT_COMPRESSION
+ useGzip:NO];
+} // gtm_dataByDeflatingBytes:length:
+
++ (NSData *)gtm_dataByDeflatingData:(NSData *)data {
+ return [self gtm_dataByCompressingBytes:[data bytes]
+ length:[data length]
+ compressionLevel:Z_DEFAULT_COMPRESSION
+ useGzip:NO];
+} // gtm_dataByDeflatingData:
+
++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes
+ length:(NSUInteger)length
+ compressionLevel:(int)level {
+ return [self gtm_dataByCompressingBytes:bytes
+ length:length
+ compressionLevel:level
+ useGzip:NO];
+} // gtm_dataByDeflatingBytes:length:level:
+
++ (NSData *)gtm_dataByDeflatingData:(NSData *)data
+ compressionLevel:(int)level {
+ return [self gtm_dataByCompressingBytes:[data bytes]
+ length:[data length]
+ compressionLevel:level
+ useGzip:NO];
+} // gtm_dataByDeflatingData:level:
+
++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes
+ length:(NSUInteger)length {
+ if (!bytes || !length) {
+ return nil;
+ }
+
+ // TODO: support 64bit inputs
+ // avail_in is a uInt, so if length > UINT_MAX we actually need to loop
+ // feeding the data until we've gotten it all in. not supporting this
+ // at the moment.
+ NSAssert(length <= UINT_MAX, @"Currently don't support >32bit lengths");
+
+ z_stream strm;
+ bzero(&strm, sizeof(z_stream));
+
+ // setup the input
+ strm.avail_in = (unsigned int)length;
+ strm.next_in = (unsigned char*)bytes;
+
+ int windowBits = 15; // 15 to enable any window size
+ windowBits += 32; // and +32 to enable zlib or gzip header detection.
+ int retCode;
+ if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) {
+ // COV_NF_START - no real way to force this in a unittest (we guard all args)
+ NSLog(@"Failed to init for inflate, error %d", retCode);
+ return nil;
+ // COV_NF_END
+ }
+
+ // hint the size at 4x the input size
+ NSMutableData *result = [NSMutableData dataWithCapacity:(length*4)];
+ unsigned char output[kChunkSize];
+
+ // loop to collect the data
+ do {
+ // update what we're passing in
+ strm.avail_out = kChunkSize;
+ strm.next_out = output;
+ retCode = inflate(&strm, Z_NO_FLUSH);
+ if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) {
+ NSLog(@"Error trying to inflate some of the payload, error %d",
+ retCode);
+ inflateEnd(&strm);
+ return nil;
+ }
+ // collect what we got
+ unsigned gotBack = kChunkSize - strm.avail_out;
+ if (gotBack > 0) {
+ [result appendBytes:output length:gotBack];
+ }
+
+ } while (retCode == Z_OK);
+
+ // make sure there wasn't more data tacked onto the end of a valid compressed
+ // stream.
+ if (strm.avail_in != 0) {
+ NSLog(@"thought we finished inflate w/o using all input, %u bytes left",
+ strm.avail_in);
+ result = nil;
+ }
+ // the only way out of the loop was by hitting the end of the stream
+ NSAssert(retCode == Z_STREAM_END,
+ @"thought we finished inflate w/o getting a result of stream end, code %d",
+ retCode);
+
+ // clean up
+ inflateEnd(&strm);
+
+ return result;
+} // gtm_dataByInflatingBytes:length:
+
++ (NSData *)gtm_dataByInflatingData:(NSData *)data {
+ return [self gtm_dataByInflatingBytes:[data bytes]
+ length:[data length]];
+} // gtm_dataByInflatingData:
+
+@end
112 Categories/NSData/NSData+CommonCrypto.h
@@ -0,0 +1,112 @@
+/*
+ * NSData+CommonCrypto.h
+ * AQToolkit
+ *
+ * Created by Jim Dovey on 31/8/2008.
+ *
+ * Copyright (c) 2008-2009, Jim Dovey
+ * All rights reserved. (New BSD)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of this project's author nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <Foundation/NSData.h>
+#import <Foundation/NSError.h>
+#import <CommonCrypto/CommonCryptor.h>
+#import <CommonCrypto/CommonHMAC.h>
+
+extern NSString * const kCommonCryptoErrorDomain;
+
+@interface NSError (CommonCryptoErrorDomain)
++ (NSError *) errorWithCCCryptorStatus: (CCCryptorStatus) status;
+@end
+
+@interface NSData (CommonDigest)
+
+- (NSData *) MD2Sum;
+- (NSData *) MD4Sum;
+- (NSData *) MD5Sum;
+
+- (NSData *) SHA1Hash;
+- (NSData *) SHA224Hash;
+- (NSData *) SHA256Hash;
+- (NSData *) SHA384Hash;
+- (NSData *) SHA512Hash;
+
+@end
+
+@interface NSData (CommonCryptor)
+
+- (NSData *) AES256EncryptedDataUsingKey: (id) key error: (NSError **) error;
+- (NSData *) decryptedAES256DataUsingKey: (id) key error: (NSError **) error;
+
+- (NSData *) DESEncryptedDataUsingKey: (id) key error: (NSError **) error;
+- (NSData *) decryptedDESDataUsingKey: (id) key error: (NSError **) error;
+
+- (NSData *) CASTEncryptedDataUsingKey: (id) key error: (NSError **) error;
+- (NSData *) decryptedCASTDataUsingKey: (id) key error: (NSError **) error;
+
+@end
+
+@interface NSData (LowLevelCommonCryptor)
+
+- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ error: (CCCryptorStatus *) error;
+- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ options: (CCOptions) options
+ error: (CCCryptorStatus *) error;
+- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ initializationVector: (id) iv // data or string
+ options: (CCOptions) options
+ error: (CCCryptorStatus *) error;
+
+- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ error: (CCCryptorStatus *) error;
+- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ options: (CCOptions) options
+ error: (CCCryptorStatus *) error;
+- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
+ key: (id) key // data or string
+ initializationVector: (id) iv // data or string
+ options: (CCOptions) options
+ error: (CCCryptorStatus *) error;
+
+@end
+
+@interface NSData (CommonHMAC)
+
+- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm;
+- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm key: (id) key;
+
+@end
541 Categories/NSData/NSData+CommonCrypto.m
@@ -0,0 +1,541 @@
+/*
+ * NSData+CommonCrypto.m
+ * AQToolkit
+ *
+ * Created by Jim Dovey on 31/8/2008.
+ *
+ * Copyright (c) 2008-2009, Jim Dovey
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of this project's author nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "NSData+CommonCrypto.h"
+#import <CommonCrypto/CommonDigest.h>
+#import <CommonCrypto/CommonCryptor.h>
+#import <CommonCrypto/CommonHMAC.h>
+
+NSString * const kCommonCryptoErrorDomain = @"CommonCryptoErrorDomain";
+
+@implementation NSError (CommonCryptoErrorDomain)
+
++ (NSError *) errorWithCCCryptorStatus: (CCCryptorStatus) status
+{
+ NSString * description = nil, * reason = nil;
+
+ switch ( status )
+ {
+ case kCCSuccess:
+ description = NSLocalizedString(@"Success", @"Error description");
+ break;
+
+ case kCCParamError:
+ description = NSLocalizedString(@"Parameter Error", @"Error description");
+ reason = NSLocalizedString(@"Illegal parameter supplied to encryption/decryption algorithm", @"Error reason");
+ break;
+
+ case kCCBufferTooSmall:
+ description = NSLocalizedString(@"Buffer Too Small", @"Error description");
+ reason = NSLocalizedString(@"Insufficient buffer provided for specified operation", @"Error reason");
+ break;
+
+ case kCCMemoryFailure:
+ description = NSLocalizedString(@"Memory Failure", @"Error description");
+ reason = NSLocalizedString(@"Failed to allocate memory", @"Error reason");
+ break;
+
+ case kCCAlignmentError:
+ description = NSLocalizedString(@"Alignment Error", @"Error description");
+ reason = NSLocalizedString(@"Input size to encryption algorithm was not aligned correctly", @"Error reason");
+ break;
+
+ case kCCDecodeError:
+ description = NSLocalizedString(@"Decode Error", @"Error description");
+ reason = NSLocalizedString(@"Input data did not decode or decrypt correctly", @"Error reason");
+ break;
+
+ case kCCUnimplemented:
+ description = NSLocalizedString(@"Unimplemented Function", @"Error description");
+ reason = NSLocalizedString(@"Function not implemented for the current algorithm", @"Error reason");
+ break;
+
+ default:
+ description = NSLocalizedString(@"Unknown Error", @"Error description");
+ break;
+ }
+
+ NSMutableDictionary * userInfo = [[NSMutableDictionary alloc] init];
+ [userInfo setObject: description forKey: NSLocalizedDescriptionKey];
+