diff options
-rw-r--r-- | Foundation/GTMNSData+Hex.h | 37 | ||||
-rw-r--r-- | Foundation/GTMNSData+Hex.m | 102 | ||||
-rw-r--r-- | Foundation/GTMNSData+HexTest.m | 58 | ||||
-rw-r--r-- | Foundation/GTMNSDictionary+CaseInsensitive.h | 42 | ||||
-rw-r--r-- | Foundation/GTMNSDictionary+CaseInsensitive.m | 116 | ||||
-rw-r--r-- | Foundation/GTMNSDictionary+CaseInsensitiveTest.m | 119 | ||||
-rw-r--r-- | GTM.xcodeproj/project.pbxproj | 24 | ||||
-rw-r--r-- | GTMiPhone.xcodeproj/project.pbxproj | 20 | ||||
-rw-r--r-- | ReleaseNotes.txt | 3 |
9 files changed, 521 insertions, 0 deletions
diff --git a/Foundation/GTMNSData+Hex.h b/Foundation/GTMNSData+Hex.h new file mode 100644 index 0000000..b1e668d --- /dev/null +++ b/Foundation/GTMNSData+Hex.h @@ -0,0 +1,37 @@ +// +// GTMNSData+Hex.h +// +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + +/// Helpers for dealing w/ hex encoded strings. +@interface NSData (GTMHexAdditions) + +/// Return an autoreleased NSData w/ the result of decoding |hexString| to +/// binary data. +/// +/// Will return |nil| if |hexString| contains any non-hex characters (i.e. +/// 0-9, a-f, A-F) or if the length of |hexString| is not cleanly divisible by +/// two. +/// Leading 0x prefix is not supported and will result in a |nil| return value. ++ (NSData *)gtm_dataWithHexString:(NSString *)hexString; + +/// Return an autoreleased NSString w/ the result of encoding the NSData bytes +/// as hex. No leading 0x prefix is included. +- (NSString *)gtm_hexString; + +@end diff --git a/Foundation/GTMNSData+Hex.m b/Foundation/GTMNSData+Hex.m new file mode 100644 index 0000000..c7e740d --- /dev/null +++ b/Foundation/GTMNSData+Hex.m @@ -0,0 +1,102 @@ +// +// GTMNSData+Hex.m +// +// Copyright 2009 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+Hex.h" +#import "GTMDefines.h" + +@implementation NSData (GTMHexAdditions) + ++ (NSData *)gtm_dataWithHexString:(NSString *)hexString { + NSData *hexData = [hexString dataUsingEncoding:NSASCIIStringEncoding]; + const char *hexBuf = [hexData bytes]; + NSUInteger hexLen = [hexData length]; + + // This indicates an error converting to ASCII. + if (hexString && !hexData) { + return nil; + } + + if ((hexLen % 2) != 0) { + return nil; + } + + NSMutableData *binaryData = [NSMutableData dataWithLength:(hexLen / 2)]; + unsigned char *binaryPtr = [binaryData mutableBytes]; + unsigned char value = 0; + for (NSUInteger i = 0; i < hexLen; i++) { + char c = hexBuf[i]; + + if (!isxdigit(c)) { + return nil; + } + + if (isdigit(c)) { + value += c - '0'; + } else if (islower(c)) { + value += 10 + c - 'a'; + } else { + value += 10 + c - 'A'; + } + + if (i & 1) { + *binaryPtr++ = value; + value = 0; + } else { + value <<= 4; + } + } + + return [NSData dataWithData:binaryData]; +} + +- (NSString *)gtm_hexString { + static const char kHexTable[] = + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + + const unsigned char *binaryPtr = [self bytes]; + NSUInteger binaryLen = [self length]; + + NSMutableData *hexData = [NSMutableData dataWithLength:(2 * binaryLen)]; + char *hexPtr = [hexData mutableBytes]; + + for (NSUInteger i = 0; i < binaryLen; i++) { + *hexPtr++ = kHexTable[(*binaryPtr)*2]; + *hexPtr++ = kHexTable[(*binaryPtr)*2 + 1]; + ++binaryPtr; + } + + return [[[NSString alloc] initWithData:hexData + encoding:NSASCIIStringEncoding] autorelease]; +} + +@end diff --git a/Foundation/GTMNSData+HexTest.m b/Foundation/GTMNSData+HexTest.m new file mode 100644 index 0000000..6bc1608 --- /dev/null +++ b/Foundation/GTMNSData+HexTest.m @@ -0,0 +1,58 @@ +// +// GTMNSData+HexTest.m +// +// Copyright 2009 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 "GTMSenTestCase.h" +#import "GTMNSData+Hex.h" + +@interface GTMNSData_HexTest : GTMTestCase +@end + +@implementation GTMNSData_HexTest + +- (void)testNSDataHexAdditions { + NSString *testString = @"1c2f0032f40123456789abcdef"; + char testBytes[] = { 0x1c, 0x2f, 0x00, 0x32, 0xf4, 0x01, 0x23, + 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + NSData *testData = [NSData dataWithBytes:testBytes length:sizeof(testBytes)]; + + STAssertTrue([[testData gtm_hexString] isEqual:testString], + @"gtm_hexString doesn't encode as expected"); + + STAssertEqualStrings([[NSData data] gtm_hexString], @"", + @"gtm_hexString empty data should return empty string"); + + STAssertTrue([[NSData gtm_dataWithHexString:testString] isEqual:testData], + @"gtm_dataWithHexString: doesn't decode as expected"); + + STAssertNil([NSData gtm_dataWithHexString:@"1c2f003"], + @"gtm_dataWithHexString: parsed hex from an odd size string"); + + STAssertNil([NSData gtm_dataWithHexString:@"1c2f00ft"], + @"gtm_dataWithHexString: parsed hex from a non hex string"); + + STAssertNil([NSData gtm_dataWithHexString:@"abcdéf"], + @"gtm_dataWithHexString: parsed a non-ASCII character"); + + STAssertNotNil([NSData gtm_dataWithHexString:@""], + @"gtm_dataWithHexString: empty input resulted in nil output"); + + STAssertNotNil([NSData gtm_dataWithHexString:nil], + @"gtm_dataWithHexString: nil input resulted in nil output"); +} + +@end diff --git a/Foundation/GTMNSDictionary+CaseInsensitive.h b/Foundation/GTMNSDictionary+CaseInsensitive.h new file mode 100644 index 0000000..a31e81c --- /dev/null +++ b/Foundation/GTMNSDictionary+CaseInsensitive.h @@ -0,0 +1,42 @@ +// +// GTMNSDictionary+CaseInsensitive.h +// +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + +/// Utility for building case-insensitive NSDictionary objects. +@interface NSDictionary (GTMNSDictionaryCaseInsensitiveAdditions) + +/// Initializes an NSDictionary with a case-insensitive comparison function +/// for NSString keys, while non-NSString keys are treated normally. +/// +/// The case for NSString keys is preserved, though duplicate keys (when +/// compared in a case-insensitive fashion) have one of their values dropped +/// arbitrarily. +/// +/// An example of use with HTTP headers in an NSHTTPURLResponse object: +/// +/// NSDictionary *headers = +/// [NSDictionary gtm_dictionaryWithDictionaryCaseInsensitive: +/// [response allHeaderFields]]; +/// NSString *contentType = [headers objectForKey:@"Content-Type"]; +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary; + +/// Returns a newly created and autoreleased NSDictionary object as above. ++ (id)gtm_dictionaryWithDictionaryCaseInsensitive:(NSDictionary *)dictionary; + +@end diff --git a/Foundation/GTMNSDictionary+CaseInsensitive.m b/Foundation/GTMNSDictionary+CaseInsensitive.m new file mode 100644 index 0000000..96494c2 --- /dev/null +++ b/Foundation/GTMNSDictionary+CaseInsensitive.m @@ -0,0 +1,116 @@ +// +// GTMNSDictionary+CaseInsensitive.m +// +// Copyright 2009 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 "GTMNSDictionary+CaseInsensitive.h" +#import "GTMDefines.h" +#import <CoreFoundation/CoreFoundation.h> + +@interface NSMutableDictionary (GTMNSMutableDictionaryCaseInsensitiveAdditions) + +// Returns a mutable equivalent to GTMNSDictionaryCaseInsensitiveAdditions. +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary; + +@end + +static Boolean CaseInsensitiveEqualCallback(const void *a, const void *b) { + id idA = (id)a; + id idB = (id)b; + Boolean ret = FALSE; + if ([idA isKindOfClass:[NSString class]] && + [idB isKindOfClass:[NSString class]]) { + ret = ([idA compare:idB options:NSCaseInsensitiveSearch|NSLiteralSearch] + == NSOrderedSame); + } else { + ret = [idA isEqual:idB]; + } + return ret; +} + +static CFHashCode CaseInsensitiveHashCallback(const void *value) { + id idValue = (id)value; + CFHashCode ret = 0; + if ([idValue isKindOfClass:[NSString class]]) { + ret = [[idValue lowercaseString] hash]; + } else { + ret = [idValue hash]; + } + return ret; +} + +@implementation NSDictionary (GTMNSDictionaryCaseInsensitiveAdditions) + +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + [self release]; + self = nil; + + CFIndex count = 0; + void *keys = NULL; + void *values = NULL; + + if (dictionary) { + count = CFDictionaryGetCount((CFDictionaryRef)dictionary); + + if (count) { + keys = malloc(count * sizeof(void *)); + values = malloc(count * sizeof(void *)); + if (!keys || !values) { + free(keys); + free(values); + return self; + } + + CFDictionaryGetKeysAndValues((CFDictionaryRef)dictionary, keys, values); + } + } + + CFDictionaryKeyCallBacks keyCallbacks = kCFCopyStringDictionaryKeyCallBacks; + _GTMDevAssert(keyCallbacks.version == 0, + @"CFDictionaryKeyCallBacks structure updated"); + keyCallbacks.equal = CaseInsensitiveEqualCallback; + keyCallbacks.hash = CaseInsensitiveHashCallback; + + self = (id)CFDictionaryCreate(kCFAllocatorDefault, + keys, values, count, &keyCallbacks, + &kCFTypeDictionaryValueCallBacks); + + free(keys); + free(values); + + return self; +} + ++ (id)gtm_dictionaryWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + return [[[self alloc] + gtm_initWithDictionaryCaseInsensitive:dictionary] autorelease]; +} + +@end + +@implementation NSMutableDictionary (GTMNSMutableDictionaryCaseInsensitiveAdditions) + +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + if ((self = [super gtm_initWithDictionaryCaseInsensitive:dictionary])) { + id copy = (id)CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, + (CFDictionaryRef)self); + [self release]; + self = copy; + } + return self; +} + +@end diff --git a/Foundation/GTMNSDictionary+CaseInsensitiveTest.m b/Foundation/GTMNSDictionary+CaseInsensitiveTest.m new file mode 100644 index 0000000..67584ff --- /dev/null +++ b/Foundation/GTMNSDictionary+CaseInsensitiveTest.m @@ -0,0 +1,119 @@ +// +// GTMNSDictionary+CaseInsensitiveTest.m +// +// Copyright 2009 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 "GTMSenTestCase.h" +#import "GTMNSDictionary+CaseInsensitive.h" + +@interface GTMNSDictionary_CaseInsensitiveTest : GTMTestCase +@end + +@implementation GTMNSDictionary_CaseInsensitiveTest + +- (void)testNSDictionaryCaseInsensitiveAdditions { + NSURL *objKey = [NSURL URLWithString:@"http://WWW.Google.COM/"]; + NSURL *lcObjKey = [NSURL URLWithString:[[objKey absoluteString] + lowercaseString]]; + + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: + @"value", @"key", + @"value", @"KEY", + @"bar", @"FOO", + @"yes", objKey, + nil]; + + NSDictionary *ciDict = + [NSDictionary gtm_dictionaryWithDictionaryCaseInsensitive:dict]; + + STAssertNotNil(ciDict, @"gtm_dictionaryWithDictionaryCaseInsensitive failed"); + + STAssertTrue([ciDict count] == 3, + @"wrong count, multiple 'key' entries should be folded."); + + STAssertEqualStrings([ciDict objectForKey:@"foo"], @"bar", + @"case insensitive key lookup failed"); + + STAssertEqualStrings([ciDict objectForKey:@"kEy"], @"value", + @"case insensitive key lookup failed"); + + STAssertNotNil([ciDict objectForKey:objKey], + @"exact matches on non-NSString objects should still work."); + + STAssertNil([ciDict objectForKey:lcObjKey], + @"only NSString and subclasses are case-insensitive."); + + STAssertNotNil([NSDictionary gtm_dictionaryWithDictionaryCaseInsensitive: + [NSDictionary dictionary]], + @"empty dictionary should not return nil"); + + STAssertNotNil([NSDictionary gtm_dictionaryWithDictionaryCaseInsensitive: + nil], + @"nil dictionary should return empty dictionary"); + + STAssertNotNil([[[NSDictionary alloc] gtm_initWithDictionaryCaseInsensitive: + nil] autorelease], + @"nil dictionary should return empty dictionary"); +} + +- (void)testNSMutableDictionaryCaseInsensitiveAdditions { + NSURL *objKey = [NSURL URLWithString:@"http://WWW.Google.COM/"]; + NSURL *lcObjKey = [NSURL URLWithString:[[objKey absoluteString] + lowercaseString]]; + + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: + @"value", @"key", + @"value", @"KEY", + @"bar", @"FOO", + @"yes", objKey, + nil]; + + NSMutableDictionary *ciDict = + [NSMutableDictionary gtm_dictionaryWithDictionaryCaseInsensitive:dict]; + + STAssertNotNil(ciDict, @"gtm_dictionaryWithDictionaryCaseInsensitive failed"); + + STAssertTrue([ciDict count] == 3, + @"wrong count, multiple 'key' entries should be folded."); + + STAssertEqualStrings([ciDict objectForKey:@"foo"], @"bar", + @"case insensitive key lookup failed"); + + STAssertEqualStrings([ciDict objectForKey:@"kEy"], @"value", + @"case insensitive key lookup failed"); + + STAssertNotNil([ciDict objectForKey:objKey], + @"exact matches on non-NSString objects should still work."); + + STAssertNil([ciDict objectForKey:lcObjKey], + @"only NSString and subclasses are case-insensitive."); + + NSObject *obj = [[[NSObject alloc] init] autorelease]; + [ciDict setObject:obj forKey:@"kEy"]; + STAssertEquals([ciDict objectForKey:@"key"], obj, + @"mutable dictionary value not overwritten"); + + STAssertNotNil( + [NSMutableDictionary gtm_dictionaryWithDictionaryCaseInsensitive: + [NSDictionary dictionary]], + @"empty dictionary should not return nil"); + + STAssertNotNil( + [NSMutableDictionary gtm_dictionaryWithDictionaryCaseInsensitive:nil], + @"nil dictionary should return empty dictionary"); +} + +@end diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj index f2cb27b..18f50c1 100644 --- a/GTM.xcodeproj/project.pbxproj +++ b/GTM.xcodeproj/project.pbxproj @@ -34,6 +34,12 @@ /* End PBXAppleScriptBuildPhase section */ /* Begin PBXBuildFile section */ + 0BFAD4C5104D06EF002BEB27 /* GTMNSData+Hex.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BFAD4BF104D06EF002BEB27 /* GTMNSData+Hex.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0BFAD4C6104D06EF002BEB27 /* GTMNSData+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BFAD4C0104D06EF002BEB27 /* GTMNSData+Hex.m */; }; + 0BFAD4C8104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BFAD4C2104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0BFAD4C9104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BFAD4C3104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m */; }; + 0BFAD4CB104D06FE002BEB27 /* GTMNSData+HexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BFAD4C1104D06EF002BEB27 /* GTMNSData+HexTest.m */; }; + 0BFAD4CC104D06FE002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BFAD4C4104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m */; }; 1012DF560F4252BD004794DB /* GTMAbstractDOListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 1012DF540F4252BD004794DB /* GTMAbstractDOListener.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1012DF570F4252BD004794DB /* GTMAbstractDOListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 1012DF550F4252BD004794DB /* GTMAbstractDOListener.m */; }; 1012DF5A0F425525004794DB /* GTMAbstractDOListenerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1012DF590F425525004794DB /* GTMAbstractDOListenerTest.m */; }; @@ -388,6 +394,12 @@ /* Begin PBXFileReference section */ 0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; }; 0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; }; + 0BFAD4BF104D06EF002BEB27 /* GTMNSData+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSData+Hex.h"; sourceTree = "<group>"; }; + 0BFAD4C0104D06EF002BEB27 /* GTMNSData+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSData+Hex.m"; sourceTree = "<group>"; }; + 0BFAD4C1104D06EF002BEB27 /* GTMNSData+HexTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSData+HexTest.m"; sourceTree = "<group>"; }; + 0BFAD4C2104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSDictionary+CaseInsensitive.h"; sourceTree = "<group>"; }; + 0BFAD4C3104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSDictionary+CaseInsensitive.m"; sourceTree = "<group>"; }; + 0BFAD4C4104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSDictionary+CaseInsensitiveTest.m"; sourceTree = "<group>"; }; 1012DF540F4252BD004794DB /* GTMAbstractDOListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMAbstractDOListener.h; sourceTree = "<group>"; }; 1012DF550F4252BD004794DB /* GTMAbstractDOListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMAbstractDOListener.m; sourceTree = "<group>"; }; 1012DF590F425525004794DB /* GTMAbstractDOListenerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMAbstractDOListenerTest.m; sourceTree = "<group>"; }; @@ -1040,6 +1052,12 @@ F48FE2720D198CCE009257D2 /* Foundation */ = { isa = PBXGroup; children = ( + 0BFAD4BF104D06EF002BEB27 /* GTMNSData+Hex.h */, + 0BFAD4C0104D06EF002BEB27 /* GTMNSData+Hex.m */, + 0BFAD4C1104D06EF002BEB27 /* GTMNSData+HexTest.m */, + 0BFAD4C2104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h */, + 0BFAD4C3104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m */, + 0BFAD4C4104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m */, F95B567B0F46208E0051A6F1 /* GTMSQLite.h */, F95B567C0F46208E0051A6F1 /* GTMSQLite.m */, F95B567D0F46208E0051A6F1 /* GTMSQLiteTest.m */, @@ -1248,6 +1266,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 0BFAD4C5104D06EF002BEB27 /* GTMNSData+Hex.h in Headers */, + 0BFAD4C8104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h in Headers */, F93207DE0F4B82DB005F37EA /* GTMSQLite.h in Headers */, F42E09490D199BBF00D5DDE0 /* GTMDelegatingTableColumn.h in Headers */, F42E094B0D199BBF00D5DDE0 /* GTMGarbageCollection.h in Headers */, @@ -1778,6 +1798,8 @@ 108930850F4CCB380018D4A0 /* GTMTransientRootPortProxyTest.m in Sources */, 8BD35B940FB22986009058F5 /* GTMNSScanner+JSONTest.m in Sources */, 8BF4D2E80FC70751009ABC3F /* GTMGoogleSearchTest.m in Sources */, + 0BFAD4CB104D06FE002BEB27 /* GTMNSData+HexTest.m in Sources */, + 0BFAD4CC104D06FE002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1846,6 +1868,8 @@ 8BF4D2E70FC7073A009ABC3F /* GTMGoogleSearch.m in Sources */, 8207B89C0FEA7AA1008A527B /* GTMWindowSheetController.m in Sources */, F43C7A581021FAA300ABF03C /* GTMUILocalizerAndLayoutTweaker.m in Sources */, + 0BFAD4C6104D06EF002BEB27 /* GTMNSData+Hex.m in Sources */, + 0BFAD4C9104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/GTMiPhone.xcodeproj/project.pbxproj b/GTMiPhone.xcodeproj/project.pbxproj index aad11ef..1d4d425 100644 --- a/GTMiPhone.xcodeproj/project.pbxproj +++ b/GTMiPhone.xcodeproj/project.pbxproj @@ -21,6 +21,10 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 0B859D9F104D08160064FE46 /* GTMNSData+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B859D9A104D08050064FE46 /* GTMNSData+Hex.m */; }; + 0B859DA0104D08160064FE46 /* GTMNSData+HexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B859D9B104D08050064FE46 /* GTMNSData+HexTest.m */; }; + 0B859DA1104D08160064FE46 /* GTMNSDictionary+CaseInsensitive.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B859D9D104D08050064FE46 /* GTMNSDictionary+CaseInsensitive.m */; }; + 0B859DA2104D08160064FE46 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B859D9E104D08050064FE46 /* GTMNSDictionary+CaseInsensitiveTest.m */; }; 13C1ED4F104896C900907CD8 /* GTMUIView+SubtreeDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C1ED4C104896C900907CD8 /* GTMUIView+SubtreeDescription.m */; }; 13C1ED50104896C900907CD8 /* GTMUIView+SubtreeDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C1ED4D104896C900907CD8 /* GTMUIView+SubtreeDescriptionTest.m */; }; 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; }; @@ -134,6 +138,12 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0B859D99104D08050064FE46 /* GTMNSData+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSData+Hex.h"; sourceTree = "<group>"; }; + 0B859D9A104D08050064FE46 /* GTMNSData+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSData+Hex.m"; sourceTree = "<group>"; }; + 0B859D9B104D08050064FE46 /* GTMNSData+HexTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSData+HexTest.m"; sourceTree = "<group>"; }; + 0B859D9C104D08050064FE46 /* GTMNSDictionary+CaseInsensitive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSDictionary+CaseInsensitive.h"; sourceTree = "<group>"; }; + 0B859D9D104D08050064FE46 /* GTMNSDictionary+CaseInsensitive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSDictionary+CaseInsensitive.m"; sourceTree = "<group>"; }; + 0B859D9E104D08050064FE46 /* GTMNSDictionary+CaseInsensitiveTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSDictionary+CaseInsensitiveTest.m"; sourceTree = "<group>"; }; 13C1ED4C104896C900907CD8 /* GTMUIView+SubtreeDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMUIView+SubtreeDescription.m"; sourceTree = "<group>"; }; 13C1ED4D104896C900907CD8 /* GTMUIView+SubtreeDescriptionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMUIView+SubtreeDescriptionTest.m"; sourceTree = "<group>"; }; 13C1ED4E104896C900907CD8 /* GTMUIView+SubtreeDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMUIView+SubtreeDescription.h"; sourceTree = "<group>"; }; @@ -390,6 +400,12 @@ 8BC047760DAE928A00C2D1CA /* Foundation */ = { isa = PBXGroup; children = ( + 0B859D99104D08050064FE46 /* GTMNSData+Hex.h */, + 0B859D9A104D08050064FE46 /* GTMNSData+Hex.m */, + 0B859D9B104D08050064FE46 /* GTMNSData+HexTest.m */, + 0B859D9C104D08050064FE46 /* GTMNSDictionary+CaseInsensitive.h */, + 0B859D9D104D08050064FE46 /* GTMNSDictionary+CaseInsensitive.m */, + 0B859D9E104D08050064FE46 /* GTMNSDictionary+CaseInsensitiveTest.m */, F439ADE80DBD3C0000BE9B91 /* GTMBase64.h */, F439ADE90DBD3C0000BE9B91 /* GTMBase64.m */, F439ADEA0DBD3C0000BE9B91 /* GTMBase64Test.m */, @@ -746,6 +762,10 @@ 64D0F5C90FD3E65C00506CC7 /* GTMUIImage+Resize.m in Sources */, 13C1ED4F104896C900907CD8 /* GTMUIView+SubtreeDescription.m in Sources */, 13C1ED50104896C900907CD8 /* GTMUIView+SubtreeDescriptionTest.m in Sources */, + 0B859D9F104D08160064FE46 /* GTMNSData+Hex.m in Sources */, + 0B859DA0104D08160064FE46 /* GTMNSData+HexTest.m in Sources */, + 0B859DA1104D08160064FE46 /* GTMNSDictionary+CaseInsensitive.m in Sources */, + 0B859DA2104D08160064FE46 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index e4da8c8..1e9a1ae 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -328,6 +328,9 @@ Changes since 1.5.1 SDK from compile time. Also removed some of the formatting options so try and make it simpler to follow. +- Added GTMNSDictionary+CaseInsensitive, e.g. for use with HTTP headers. + +- Added GTMNSData+Hex for conversion to and from hex strings. Release 1.5.1 Changes since 1.5.0 |