설명 없음

AWSCategory.m 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. //
  2. // Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License").
  5. // You may not use this file except in compliance with the License.
  6. // A copy of the License is located at
  7. //
  8. // http://aws.amazon.com/apache2.0
  9. //
  10. // or in the "license" file accompanying this file. This file is distributed
  11. // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. // express or implied. See the License for the specific language governing
  13. // permissions and limitations under the License.
  14. //
  15. #import "AWSCategory.h"
  16. #import <objc/runtime.h>
  17. #import <CommonCrypto/CommonCryptor.h>
  18. #import <CommonCrypto/CommonDigest.h>
  19. #import "AWSCocoaLumberjack.h"
  20. #import "AWSGZIP.h"
  21. #import "AWSMantle.h"
  22. NSString *const AWSDateRFC822DateFormat1 = @"EEE, dd MMM yyyy HH:mm:ss z";
  23. NSString *const AWSDateISO8601DateFormat1 = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
  24. NSString *const AWSDateISO8601DateFormat2 = @"yyyyMMdd'T'HHmmss'Z'";
  25. NSString *const AWSDateISO8601DateFormat3 = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
  26. NSString *const AWSDateShortDateFormat1 = @"yyyyMMdd";
  27. NSString *const AWSDateShortDateFormat2 = @"yyyy-MM-dd";
  28. @interface AWSCategory : NSObject
  29. + (void)loadCategories;
  30. @end
  31. @implementation AWSCategory
  32. + (void)loadCategories {
  33. static dispatch_once_t onceToken;
  34. dispatch_once(&onceToken, ^{
  35. awsgzip_loadGZIP();
  36. awsmtl_loadMTLPredefinedTransformerAdditions();
  37. awsmtl_loadMTLNSCoding();
  38. });
  39. }
  40. @end
  41. @implementation NSDate (AWS)
  42. static NSTimeInterval _clockskew = 0.0;
  43. + (NSDate *)aws_clockSkewFixedDate {
  44. return [[NSDate date] dateByAddingTimeInterval:-1 * _clockskew];
  45. }
  46. + (NSDate *)aws_dateFromString:(NSString *)string {
  47. NSDate *parsedDate = nil;
  48. NSArray *arrayOfDateFormat = @[AWSDateRFC822DateFormat1,
  49. AWSDateISO8601DateFormat1,
  50. AWSDateISO8601DateFormat2,
  51. AWSDateISO8601DateFormat3];
  52. for (NSString *dateFormat in arrayOfDateFormat) {
  53. if (!parsedDate) {
  54. parsedDate = [NSDate aws_dateFromString:string format:dateFormat];
  55. } else {
  56. break;
  57. }
  58. }
  59. return parsedDate;
  60. }
  61. + (NSDate *)aws_dateFromString:(NSString *)string format:(NSString *)dateFormat {
  62. if ([dateFormat isEqualToString:AWSDateRFC822DateFormat1]) {
  63. return [[NSDate aws_RFC822Date1Formatter] dateFromString:string];
  64. }
  65. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat1]) {
  66. return [[NSDate aws_ISO8601Date1Formatter] dateFromString:string];
  67. }
  68. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat2]) {
  69. return [[NSDate aws_ISO8601Date2Formatter] dateFromString:string];
  70. }
  71. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat3]) {
  72. return [[NSDate aws_ISO8601Date3Formatter] dateFromString:string];
  73. }
  74. if ([dateFormat isEqualToString:AWSDateShortDateFormat1]) {
  75. return [[NSDate aws_ShortDateFormat1Formatter] dateFromString:string];
  76. }
  77. if ([dateFormat isEqualToString:AWSDateShortDateFormat2]) {
  78. return [[NSDate aws_ShortDateFormat2Formatter] dateFromString:string];
  79. }
  80. NSDateFormatter *dateFormatter = [NSDateFormatter new];
  81. dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  82. dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  83. dateFormatter.dateFormat = dateFormat;
  84. return [dateFormatter dateFromString:string];
  85. }
  86. - (NSString *)aws_stringValue:(NSString *)dateFormat {
  87. if ([dateFormat isEqualToString:AWSDateRFC822DateFormat1]) {
  88. return [[NSDate aws_RFC822Date1Formatter] stringFromDate:self];
  89. }
  90. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat1]) {
  91. return [[NSDate aws_ISO8601Date1Formatter] stringFromDate:self];
  92. }
  93. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat2]) {
  94. return [[NSDate aws_ISO8601Date2Formatter] stringFromDate:self];
  95. }
  96. if ([dateFormat isEqualToString:AWSDateISO8601DateFormat3]) {
  97. return [[NSDate aws_ISO8601Date3Formatter] stringFromDate:self];
  98. }
  99. if ([dateFormat isEqualToString:AWSDateShortDateFormat1]) {
  100. return [[NSDate aws_ShortDateFormat1Formatter] stringFromDate:self];
  101. }
  102. if ([dateFormat isEqualToString:AWSDateShortDateFormat2]) {
  103. return [[NSDate aws_ShortDateFormat2Formatter] stringFromDate:self];
  104. }
  105. NSDateFormatter *dateFormatter = [NSDateFormatter new];
  106. dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  107. dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  108. dateFormatter.dateFormat = dateFormat;
  109. return [dateFormatter stringFromDate:self];
  110. }
  111. + (NSDateFormatter *)aws_RFC822Date1Formatter {
  112. static NSDateFormatter *_dateFormatter = nil;
  113. static dispatch_once_t onceToken;
  114. dispatch_once(&onceToken, ^{
  115. _dateFormatter = [NSDateFormatter new];
  116. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  117. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  118. _dateFormatter.dateFormat = AWSDateRFC822DateFormat1;
  119. });
  120. return _dateFormatter;
  121. }
  122. + (NSDateFormatter *)aws_ISO8601Date1Formatter {
  123. static NSDateFormatter *_dateFormatter = nil;
  124. static dispatch_once_t onceToken;
  125. dispatch_once(&onceToken, ^{
  126. _dateFormatter = [NSDateFormatter new];
  127. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  128. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  129. _dateFormatter.dateFormat = AWSDateISO8601DateFormat1;
  130. });
  131. return _dateFormatter;
  132. }
  133. + (NSDateFormatter *)aws_ISO8601Date2Formatter {
  134. static NSDateFormatter *_dateFormatter = nil;
  135. static dispatch_once_t onceToken;
  136. dispatch_once(&onceToken, ^{
  137. _dateFormatter = [NSDateFormatter new];
  138. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  139. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  140. _dateFormatter.dateFormat = AWSDateISO8601DateFormat2;
  141. });
  142. return _dateFormatter;
  143. }
  144. + (NSDateFormatter *)aws_ISO8601Date3Formatter {
  145. static NSDateFormatter *_dateFormatter = nil;
  146. static dispatch_once_t onceToken;
  147. dispatch_once(&onceToken, ^{
  148. _dateFormatter = [NSDateFormatter new];
  149. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  150. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  151. _dateFormatter.dateFormat = AWSDateISO8601DateFormat3;
  152. });
  153. return _dateFormatter;
  154. }
  155. + (NSDateFormatter *)aws_ShortDateFormat1Formatter {
  156. static NSDateFormatter *_dateFormatter = nil;
  157. static dispatch_once_t onceToken;
  158. dispatch_once(&onceToken, ^{
  159. _dateFormatter = [NSDateFormatter new];
  160. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  161. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  162. _dateFormatter.dateFormat = AWSDateShortDateFormat1;
  163. });
  164. return _dateFormatter;
  165. }
  166. + (NSDateFormatter *)aws_ShortDateFormat2Formatter {
  167. static NSDateFormatter *_dateFormatter = nil;
  168. static dispatch_once_t onceToken;
  169. dispatch_once(&onceToken, ^{
  170. _dateFormatter = [NSDateFormatter new];
  171. _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
  172. _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  173. _dateFormatter.dateFormat = AWSDateShortDateFormat2;
  174. });
  175. return _dateFormatter;
  176. }
  177. + (void)aws_setRuntimeClockSkew:(NSTimeInterval)clockskew {
  178. @synchronized(self) {
  179. _clockskew = clockskew;
  180. }
  181. }
  182. + (NSTimeInterval)aws_getRuntimeClockSkew {
  183. @synchronized(self) {
  184. return _clockskew;
  185. }
  186. }
  187. @end
  188. @implementation NSDictionary (AWS)
  189. - (NSDictionary *)aws_removeNullValues {
  190. return [self aws_recursivelyRemoveNullEntries:self];
  191. }
  192. - (NSDictionary *)aws_recursivelyRemoveNullEntries:(NSDictionary *)inputDictionary {
  193. NSMutableDictionary *resultMutableDictionary = [NSMutableDictionary new];
  194. for (NSString *key in inputDictionary) {
  195. id value = inputDictionary[key];
  196. if ([value isEqual:[NSNull null]]) {
  197. continue;
  198. }
  199. if([value isKindOfClass:[NSDictionary class]]) {
  200. [resultMutableDictionary setObject:[self aws_recursivelyRemoveNullEntries:value] forKey:key];
  201. } else {
  202. [resultMutableDictionary setObject:value forKey:key];
  203. }
  204. }
  205. return resultMutableDictionary;
  206. }
  207. -(id) aws_objectForCaseInsensitiveKey:(id)aKey {
  208. for (NSString *key in self.allKeys) {
  209. if ([key compare:aKey options:NSCaseInsensitiveSearch] == NSOrderedSame) {
  210. return [self objectForKey:key];
  211. }
  212. }
  213. return nil;
  214. }
  215. @end
  216. @implementation NSJSONSerialization (AWS)
  217. + (NSData *)aws_dataWithJSONObject:(id)obj
  218. options:(NSJSONWritingOptions)opt
  219. error:(NSError **)error {
  220. if (!obj) {
  221. return nil;
  222. }
  223. if ([NSJSONSerialization isValidJSONObject:obj]) {
  224. return [NSJSONSerialization dataWithJSONObject:obj
  225. options:opt
  226. error:error];
  227. } else {
  228. NSData *JSONData = [NSJSONSerialization dataWithJSONObject:@[obj]
  229. options:opt
  230. error:error];
  231. NSString *JSONString = [[NSString alloc] initWithData:JSONData
  232. encoding:NSUTF8StringEncoding];
  233. if ([JSONString length] > 2) {
  234. JSONString = [JSONString substringWithRange:NSMakeRange(1, [JSONString length] - 2)];
  235. return [JSONString dataUsingEncoding:NSUTF8StringEncoding];
  236. } else {
  237. return nil;
  238. }
  239. }
  240. }
  241. @end
  242. @implementation NSNumber (AWS)
  243. + (NSNumber *)aws_numberFromString:(NSString *)string {
  244. static NSNumberFormatter *numberFormatter = nil;
  245. static dispatch_once_t onceToken;
  246. dispatch_once(&onceToken, ^{
  247. numberFormatter = [NSNumberFormatter new];
  248. numberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  249. });
  250. return [numberFormatter numberFromString:string];
  251. }
  252. @end
  253. @implementation NSObject (AWS)
  254. - (NSDictionary *)aws_properties {
  255. NSMutableDictionary *propertyDictionary;
  256. if ([self superclass] != [NSObject class]) {
  257. propertyDictionary = [NSMutableDictionary dictionaryWithDictionary:[[self superclass] aws_properties]];
  258. } else {
  259. propertyDictionary = [NSMutableDictionary dictionary];
  260. }
  261. unsigned int propertyListCount;
  262. objc_property_t *properties = class_copyPropertyList([self class], &propertyListCount);
  263. for(uint32_t i = 0; i < propertyListCount; i++) {
  264. objc_property_t property = properties[i];
  265. const char *propertyName = property_getName(property);
  266. const char *attributes = property_getAttributes(property);
  267. if(propertyName) {
  268. NSString *propertyNameString = [NSString stringWithCString:propertyName
  269. encoding:[NSString defaultCStringEncoding]];
  270. NSString *attributesString = [NSString stringWithCString:attributes
  271. encoding:[NSString defaultCStringEncoding]];
  272. [propertyDictionary setObject:attributesString forKey:propertyNameString];
  273. }
  274. }
  275. free(properties);
  276. return propertyDictionary;
  277. }
  278. - (void)aws_copyPropertiesFromObject:(NSObject *)object {
  279. NSDictionary *propertiesToObject = [self aws_properties];
  280. NSDictionary *propertiesFromObject = [object aws_properties];
  281. for (NSString *key in [propertiesFromObject allKeys]) {
  282. if ([propertiesToObject objectForKey:key]) {
  283. NSString *attributes = [propertiesFromObject valueForKey:key];
  284. /**
  285. * If it's not a readonly property
  286. * Ref. https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW1
  287. */
  288. if ([attributes rangeOfString:@",R,"].location == NSNotFound) {
  289. if (![key isEqualToString:@"uploadProgress"] && ![key isEqualToString:@"downloadProgress"]) {
  290. //do not copy progress block since they do not have getter method and they have already been copied via internalRequest. copy it again will result in overwrite the current value to nil.
  291. [self setValue:[object valueForKey:key]
  292. forKey:key];
  293. }
  294. }
  295. }
  296. }
  297. }
  298. @end
  299. @implementation NSString (AWS)
  300. + (NSString *)aws_base64md5FromData:(NSData *)data {
  301. if([data length] > UINT32_MAX)
  302. {
  303. //The NSData size is too large. The maximum allowable size is UINT32_MAX.
  304. return nil;
  305. }
  306. const void *cStr = [data bytes];
  307. unsigned char result[CC_MD5_DIGEST_LENGTH];
  308. CC_MD5(cStr, (uint32_t)[data length], result);
  309. NSData *md5 = [[NSData alloc] initWithBytes:result length:CC_MD5_DIGEST_LENGTH];
  310. return [md5 base64EncodedStringWithOptions:kNilOptions];
  311. }
  312. - (BOOL)aws_isBase64Data {
  313. if ([self length] % 4 == 0) {
  314. static NSCharacterSet *invertedBase64CharacterSet = nil;
  315. if (invertedBase64CharacterSet == nil) {
  316. invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="] invertedSet];
  317. }
  318. return [self rangeOfCharacterFromSet:invertedBase64CharacterSet
  319. options:NSLiteralSearch].location == NSNotFound;
  320. }
  321. return NO;
  322. }
  323. - (NSString *)aws_stringWithURLEncoding {
  324. #pragma clang diagnostic push
  325. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  326. return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
  327. (__bridge CFStringRef)[self aws_decodeURLEncoding],
  328. NULL,
  329. (CFStringRef)@"!*'\();:@&=+$,/?%#[] ",
  330. kCFStringEncodingUTF8));
  331. #pragma clang diagnostic pop
  332. }
  333. - (NSString *)aws_stringWithURLEncodingPath {
  334. #pragma clang diagnostic push
  335. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  336. return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
  337. (__bridge CFStringRef)[self aws_decodeURLEncoding],
  338. NULL,
  339. (CFStringRef)@"!*'\();:@&=+$,?%#[] ",
  340. kCFStringEncodingUTF8));
  341. #pragma clang diagnostic pop
  342. }
  343. - (NSString *)aws_stringWithURLEncodingPathWithoutPriorDecoding {
  344. #pragma clang diagnostic push
  345. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  346. return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
  347. (__bridge CFStringRef)self,
  348. NULL,
  349. (CFStringRef)@"!*'\();:@&=+$,?%#[] ",
  350. kCFStringEncodingUTF8));
  351. #pragma clang diagnostic pop
  352. }
  353. - (NSString *)aws_decodeURLEncoding {
  354. NSString *result = [self stringByRemovingPercentEncoding];
  355. return result?result:self;
  356. }
  357. - (NSString *)aws_md5String {
  358. NSData *dataString = [self dataUsingEncoding:NSUTF8StringEncoding];
  359. unsigned char digestArray[CC_MD5_DIGEST_LENGTH];
  360. CC_MD5([dataString bytes], (CC_LONG)[dataString length], digestArray);
  361. NSMutableString *md5String = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  362. for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
  363. [md5String appendFormat:@"%02x", digestArray[i]];
  364. }
  365. return md5String;
  366. }
  367. - (NSString *)aws_md5StringLittleEndian {
  368. NSData *dataString = [self dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
  369. unsigned char digestArray[CC_MD5_DIGEST_LENGTH];
  370. CC_MD5([dataString bytes], (CC_LONG)[dataString length], digestArray);
  371. NSMutableString *md5String = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  372. for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
  373. [md5String appendFormat:@"%02x", digestArray[i]];
  374. }
  375. return md5String;
  376. }
  377. - (BOOL)aws_isDNSBucketName {
  378. if ([self length] < 3 || [self length] > 63) {
  379. return NO;
  380. }
  381. if ([self hasSuffix:@"-"]) {
  382. return NO;
  383. }
  384. if ([self aws_contains:@"_"]) {
  385. return NO;
  386. }
  387. if ([self aws_contains:@"-."] || [self aws_contains:@".-"]) {
  388. return NO;
  389. }
  390. if ([[self lowercaseString] isEqualToString:self] == NO) {
  391. return NO;
  392. }
  393. return YES;
  394. }
  395. - (BOOL)aws_isVirtualHostedStyleCompliant {
  396. if (![self aws_isDNSBucketName]) {
  397. return NO;
  398. } else {
  399. return ![self aws_contains:@"."];
  400. }
  401. }
  402. - (AWSRegionType)aws_regionTypeValue {
  403. if ([self isEqualToString:@"AWSRegionUSEast1"]
  404. || [self isEqualToString:@"USEast1"]
  405. || [self isEqualToString:@"us-east-1"]) {
  406. return AWSRegionUSEast1;
  407. }
  408. if ([self isEqualToString:@"AWSRegionUSEast2"]
  409. || [self isEqualToString:@"USEast2"]
  410. || [self isEqualToString:@"us-east-2"]) {
  411. return AWSRegionUSEast2;
  412. }
  413. if ([self isEqualToString:@"AWSRegionUSWest1"]
  414. || [self isEqualToString:@"USWest1"]
  415. || [self isEqualToString:@"us-west-1"]) {
  416. return AWSRegionUSWest1;
  417. }
  418. if ([self isEqualToString:@"AWSRegionUSWest2"]
  419. || [self isEqualToString:@"USWest2"]
  420. || [self isEqualToString:@"us-west-2"]) {
  421. return AWSRegionUSWest2;
  422. }
  423. if ([self isEqualToString:@"AWSRegionEUWest1"]
  424. || [self isEqualToString:@"EUWest1"]
  425. || [self isEqualToString:@"eu-west-1"]) {
  426. return AWSRegionEUWest1;
  427. }
  428. if ([self isEqualToString:@"AWSRegionEUWest2"]
  429. || [self isEqualToString:@"EUWest2"]
  430. || [self isEqualToString:@"eu-west-2"]) {
  431. return AWSRegionEUWest2;
  432. }
  433. if ([self isEqualToString:@"AWSRegionEUCentral1"]
  434. || [self isEqualToString:@"EUCentral1"]
  435. || [self isEqualToString:@"eu-central-1"]) {
  436. return AWSRegionEUCentral1;
  437. }
  438. if ([self isEqualToString:@"AWSRegionAPNortheast1"]
  439. || [self isEqualToString:@"APNortheast1"]
  440. || [self isEqualToString:@"ap-northeast-1"]) {
  441. return AWSRegionAPNortheast1;
  442. }
  443. if ([self isEqualToString:@"AWSRegionAPNortheast2"]
  444. || [self isEqualToString:@"APNortheast2"]
  445. || [self isEqualToString:@"ap-northeast-2"]) {
  446. return AWSRegionAPNortheast2;
  447. }
  448. if ([self isEqualToString:@"AWSRegionAPSoutheast1"]
  449. || [self isEqualToString:@"APSoutheast1"]
  450. || [self isEqualToString:@"ap-southeast-1"]) {
  451. return AWSRegionAPSoutheast1;
  452. }
  453. if ([self isEqualToString:@"AWSRegionAPSoutheast2"]
  454. || [self isEqualToString:@"APSoutheast2"]
  455. || [self isEqualToString:@"ap-southeast-2"]) {
  456. return AWSRegionAPSoutheast2;
  457. }
  458. if ([self isEqualToString:@"AWSRegionAPSouth1"]
  459. || [self isEqualToString:@"APSouth1"]
  460. || [self isEqualToString:@"ap-south-1"]) {
  461. return AWSRegionAPSouth1;
  462. }
  463. if ([self isEqualToString:@"AWSRegionSAEast1"]
  464. || [self isEqualToString:@"SAEast1"]
  465. || [self isEqualToString:@"sa-east-1"]) {
  466. return AWSRegionSAEast1;
  467. }
  468. if ([self isEqualToString:@"AWSRegionCACentral1"]
  469. || [self isEqualToString:@"CACentral1"]
  470. || [self isEqualToString:@"ca-central-1"]) {
  471. return AWSRegionCACentral1;
  472. }
  473. if ([self isEqualToString:@"AWSRegionUSGovWest1"]
  474. || [self isEqualToString:@"USGovWest1"]
  475. || [self isEqualToString:@"us-gov-west-1"]) {
  476. return AWSRegionUSGovWest1;
  477. }
  478. if ([self isEqualToString:@"AWSRegionCNNorth1"]
  479. || [self isEqualToString:@"CNNorth1"]
  480. || [self isEqualToString:@"cn-north-1"]) {
  481. return AWSRegionCNNorth1;
  482. }
  483. if ([self isEqualToString:@"AWSRegionCNNorthWest1"]
  484. || [self isEqualToString:@"CNNorthWest1"]
  485. || [self isEqualToString:@"cn-northwest-1"]) {
  486. return AWSRegionCNNorthWest1;
  487. }
  488. if ([self isEqualToString:@"AWSRegionEUWest3"]
  489. || [self isEqualToString:@"EUWest3"]
  490. || [self isEqualToString:@"eu-west-3"]) {
  491. return AWSRegionEUWest3;
  492. }
  493. if ([self isEqualToString:@"AWSRegionUSGovEast1"]
  494. || [self isEqualToString:@"USGovEast1"]
  495. || [self isEqualToString:@"us-gov-east-1"]) {
  496. return AWSRegionUSGovEast1;
  497. }
  498. if ([self isEqualToString:@"AWSRegionEUNorth1"]
  499. || [self isEqualToString:@"EUNorth1"]
  500. || [self isEqualToString:@"eu-north-1"]) {
  501. return AWSRegionEUNorth1;
  502. }
  503. return AWSRegionUnknown;
  504. }
  505. - (BOOL)aws_contains:(NSString *)searchString {
  506. NSRange range = [self rangeOfString:searchString];
  507. return (range.location != NSNotFound);
  508. }
  509. @end
  510. @implementation NSFileManager (AWS)
  511. - (BOOL)aws_atomicallyCopyItemAtURL:(NSURL *)sourceURL
  512. toURL:(NSURL *)destinationURL
  513. backupItemName:(NSString *)backupItemName
  514. error:(NSError **)outError {
  515. NSURL *tempDir = [self URLForDirectory:NSItemReplacementDirectory
  516. inDomain:NSUserDomainMask
  517. appropriateForURL:destinationURL
  518. create:YES
  519. error:outError];
  520. if (!tempDir) return NO;
  521. NSURL *tempURL = [tempDir URLByAppendingPathComponent:[destinationURL lastPathComponent]];
  522. BOOL result = [self copyItemAtURL:sourceURL toURL:tempURL error:outError];
  523. if (result) {
  524. result = [self replaceItemAtURL:destinationURL
  525. withItemAtURL:tempURL
  526. backupItemName:backupItemName
  527. options:NSFileManagerItemReplacementUsingNewMetadataOnly
  528. resultingItemURL:nil
  529. error:outError];
  530. if (NO == result) {
  531. if (backupItemName) {
  532. NSURL *backupItemURL = [[destinationURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:backupItemName];
  533. NSError *error = nil;
  534. BOOL success = [self replaceItemAtURL:destinationURL
  535. withItemAtURL:backupItemURL
  536. backupItemName:nil
  537. options:NSFileManagerItemReplacementUsingNewMetadataOnly
  538. resultingItemURL:nil error:&error];
  539. if (NO == success) {
  540. if (error) {
  541. AWSDDLogError(@"Failed to move backupItemURL directory(%@) to destinationURL(%@): %@" ,backupItemURL,destinationURL,error);
  542. }
  543. if ([self fileExistsAtPath:[destinationURL path]]) {
  544. NSError *removeError = nil;
  545. if (NO == [self removeItemAtURL:destinationURL error:&removeError]) {
  546. AWSDDLogError(@"Failed to remove destinationURL(%@): %@",destinationURL,removeError);
  547. }
  548. }
  549. }
  550. }
  551. }
  552. }
  553. NSError *error;
  554. if (![self removeItemAtURL:tempDir error:&error])
  555. {
  556. AWSDDLogError(@"Failed to remove temp(%@) directory after atomic copy: %@",tempDir,error);
  557. }
  558. return result;
  559. }
  560. @end