aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Foundation/GTMBase64.h189
-rw-r--r--Foundation/GTMBase64.m692
-rw-r--r--Foundation/GTMBase64Test.m437
-rw-r--r--Foundation/GTMHTTPFetcher.h22
-rw-r--r--Foundation/GTMHTTPServer.h144
-rw-r--r--Foundation/GTMHTTPServer.m624
-rw-r--r--Foundation/GTMHTTPServerTest.m652
-rw-r--r--Foundation/GTMNSData+Hex.h43
-rw-r--r--Foundation/GTMNSData+Hex.m102
-rw-r--r--Foundation/GTMNSData+HexTest.m58
-rw-r--r--GTM.xcodeproj/project.pbxproj42
-rw-r--r--GTMiPhone.xcodeproj/project.pbxproj36
-rw-r--r--ReleaseNotes.txt13
-rw-r--r--UnitTesting/GTMTestHTTPServer.h39
-rw-r--r--UnitTesting/GTMTestHTTPServer.m166
-rw-r--r--iPhone/GTMABAddressBook.h328
-rw-r--r--iPhone/GTMABAddressBook.m901
-rw-r--r--iPhone/GTMABAddressBook.stringsbin1428 -> 0 bytes
-rw-r--r--iPhone/GTMABAddressBookTest.m608
19 files changed, 13 insertions, 5083 deletions
diff --git a/Foundation/GTMBase64.h b/Foundation/GTMBase64.h
deleted file mode 100644
index 8a3b919..0000000
--- a/Foundation/GTMBase64.h
+++ /dev/null
@@ -1,189 +0,0 @@
-//
-// 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.
-
-
-#import <Foundation/Foundation.h>
-#import "GTMDefines.h"
-
-// GTMBase64
-//
-/// Helper for handling Base64 and WebSafeBase64 encodings
-//
-/// The webSafe methods use different character set and also the results aren't
-/// always padded to a multiple of 4 characters. This is done so the resulting
-/// data can be used in urls and url query arguments without needing any
-/// encoding. You must use the webSafe* methods together, the data does not
-/// interop with the RFC methods.
-//
-@interface GTMBase64 : NSObject
-
-//
-// Standard Base64 (RFC) handling
-//
-
-// encodeData:
-//
-/// Base64 encodes contents of the NSData object.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)encodeData:(NSData *)data;
-
-// decodeData:
-//
-/// Base64 decodes contents of the NSData object.
-//
-/// Returns:
-/// A new autoreleased NSData with the decoded payload. nil for any error.
-//
-+(NSData *)decodeData:(NSData *)data;
-
-// encodeBytes:length:
-//
-/// Base64 encodes the data pointed at by |bytes|.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length;
-
-// decodeBytes:length:
-//
-/// Base64 decodes the data pointed at by |bytes|.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length;
-
-// stringByEncodingData:
-//
-/// Base64 encodes contents of the NSData object.
-//
-/// Returns:
-/// A new autoreleased NSString with the encoded payload. nil for any error.
-//
-+(NSString *)stringByEncodingData:(NSData *)data;
-
-// stringByEncodingBytes:length:
-//
-/// Base64 encodes the data pointed at by |bytes|.
-//
-/// Returns:
-/// A new autoreleased NSString with the encoded payload. nil for any error.
-//
-+(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length;
-
-// decodeString:
-//
-/// Base64 decodes contents of the NSString.
-//
-/// Returns:
-/// A new autoreleased NSData with the decoded payload. nil for any error.
-//
-+(NSData *)decodeString:(NSString *)string;
-
-//
-// Modified Base64 encoding so the results can go onto urls.
-//
-// The changes are in the characters generated and also allows the result to
-// not be padded to a multiple of 4.
-// Must use the matching call to encode/decode, won't interop with the
-// RFC versions.
-//
-
-// webSafeEncodeData:padded:
-//
-/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
-/// then padding characters are added so the result length is a multiple of 4.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)webSafeEncodeData:(NSData *)data
- padded:(BOOL)padded;
-
-// webSafeDecodeData:
-//
-/// WebSafe Base64 decodes contents of the NSData object.
-//
-/// Returns:
-/// A new autoreleased NSData with the decoded payload. nil for any error.
-//
-+(NSData *)webSafeDecodeData:(NSData *)data;
-
-// webSafeEncodeBytes:length:padded:
-//
-/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
-/// then padding characters are added so the result length is a multiple of 4.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)webSafeEncodeBytes:(const void *)bytes
- length:(NSUInteger)length
- padded:(BOOL)padded;
-
-// webSafeDecodeBytes:length:
-//
-/// WebSafe Base64 decodes the data pointed at by |bytes|.
-//
-/// Returns:
-/// A new autoreleased NSData with the encoded payload. nil for any error.
-//
-+(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length;
-
-// stringByWebSafeEncodingData:padded:
-//
-/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
-/// then padding characters are added so the result length is a multiple of 4.
-//
-/// Returns:
-/// A new autoreleased NSString with the encoded payload. nil for any error.
-//
-+(NSString *)stringByWebSafeEncodingData:(NSData *)data
- padded:(BOOL)padded;
-
-// stringByWebSafeEncodingBytes:length:padded:
-//
-/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
-/// then padding characters are added so the result length is a multiple of 4.
-//
-/// Returns:
-/// A new autoreleased NSString with the encoded payload. nil for any error.
-//
-+(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
- length:(NSUInteger)length
- padded:(BOOL)padded;
-
-// webSafeDecodeString:
-//
-/// WebSafe Base64 decodes contents of the NSString.
-//
-/// Returns:
-/// A new autoreleased NSData with the decoded payload. nil for any error.
-//
-+(NSData *)webSafeDecodeString:(NSString *)string;
-
-@end
diff --git a/Foundation/GTMBase64.m b/Foundation/GTMBase64.m
deleted file mode 100644
index 7c4c68c..0000000
--- a/Foundation/GTMBase64.m
+++ /dev/null
@@ -1,692 +0,0 @@
-//
-// GTMBase64.m
-//
-// Copyright 2006-2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-#import "GTMBase64.h"
-#import "GTMDefines.h"
-
-static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-static const char kBase64PaddingChar = '=';
-static const char kBase64InvalidChar = 99;
-
-static const char kBase64DecodeChars[] = {
- // This array was generated by the following code:
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = 99;
- // else
- // idx = pos - Base64;
- // if (idx == 99)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 62/*+*/, 99, 99, 99, 63/*/ */,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
- 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99,
- 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
-};
-
-static const char kWebSafeBase64DecodeChars[] = {
- // This array was generated by the following code:
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = 99;
- // else
- // idx = pos - Base64;
- // if (idx == 99)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 62/*-*/, 99, 99,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
- 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 63/*_*/,
- 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
-};
-
-
-// Tests a 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.
-//
-GTM_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
-//
-GTM_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
-//
-GTM_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) {
- return (srcLen + 3) / 4 * 3;
-}
-
-
-@interface GTMBase64 (PrivateMethods)
-
-+(NSData *)baseEncode:(const void *)bytes
- length:(NSUInteger)length
- charset:(const char *)charset
- padded:(BOOL)padded;
-
-+(NSData *)baseDecode:(const void *)bytes
- length:(NSUInteger)length
- charset:(const char*)charset
- requirePadding:(BOOL)requirePadding;
-
-+(NSUInteger)baseEncode:(const char *)srcBytes
- srcLen:(NSUInteger)srcLen
- destBytes:(char *)destBytes
- destLen:(NSUInteger)destLen
- charset:(const char *)charset
- padded:(BOOL)padded;
-
-+(NSUInteger)baseDecode:(const char *)srcBytes
- srcLen:(NSUInteger)srcLen
- destBytes:(char *)destBytes
- destLen:(NSUInteger)destLen
- charset:(const char *)charset
- requirePadding:(BOOL)requirePadding;
-
-@end
-
-
-@implementation GTMBase64
-
-//
-// Standard Base64 (RFC) handling
-//
-
-+(NSData *)encodeData:(NSData *)data {
- return [self baseEncode:[data bytes]
- length:[data length]
- charset:kBase64EncodeChars
- padded:YES];
-}
-
-+(NSData *)decodeData:(NSData *)data {
- return [self baseDecode:[data bytes]
- length:[data length]
- charset:kBase64DecodeChars
- requirePadding:YES];
-}
-
-+(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
- return [self baseEncode:bytes
- length:length
- charset:kBase64EncodeChars
- padded:YES];
-}
-
-+(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
- return [self baseDecode:bytes
- length:length
- charset:kBase64DecodeChars
- requirePadding:YES];
-}
-
-+(NSString *)stringByEncodingData:(NSData *)data {
- NSString *result = nil;
- NSData *converted = [self baseEncode:[data bytes]
- length:[data length]
- charset:kBase64EncodeChars
- padded:YES];
- if (converted) {
- result = [[[NSString alloc] initWithData:converted
- encoding:NSASCIIStringEncoding] autorelease];
- }
- return result;
-}
-
-+(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
- NSString *result = nil;
- NSData *converted = [self baseEncode:bytes
- length:length
- charset:kBase64EncodeChars
- padded:YES];
- if (converted) {
- result = [[[NSString alloc] initWithData:converted
- encoding:NSASCIIStringEncoding] autorelease];
- }
- return result;
-}
-
-+(NSData *)decodeString:(NSString *)string {
- NSData *result = nil;
- NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
- if (data) {
- result = [self baseDecode:[data bytes]
- length:[data length]
- charset:kBase64DecodeChars
- requirePadding:YES];
- }
- return result;
-}
-
-//
-// Modified Base64 encoding so the results can go onto urls.
-//
-// The changes are in the characters generated and also the result isn't
-// padded to a multiple of 4.
-// Must use the matching call to encode/decode, won't interop with the
-// RFC versions.
-//
-
-+(NSData *)webSafeEncodeData:(NSData *)data
- padded:(BOOL)padded {
- return [self baseEncode:[data bytes]
- length:[data length]
- charset:kWebSafeBase64EncodeChars
- padded:padded];
-}
-
-+(NSData *)webSafeDecodeData:(NSData *)data {
- return [self baseDecode:[data bytes]
- length:[data length]
- charset:kWebSafeBase64DecodeChars
- requirePadding:NO];
-}
-
-+(NSData *)webSafeEncodeBytes:(const void *)bytes
- length:(NSUInteger)length
- padded:(BOOL)padded {
- return [self baseEncode:bytes
- length:length
- charset:kWebSafeBase64EncodeChars
- padded:padded];
-}
-
-+(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
- return [self baseDecode:bytes
- length:length
- charset:kWebSafeBase64DecodeChars
- requirePadding:NO];
-}
-
-+(NSString *)stringByWebSafeEncodingData:(NSData *)data
- padded:(BOOL)padded {
- NSString *result = nil;
- NSData *converted = [self baseEncode:[data bytes]
- length:[data length]
- charset:kWebSafeBase64EncodeChars
- padded:padded];
- if (converted) {
- result = [[[NSString alloc] initWithData:converted
- encoding:NSASCIIStringEncoding] autorelease];
- }
- return result;
-}
-
-+(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
- length:(NSUInteger)length
- padded:(BOOL)padded {
- NSString *result = nil;
- NSData *converted = [self baseEncode:bytes
- length:length
- charset:kWebSafeBase64EncodeChars
- padded:padded];
- if (converted) {
- result = [[[NSString alloc] initWithData:converted
- encoding:NSASCIIStringEncoding] autorelease];
- }
- return result;
-}
-
-+(NSData *)webSafeDecodeString:(NSString *)string {
- NSData *result = nil;
- NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
- if (data) {
- result = [self baseDecode:[data bytes]
- length:[data length]
- charset:kWebSafeBase64DecodeChars
- requirePadding:NO];
- }
- return result;
-}
-
-@end
-
-@implementation GTMBase64 (PrivateMethods)
-
-//
-// baseEncode:length:charset:padded:
-//
-// Does the common lifting of creating the dest NSData. it creates & sizes the
-// data for the results. |charset| is the characters to use for the encoding
-// of the data. |padding| controls if the encoded data should be padded to a
-// multiple of 4.
-//
-// Returns:
-// an autorelease NSData with the encoded data, nil if any error.
-//
-+(NSData *)baseEncode:(const void *)bytes
- length:(NSUInteger)length
- charset:(const char *)charset
- padded:(BOOL)padded {
- // how big could it be?
- NSUInteger maxLength = CalcEncodedLength(length, padded);
- // make space
- NSMutableData *result = [NSMutableData data];
- [result setLength:maxLength];
- // do it
- NSUInteger finalLength = [self baseEncode:bytes
- srcLen:length
- destBytes:[result mutableBytes]
- destLen:[result length]
- charset:charset
- padded:padded];
- if (finalLength) {
- _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
- } else {
- // shouldn't happen, this means we ran out of space
- result = nil;
- }
- return result;
-}
-
-//
-// baseDecode:length:charset:requirePadding:
-//
-// Does the common lifting of creating the dest NSData. it creates & sizes the
-// data for the results. |charset| is the characters to use for the decoding
-// of the data.
-//
-// Returns:
-// an autorelease NSData with the decoded data, nil if any error.
-//
-//
-+(NSData *)baseDecode:(const void *)bytes
- length:(NSUInteger)length
- charset:(const char *)charset
- requirePadding:(BOOL)requirePadding {
- // could try to calculate what it will end up as
- NSUInteger maxLength = GuessDecodedLength(length);
- // make space
- NSMutableData *result = [NSMutableData data];
- [result setLength:maxLength];
- // do it
- NSUInteger finalLength = [self baseDecode:bytes
- srcLen:length
- destBytes:[result mutableBytes]
- destLen:[result length]
- charset:charset
- requirePadding:requirePadding];
- if (finalLength) {
- if (finalLength != maxLength) {
- // resize down to how big it was
- [result setLength:finalLength];
- }
- } else {
- // either an error in the args, or we ran out of space
- result = nil;
- }
- return result;
-}
-
-//
-// baseEncode:srcLen:destBytes:destLen:charset:padded:
-//
-// Encodes the buffer into the larger. returns the length of the encoded
-// data, or zero for an error.
-// |charset| is the characters to use for the encoding
-// |padded| tells if the result should be padded to a multiple of 4.
-//
-// Returns:
-// the length of the encoded data. zero if any error.
-//
-+(NSUInteger)baseEncode:(const char *)srcBytes
- srcLen:(NSUInteger)srcLen
- destBytes:(char *)destBytes
- destLen:(NSUInteger)destLen
- charset:(const char *)charset
- padded:(BOOL)padded {
- if (!srcLen || !destLen || !srcBytes || !destBytes) {
- return 0;
- }
-
- char *curDest = destBytes;
- const unsigned char *curSrc = (const unsigned char *)(srcBytes);
-
- // Three bytes of data encodes to four characters of cyphertext.
- // So we can pump through three-byte chunks atomically.
- while (srcLen > 2) {
- // space?
- _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
- curDest[0] = charset[curSrc[0] >> 2];
- curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
- curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
- curDest[3] = charset[curSrc[2] & 0x3f];
-
- curDest += 4;
- curSrc += 3;
- srcLen -= 3;
- destLen -= 4;
- }
-
- // now deal with the tail (<=2 bytes)
- switch (srcLen) {
- case 0:
- // Nothing left; nothing more to do.
- break;
- case 1:
- // One byte left: this encodes to two characters, and (optionally)
- // two pad characters to round out the four-character cypherblock.
- _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
- curDest[0] = charset[curSrc[0] >> 2];
- curDest[1] = charset[(curSrc[0] & 0x03) << 4];
- curDest += 2;
- if (padded) {
- _GTMDevAssert(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.
- _GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong");
- curDest[0] = charset[curSrc[0] >> 2];
- curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
- curDest[2] = charset[(curSrc[1] & 0x0f) << 2];
- curDest += 3;
- if (padded) {
- _GTMDevAssert(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.
- _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
- destBytes[destIndex] = decode << 2;
- state = 1;
- break;
- case 1:
- // We're one character into a four-character cyphertext block.
- // This sets the low two bits of the first plaintext byte,
- // and the high four bits of the second plaintext byte.
- _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
- destBytes[destIndex] |= decode >> 4;
- destBytes[destIndex+1] = (decode & 0x0f) << 4;
- destIndex++;
- state = 2;
- break;
- case 2:
- // We're two characters into a four-character cyphertext block.
- // This sets the low four bits of the second plaintext
- // byte, and the high two bits of the third plaintext byte.
- // However, if this is the end of data, and those two
- // bits are zero, it could be that those two bits are
- // leftovers from the encoding of data that had a length
- // of two mod three.
- _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
- destBytes[destIndex] |= decode >> 2;
- destBytes[destIndex+1] = (decode & 0x03) << 6;
- destIndex++;
- state = 3;
- break;
- case 3:
- // We're at the last character of a four-character cyphertext block.
- // This sets the low six bits of the third plaintext byte.
- _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
- destBytes[destIndex] |= decode;
- destIndex++;
- state = 0;
- break;
- }
- }
-
- // We are done decoding Base-64 chars. Let's see if we ended
- // on a byte boundary, and/or with erroneous trailing characters.
- if (ch == kBase64PaddingChar) { // We got a pad char
- if ((state == 0) || (state == 1)) {
- return 0; // Invalid '=' in first or second position
- }
- if (srcLen == 0) {
- if (state == 2) { // We run out of input but we still need another '='
- return 0;
- }
- // Otherwise, we are in state 3 and only need this '='
- } else {
- if (state == 2) { // need another '='
- while ((ch = *srcBytes++) && (srcLen-- > 0)) {
- if (!IsSpace(ch))
- break;
- }
- if (ch != kBase64PaddingChar) {
- return 0;
- }
- }
- // state = 1 or 2, check if all remain padding is space
- while ((ch = *srcBytes++) && (srcLen-- > 0)) {
- if (!IsSpace(ch)) {
- return 0;
- }
- }
- }
- } else {
- // We ended by seeing the end of the string.
-
- if (requirePadding) {
- // If we require padding, then anything but state 0 is an error.
- if (state != 0) {
- return 0;
- }
- } else {
- // Make sure we have no partial bytes lying around. Note that we do not
- // require trailing '=', so states 2 and 3 are okay too.
- if (state == 1) {
- return 0;
- }
- }
- }
-
- // If then next piece of output was valid and got written to it means we got a
- // very carefully crafted input that appeared valid but contains some trailing
- // bits past the real length, so just toss the thing.
- if ((destIndex < destLen) &&
- (destBytes[destIndex] != 0)) {
- return 0;
- }
-
- return destIndex;
-}
-
-@end
diff --git a/Foundation/GTMBase64Test.m b/Foundation/GTMBase64Test.m
deleted file mode 100644
index 084ea1e..0000000
--- a/Foundation/GTMBase64Test.m
+++ /dev/null
@@ -1,437 +0,0 @@
-//
-// GTMBase64Test.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 "GTMSenTestCase.h"
-#import "GTMBase64.h"
-#include <stdlib.h> // for randiom/srandomdev
-
-static void FillWithRandom(char *data, NSUInteger len) {
- char *max = data + len;
- for ( ; data < max ; ++data) {
- *data = random() & 0xFF;
- }
-}
-
-static BOOL NoEqualChar(NSData *data) {
- const char *scan = [data bytes];
- const char *max = scan + [data length];
- for ( ; scan < max ; ++scan) {
- if (*scan == '=') {
- return NO;
- }
- }
- return YES;
-}
-
-@interface GTMBase64Test : GTMTestCase
-@end
-
-@implementation GTMBase64Test
-
-- (void)setUp {
- // seed random from /dev/random
- srandomdev();
-}
-
-- (void)testBase64 {
- // generate a range of sizes w/ random content
- for (int x = 1 ; x < 1024 ; ++x) {
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:x];
- FillWithRandom([data mutableBytes], [data length]);
-
- // w/ *Bytes apis
- NSData *encoded = [GTMBase64 encodeBytes:[data bytes] length:[data length]];
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- NSData *dataPrime = [GTMBase64 decodeBytes:[encoded bytes]
- length:[encoded length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Bytes apis");
-
- // w/ *Data apis
- encoded = [GTMBase64 encodeData:data];
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- dataPrime = [GTMBase64 decodeData:encoded];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Data apis");
-
- // Bytes to String and back
- NSString *encodedString = [GTMBase64 stringByEncodingBytes:[data bytes]
- length:[data length]];
- STAssertEquals(([encodedString length] % 4), (NSUInteger)0,
- @"encoded size for Bytes to Strings should be a multiple of 4");
- dataPrime = [GTMBase64 decodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Bytes to Strings");
-
- // Data to String and back
- encodedString = [GTMBase64 stringByEncodingData:data];
- STAssertEquals(([encodedString length] % 4), (NSUInteger)0,
- @"encoded size for Data to Strings should be a multiple of 4");
- dataPrime = [GTMBase64 decodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Bytes to Strings");
- }
-
- {
- // now test all byte values
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:256];
- unsigned char *scan = (unsigned char*)[data mutableBytes];
- for (int x = 0 ; x <= 255 ; ++x) {
- *scan++ = x;
- }
-
- // w/ *Bytes apis
- NSData *encoded = [GTMBase64 encodeBytes:[data bytes] length:[data length]];
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- NSData *dataPrime = [GTMBase64 decodeBytes:[encoded bytes]
- length:[encoded length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Bytes apis");
-
- // w/ *Data apis
- encoded = [GTMBase64 encodeData:data];
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- dataPrime = [GTMBase64 decodeData:encoded];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Data apis");
-
- // Bytes to String and back
- NSString *encodedString = [GTMBase64 stringByEncodingBytes:[data bytes]
- length:[data length]];
- STAssertEquals(([encodedString length] % 4), (NSUInteger)0,
- @"encoded size for Bytes to Strings should be a multiple of 4");
- dataPrime = [GTMBase64 decodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Bytes to Strings");
-
- // Data to String and back
- encodedString = [GTMBase64 stringByEncodingData:data];
- STAssertEquals(([encodedString length] % 4), (NSUInteger)0,
- @"encoded size for Data to Strings should be a multiple of 4");
- dataPrime = [GTMBase64 decodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Data to Strings");
- }
-
- {
- // test w/ a mix of spacing characters
-
- // generate some data, encode it, and add spaces
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:253]; // should get some padding chars on the end
- FillWithRandom([data mutableBytes], [data length]);
-
- NSString *encodedString = [GTMBase64 stringByEncodingData:data];
- NSMutableString *encodedAndSpaced =
- [[encodedString mutableCopy] autorelease];
-
- NSString *spaces[] = { @"\t", @"\n", @"\r", @" " };
- const NSUInteger numSpaces = sizeof(spaces) / sizeof(NSString*);
- for (int x = 0 ; x < 512 ; ++x) {
- NSUInteger offset = random() % ([encodedAndSpaced length] + 1);
- [encodedAndSpaced insertString:spaces[random() % numSpaces]
- atIndex:offset];
- }
-
- // we'll need it as data for apis
- NSData *encodedAsData =
- [encodedAndSpaced dataUsingEncoding:NSASCIIStringEncoding];
- STAssertNotNil(encodedAsData, @"failed to extract from string");
- STAssertEquals([encodedAsData length], [encodedAndSpaced length],
- @"lengths for encoded string and data didn't match?");
-
- // all the decode modes
- NSData *dataPrime = [GTMBase64 decodeData:encodedAsData];
- STAssertEqualObjects(data, dataPrime,
- @"failed Data decode w/ spaces");
- dataPrime = [GTMBase64 decodeBytes:[encodedAsData bytes]
- length:[encodedAsData length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed Bytes decode w/ spaces");
- dataPrime = [GTMBase64 decodeString:encodedAndSpaced];
- STAssertEqualObjects(data, dataPrime,
- @"failed String decode w/ spaces");
- }
-}
-
-- (void)testWebSafeBase64 {
- // loop to test w/ and w/o padding
- for (int paddedLoop = 0; paddedLoop < 2 ; ++paddedLoop) {
- BOOL padded = (paddedLoop == 1);
-
- // generate a range of sizes w/ random content
- for (int x = 1 ; x < 1024 ; ++x) {
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:x];
- FillWithRandom([data mutableBytes], [data length]);
-
- // w/ *Bytes apis
- NSData *encoded = [GTMBase64 webSafeEncodeBytes:[data bytes]
- length:[data length]
- padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via *Bytes apis had a base64 padding char");
- }
- NSData *dataPrime = [GTMBase64 webSafeDecodeBytes:[encoded bytes]
- length:[encoded length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Bytes apis");
-
- // w/ *Data apis
- encoded = [GTMBase64 webSafeEncodeData:data padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via *Data apis had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeData:encoded];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Data apis");
-
- // Bytes to String and back
- NSString *encodedString =
- [GTMBase64 stringByWebSafeEncodingBytes:[data bytes]
- length:[data length]
- padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via Bytes to Strings had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Bytes to Strings");
-
- // Data to String and back
- encodedString =
- [GTMBase64 stringByWebSafeEncodingData:data padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via Data to Strings had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Data to Strings");
- }
-
- {
- // now test all byte values
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:256];
- unsigned char *scan = (unsigned char*)[data mutableBytes];
- for (int x = 0 ; x <= 255 ; ++x) {
- *scan++ = x;
- }
-
- // w/ *Bytes apis
- NSData *encoded =
- [GTMBase64 webSafeEncodeBytes:[data bytes]
- length:[data length]
- padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via *Bytes apis had a base64 padding char");
- }
- NSData *dataPrime = [GTMBase64 webSafeDecodeBytes:[encoded bytes]
- length:[encoded length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Bytes apis");
-
- // w/ *Data apis
- encoded = [GTMBase64 webSafeEncodeData:data padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via *Data apis had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeData:encoded];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip via *Data apis");
-
- // Bytes to String and back
- NSString *encodedString =
- [GTMBase64 stringByWebSafeEncodingBytes:[data bytes]
- length:[data length]
- padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Bytes apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via Bytes to Strings had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Bytes to Strings");
-
- // Data to String and back
- encodedString =
- [GTMBase64 stringByWebSafeEncodingData:data padded:padded];
- if (padded) {
- STAssertEquals(([encoded length] % 4), (NSUInteger)0,
- @"encoded size via *Data apis should be a multiple of 4");
- } else {
- STAssertTrue(NoEqualChar(encoded),
- @"encoded via Data to Strings had a base64 padding char");
- }
- dataPrime = [GTMBase64 webSafeDecodeString:encodedString];
- STAssertEqualObjects(data, dataPrime,
- @"failed to round trip for Data to Strings");
- }
-
- {
- // test w/ a mix of spacing characters
-
- // generate some data, encode it, and add spaces
- NSMutableData *data = [NSMutableData data];
- STAssertNotNil(data, @"failed to alloc data block");
-
- [data setLength:253]; // should get some padding chars on the end
- FillWithRandom([data mutableBytes], [data length]);
-
- NSString *encodedString = [GTMBase64 stringByWebSafeEncodingData:data
- padded:padded];
- NSMutableString *encodedAndSpaced =
- [[encodedString mutableCopy] autorelease];
-
- NSString *spaces[] = { @"\t", @"\n", @"\r", @" " };
- const NSUInteger numSpaces = sizeof(spaces) / sizeof(NSString*);
- for (int x = 0 ; x < 512 ; ++x) {
- NSUInteger offset = random() % ([encodedAndSpaced length] + 1);
- [encodedAndSpaced insertString:spaces[random() % numSpaces]
- atIndex:offset];
- }
-
- // we'll need it as data for apis
- NSData *encodedAsData =
- [encodedAndSpaced dataUsingEncoding:NSASCIIStringEncoding];
- STAssertNotNil(encodedAsData, @"failed to extract from string");
- STAssertEquals([encodedAsData length], [encodedAndSpaced length],
- @"lengths for encoded string and data didn't match?");
-
- // all the decode modes
- NSData *dataPrime = [GTMBase64 webSafeDecodeData:encodedAsData];
- STAssertEqualObjects(data, dataPrime,
- @"failed Data decode w/ spaces");
- dataPrime = [GTMBase64 webSafeDecodeBytes:[encodedAsData bytes]
- length:[encodedAsData length]];
- STAssertEqualObjects(data, dataPrime,
- @"failed Bytes decode w/ spaces");
- dataPrime = [GTMBase64 webSafeDecodeString:encodedAndSpaced];
- STAssertEqualObjects(data, dataPrime,
- @"failed String decode w/ spaces");
- }
- } // paddedLoop
-}
-
-- (void)testErrors {
- const int something = 0;
- NSString *nonAscString = [NSString stringWithUTF8String:"This test ©™®๒०᠐٧"];
-
- STAssertNil([GTMBase64 encodeData:nil], @"it worked?");
- STAssertNil([GTMBase64 decodeData:nil], @"it worked?");
- STAssertNil([GTMBase64 encodeBytes:NULL length:10], @"it worked?");
- STAssertNil([GTMBase64 encodeBytes:&something length:0], @"it worked?");
- STAssertNil([GTMBase64 decodeBytes:NULL length:10], @"it worked?");
- STAssertNil([GTMBase64 decodeBytes:&something length:0], @"it worked?");
- STAssertNil([GTMBase64 stringByEncodingData:nil], @"it worked?");
- STAssertNil([GTMBase64 stringByEncodingBytes:NULL length:10], @"it worked?");
- STAssertNil([GTMBase64 stringByEncodingBytes:&something length:0], @"it worked?");
- STAssertNil([GTMBase64 decodeString:nil], @"it worked?");
- // test some pads at the end that aren't right
- STAssertNil([GTMBase64 decodeString:@"=="], @"it worked?"); // just pads
- STAssertNil([GTMBase64 decodeString:@"vw="], @"it worked?"); // missing pad (in state 2)
- STAssertNil([GTMBase64 decodeString:@"vw"], @"it worked?"); // missing pad (in state 2)
- STAssertNil([GTMBase64 decodeString:@"NNw"], @"it worked?"); // missing pad (in state 3)
- STAssertNil([GTMBase64 decodeString:@"vw=v"], @"it worked?"); // missing pad, has something else
- STAssertNil([GTMBase64 decodeString:@"v="], @"it worked?"); // missing a needed char, has pad instead
- STAssertNil([GTMBase64 decodeString:@"v"], @"it worked?"); // missing a needed char
- STAssertNil([GTMBase64 decodeString:@"vw== vw"], @"it worked?");
- STAssertNil([GTMBase64 decodeString:nonAscString], @"it worked?");
- STAssertNil([GTMBase64 decodeString:@"@@@not valid###"], @"it worked?");
- // carefully crafted bad input to make sure we don't overwalk
- STAssertNil([GTMBase64 decodeString:@"WD=="], @"it worked?");
-
- STAssertNil([GTMBase64 webSafeEncodeData:nil padded:YES], @"it worked?");
- STAssertNil([GTMBase64 webSafeDecodeData:nil], @"it worked?");
- STAssertNil([GTMBase64 webSafeEncodeBytes:NULL length:10 padded:YES],
- @"it worked?");
- STAssertNil([GTMBase64 webSafeEncodeBytes:&something length:0 padded:YES],
- @"it worked?");
- STAssertNil([GTMBase64 webSafeDecodeBytes:NULL length:10], @"it worked?");
- STAssertNil([GTMBase64 webSafeDecodeBytes:&something length:0], @"it worked?");
- STAssertNil([GTMBase64 stringByWebSafeEncodingData:nil padded:YES],
- @"it worked?");
- STAssertNil([GTMBase64 stringByWebSafeEncodingBytes:NULL
- length:10
- padded:YES],
- @"it worked?");
- STAssertNil([GTMBase64 stringByWebSafeEncodingBytes:&something
- length:0
- padded:YES],
- @"it worked?");
- STAssertNil([GTMBase64 webSafeDecodeString:nil], @"it worked?");
- // test some pads at the end that aren't right
- STAssertNil([GTMBase64 webSafeDecodeString:@"=="], @"it worked?"); // just pad chars
- STAssertNil([GTMBase64 webSafeDecodeString:@"aw="], @"it worked?"); // missing pad
- STAssertNil([GTMBase64 webSafeDecodeString:@"aw=a"], @"it worked?"); // missing pad, has something else
- STAssertNil([GTMBase64 webSafeDecodeString:@"a"], @"it worked?"); // missing a needed char
- STAssertNil([GTMBase64 webSafeDecodeString:@"a="], @"it worked?"); // missing a needed char, has pad instead
- STAssertNil([GTMBase64 webSafeDecodeString:@"aw== a"], @"it worked?"); // missing pad
- STAssertNil([GTMBase64 webSafeDecodeString:nonAscString], @"it worked?");
- STAssertNil([GTMBase64 webSafeDecodeString:@"@@@not valid###"], @"it worked?");
- // carefully crafted bad input to make sure we don't overwalk
- STAssertNil([GTMBase64 webSafeDecodeString:@"WD=="], @"it worked?");
-
- // make sure our local helper is working right
- STAssertFalse(NoEqualChar([NSData dataWithBytes:"aa=zz" length:5]), @"");
-}
-
-@end
diff --git a/Foundation/GTMHTTPFetcher.h b/Foundation/GTMHTTPFetcher.h
deleted file mode 100644
index 7377d1c..0000000
--- a/Foundation/GTMHTTPFetcher.h
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// GTMHTTPFetcher.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.
-//
-
-// This class is no more. If you want something like it's functionality, look
-// at using the version in the Objective-C GData Client
-// (http://code.google.com/p/gdata-objectivec-client/). It provides the same
-// functionality and will continue to be maintained.
diff --git a/Foundation/GTMHTTPServer.h b/Foundation/GTMHTTPServer.h
deleted file mode 100644
index 3920968..0000000
--- a/Foundation/GTMHTTPServer.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//
-// GTMHTTPServer.h
-//
-// This is a *very* *simple* webserver that can be built into something, it is
-// not meant to stand up a site, it sends all requests to its delegate for
-// processing on the main thread. It does not support pipelining, etc. It's
-// great for places where you need a simple webserver to unittest some code
-// that hits a server.
-//
-// NOTE: there are several TODOs left in here as markers for things that could
-// be done if one wanted to add more to this class.
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-// Based a little on HTTPServer, part of the CocoaHTTPServer sample code
-// http://developer.apple.com/samplecode/CocoaHTTPServer/index.html
-//
-
-#import <Foundation/Foundation.h>
-#import "GTMDefines.h"
-
-#if GTM_IPHONE_SDK
-#import <CFNetwork/CFNetwork.h>
-#endif // GTM_IPHONE_SDK
-
-// Global contants needed for errors from start
-
-#undef _EXTERN
-#undef _INITIALIZE_AS
-#ifdef GTMHTTPSERVER_DEFINE_GLOBALS
-#define _EXTERN
-#define _INITIALIZE_AS(x) =x
-#else
-#define _EXTERN GTM_EXTERN
-#define _INITIALIZE_AS(x)
-#endif
-
-_EXTERN NSString* kGTMHTTPServerErrorDomain _INITIALIZE_AS(@"com.google.mactoolbox.HTTPServerDomain");
-enum {
- kGTMHTTPServerSocketCreateFailedError = -100,
- kGTMHTTPServerBindFailedError = -101,
- kGTMHTTPServerListenFailedError = -102,
- kGTMHTTPServerHandleCreateFailedError = -103,
-};
-
-@class GTMHTTPRequestMessage, GTMHTTPResponseMessage;
-
-// ----------------------------------------------------------------------------
-
-// See comment at top of file for the intened use of this class.
-@interface GTMHTTPServer : NSObject {
- @private
- __weak id delegate_;
- uint16_t port_;
- BOOL reusePort_;
- BOOL localhostOnly_;
- NSFileHandle *listenHandle_;
- NSMutableArray *connections_;
-}
-
-// The delegate must support the httpServer:handleRequest: method in
-// NSObject(GTMHTTPServerDelegateMethods) below.
-- (id)initWithDelegate:(id)delegate;
-
-- (id)delegate;
-
-// Passing port zero will let one get assigned.
-- (uint16_t)port;
-- (void)setPort:(uint16_t)port;
-
-// Controls listening socket behavior: SO_REUSEADDR vs SO_REUSEPORT.
-// The default is NO (SO_REUSEADDR)
-- (BOOL)reusePort;
-- (void)setReusePort:(BOOL)reusePort;
-
-// Receive connections on the localHost loopback address only or on all
-// interfaces for this machine. The default is to only listen on localhost.
-- (BOOL)localhostOnly;
-- (void)setLocalhostOnly:(BOOL)yesno;
-
-// Start/Stop the web server. If there is an error starting up the server, |NO|
-// is returned, and the specific startup failure can be returned in |error| (see
-// above for the error domain and error codes). If the server is started, |YES|
-// is returned and the server's delegate is called for any requests that come
-// in.
-- (BOOL)start:(NSError **)error;
-- (void)stop;
-
-// returns the number of requests currently active in the server (i.e.-being
-// read in, sent replies).
-- (NSUInteger)activeRequestCount;
-
-@end
-
-@interface NSObject (GTMHTTPServerDelegateMethods)
-- (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
- handleRequest:(GTMHTTPRequestMessage *)request;
-@end
-
-// ----------------------------------------------------------------------------
-
-// Encapsulates an http request, one of these is sent to the server's delegate
-// for each request.
-@interface GTMHTTPRequestMessage : NSObject {
- @private
- CFHTTPMessageRef message_;
-}
-- (NSString *)version;
-- (NSURL *)URL;
-- (NSString *)method;
-- (NSData *)body;
-- (NSDictionary *)allHeaderFieldValues;
-@end
-
-// ----------------------------------------------------------------------------
-
-// Encapsulates an http response, the server's delegate should return one for
-// each request received.
-@interface GTMHTTPResponseMessage : NSObject {
- @private
- CFHTTPMessageRef message_;
-}
-+ (id)responseWithString:(NSString *)plainText;
-+ (id)responseWithHTMLString:(NSString *)htmlString;
-+ (id)responseWithBody:(NSData *)body
- contentType:(NSString *)contentType
- statusCode:(int)statusCode;
-+ (id)emptyResponseWithCode:(int)statusCode;
-// TODO: class method for redirections?
-// TODO: add helper for expire/no-cache
-- (void)setValue:(NSString*)value forHeaderField:(NSString*)headerField;
-@end
diff --git a/Foundation/GTMHTTPServer.m b/Foundation/GTMHTTPServer.m
deleted file mode 100644
index 57e6077..0000000
--- a/Foundation/GTMHTTPServer.m
+++ /dev/null
@@ -1,624 +0,0 @@
-//
-// GTMHTTPServer.m
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-// Based a little on HTTPServer, part of the CocoaHTTPServer sample code
-// http://developer.apple.com/samplecode/CocoaHTTPServer/index.html
-//
-
-#import <netinet/in.h>
-#import <sys/socket.h>
-#import <unistd.h>
-
-#define GTMHTTPSERVER_DEFINE_GLOBALS
-#import "GTMHTTPServer.h"
-#import "GTMDebugSelectorValidation.h"
-#import "GTMGarbageCollection.h"
-#import "GTMDefines.h"
-#import "GTMTypeCasting.h"
-
-@interface GTMHTTPServer (PrivateMethods)
-- (void)acceptedConnectionNotification:(NSNotification *)notification;
-- (NSMutableDictionary *)connectionWithFileHandle:(NSFileHandle *)fileHandle;
-- (void)dataAvailableNotification:(NSNotification *)notification;
-- (NSMutableDictionary *)lookupConnection:(NSFileHandle *)fileHandle;
-- (void)closeConnection:(NSMutableDictionary *)connDict;
-- (void)sendResponseOnNewThread:(NSMutableDictionary *)connDict;
-- (void)sentResponse:(NSMutableDictionary *)connDict;
-@end
-
-// keys for our connection dictionaries
-static NSString *kFileHandle = @"FileHandle";
-static NSString *kRequest = @"Request";
-static NSString *kResponse = @"Response";
-
-@interface GTMHTTPRequestMessage (PrivateHelpers)
-- (BOOL)isHeaderComplete;
-- (BOOL)appendData:(NSData *)data;
-- (NSString *)headerFieldValueForKey:(NSString *)key;
-- (UInt32)contentLength;
-- (void)setBody:(NSData *)body;
-@end
-
-@interface GTMHTTPResponseMessage (PrivateMethods)
-- (id)initWithBody:(NSData *)body
- contentType:(NSString *)contentType
- statusCode:(int)statusCode;
-- (NSData*)serializedData;
-@end
-
-@implementation GTMHTTPServer
-
-- (id)init {
- return [self initWithDelegate:nil];
-}
-
-- (id)initWithDelegate:(id)delegate {
- self = [super init];
- if (self) {
- if (!delegate) {
- _GTMDevLog(@"missing delegate");
- [self release];
- return nil;
- }
- delegate_ = delegate;
- GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(delegate_,
- @selector(httpServer:handleRequest:),
- // return type
- @encode(GTMHTTPResponseMessage *),
- // args
- @encode(GTMHTTPServer *),
- @encode(GTMHTTPRequestMessage *),
- NULL);
- localhostOnly_ = YES;
- connections_ = [[NSMutableArray alloc] init];
- }
- return self;
-}
-
-- (void)dealloc {
- [self stop];
- [connections_ release];
- [super dealloc];
-}
-
-#if GTM_SUPPORT_GC
-- (void)finalize {
- [self stop];
- [super finalize];
-}
-#endif
-
-- (id)delegate {
- return delegate_;
-}
-
-- (uint16_t)port {
- return port_;
-}
-
-- (void)setPort:(uint16_t)port {
- port_ = port;
-}
-
-- (BOOL)reusePort {
- return reusePort_;
-}
-
-- (void)setReusePort:(BOOL)yesno {
- reusePort_ = yesno;
-}
-
-- (BOOL)localhostOnly {
- return localhostOnly_;
-}
-
-- (void)setLocalhostOnly:(BOOL)yesno {
- localhostOnly_ = yesno;
-}
-
-- (BOOL)start:(NSError **)error {
- _GTMDevAssert(listenHandle_ == nil,
- @"start called when we already have a listenHandle_");
-
- if (error) *error = NULL;
-
- NSInteger startFailureCode = 0;
- int fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd <= 0) {
- // COV_NF_START - we'd need to use up *all* sockets to test this?
- startFailureCode = kGTMHTTPServerSocketCreateFailedError;
- goto startFailed;
- // COV_NF_END
- }
-
- // enable address reuse quicker after we are done w/ our socket
- int yes = 1;
- int sock_opt = reusePort_ ? SO_REUSEPORT : SO_REUSEADDR;
- if (setsockopt(fd, SOL_SOCKET, sock_opt,
- (void *)&yes, (socklen_t)sizeof(yes)) != 0) {
- _GTMDevLog(@"failed to mark the socket as reusable"); // COV_NF_LINE
- }
-
- // bind
- struct sockaddr_in addr;
- bzero(&addr, sizeof(addr));
- addr.sin_len = sizeof(addr);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port_);
- if (localhostOnly_) {
- addr.sin_addr.s_addr = htonl(0x7F000001);
- } else {
- // COV_NF_START - testing this could cause a leopard firewall prompt during tests.
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- // COV_NF_END
- }
- if (bind(fd, (struct sockaddr*)(&addr), (socklen_t)sizeof(addr)) != 0) {
- startFailureCode = kGTMHTTPServerBindFailedError;
- goto startFailed;
- }
-
- // collect the port back out
- if (port_ == 0) {
- socklen_t len = (socklen_t)sizeof(addr);
- if (getsockname(fd, (struct sockaddr*)(&addr), &len) == 0) {
- port_ = ntohs(addr.sin_port);
- }
- }
-
- // tell it to listen for connections
- if (listen(fd, 5) != 0) {
- // COV_NF_START
- startFailureCode = kGTMHTTPServerListenFailedError;
- goto startFailed;
- // COV_NF_END
- }
-
- // now use a filehandle to accept connections
- listenHandle_ =
- [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:YES];
- if (listenHandle_ == nil) {
- // COV_NF_START - we'd need to run out of memory to test this?
- startFailureCode = kGTMHTTPServerHandleCreateFailedError;
- goto startFailed;
- // COV_NF_END
- }
-
- // setup notifications for connects
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(acceptedConnectionNotification:)
- name:NSFileHandleConnectionAcceptedNotification
- object:listenHandle_];
- [listenHandle_ acceptConnectionInBackgroundAndNotify];
-
- // TODO: maybe hit the delegate incase it wants to register w/ NSNetService,
- // or just know we're up and running?
-
- return YES;
-
-startFailed:
- if (error) {
- *error = [[[NSError alloc] initWithDomain:kGTMHTTPServerErrorDomain
- code:startFailureCode
- userInfo:nil] autorelease];
- }
- if (fd > 0) {
- close(fd);
- }
- return NO;
-}
-
-- (void)stop {
- if (listenHandle_) {
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center removeObserver:self
- name:NSFileHandleConnectionAcceptedNotification
- object:listenHandle_];
- [listenHandle_ release];
- listenHandle_ = nil;
- // TODO: maybe hit the delegate in case it wants to unregister w/
- // NSNetService, or just know we've stopped running?
- }
- [connections_ removeAllObjects];
-}
-
-- (NSUInteger)activeRequestCount {
- return [connections_ count];
-}
-
-- (NSString *)description {
- NSString *result =
- [NSString stringWithFormat:@"%@<%p>{ port=%d localHostOnly=%@ status=%@ }",
- [self class], self, port_, (localhostOnly_ ? @"YES" : @"NO"),
- (listenHandle_ != nil ? @"Started" : @"Stopped") ];
- return result;
-}
-
-
-@end
-
-@implementation GTMHTTPServer (PrivateMethods)
-
-- (void)acceptedConnectionNotification:(NSNotification *)notification {
- NSDictionary *userInfo = [notification userInfo];
- NSFileHandle *newConnection =
- [userInfo objectForKey:NSFileHandleNotificationFileHandleItem];
- _GTMDevAssert(newConnection != nil,
- @"failed to get the connection in the notification: %@",
- notification);
-
- // make sure we accept more...
- [listenHandle_ acceptConnectionInBackgroundAndNotify];
-
- // TODO: could let the delegate look at the address, before we start working
- // on it.
-
- NSMutableDictionary *connDict =
- [self connectionWithFileHandle:newConnection];
- [connections_ addObject:connDict];
-}
-
-- (NSMutableDictionary *)connectionWithFileHandle:(NSFileHandle *)fileHandle {
- NSMutableDictionary *result = [NSMutableDictionary dictionary];
-
- [result setObject:fileHandle forKey:kFileHandle];
-
- GTMHTTPRequestMessage *request =
- [[[GTMHTTPRequestMessage alloc] init] autorelease];
- [result setObject:request forKey:kRequest];
-
- // setup for data notifications
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(dataAvailableNotification:)
- name:NSFileHandleReadCompletionNotification
- object:fileHandle];
- [fileHandle readInBackgroundAndNotify];
-
- return result;
-}
-
-- (void)dataAvailableNotification:(NSNotification *)notification {
- NSFileHandle *connectionHandle = GTM_STATIC_CAST(NSFileHandle,
- [notification object]);
- NSMutableDictionary *connDict = [self lookupConnection:connectionHandle];
- if (connDict == nil) return; // we are no longer tracking this one
-
- NSDictionary *userInfo = [notification userInfo];
- NSData *readData = [userInfo objectForKey:NSFileHandleNotificationDataItem];
- if ([readData length] == 0) {
- // remote side closed
- [self closeConnection:connDict];
- return;
- }
-
- // Use a local pool to keep memory down incase the runloop we're in doesn't
- // drain until it gets a UI event.
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- @try {
- // Like Apple's sample, we just keep adding data until we get a full header
- // and any referenced body.
-
- GTMHTTPRequestMessage *request = [connDict objectForKey:kRequest];
- [request appendData:readData];
-
- // Is the header complete yet?
- if (![request isHeaderComplete]) {
- // more data...
- [connectionHandle readInBackgroundAndNotify];
- } else {
-
- // Do we have all the body?
- UInt32 contentLength = [request contentLength];
- NSData *body = [request body];
- NSUInteger bodyLength = [body length];
- if (contentLength > bodyLength) {
- // need more data...
- [connectionHandle readInBackgroundAndNotify];
- } else {
-
- if (contentLength < bodyLength) {
- // We got extra (probably someone trying to pipeline on us), trim
- // and let the extra data go...
- NSData *newBody = [NSData dataWithBytes:[body bytes]
- length:contentLength];
- [request setBody:newBody];
- _GTMDevLog(@"Got %lu extra bytes on http request, ignoring them",
- (unsigned long)(bodyLength - contentLength));
- }
-
- GTMHTTPResponseMessage *response = nil;
- @try {
- // Off to the delegate
- response = [delegate_ httpServer:self handleRequest:request];
- } @catch (NSException *e) {
- _GTMDevLog(@"Exception trying to handle http request: %@", e);
- } // COV_NF_LINE - radar 5851992 only reachable w/ an uncaught exception which isn't testable
-
- if (response) {
- // We don't support connection reuse, so we add (force) the header to
- // close every connection.
- [response setValue:@"close" forHeaderField:@"Connection"];
-
- // spawn thread to send reply (since we do a blocking send)
- [connDict setObject:response forKey:kResponse];
- [NSThread detachNewThreadSelector:@selector(sendResponseOnNewThread:)
- toTarget:self
- withObject:connDict];
- } else {
- // No response, shut it down
- [self closeConnection:connDict];
- }
-
- }
- }
- } @catch (NSException *e) { // COV_NF_START
- _GTMDevLog(@"exception while read data: %@", e);
- // exception while dealing with the connection, close it
- } // COV_NF_END
- @finally {
- [pool drain];
- }
-}
-
-- (NSMutableDictionary *)lookupConnection:(NSFileHandle *)fileHandle {
- NSMutableDictionary *result = nil;
- NSMutableDictionary *connDict;
- GTM_FOREACH_OBJECT(connDict, connections_) {
- if (fileHandle == [connDict objectForKey:kFileHandle]) {
- result = connDict;
- break;
- }
- }
- return result;
-}
-
-- (void)closeConnection:(NSMutableDictionary *)connDict {
- // remove the notification
- NSFileHandle *connectionHandle = [connDict objectForKey:kFileHandle];
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center removeObserver:self
- name:NSFileHandleReadCompletionNotification
- object:connectionHandle];
- // in a non GC world, we're fine just letting the connect get closed when
- // the object is release when it comes out of connections_, but in a GC world
- // it won't get cleaned up
- [connectionHandle closeFile];
-
- // remove it from the list
- [connections_ removeObject:connDict];
-}
-
-- (void)sendResponseOnNewThread:(NSMutableDictionary *)connDict {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- @try {
- GTMHTTPResponseMessage *response = [connDict objectForKey:kResponse];
- NSFileHandle *connectionHandle = [connDict objectForKey:kFileHandle];
- NSData *serialized = [response serializedData];
- [connectionHandle writeData:serialized];
- } @catch (NSException *e) { // COV_NF_START - causing an exception here is to hard in a test
- // TODO: let the delegate know about the exception (but do it on the main
- // thread)
- _GTMDevLog(@"exception while sending reply: %@", e);
- } // COV_NF_END
-
- // back to the main thread to close things down
- [self performSelectorOnMainThread:@selector(sentResponse:)
- withObject:connDict
- waitUntilDone:NO];
-
- [pool release];
-}
-
-- (void)sentResponse:(NSMutableDictionary *)connDict {
- // make sure we're still tracking this connection (in case server was stopped)
- NSFileHandle *connection = [connDict objectForKey:kFileHandle];
- NSMutableDictionary *connDict2 = [self lookupConnection:connection];
- if (connDict != connDict2) return;
-
- // TODO: message the delegate that it was sent
-
- // close it down
- [self closeConnection:connDict];
-}
-
-@end
-
-#pragma mark -
-
-@implementation GTMHTTPRequestMessage
-
-- (id)init {
- self = [super init];
- if (self) {
- message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, YES);
- }
- return self;
-}
-
-- (void)dealloc {
- if (message_) {
- CFRelease(message_);
- }
- [super dealloc];
-}
-
-- (NSString *)version {
- return GTMCFAutorelease(CFHTTPMessageCopyVersion(message_));
-}
-
-- (NSURL *)URL {
- return GTMCFAutorelease(CFHTTPMessageCopyRequestURL(message_));
-}
-
-- (NSString *)method {
- return GTMCFAutorelease(CFHTTPMessageCopyRequestMethod(message_));
-}
-
-- (NSData *)body {
- return GTMCFAutorelease(CFHTTPMessageCopyBody(message_));
-}
-
-- (NSDictionary *)allHeaderFieldValues {
- return GTMCFAutorelease(CFHTTPMessageCopyAllHeaderFields(message_));
-}
-
-- (NSString *)description {
- CFStringRef desc = CFCopyDescription(message_);
- NSString *result =
- [NSString stringWithFormat:@"%@<%p>{ message=%@ }", [self class], self, desc];
- CFRelease(desc);
- return result;
-}
-
-@end
-
-@implementation GTMHTTPRequestMessage (PrivateHelpers)
-
-- (BOOL)isHeaderComplete {
- return CFHTTPMessageIsHeaderComplete(message_) ? YES : NO;
-}
-
-- (BOOL)appendData:(NSData *)data {
- return CFHTTPMessageAppendBytes(message_,
- [data bytes], [data length]) ? YES : NO;
-}
-
-- (NSString *)headerFieldValueForKey:(NSString *)key {
- CFStringRef value = NULL;
- if (key) {
- value = CFHTTPMessageCopyHeaderFieldValue(message_, (CFStringRef)key);
- }
- return GTMCFAutorelease(value);
-}
-
-- (UInt32)contentLength {
- return [[self headerFieldValueForKey:@"Content-Length"] intValue];
-}
-
-- (void)setBody:(NSData *)body {
- if (!body) {
- body = [NSData data]; // COV_NF_LINE - can only happen in we fail to make the new data object
- }
- CFHTTPMessageSetBody(message_, (CFDataRef)body);
-}
-
-@end
-
-#pragma mark -
-
-@implementation GTMHTTPResponseMessage
-
-- (id)init {
- return [self initWithBody:nil contentType:nil statusCode:0];
-}
-
-- (void)dealloc {
- if (message_) {
- CFRelease(message_);
- }
- [super dealloc];
-}
-
-+ (id)responseWithString:(NSString *)plainText {
- NSData *body = [plainText dataUsingEncoding:NSUTF8StringEncoding];
- return [self responseWithBody:body
- contentType:@"text/plain; charset=UTF-8"
- statusCode:200];
-}
-
-+ (id)responseWithHTMLString:(NSString *)htmlString {
- return [self responseWithBody:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
- contentType:@"text/html; charset=UTF-8"
- statusCode:200];
-}
-
-+ (id)responseWithBody:(NSData *)body
- contentType:(NSString *)contentType
- statusCode:(int)statusCode {
- return [[[[self class] alloc] initWithBody:body
- contentType:contentType
- statusCode:statusCode] autorelease];
-}
-
-+ (id)emptyResponseWithCode:(int)statusCode {
- return [[[[self class] alloc] initWithBody:nil
- contentType:nil
- statusCode:statusCode] autorelease];
-}
-
-- (void)setValue:(NSString*)value forHeaderField:(NSString*)headerField {
- if ([headerField length] == 0) return;
- if (value == nil) {
- value = @"";
- }
- CFHTTPMessageSetHeaderFieldValue(message_,
- (CFStringRef)headerField, (CFStringRef)value);
-}
-
-- (NSString *)description {
- CFStringRef desc = CFCopyDescription(message_);
- NSString *result =
- [NSString stringWithFormat:@"%@<%p>{ message=%@ }", [self class], self, desc];
- CFRelease(desc);
- return result;
-}
-
-@end
-
-@implementation GTMHTTPResponseMessage (PrivateMethods)
-
-- (id)initWithBody:(NSData *)body
- contentType:(NSString *)contentType
- statusCode:(int)statusCode {
- self = [super init];
- if (self) {
- if ((statusCode < 100) || (statusCode > 599)) {
- [self release];
- return nil;
- }
- message_ = CFHTTPMessageCreateResponse(kCFAllocatorDefault,
- statusCode, NULL,
- kCFHTTPVersion1_0);
- if (!message_) {
- // COV_NF_START
- [self release];
- return nil;
- // COV_NF_END
- }
- NSUInteger bodyLength = 0;
- if (body) {
- bodyLength = [body length];
- CFHTTPMessageSetBody(message_, (CFDataRef)body);
- }
- if ([contentType length] == 0) {
- contentType = @"text/html";
- }
- NSString *bodyLenStr =
- [NSString stringWithFormat:@"%lu", (unsigned long)bodyLength];
- [self setValue:bodyLenStr forHeaderField:@"Content-Length"];
- [self setValue:contentType forHeaderField:@"Content-Type"];
- }
- return self;
-}
-
-- (NSData *)serializedData {
- return GTMCFAutorelease(CFHTTPMessageCopySerializedMessage(message_));
-}
-
-@end
diff --git a/Foundation/GTMHTTPServerTest.m b/Foundation/GTMHTTPServerTest.m
deleted file mode 100644
index 0cafaa2..0000000
--- a/Foundation/GTMHTTPServerTest.m
+++ /dev/null
@@ -1,652 +0,0 @@
-//
-// GTMHTTPServerTest.m
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-#import <netinet/in.h>
-#import <sys/socket.h>
-#import <unistd.h>
-#import "GTMSenTestCase.h"
-#import "GTMUnitTestDevLog.h"
-#import "GTMHTTPServer.h"
-#import "GTMRegex.h"
-#import "GTMGarbageCollection.h"
-
-@interface GTMHTTPServerTest : GTMTestCase {
- CFHTTPMessageRef fetchedMessage_;
- BOOL complete_;
-}
-@end
-
-@interface GTMHTTPServerTest (PrivateMethods)
-- (NSData *)fetchFromPort:(unsigned short)port
- payload:(NSString *)payload
- chunkSize:(NSUInteger)chunkSize;
-- (NSFileHandle *)fileHandleSendingToPort:(unsigned short)port
- payload:(NSString *)payload
- chunkSize:(NSUInteger)chunkSize;
-- (void)readData:(NSNotification *)notification;
-@end
-
-// helper class
-@interface TestServerDelegate : NSObject {
- NSMutableArray *requests_;
- NSMutableArray *responses_;
-}
-+ (id)testServerDelegate;
-- (NSUInteger)requestCount;
-- (GTMHTTPRequestMessage *)popRequest;
-- (void)pushResponse:(GTMHTTPResponseMessage *)message;
-@end
-
-// helper that throws while handling its request
-@interface TestThrowingServerDelegate : TestServerDelegate
-- (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
- handleRequest:(GTMHTTPRequestMessage *)request;
-@end
-
-// The timings used for waiting for replies
-const NSTimeInterval kGiveUpInterval = 5.0;
-const NSTimeInterval kRunLoopInterval = 0.01;
-
-// the size we break writes up into to test the reading code and how long to
-// wait between writes.
-const NSUInteger kSendChunkSize = 12;
-const NSTimeInterval kSendChunkInterval = 0.05;
-
-// ----------------------------------------------------------------------------
-
-@implementation GTMHTTPServerTest
-
-- (void)testInit {
- // bad delegates
- [GTMUnitTestDevLog expectString:@"missing delegate"];
- STAssertNil([[GTMHTTPServer alloc] init], nil);
- [GTMUnitTestDevLog expectString:@"missing delegate"];
- STAssertNil([[GTMHTTPServer alloc] initWithDelegate:nil], nil);
-
- TestServerDelegate *delegate = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
-
- // some attributes
-
- STAssertTrue([server delegate] == delegate, nil);
-
- [server setLocalhostOnly:NO];
- STAssertFalse([server localhostOnly], nil);
- [server setLocalhostOnly:YES];
- STAssertTrue([server localhostOnly], nil);
-
- STAssertEquals([server port], (uint16_t)0, nil);
- [server setPort:8080];
- STAssertEquals([server port], (uint16_t)8080, nil);
- [server setPort:80];
- STAssertEquals([server port], (uint16_t)80, nil);
-
- // description (atleast 10 chars)
- STAssertGreaterThan([[server description] length], (NSUInteger)10, nil);
-}
-
-- (void)testStartStop {
- TestServerDelegate *delegate1 = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate1, nil);
- GTMHTTPServer *server1 =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate1] autorelease];
- STAssertNotNil(server1, nil);
- NSError *error = nil;
- STAssertTrue([server1 start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
- STAssertGreaterThanOrEqual([server1 port], (uint16_t)1024,
- @"how'd we get a reserved port?");
-
- TestServerDelegate *delegate2 = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate2, nil);
- GTMHTTPServer *server2 =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate2] autorelease];
- STAssertNotNil(server2, nil);
-
- // try the reserved port
- [server2 setPort:666];
- error = nil;
- STAssertFalse([server2 start:&error], nil);
- STAssertNotNil(error, nil);
- STAssertEqualObjects([error domain], kGTMHTTPServerErrorDomain, nil);
- STAssertEquals([error code], (NSInteger)kGTMHTTPServerBindFailedError,
- @"port should have been reserved");
-
- // try the same port
- [server2 setPort:[server1 port]];
- error = nil;
- STAssertFalse([server2 start:&error], nil);
- STAssertNotNil(error, nil);
- STAssertEqualObjects([error domain], kGTMHTTPServerErrorDomain, nil);
- STAssertEquals([error code], (NSInteger)kGTMHTTPServerBindFailedError,
- @"port should have been in use");
-
- // try a random port again so we really start (prove two can run at once)
- [server2 setPort:0];
- error = nil;
- STAssertTrue([server2 start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
-
- // shut them down
- [server1 stop];
- [server2 stop];
-}
-
-- (void)testRestart {
- TestServerDelegate *delegate = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
- [server setLocalhostOnly:YES];
- [server setReusePort:YES];
- NSError *error = nil;
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
- uint16_t prevPort = [server port];
- STAssertGreaterThanOrEqual(prevPort, (uint16_t)1024,
- @"how'd we get a reserved port?");
- // restart and make sure it works
- [server stop];
- error = nil;
- [server setPort:prevPort];
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
-}
-
-- (void)testRequests {
- TestServerDelegate *delegate = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
- NSError *error = nil;
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
-
- // a request to test all the fields of a request object
-
- NSString *payload =
- @"PUT /some/server/path HTTP/1.0\r\n"
- @"Content-Length: 16\r\n"
- @"Custom-Header: Custom_Value\r\n"
- @"\r\n"
- @"this is the body";
- NSData *reply =
- [self fetchFromPort:[server port] payload:payload chunkSize:kSendChunkSize];
- STAssertNotNil(reply, nil);
-
- GTMHTTPRequestMessage *request = [delegate popRequest];
- STAssertEqualObjects([request version], @"HTTP/1.0", nil);
- STAssertEqualObjects([[request URL] absoluteString], @"/some/server/path", nil);
- STAssertEqualObjects([request method], @"PUT", nil);
- STAssertEqualObjects([request body],
- [@"this is the body" dataUsingEncoding:NSUTF8StringEncoding],
- nil);
- NSDictionary *allHeaders = [request allHeaderFieldValues];
- STAssertNotNil(allHeaders, nil);
- STAssertEquals([allHeaders count], (NSUInteger)2, nil);
- STAssertEqualObjects([allHeaders objectForKey:@"Content-Length"],
- @"16", nil);
- STAssertEqualObjects([allHeaders objectForKey:@"Custom-Header"],
- @"Custom_Value", nil);
- STAssertGreaterThan([[request description] length], (NSUInteger)10, nil);
-
- // test different request types (in simple form)
-
- typedef struct {
- NSString *method;
- NSString *url;
- } TestData;
-
- TestData data[] = {
- { @"GET", @"/foo/bar" },
- { @"HEAD", @"/foo/baz" },
- { @"POST", @"/foo" },
- { @"PUT", @"/foo/spam" },
- { @"DELETE", @"/fooby/doo" },
- { @"TRACE", @"/something.html" },
- { @"CONNECT", @"/spam" },
- { @"OPTIONS", @"/wee/doggies" },
- };
-
- for (size_t i = 0; i < sizeof(data) / sizeof(TestData); i++) {
- payload = [NSString stringWithFormat:@"%@ %@ HTTP/1.0\r\n\r\n",
- data[i].method, data[i].url];
- STAssertNotNil(payload, nil);
- reply = [self fetchFromPort:[server port]
- payload:payload
- chunkSize:kSendChunkSize];
- STAssertNotNil(reply, // just want a reply in this test
- @"failed of method %@", data[i].method);
- request = [delegate popRequest];
- STAssertEqualObjects([[request URL] absoluteString], data[i].url,
- @"urls didn't match for index %d", i);
- STAssertEqualObjects([request method], data[i].method,
- @"methods didn't match for index %d", i);
- }
-
- [server stop];
-}
-
-- (void)testResponses {
-
- // some quick init tests for invalid things
- STAssertNil([[GTMHTTPResponseMessage alloc] init], nil);
- STAssertNil([GTMHTTPResponseMessage responseWithBody:nil
- contentType:nil
- statusCode:99],
- nil);
- STAssertNil([GTMHTTPResponseMessage responseWithBody:nil
- contentType:nil
- statusCode:602],
- nil);
-
- TestServerDelegate *delegate = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
- NSError *error = nil;
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
-
- // test the html helper
-
- GTMHTTPResponseMessage *expectedResponse =
- [GTMHTTPResponseMessage responseWithHTMLString:@"Success!"];
- STAssertNotNil(expectedResponse, nil);
- STAssertGreaterThan([[expectedResponse description] length],
- (NSUInteger)0, nil);
- [delegate pushResponse:expectedResponse];
- NSData *responseData = [self fetchFromPort:[server port]
- payload:@"GET /foo HTTP/1.0\r\n\r\n"
- chunkSize:kSendChunkSize];
- STAssertNotNil(responseData, nil);
- NSString *responseString =
- [[[NSString alloc] initWithData:responseData
- encoding:NSUTF8StringEncoding] autorelease];
- STAssertNotNil(responseString, nil);
- STAssertTrue([responseString hasPrefix:@"HTTP/1.0 200 OK"],
- @"String: %@", responseString);
- STAssertTrue([responseString hasSuffix:@"Success!"],
- @"String: %@ should end w/ our data", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Content-Length: 8"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Content-Type: text/html; charset=UTF-8"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
-
- // test the plain code response
-
- expectedResponse = [GTMHTTPResponseMessage emptyResponseWithCode:299];
- STAssertNotNil(expectedResponse, nil);
- STAssertGreaterThan([[expectedResponse description] length],
- (NSUInteger)0, nil);
- [delegate pushResponse:expectedResponse];
- responseData = [self fetchFromPort:[server port]
- payload:@"GET /foo HTTP/1.0\r\n\r\n"
- chunkSize:kSendChunkSize];
- STAssertNotNil(responseData, nil);
- responseString =
- [[[NSString alloc] initWithData:responseData
- encoding:NSUTF8StringEncoding] autorelease];
- STAssertNotNil(responseString, nil);
- STAssertTrue([responseString hasPrefix:@"HTTP/1.0 299 "],
- @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Content-Length: 0"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Content-Type: text/html"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
-
- // test the general api w/ extra header add
-
- expectedResponse =
- [GTMHTTPResponseMessage responseWithBody:[@"FOO" dataUsingEncoding:NSUTF8StringEncoding]
- contentType:@"some/type"
- statusCode:298];
- STAssertNotNil(expectedResponse, nil);
- STAssertGreaterThan([[expectedResponse description] length],
- (NSUInteger)0, nil);
- [expectedResponse setValue:@"Custom_Value"
- forHeaderField:@"Custom-Header"];
- [expectedResponse setValue:nil
- forHeaderField:@"Custom-Header2"];
- [delegate pushResponse:expectedResponse];
- responseData = [self fetchFromPort:[server port]
- payload:@"GET /foo HTTP/1.0\r\n\r\n"
- chunkSize:kSendChunkSize];
- STAssertNotNil(responseData, nil);
- responseString =
- [[[NSString alloc] initWithData:responseData
- encoding:NSUTF8StringEncoding] autorelease];
- STAssertNotNil(responseString, nil);
- STAssertTrue([responseString hasPrefix:@"HTTP/1.0 298"],
- @"String: %@", responseString);
- STAssertTrue([responseString hasSuffix:@"FOO"], @"should end w/ our data");
- STAssertNotEquals([responseString rangeOfString:@"Content-Length: 3"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Content-Type: some/type"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Custom-Header: Custom_Value"].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
- STAssertNotEquals([responseString rangeOfString:@"Custom-Header2: "].location,
- (NSUInteger)NSNotFound, @"String: %@", responseString);
-
- // test plain text response
-
- expectedResponse = [GTMHTTPResponseMessage responseWithString:@"BAR"];
- STAssertNotNil(expectedResponse, nil);
- STAssertGreaterThan([[expectedResponse description] length],
- (NSUInteger)3, nil);
- [delegate pushResponse:expectedResponse];
- responseData = [self fetchFromPort:[server port]
- payload:@"GET /bar HTTP/1.0\r\n\r\n"
- chunkSize:kSendChunkSize];
- STAssertNotNil(responseData, nil);
- responseString =
- [[[NSString alloc] initWithData:responseData
- encoding:NSUTF8StringEncoding] autorelease];
- STAssertNotNil(responseString, nil);
- STAssertTrue([responseString hasPrefix:@"HTTP/1.0 200 "], nil);
- STAssertTrue([responseString hasSuffix:@"BAR"], @"should end w/ our data");
- STAssertNotEquals([responseString rangeOfString:@"Content-Length: 3"].location,
- (NSUInteger)NSNotFound, nil);
- STAssertNotEquals([responseString rangeOfString:@"Content-Type: text/plain"].location,
- (NSUInteger)NSNotFound, nil);
-
- [server stop];
-}
-
-- (void)testRequstEdgeCases {
- // test all the odd things about requests
-
- TestServerDelegate *delegate = [TestServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
- NSError *error = nil;
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
-
- // extra data (ie-pipelining)
-
- NSString *payload =
- @"GET /some/server/path HTTP/1.0\r\n"
- @"\r\n"
- @"GET /some/server/path/too HTTP/1.0\r\n"
- @"\r\n";
- // don't chunk this, we want to make sure both requests get to our server
- [GTMUnitTestDevLog expectString:@"Got 38 extra bytes on http request, "
- "ignoring them"];
- NSData *reply =
- [self fetchFromPort:[server port] payload:payload chunkSize:0];
- STAssertNotNil(reply, nil);
- STAssertEquals([delegate requestCount], (NSUInteger)1, nil);
-
- // close w/o full request
- {
- // local pool so we can force our handle to close
- NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
- NSFileHandle *handle =
- [self fileHandleSendingToPort:[server port]
- payload:@"GET /some/server/path HTTP/"
- chunkSize:kSendChunkSize];
- STAssertNotNil(handle, nil);
- // spin the run loop so reads the start of the request
- NSDate* loopIntervalDate =
- [NSDate dateWithTimeIntervalSinceNow:kRunLoopInterval];
- [[NSRunLoop currentRunLoop] runUntilDate:loopIntervalDate];
- // make sure we see the request at this point
- STAssertEquals([server activeRequestCount], (NSUInteger)1,
- @"should have started the request by now");
- // force the connection closed and drop the pool to get all the cleanup to
- // happen.
- [handle closeFile];
- [localPool drain];
- // spin the run loop so it should see the close
- loopIntervalDate = [NSDate dateWithTimeIntervalSinceNow:kRunLoopInterval];
- [[NSRunLoop currentRunLoop] runUntilDate:loopIntervalDate];
- // make sure we didn't get a request (1 is from test before) and make sure
- // we don't have some in flight.
- STAssertEquals([delegate requestCount], (NSUInteger)1,
- @"shouldn't have gotten another request");
- STAssertEquals([server activeRequestCount], (NSUInteger)0,
- @"should have cleaned up the pending connection");
- }
-
-}
-
-- (void)testExceptionDuringRequest {
-
- TestServerDelegate *delegate = [TestThrowingServerDelegate testServerDelegate];
- STAssertNotNil(delegate, nil);
- GTMHTTPServer *server =
- [[[GTMHTTPServer alloc] initWithDelegate:delegate] autorelease];
- STAssertNotNil(server, nil);
- NSError *error = nil;
- STAssertTrue([server start:&error], @"failed to start (error=%@)", error);
- STAssertNil(error, @"error: %@", error);
- [GTMUnitTestDevLog expectString:@"Exception trying to handle http request: "
- "To test our handling"];
- NSData *responseData = [self fetchFromPort:[server port]
- payload:@"GET /foo HTTP/1.0\r\n\r\n"
- chunkSize:kSendChunkSize];
- STAssertNil(responseData, nil);
- STAssertEquals([delegate requestCount], (NSUInteger)1, nil);
- STAssertEquals([server activeRequestCount], (NSUInteger)0, nil);
-}
-
-@end
-
-// ----------------------------------------------------------------------------
-
-@implementation GTMHTTPServerTest (PrivateMethods)
-
-- (NSData *)fetchFromPort:(unsigned short)port
- payload:(NSString *)payload
- chunkSize:(NSUInteger)chunkSize {
- STAssertNULL(fetchedMessage_, nil);
- fetchedMessage_ = CFHTTPMessageCreateEmpty(NULL, false);
- complete_ = NO;
-
- NSFileHandle *handle = [self fileHandleSendingToPort:port
- payload:payload
- chunkSize:chunkSize];
-
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
- // Do not use NSFileHandleReadToEndOfFileCompletionNotification on Snow
- // Leopard as we can run into a deadlock when we call close on the
- // file handle while it is still waiting for data.
- [center addObserver:self
- selector:@selector(readData:)
- name:NSFileHandleReadCompletionNotification
- object:handle];
- [handle readInBackgroundAndNotify];
-
- // wait for our reply
- NSDate* giveUpDate = [NSDate dateWithTimeIntervalSinceNow:kGiveUpInterval];
- while (!complete_ && [giveUpDate timeIntervalSinceNow] > 0) {
- NSDate* loopIntervalDate =
- [NSDate dateWithTimeIntervalSinceNow:kRunLoopInterval];
- [[NSRunLoop currentRunLoop] runUntilDate:loopIntervalDate];
- }
-
- [center removeObserver:self
- name:NSFileHandleReadCompletionNotification
- object:handle];
- NSData *data = nil;
- if (complete_) {
- data = GTMCFAutorelease(CFHTTPMessageCopySerializedMessage(fetchedMessage_));
- }
- CFRelease(fetchedMessage_);
- fetchedMessage_ = NULL;
- complete_ = NO;
- return data;
-}
-
-- (NSFileHandle *)fileHandleSendingToPort:(unsigned short)port
- payload:(NSString *)payload
- chunkSize:(NSUInteger)chunkSize {
- int fd = socket(AF_INET, SOCK_STREAM, 0);
- STAssertGreaterThan(fd, 0, @"failed to create socket");
-
- struct sockaddr_in addr;
- bzero(&addr, sizeof(addr));
- addr.sin_len = sizeof(addr);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(0x7F000001);
- int connectResult =
- connect(fd, (struct sockaddr*)(&addr), (socklen_t)sizeof(addr));
- STAssertEquals(connectResult, 0, nil);
-
- NSFileHandle *handle =
- [[[NSFileHandle alloc] initWithFileDescriptor:fd
- closeOnDealloc:YES] autorelease];
- STAssertNotNil(handle, nil);
-
- NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
-
- // we can send in one block or in chunked mode
- if (chunkSize > 0) {
- // we don't write the data in one large block, instead of write it out
- // in bits to help test the data collection code.
- NSUInteger length = [payloadData length];
- for (NSUInteger x = 0 ; x < length ; x += chunkSize) {
- NSUInteger dataChunkSize = length - x;
- if (dataChunkSize > chunkSize) {
- dataChunkSize = chunkSize;
- }
- NSData *dataChunk
- = [payloadData subdataWithRange:NSMakeRange(x, dataChunkSize)];
- [handle writeData:dataChunk];
- // delay after all but the last chunk to give it time to be read.
- if ((x + chunkSize) < length) {
- NSDate* loopIntervalDate =
- [NSDate dateWithTimeIntervalSinceNow:kSendChunkInterval];
- [[NSRunLoop currentRunLoop] runUntilDate:loopIntervalDate];
- }
- }
- } else {
- [handle writeData:payloadData];
- }
-
- return handle;
-}
-
-- (void)readData:(NSNotification *)notification {
- NSDictionary *userInfo = [notification userInfo];
- NSData *readData = [userInfo objectForKey:NSFileHandleNotificationDataItem];
- STAssertNotNil(readData, nil);
- STAssertNotNULL(fetchedMessage_, nil);
- STAssertTrue(CFHTTPMessageAppendBytes(fetchedMessage_,
- [readData bytes],
- [readData length]), @"Data %@",
- [[[NSString alloc] initWithData:readData
- encoding:NSUTF8StringEncoding]
- autorelease]);
- if (CFHTTPMessageIsHeaderComplete(fetchedMessage_)) {
- NSString *lengthString
- = GTMCFAutorelease(CFHTTPMessageCopyHeaderFieldValue(fetchedMessage_,
- CFSTR("Content-Length")));
- if (lengthString) {
- NSUInteger length = [lengthString intValue];
- NSData *messageData = GTMCFAutorelease(CFHTTPMessageCopyBody(fetchedMessage_));
- if ([messageData length] >= length) {
- complete_ = YES;
- }
- }
- }
-}
-
-@end
-
-// ----------------------------------------------------------------------------
-
-@implementation TestServerDelegate
-
-- (id)init {
- self = [super init];
- if (self) {
- requests_ = [[NSMutableArray alloc] init];
- responses_ = [[NSMutableArray alloc] init];
- }
- return self;
-}
-
-- (void)dealloc {
- [requests_ release];
- [responses_ release];
- [super dealloc];
-}
-
-+ (id)testServerDelegate {
- return [[[[self class] alloc] init] autorelease];
-}
-
-- (NSUInteger)requestCount {
- return [requests_ count];
-}
-
-- (GTMHTTPRequestMessage *)popRequest {
- GTMHTTPRequestMessage *result = [[[requests_ lastObject] retain] autorelease];
- [requests_ removeLastObject];
- return result;
-}
-
-- (void)pushResponse:(GTMHTTPResponseMessage *)message {
- [responses_ addObject:message];
-}
-
-- (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
- handleRequest:(GTMHTTPRequestMessage *)request {
- [requests_ addObject:request];
-
- GTMHTTPResponseMessage *result = nil;
- if ([responses_ count] > 0) {
- result = [[[responses_ lastObject] retain] autorelease];
- [responses_ removeLastObject];
- } else {
- result = [GTMHTTPResponseMessage responseWithHTMLString:@"success"];
- }
- return result;
-}
-
-@end
-
-// ----------------------------------------------------------------------------
-
-@implementation TestThrowingServerDelegate
-
-- (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
- handleRequest:(GTMHTTPRequestMessage *)request {
- // let the base do its normal work for counts, etc.
- [super httpServer:server handleRequest:request];
- NSException *exception =
- [NSException exceptionWithName:@"InternalTestingException"
- reason:@"To test our handling"
- userInfo:nil];
- @throw exception;
-}
-
-@end
diff --git a/Foundation/GTMNSData+Hex.h b/Foundation/GTMNSData+Hex.h
deleted file mode 100644
index ed21f17..0000000
--- a/Foundation/GTMNSData+Hex.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// 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.
-//
-
-
-// WARNING: This class provides a subset of the functionality available in
-// GTMStringEncoding and may go away in the future.
-// Please consider using GTMStringEncoding instead.
-
-
-#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
deleted file mode 100644
index c7e740d..0000000
--- a/Foundation/GTMNSData+Hex.m
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// 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
deleted file mode 100644
index 6bc1608..0000000
--- a/Foundation/GTMNSData+HexTest.m
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// 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/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj
index 4f471d5..4f77c6c 100644
--- a/GTM.xcodeproj/project.pbxproj
+++ b/GTM.xcodeproj/project.pbxproj
@@ -40,11 +40,8 @@
0B1B9B8710FECD870084EE4B /* GTMStringEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B1B9B8410FECD870084EE4B /* GTMStringEncoding.h */; settings = {ATTRIBUTES = (Public, ); }; };
0B1B9B8810FECD870084EE4B /* GTMStringEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B1B9B8510FECD870084EE4B /* GTMStringEncoding.m */; };
0B1B9B8A10FECDA00084EE4B /* GTMStringEncodingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B1B9B8610FECD870084EE4B /* GTMStringEncodingTest.m */; };
- 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 */; };
@@ -298,9 +295,6 @@
F41A6F820E02EC3600788A6C /* GTMSignalHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F41A6F7F0E02EC3600788A6C /* GTMSignalHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
F41A6F830E02EC3600788A6C /* GTMSignalHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = F41A6F800E02EC3600788A6C /* GTMSignalHandler.m */; };
F41A6F850E02EC4D00788A6C /* GTMSignalHandlerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F41A6F810E02EC3600788A6C /* GTMSignalHandlerTest.m */; };
- F41D258B0DBD21A300774EEB /* GTMBase64.h in Headers */ = {isa = PBXBuildFile; fileRef = F41D25880DBD21A300774EEB /* GTMBase64.h */; settings = {ATTRIBUTES = (Public, ); }; };
- F41D258C0DBD21A300774EEB /* GTMBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = F41D25890DBD21A300774EEB /* GTMBase64.m */; };
- F41D258F0DBD21B900774EEB /* GTMBase64Test.m in Sources */ = {isa = PBXBuildFile; fileRef = F41D258A0DBD21A300774EEB /* GTMBase64Test.m */; };
F424F7010D9AA02B000B87EF /* GTMNSData+zlibTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F43E4E600D4E5EC90041161F /* GTMNSData+zlibTest.m */; };
F424F75F0D9AF019000B87EF /* GTMDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B1A16050D90344B00CA1E8E /* GTMDefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
F42597480E23AA57003BEA3E /* GTMNSString+Replace.h in Headers */ = {isa = PBXBuildFile; fileRef = F42597450E23AA57003BEA3E /* GTMNSString+Replace.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -393,10 +387,6 @@
F4A420F00EDDF8E000397A11 /* GTMHotKeyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = F4A420ED0EDDF8E000397A11 /* GTMHotKeyTextField.m */; };
F4A486ED1097EA0A00513483 /* GTMUnitTestingView.10.6.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F4A486EC1097EA0A00513483 /* GTMUnitTestingView.10.6.tiff */; };
F4AA2CB2109B37650025C956 /* GTMUILocalizerAndLayoutTweakerTest3-4.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F4AA2CB1109B37650025C956 /* GTMUILocalizerAndLayoutTweakerTest3-4.tiff */; };
- F4BC1C880DDDD45D00108B7D /* GTMHTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = F4BC1C860DDDD45D00108B7D /* GTMHTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- F4BC1C890DDDD45D00108B7D /* GTMHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BC1C870DDDD45D00108B7D /* GTMHTTPServer.m */; };
- F4BC1E8D0DE1FC4A00108B7D /* GTMHTTPServerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BC1E8C0DE1FC4A00108B7D /* GTMHTTPServerTest.m */; };
- F4BC22D10DE4C39000108B7D /* GTMTestHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BC22D00DE4C39000108B7D /* GTMTestHTTPServer.m */; };
F4C0B9C3108E27EE002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4C0B9C2108E27EE002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5.xib */; };
F4C0B9DA108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-0.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F4C0B9D7108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-0.tiff */; };
F4C0B9DB108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-1.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F4C0B9D8108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-1.tiff */; };
@@ -527,9 +517,6 @@
0B1B9B8410FECD870084EE4B /* GTMStringEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GTMStringEncoding.h; path = Foundation/GTMStringEncoding.h; sourceTree = SOURCE_ROOT; };
0B1B9B8510FECD870084EE4B /* GTMStringEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GTMStringEncoding.m; path = Foundation/GTMStringEncoding.m; sourceTree = SOURCE_ROOT; };
0B1B9B8610FECD870084EE4B /* GTMStringEncodingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GTMStringEncodingTest.m; path = Foundation/GTMStringEncodingTest.m; sourceTree = SOURCE_ROOT; };
- 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>"; };
@@ -786,9 +773,6 @@
F41A6F7F0E02EC3600788A6C /* GTMSignalHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMSignalHandler.h; sourceTree = "<group>"; };
F41A6F800E02EC3600788A6C /* GTMSignalHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMSignalHandler.m; sourceTree = "<group>"; };
F41A6F810E02EC3600788A6C /* GTMSignalHandlerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMSignalHandlerTest.m; sourceTree = "<group>"; };
- F41D25880DBD21A300774EEB /* GTMBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMBase64.h; sourceTree = "<group>"; };
- F41D25890DBD21A300774EEB /* GTMBase64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMBase64.m; sourceTree = "<group>"; };
- F41D258A0DBD21A300774EEB /* GTMBase64Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMBase64Test.m; sourceTree = "<group>"; };
F42597450E23AA57003BEA3E /* GTMNSString+Replace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSString+Replace.h"; sourceTree = "<group>"; };
F42597460E23AA57003BEA3E /* GTMNSString+Replace.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+Replace.m"; sourceTree = "<group>"; };
F42597470E23AA57003BEA3E /* GTMNSString+ReplaceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+ReplaceTest.m"; sourceTree = "<group>"; };
@@ -898,11 +882,6 @@
F4A420EE0EDDF8E000397A11 /* GTMHotKeyTextFieldTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHotKeyTextFieldTest.m; sourceTree = "<group>"; };
F4A486EC1097EA0A00513483 /* GTMUnitTestingView.10.6.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMUnitTestingView.10.6.tiff; sourceTree = "<group>"; };
F4AA2CB1109B37650025C956 /* GTMUILocalizerAndLayoutTweakerTest3-4.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMUILocalizerAndLayoutTweakerTest3-4.tiff"; sourceTree = "<group>"; };
- F4BC1C860DDDD45D00108B7D /* GTMHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMHTTPServer.h; sourceTree = "<group>"; };
- F4BC1C870DDDD45D00108B7D /* GTMHTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHTTPServer.m; sourceTree = "<group>"; };
- F4BC1E8C0DE1FC4A00108B7D /* GTMHTTPServerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHTTPServerTest.m; sourceTree = "<group>"; };
- F4BC22CF0DE4C39000108B7D /* GTMTestHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMTestHTTPServer.h; sourceTree = "<group>"; };
- F4BC22D00DE4C39000108B7D /* GTMTestHTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMTestHTTPServer.m; sourceTree = "<group>"; };
F4C0B9C2108E27EE002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GTMUILocalizerAndLayoutTweakerTest5.xib; sourceTree = "<group>"; };
F4C0B9D7108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-0.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMUILocalizerAndLayoutTweakerTest5-0.tiff"; sourceTree = "<group>"; };
F4C0B9D8108E3142002FC8E4 /* GTMUILocalizerAndLayoutTweakerTest5-1.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMUILocalizerAndLayoutTweakerTest5-1.tiff"; sourceTree = "<group>"; };
@@ -1382,9 +1361,6 @@
0B1B9B8410FECD870084EE4B /* GTMStringEncoding.h */,
0B1B9B8510FECD870084EE4B /* GTMStringEncoding.m */,
0B1B9B8610FECD870084EE4B /* GTMStringEncodingTest.m */,
- 0BFAD4BF104D06EF002BEB27 /* GTMNSData+Hex.h */,
- 0BFAD4C0104D06EF002BEB27 /* GTMNSData+Hex.m */,
- 0BFAD4C1104D06EF002BEB27 /* GTMNSData+HexTest.m */,
0BFAD4C2104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h */,
0BFAD4C3104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m */,
0BFAD4C4104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m */,
@@ -1404,9 +1380,6 @@
1012DF540F4252BD004794DB /* GTMAbstractDOListener.h */,
1012DF550F4252BD004794DB /* GTMAbstractDOListener.m */,
1012DF590F425525004794DB /* GTMAbstractDOListenerTest.m */,
- F41D25880DBD21A300774EEB /* GTMBase64.h */,
- F41D25890DBD21A300774EEB /* GTMBase64.m */,
- F41D258A0DBD21A300774EEB /* GTMBase64Test.m */,
8B1B49160E5F8E2100A08972 /* GTMExceptionalInlines.h */,
8B1B49170E5F8E2100A08972 /* GTMExceptionalInlines.m */,
8B1B491B0E5F904C00A08972 /* GTMExceptionalInlinesTest.m */,
@@ -1423,9 +1396,6 @@
F47F1D2E0D4914AD00925B8F /* GTMCalculatedRange.m */,
F47F1D2F0D4914AD00925B8F /* GTMCalculatedRangeTest.m */,
F48FE28D0D198D24009257D2 /* GTMGarbageCollection.h */,
- F4BC1C860DDDD45D00108B7D /* GTMHTTPServer.h */,
- F4BC1C870DDDD45D00108B7D /* GTMHTTPServer.m */,
- F4BC1E8C0DE1FC4A00108B7D /* GTMHTTPServerTest.m */,
F41711320ECDFBD500B9B276 /* GTMLightweightProxy.h */,
F41711330ECDFBD500B9B276 /* GTMLightweightProxy.m */,
F41711340ECDFBD500B9B276 /* GTMLightweightProxyTest.m */,
@@ -1544,8 +1514,6 @@
F48FE29C0D198D36009257D2 /* GTMNSObject+UnitTesting.m */,
F48FE29F0D198D36009257D2 /* GTMSenTestCase.h */,
8B7DCE180DFF39850017E983 /* GTMSenTestCase.m */,
- F4BC22CF0DE4C39000108B7D /* GTMTestHTTPServer.h */,
- F4BC22D00DE4C39000108B7D /* GTMTestHTTPServer.m */,
8B3590150E8190FA0041E21C /* GTMTestTimer.h */,
8B35901A0E8191750041E21C /* GTMTestTimerTest.m */,
8B7DCBF00DFF1A610017E983 /* GTMUnitTestDevLog.h */,
@@ -1611,7 +1579,6 @@
buildActionMask = 2147483647;
files = (
0B1B9B8710FECD870084EE4B /* GTMStringEncoding.h in Headers */,
- 0BFAD4C5104D06EF002BEB27 /* GTMNSData+Hex.h in Headers */,
0BFAD4C8104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.h in Headers */,
F93207DE0F4B82DB005F37EA /* GTMSQLite.h in Headers */,
F42E09490D199BBF00D5DDE0 /* GTMDelegatingTableColumn.h in Headers */,
@@ -1637,11 +1604,9 @@
F4FF22780D9D4835003880AC /* GTMDebugSelectorValidation.h in Headers */,
F4CA854F0DAFAAF600B4AB10 /* GTMObjC2Runtime.h in Headers */,
8BC04CD80DB003D800C2D1CA /* GTMMethodCheck.h in Headers */,
- F41D258B0DBD21A300774EEB /* GTMBase64.h in Headers */,
F431221D0DD4E3B800F45252 /* GTMStackTrace.h in Headers */,
33C372A60DD8A88500E97817 /* GTMNSString+URLArguments.h in Headers */,
33C374380DD8D44800E97817 /* GTMNSDictionary+URLArguments.h in Headers */,
- F4BC1C880DDDD45D00108B7D /* GTMHTTPServer.h in Headers */,
8BE281B00DEC7E930035B3F8 /* GTMNSAppleScript+Handler.h in Headers */,
8BE281B10DEC7E930035B3F8 /* GTMNSAppleEventDescriptor+Handler.h in Headers */,
8BE281B20DEC7E930035B3F8 /* GTMNSAppleEventDescriptor+Foundation.h in Headers */,
@@ -2208,12 +2173,9 @@
8B6F32080DA34A1B0052CA40 /* GTMObjC2RuntimeTest.m in Sources */,
8B6F32160DA34C830052CA40 /* GTMMethodCheckTest.m in Sources */,
8BC045C20DAE899100C2D1CA /* GTMGeometryUtilsTest.m in Sources */,
- F41D258F0DBD21B900774EEB /* GTMBase64Test.m in Sources */,
F431221F0DD4E3C900F45252 /* GTMStackTraceTest.m in Sources */,
33C372B40DD8A93000E97817 /* GTMNSString+URLArgumentsTest.m in Sources */,
33C3745F0DD8D85B00E97817 /* GTMNSDictionary+URLArgumentsTest.m in Sources */,
- F4BC1E8D0DE1FC4A00108B7D /* GTMHTTPServerTest.m in Sources */,
- F4BC22D10DE4C39000108B7D /* GTMTestHTTPServer.m in Sources */,
8B3344210DBF7A36009FD32C /* GTMNSAppleScript+HandlerTest.m in Sources */,
8B3344230DBF7A36009FD32C /* GTMNSAppleEventDescriptor+HandlerTest.m in Sources */,
8B3344250DBF7A36009FD32C /* GTMNSAppleEventDescriptor+FoundationTest.m in Sources */,
@@ -2241,7 +2203,6 @@
10998F8B0F4B5F1B007F179D /* GTMTransientRootProxyTest.m in Sources */,
108930850F4CCB380018D4A0 /* GTMTransientRootPortProxyTest.m in Sources */,
8BD35B940FB22986009058F5 /* GTMNSScanner+JSONTest.m in Sources */,
- 0BFAD4CB104D06FE002BEB27 /* GTMNSData+HexTest.m in Sources */,
0BFAD4CC104D06FE002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */,
8B3080151056B917006C4C7A /* GTMNSNumber+64BitTest.m in Sources */,
0B1B9B8A10FECDA00084EE4B /* GTMStringEncodingTest.m in Sources */,
@@ -2276,10 +2237,8 @@
F47A79890D746EE9002302AB /* GTMScriptRunner.m in Sources */,
F41390900D75F63C00F72B31 /* GTMNSFileManager+Path.m in Sources */,
8B45A21E0DA46E34001148C5 /* GTMObjC2Runtime.m in Sources */,
- F41D258C0DBD21A300774EEB /* GTMBase64.m in Sources */,
33C372A70DD8A88500E97817 /* GTMNSString+URLArguments.m in Sources */,
33C374390DD8D44800E97817 /* GTMNSDictionary+URLArguments.m in Sources */,
- F4BC1C890DDDD45D00108B7D /* GTMHTTPServer.m in Sources */,
8B7DCB9B0DFF0E850017E983 /* GTMFourCharCode.m in Sources */,
8B7DCBBD0DFF0F5D0017E983 /* GTMMethodCheck.m in Sources */,
8B7DCBD20DFF16070017E983 /* GTMNSAppleScript+Handler.m in Sources */,
@@ -2318,7 +2277,6 @@
8207B89C0FEA7AA1008A527B /* GTMWindowSheetController.m in Sources */,
F43C7A581021FAA300ABF03C /* GTMUILocalizerAndLayoutTweaker.m in Sources */,
7F97DB33104EBCA3004DDDEE /* GTMFadeTruncatingTextFieldCell.m in Sources */,
- 0BFAD4C6104D06EF002BEB27 /* GTMNSData+Hex.m in Sources */,
0BFAD4C9104D06EF002BEB27 /* GTMNSDictionary+CaseInsensitive.m in Sources */,
7FF768E51051B17E00D34F4B /* GTMNSImage+SearchCache.m in Sources */,
8B307FF81056B773006C4C7A /* GTMNSNumber+64Bit.m in Sources */,
diff --git a/GTMiPhone.xcodeproj/project.pbxproj b/GTMiPhone.xcodeproj/project.pbxproj
index 651b263..7e2a5e0 100644
--- a/GTMiPhone.xcodeproj/project.pbxproj
+++ b/GTMiPhone.xcodeproj/project.pbxproj
@@ -21,8 +21,6 @@
/* 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 */; };
0BBC768B10FEF62C0006FABE /* GTMStringEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BBC768910FEF61D0006FABE /* GTMStringEncoding.m */; };
@@ -62,8 +60,6 @@
8B308BCE0DAD0B8400183556 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B308BCD0DAD0B8400183556 /* QuartzCore.framework */; };
8B3AA8F30E032FC7007E31B5 /* GTMNSString+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA8F10E032FC7007E31B5 /* GTMNSString+URLArguments.m */; };
8B3AA8F40E032FC7007E31B5 /* GTMNSString+URLArgumentsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA8F20E032FC7007E31B5 /* GTMNSString+URLArgumentsTest.m */; };
- 8B3AA9240E033624007E31B5 /* GTMHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA9200E033624007E31B5 /* GTMHTTPServer.m */; };
- 8B3AA9290E033647007E31B5 /* GTMTestHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA9280E033647007E31B5 /* GTMTestHTTPServer.m */; };
8B3AA9340E0336AC007E31B5 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B3AA9330E0336AC007E31B5 /* CFNetwork.framework */; };
8B41EC0F0E0711D40040CF9F /* GTMValidatingContainersTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B41EC0C0E0711D40040CF9F /* GTMValidatingContainersTest.m */; };
8B41EC100E0711D40040CF9F /* GTMValidatingContainers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B41EC0D0E0711D40040CF9F /* GTMValidatingContainers.m */; };
@@ -103,7 +99,6 @@
8BCB5AB211C02D7D009B6C40 /* GTMNSScanner+UnsignedTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCB5AB011C02D7D009B6C40 /* GTMNSScanner+UnsignedTest.m */; };
8BD35C920FB234E1009058F5 /* GTMNSScanner+JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD35C900FB234E1009058F5 /* GTMNSScanner+JSON.m */; };
8BD35C930FB234E1009058F5 /* GTMNSScanner+JSONTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD35C910FB234E1009058F5 /* GTMNSScanner+JSONTest.m */; };
- 8BDA25130E759A6400C9769D /* GTMHTTPServerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA9210E033624007E31B5 /* GTMHTTPServerTest.m */; };
8BDA25140E759A6500C9769D /* GTMNSData+zlibTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC047800DAE928A00C2D1CA /* GTMNSData+zlibTest.m */; };
8BE839890E89C74B00C611B0 /* GTMDebugThreadValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE839870E89C74A00C611B0 /* GTMDebugThreadValidation.m */; };
8BE83A660E8B059A00C611B0 /* GTMDebugThreadValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE83A650E8B059A00C611B0 /* GTMDebugThreadValidationTest.m */; };
@@ -124,8 +119,6 @@
F418AFCE0E755C94004FB565 /* GTMNSDictionary+URLArgumentsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AFCC0E755C94004FB565 /* GTMNSDictionary+URLArgumentsTest.m */; };
F418AFD70E755D44004FB565 /* GTMPath.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AFD50E755D44004FB565 /* GTMPath.m */; };
F418AFD80E755D44004FB565 /* GTMPathTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AFD60E755D44004FB565 /* GTMPathTest.m */; };
- F439ADEB0DBD3C0000BE9B91 /* GTMBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADE90DBD3C0000BE9B91 /* GTMBase64.m */; };
- F439ADEC0DBD3C0000BE9B91 /* GTMBase64Test.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEA0DBD3C0000BE9B91 /* GTMBase64Test.m */; };
F439ADF00DBD3C4000BE9B91 /* GTMGeometryUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEE0DBD3C4000BE9B91 /* GTMGeometryUtils.m */; };
F439ADF10DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEF0DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m */; };
F4E3B3D80EB5EF2400CB713D /* GTMUIFont+LineHeight.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E3B3D70EB5EF2400CB713D /* GTMUIFont+LineHeight.m */; };
@@ -145,9 +138,6 @@
/* 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>"; };
@@ -202,11 +192,6 @@
8B3AA8F00E032FC7007E31B5 /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSString+URLArguments.h"; sourceTree = "<group>"; };
8B3AA8F10E032FC7007E31B5 /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+URLArguments.m"; sourceTree = "<group>"; };
8B3AA8F20E032FC7007E31B5 /* GTMNSString+URLArgumentsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+URLArgumentsTest.m"; sourceTree = "<group>"; };
- 8B3AA91F0E033624007E31B5 /* GTMHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMHTTPServer.h; sourceTree = "<group>"; };
- 8B3AA9200E033624007E31B5 /* GTMHTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHTTPServer.m; sourceTree = "<group>"; };
- 8B3AA9210E033624007E31B5 /* GTMHTTPServerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHTTPServerTest.m; sourceTree = "<group>"; };
- 8B3AA9270E033647007E31B5 /* GTMTestHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMTestHTTPServer.h; sourceTree = "<group>"; };
- 8B3AA9280E033647007E31B5 /* GTMTestHTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMTestHTTPServer.m; sourceTree = "<group>"; };
8B3AA9330E0336AC007E31B5 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
8B41EC0C0E0711D40040CF9F /* GTMValidatingContainersTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMValidatingContainersTest.m; sourceTree = "<group>"; };
8B41EC0D0E0711D40040CF9F /* GTMValidatingContainers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMValidatingContainers.m; sourceTree = "<group>"; };
@@ -310,9 +295,6 @@
F418AFD40E755D44004FB565 /* GTMPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMPath.h; sourceTree = "<group>"; };
F418AFD50E755D44004FB565 /* GTMPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMPath.m; sourceTree = "<group>"; };
F418AFD60E755D44004FB565 /* GTMPathTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMPathTest.m; sourceTree = "<group>"; };
- F439ADE80DBD3C0000BE9B91 /* GTMBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMBase64.h; sourceTree = "<group>"; };
- F439ADE90DBD3C0000BE9B91 /* GTMBase64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMBase64.m; sourceTree = "<group>"; };
- F439ADEA0DBD3C0000BE9B91 /* GTMBase64Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMBase64Test.m; sourceTree = "<group>"; };
F439ADED0DBD3C4000BE9B91 /* GTMGeometryUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMGeometryUtils.h; sourceTree = "<group>"; };
F439ADEE0DBD3C4000BE9B91 /* GTMGeometryUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMGeometryUtils.m; sourceTree = "<group>"; };
F439ADEF0DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMGeometryUtilsTest.m; sourceTree = "<group>"; };
@@ -456,15 +438,9 @@
0BBC768810FEF61D0006FABE /* GTMStringEncoding.h */,
0BBC768910FEF61D0006FABE /* GTMStringEncoding.m */,
0BBC768A10FEF61D0006FABE /* GTMStringEncodingTest.m */,
- 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 */,
8BC047770DAE928A00C2D1CA /* GTMCalculatedRange.h */,
8BC047780DAE928A00C2D1CA /* GTMCalculatedRange.m */,
8BC047790DAE928A00C2D1CA /* GTMCalculatedRangeTest.m */,
@@ -475,9 +451,6 @@
F439ADED0DBD3C4000BE9B91 /* GTMGeometryUtils.h */,
F439ADEE0DBD3C4000BE9B91 /* GTMGeometryUtils.m */,
F439ADEF0DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m */,
- 8B3AA91F0E033624007E31B5 /* GTMHTTPServer.h */,
- 8B3AA9200E033624007E31B5 /* GTMHTTPServer.m */,
- 8B3AA9210E033624007E31B5 /* GTMHTTPServerTest.m */,
F41711570ECDFF0400B9B276 /* GTMLightweightProxy.h */,
F41711580ECDFF0400B9B276 /* GTMLightweightProxy.m */,
F41711590ECDFF0400B9B276 /* GTMLightweightProxyTest.m */,
@@ -566,8 +539,6 @@
isa = PBXGroup;
children = (
8B7DCEA90DFF4C760017E983 /* GTMDevLogUnitTestingBridge.m */,
- 8B3AA9270E033647007E31B5 /* GTMTestHTTPServer.h */,
- 8B3AA9280E033647007E31B5 /* GTMTestHTTPServer.m */,
8BC047A00DAE928A00C2D1CA /* GTMCALayer+UnitTesting.h */,
8BC047A10DAE928A00C2D1CA /* GTMCALayer+UnitTesting.m */,
8B5547C70DB3BBF20014CC1C /* GTMUIKit+UnitTesting.m */,
@@ -812,8 +783,6 @@
8BC04A750DAF145200C2D1CA /* GTMSystemVersion.m in Sources */,
8B5547CA0DB3BBF20014CC1C /* GTMUIKit+UnitTesting.m in Sources */,
8B5547CB0DB3BBF20014CC1C /* GTMUIKit+UnitTestingTest.m in Sources */,
- F439ADEB0DBD3C0000BE9B91 /* GTMBase64.m in Sources */,
- F439ADEC0DBD3C0000BE9B91 /* GTMBase64Test.m in Sources */,
F439ADF00DBD3C4000BE9B91 /* GTMGeometryUtils.m in Sources */,
F439ADF10DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m in Sources */,
8B7DCEAA0DFF4C760017E983 /* GTMDevLogUnitTestingBridge.m in Sources */,
@@ -821,8 +790,6 @@
67A7820C0E00927400EBF506 /* GTMIPhoneUnitTestDelegate.m in Sources */,
8B3AA8F30E032FC7007E31B5 /* GTMNSString+URLArguments.m in Sources */,
8B3AA8F40E032FC7007E31B5 /* GTMNSString+URLArgumentsTest.m in Sources */,
- 8B3AA9240E033624007E31B5 /* GTMHTTPServer.m in Sources */,
- 8B3AA9290E033647007E31B5 /* GTMTestHTTPServer.m in Sources */,
8B41EC0F0E0711D40040CF9F /* GTMValidatingContainersTest.m in Sources */,
8B41EC100E0711D40040CF9F /* GTMValidatingContainers.m in Sources */,
F418AF990E7558EC004FB565 /* GTMExceptionalInlines.m in Sources */,
@@ -835,7 +802,6 @@
F418AFCE0E755C94004FB565 /* GTMNSDictionary+URLArgumentsTest.m in Sources */,
F418AFD70E755D44004FB565 /* GTMPath.m in Sources */,
F418AFD80E755D44004FB565 /* GTMPathTest.m in Sources */,
- 8BDA25130E759A6400C9769D /* GTMHTTPServerTest.m in Sources */,
8BDA25140E759A6500C9769D /* GTMNSData+zlibTest.m in Sources */,
8BE839890E89C74B00C611B0 /* GTMDebugThreadValidation.m in Sources */,
8BE83A660E8B059A00C611B0 /* GTMDebugThreadValidationTest.m in Sources */,
@@ -856,8 +822,6 @@
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 */,
0BBC768B10FEF62C0006FABE /* GTMStringEncoding.m in Sources */,
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt
index d5ff42a..2f26e92 100644
--- a/ReleaseNotes.txt
+++ b/ReleaseNotes.txt
@@ -3,6 +3,19 @@ Google Toolbox for Mac Release Notes
Project site: http://code.google.com/p/google-toolbox-for-mac/
Discussion group: http://groups.google.com/group/google-toolbox-for-mac
+Release 2.0.??
+Changes since 1.6.0
+??-??-??
+
+- Removed iPhone/GTMABAddressBook in favor of AddressBook/GTMABAddressBook.
+
+- Removed Foundation/GTMHTTPServer and UnitTesting/GTMTestHTTPServer, they
+ are going to go live with the fetcher used by GData (since they were done
+ for that testing).
+
+- Removed Foundation/GTMBase64 and Foundation/GTMNSData+Hex in favor of
+ Foundation/GTMStringEncoding.
+
Release 1.6.0
Changes since 1.5.1
diff --git a/UnitTesting/GTMTestHTTPServer.h b/UnitTesting/GTMTestHTTPServer.h
deleted file mode 100644
index 0128718..0000000
--- a/UnitTesting/GTMTestHTTPServer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// GTMTestHTTPServer.h
-//
-// Copyright 2007-2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-#import <Foundation/Foundation.h>
-
-@class GTMHTTPServer;
-
-// This is a HTTP Server that can respond to certain requests that look like
-// Google service logins. It takes extra url arguments to tell it what to
-// return for testing the code using it. See GTMHTTPFetcherTest for an example
-// of its usage.
-@interface GTMTestHTTPServer : NSObject {
- NSString *docRoot_;
- GTMHTTPServer *server_;
-}
-
-// Any url that isn't a specific server request (login, etc.), will be fetched
-// off |docRoot| (to allow canned repsonses).
-- (id)initWithDocRoot:(NSString *)docRoot;
-
-// fetch the port the server is running on
-- (uint16_t)port;
-
-@end
diff --git a/UnitTesting/GTMTestHTTPServer.m b/UnitTesting/GTMTestHTTPServer.m
deleted file mode 100644
index 7744b5e..0000000
--- a/UnitTesting/GTMTestHTTPServer.m
+++ /dev/null
@@ -1,166 +0,0 @@
-//
-// GTMTestHTTPServer.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 "GTMTestHTTPServer.h"
-#import "GTMHTTPServer.h"
-#import "GTMRegex.h"
-
-static NSArray *GetSubPatternsOfFirstStringMatchedByPattern(NSString *stringToSearch,
- NSString *pattern) {
- GTMRegex *regex = [GTMRegex regexWithPattern:pattern];
- NSString *firstMatch = [regex firstSubStringMatchedInString:stringToSearch];
- NSArray *subPatterns = [regex subPatternsOfString:firstMatch];
- return subPatterns;
-}
-
-@implementation GTMTestHTTPServer
-
-- (id)initWithDocRoot:(NSString *)docRoot {
- self = [super init];
- if (self) {
- docRoot_ = [docRoot copy];
- server_ = [[GTMHTTPServer alloc] initWithDelegate:self];
- NSError *error = nil;
- if ((docRoot == nil) || (![server_ start:&error])) {
- _GTMDevLog(@"Failed to start up the webserver (docRoot='%@', error=%@)",
- docRoot_, error);
- [self release];
- return nil;
- }
- }
- return self;
-}
-
-- (void)dealloc {
- [docRoot_ release];
- [server_ release];
- [super dealloc];
-}
-
-- (uint16_t)port {
- return [server_ port];
-}
-
-- (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
- handleRequest:(GTMHTTPRequestMessage *)request {
- _GTMDevAssert(server == server_, @"how'd we get a different server?!");
- UInt32 resultStatus = 0;
- NSData *data = nil;
- // clients should treat dates as opaque, generally
- NSString *modifiedDate = @"thursday";
-
- NSString *postString = @"";
- NSData *postData = [request body];
- if ([postData length] > 0) {
- postString = [[[NSString alloc] initWithData:postData
- encoding:NSUTF8StringEncoding] autorelease];
- }
-
- NSDictionary *allHeaders = [request allHeaderFieldValues];
- NSString *ifModifiedSince = [allHeaders objectForKey:@"If-Modified-Since"];
- NSString *authorization = [allHeaders objectForKey:@"Authorization"];
- NSString *path = [[request URL] absoluteString];
-
- if ([path hasSuffix:@".auth"]) {
- if (![authorization isEqualToString:@"GoogleLogin auth=GoodAuthToken"]) {
- GTMHTTPResponseMessage *response =
- [GTMHTTPResponseMessage emptyResponseWithCode:401];
- return response;
- } else {
- path = [path substringToIndex:[path length] - 5];
- }
- }
-
- NSString *overrideHeader = [allHeaders objectForKey:@"X-HTTP-Method-Override"];
- NSString *httpCommand = [request method];
- if ([httpCommand isEqualToString:@"POST"] &&
- [overrideHeader length] > 1) {
- httpCommand = overrideHeader;
- }
- NSArray *searchResult = nil;
- if ([path hasSuffix:@"/accounts/ClientLogin"]) {
- // it's a sign-in attempt; it's good unless the password is "bad" or
- // "captcha"
-
- // use regular expression to find the password
- NSString *password = @"";
- searchResult = GetSubPatternsOfFirstStringMatchedByPattern(path, @"Passwd=([^&\n]*)");
- if ([searchResult count] == 2) {
- password = [searchResult objectAtIndex:1];
- }
-
- if ([password isEqualToString:@"bad"]) {
- resultStatus = 403;
- } else if ([password isEqualToString:@"captcha"]) {
- NSString *loginToken = @"";
- NSString *loginCaptcha = @"";
-
- searchResult = GetSubPatternsOfFirstStringMatchedByPattern(postString, @"logintoken=([^&\n]*)");
- if ([searchResult count] == 2) {
- loginToken = [searchResult objectAtIndex:1];
- }
-
- searchResult = GetSubPatternsOfFirstStringMatchedByPattern(postString, @"logincaptcha=([^&\n]*)");
- if ([searchResult count] == 2) {
- loginCaptcha = [searchResult objectAtIndex:1];
- }
-
- if ([loginToken isEqualToString:@"CapToken"] &&
- [loginCaptcha isEqualToString:@"good"]) {
- resultStatus = 200;
- } else {
- // incorrect captcha token or answer provided
- resultStatus = 403;
- }
- } else {
- // valid username/password
- resultStatus = 200;
- }
- } else if ([httpCommand isEqualToString:@"DELETE"]) {
- // it's an object delete; read and return empty data
- resultStatus = 200;
- } else {
- // queries that have something like "?status=456" should fail with the
- // status code
- searchResult = GetSubPatternsOfFirstStringMatchedByPattern(path, @"status=([0-9]+)");
- if ([searchResult count] == 2) {
- resultStatus = [[searchResult objectAtIndex:1] intValue];
- } else if ([ifModifiedSince isEqualToString:modifiedDate]) {
- resultStatus = 304;
- } else {
- NSString *docPath = [docRoot_ stringByAppendingPathComponent:path];
- data = [NSData dataWithContentsOfFile:docPath];
- if (data) {
- resultStatus = 200;
- } else {
- resultStatus = 404;
- }
- }
- }
-
- GTMHTTPResponseMessage *response =
- [GTMHTTPResponseMessage responseWithBody:data
- contentType:@"text/plain"
- statusCode:resultStatus];
- [response setValue:modifiedDate forHeaderField:@"Last-Modified"];
- [response setValue:[NSString stringWithFormat:@"TestCookie=%@", [path lastPathComponent]]
- forHeaderField:@"Set-Cookie"];
- return response;
-}
-
-@end
diff --git a/iPhone/GTMABAddressBook.h b/iPhone/GTMABAddressBook.h
deleted file mode 100644
index 828f05a..0000000
--- a/iPhone/GTMABAddressBook.h
+++ /dev/null
@@ -1,328 +0,0 @@
-//
-// GTMABAddressBook.h
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-// These classes wrap up the iPhone AddressBook 'C' API in a manner very
-// similar to that found on Mac OS X. They differ only in that none of these
-// routines throws, and some of the types are different as necessitated by
-// the APIs that they wrap. These wrappers also protect you from a number
-// of issues in the AddressBook API (as of iPhone SDK 2.0/2.1)
-//
-// Note that there is a strings file that you may want to localize
-// (GTMABAddressBook.strings).
-//
-// If things seem strange, it may be due to one of the following radars:
-// 6240394 AddressBook framework constants not initialized until
-// ABCreateAddressBook called
-// -- CLOSED as designed
-// 6208390 Integer and real values don't work in ABMultiValueRefs
-// (and this isn't part of the title, but dictionaries don't work
-// either)
-// 6207605 RecordIDs for people and groups are not unique in AddressBook
-// -- CLOSED as designed
-// 6204021 kABGroupNameProperty and kABPersonFirstNameProperty have the same
-// value
-// 6203982 ABPersonCopyLocalizedPropertyName returns name for
-// kABGroupNameProperty
-// 6203961 ABPersonGetTypeOfProperty returns a type for kABGroupNameProperty
-// 6203854 ABMultiValues hash to their address
-// 6203836 ABRecords hash to their address
-// -- CLOSED behaves correctly
-// 6203606 Need CFTypeIDs for AddressBook CFTypes
-// 6202868 ABPersonSetImageData should validate image data
-// 6202860 Passing nil person into ABGroupAddMember crashes
-// -- CLOSED behaves correctly
-// 6202827 Passing nil info ABMultiValueAddValueAndLabel causes crash
-// -- CLOSED behaves correctly
-// 6202807 ABMultiValueInsertValueAndLabelAtIndex allows you to insert values
-// past end
-// 6201276 Removing a NULL record using ABAddressBookRemoveRecord crashes
-// -- CLOSED behaves correctly
-// 6201258 Adding a NULL record using ABAddressBookAddRecord crashes
-// -- CLOSED behaves correctly
-// 6201046 ABRecordSetValue returns true even if you pass in a bad type for a
-// value
-// 6201005 ABRecordRemoveValue returns true for value that aren't in the record
-// -- CLOSED behaves correctly
-// 6200703 ABAddressBookAddRecord doesn't add an item to the people array until
-// it's saved
-// 6200638 ABAddressBookHasUnsavedChanges doesn't work
-
-#import <UIKit/UIKit.h>
-#import <AddressBook/AddressBook.h>
-#import "GTMDefines.h"
-
-#if !GTM_IPHONE_SDK
-#error This file is for iPhone use only use ABAddressBook on Mac OS X
-#endif
-
-@class GTMABPerson;
-@class GTMABGroup;
-@class GTMABRecord;
-
-GTM_EXTERN NSString *const kGTMABUnknownPropertyName;
-
-// Wrapper for an AddressBook on iPhone
-@interface GTMABAddressBook : NSObject {
- @private
- ABAddressBookRef addressBook_;
-}
-
-// Returns a new instance of an address book.
-+ (GTMABAddressBook *)addressBook;
-
-// Return the address book reference
-- (ABAddressBookRef)addressBookRef;
-
-// Saves changes made since the last save
-// Return YES if successful (or there was no change)
-- (BOOL)save;
-
-// Saves changes made since the last save
-// Return YES if successful (or there was no change)
-- (BOOL)saveAndReturnError:(NSError **)error;
-
-// Returns YES if there are unsaved changes
-// The unsaved changes flag is automatically set when changes are made
-// As of iPhone 2.1, this does not work, and will always return NO.
-// Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
-- (BOOL)hasUnsavedChanges;
-
-// Reverts any changes that have been made and resets the unsaved flag
-// Be sure to read notes for -hasUnsavedChanges and -people and -groups.
-- (void)revert;
-
-// Returns a GTMABPerson matching an ID
-// Returns nil if the record could not be found
-- (GTMABPerson *)personForId:(ABRecordID)uniqueId;
-
-// Returns a GTMABGroup matching an ID
-// Returns nil if the record could not be found
-- (GTMABGroup *)groupForId:(ABRecordID)uniqueId;
-
-// Adds a record (ABPerson or ABGroup) to the AddressBook database
-// Be sure to read notes for -people and -group.
-- (BOOL)addRecord:(GTMABRecord *)record;
-
-// Removes a record (ABPerson or ABGroup) from the AddressBook database
-- (BOOL)removeRecord:(GTMABRecord *)record;
-
-// Returns an array (GTMABPerson) of all the people in the AddressBook database
-// As of iPhone 2.1, this array will not contain new entries until you save
-// the address book.
-// Radar 6200703: ABAddressBookAddRecord doesn't add an item to the people array
-// until it's saved
-- (NSArray *)people;
-
-// Returns an array of all the groups (GTMABGroup) in the AddressBook database
-// As of iPhone 2.1, this array will not contain new entries until you save
-// the address book.
-// Radar 6200703: ABAddressBookAddRecord doesn't add an item to the people array
-// until it's saved
-- (NSArray *)groups;
-
-// Returns a localized name for a given label
-+ (NSString *)localizedLabel:(CFStringRef)label;
-
-@end
-
-// Wrapper for a ABRecord on iPhone.
-// A abstract class. Instantiate one of the concrete subclasses, GTMABPerson or
-// GTMABGroup.
-@interface GTMABRecord : NSObject {
- @private
- ABRecordRef record_;
-}
-
-// Create a record with a recordRef.
-// Since GTMABRecord is an abstract base class, attempting to create one
-// of these directly will throw an exception. Use with one of the concrete
-// subclasses.
-+ (id)recordWithRecord:(ABRecordRef)record;
-
-// Designated initializer
-// Since GTMABRecord is an abstract base class, attempting to create one
-// of these directly will throw an exception. Use with one of the concrete
-// subclasses.
-- (id)initWithRecord:(ABRecordRef)record;
-
-// Return our recordRef
-- (ABRecordRef)recordRef;
-
-// Return the recordID for the record
-- (ABRecordID)recordID;
-
-// Returns the value of a given property.
-// The type of the value depends on the property type.
-- (id)valueForProperty:(ABPropertyID)property;
-
-// Set the value of a given property.
-// The type of the value must match the property type.
-// Returns YES if value set properly
-- (BOOL)setValue:(id)value forProperty:(ABPropertyID)property;
-
-// Removes the value for the property
-// Returns yes if value removed
-- (BOOL)removeValueForProperty:(ABPropertyID)property;
-
-// returns a human friendly name for the record
-- (NSString *)compositeName;
-
-// returns the type of a property
-+ (ABPropertyType)typeOfProperty:(ABPropertyID)property;
-
-// returns a human friendly localized name for a property
-+ (NSString *)localizedPropertyName:(ABPropertyID)property;
-@end
-
-// Wrapper for an ABPerson on iPhone
-@interface GTMABPerson : GTMABRecord
-
-// Creates a person with a first name and a last name.
-+ (GTMABPerson *)personWithFirstName:(NSString *)first
- lastName:(NSString *)last;
-
-// Sets image data for a person. Data must be to a block of data that
-// will create a valid UIImage.
-- (BOOL)setImageData:(NSData *)data;
-
-// Returns the image data.
-- (NSData *)imageData;
-
-// Returns the image for a person
-- (UIImage *)image;
-
-// Sets a the image for a person
-- (BOOL)setImage:(UIImage *)image;
-
-// Returns the format in with names are composited
-+ (ABPersonCompositeNameFormat)compositeNameFormat;
-@end
-
-// Wrapper for a ABGroup on iPhone
-@interface GTMABGroup : GTMABRecord
-// Create a new group named |name|
-+ (GTMABGroup *)groupNamed:(NSString *)name;
-
-// Return an array of members (GTMABPerson)
-- (NSArray *)members;
-
-// Add a member to a group
-- (BOOL)addMember:(GTMABPerson *)person;
-
-// Remove a member from a group
-- (BOOL)removeMember:(GTMABPerson *)person;
-@end
-
-// GTMABMultiValue does not supprt NSFastEnumeration because in
-// the Apple frameworks it returns identifiers which are already NSStrings.
-// In our case identifiers aren't NS types, and it doesn't make sense
-// to convert them to NSNumbers just to convert them back so you can
-// actually get at the values and labels.
-// Instead we supply valueEnumerator and labelEnumerator which you can
-// fast enumerate on to get values and labels directly.
-@interface GTMABMultiValue : NSObject <NSCopying, NSMutableCopying> {
- @protected
- ABMultiValueRef multiValue_;
-}
-
-// Create a multi value
-- (id)initWithMultiValue:(ABMultiValueRef)multiValue;
-
-// return it's ref
-- (ABMultiValueRef)multiValueRef;
-
-// Returns the number of value/label pairs
-- (NSUInteger)count;
-
-// Returns a value at a given index
-// Returns nil if index is out of bounds
-- (id)valueAtIndex:(NSUInteger)idx;
-
-// Returns a label at a given index
-// Returns nil if index is out of bounds
-- (NSString *)labelAtIndex:(NSUInteger)idx;
-
-// Returns an identifier at a given index
-// Returns kABMultiValueInvalidIdentifier if index is out of bounds
-- (ABMultiValueIdentifier)identifierAtIndex:(NSUInteger)idx;
-
-// Returns the index of a given identifier
-// Returns NSNotFound if not found
-- (NSUInteger)indexForIdentifier:(ABMultiValueIdentifier)identifier;
-
-// Type of the contents of this multivalue
-- (ABPropertyType)propertyType;
-
-// Returns the value for a given identifier
-// Returns nil if the identifier is not found
-- (id)valueForIdentifier:(ABMultiValueIdentifier)identifier;
-
-// Returns the value for a given identifier
-// Returns nil if the identifier is not found
-- (NSString *)labelForIdentifier:(ABMultiValueIdentifier)identifier;
-
-// Returns an enumerator for enumerating through values
-- (NSEnumerator *)valueEnumerator;
-
-// Returns an enumerator for enumerating through labels
-- (NSEnumerator *)labelEnumerator;
-
-@end
-
-@interface GTMABMutableMultiValue : GTMABMultiValue {
- @private
- // Use unsigned long here instead of NSUInteger because that's what
- // NSFastEnumeration Protocol wants currently (iPhone 2.1)
- unsigned long mutations_;
-}
-
-// Create a new mutable multivalue with a given type
-+ (id)valueWithPropertyType:(ABPropertyType)type;
-
-// Create a new mutable multivalue with a given type
-- (id)initWithPropertyType:(ABPropertyType)type;
-
-// Create a new mutable multivalue based on |multiValue|
-- (id)initWithMutableMultiValue:(ABMutableMultiValueRef)multiValue;
-
-// Adds a value with its label
-// Returns the identifier if successful, kABMultiValueInvalidIdentifier
-// otherwise.
-- (ABMultiValueIdentifier)addValue:(id)value withLabel:(CFStringRef)label;
-
-// Insert a value/label pair at a given index
-// Returns the identifier if successful. kABMultiValueInvalidIdentifier
-// otherwise
-// If index is out of bounds, returns kABMultiValueInvalidIdentifier.
-- (ABMultiValueIdentifier)insertValue:(id)value
- withLabel:(CFStringRef)label
- atIndex:(NSUInteger)index;
-
-// Removes a value/label pair at a given index
-// Returns NO if index out of bounds
-- (BOOL)removeValueAndLabelAtIndex:(NSUInteger)index;
-
-// Replaces a value at a given index
-// Returns NO if index out of bounds
-- (BOOL)replaceValueAtIndex:(NSUInteger)index withValue:(id)value;
-
-// Replaces a label at a given index
-// Returns NO if index out of bounds
-- (BOOL)replaceLabelAtIndex:(NSUInteger)index withLabel:(CFStringRef)label;
-
-@end
diff --git a/iPhone/GTMABAddressBook.m b/iPhone/GTMABAddressBook.m
deleted file mode 100644
index bb84e61..0000000
--- a/iPhone/GTMABAddressBook.m
+++ /dev/null
@@ -1,901 +0,0 @@
-//
-// GTMAddressBook.m
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-#import "GTMABAddressBook.h"
-#import "GTMGarbageCollection.h"
-
-NSString *const kGTMABUnknownPropertyName = @"UNKNOWN_PROPERTY";
-
-typedef struct {
- ABPropertyType pType;
- Class class;
-} TypeClassNameMap;
-
-@interface GTMABMultiValue ()
-- (unsigned long*)mutations;
-@end
-
-@interface GTMABMutableMultiValue ()
-// Checks to see if a value is a valid type to be stored in this multivalue
-- (BOOL)checkValueType:(id)value;
-@end
-
-@interface GTMABMultiValueEnumerator : NSEnumerator {
- @private
- __weak ABMultiValueRef ref_; // ref_ cached from enumeree_
- GTMABMultiValue *enumeree_;
- unsigned long mutations_;
- NSUInteger count_;
- NSUInteger index_;
- BOOL useLabels_;
-}
-+ (id)valueEnumeratorFor:(GTMABMultiValue*)enumeree;
-+ (id)labelEnumeratorFor:(GTMABMultiValue*)enumeree;
-- (id)initWithEnumeree:(GTMABMultiValue*)enumeree useLabels:(BOOL)useLabels;
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
- objects:(id *)stackbuf
- count:(NSUInteger)len;
-@end
-
-@implementation GTMABAddressBook
-+ (GTMABAddressBook *)addressBook {
- return [[[self alloc] init] autorelease];
-}
-
-- (id)init {
- if ((self = [super init])) {
- addressBook_ = ABAddressBookCreate();
- if (!addressBook_) {
- // COV_NF_START
- [self release];
- self = nil;
- // COV_NF_END
- }
- }
- return self;
-}
-
-- (void)dealloc {
- if (addressBook_) {
- CFRelease(addressBook_);
- }
- [super dealloc];
-}
-
-- (BOOL)save {
- return [self saveAndReturnError:NULL];
-}
-
-- (BOOL)saveAndReturnError:(NSError **)error {
- CFErrorRef cfError = NULL;
- bool wasGood = ABAddressBookSave(addressBook_, &cfError);
- GTMCFAutorelease(cfError);
- if (error) {
- *error = (NSError *)cfError; // COV_NF_LINE
- }
- return wasGood ? YES : NO;
-}
-
-- (BOOL)hasUnsavedChanges {
- return ABAddressBookHasUnsavedChanges(addressBook_);
-}
-
-- (void)revert {
- ABAddressBookRevert(addressBook_);
-}
-
-- (BOOL)addRecord:(GTMABRecord *)record {
- // Note: we check for bad data here because of radar
- // 6201258 Adding a NULL record using ABAddressBookAddRecord crashes
- if (!record) return NO;
- CFErrorRef cfError = NULL;
- bool wasGood = ABAddressBookAddRecord(addressBook_,
- [record recordRef], &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (BOOL)removeRecord:(GTMABRecord *)record {
- // Note: we check for bad data here because of radar
- // 6201276 Removing a NULL record using ABAddressBookRemoveRecord crashes
- if (!record) return NO;
- CFErrorRef cfError = NULL;
- bool wasGood = ABAddressBookRemoveRecord(addressBook_,
- [record recordRef], &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (NSArray *)people {
- NSArray *people
- = GTMCFAutorelease(ABAddressBookCopyArrayOfAllPeople(addressBook_));
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:[people count]];
- for (id person in people) {
- [result addObject:[GTMABPerson recordWithRecord:person]];
- }
- return result;
-}
-
-- (NSArray *)groups {
- NSArray *groups
- = GTMCFAutorelease(ABAddressBookCopyArrayOfAllGroups(addressBook_));
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:[groups count]];
- for (id group in groups) {
- [result addObject:[GTMABGroup recordWithRecord:group]];
- }
- return result;
-}
-
-- (ABAddressBookRef)addressBookRef {
- return addressBook_;
-}
-
-- (GTMABPerson *)personForId:(ABRecordID)uniqueId {
- GTMABPerson *person = nil;
- ABRecordRef ref = ABAddressBookGetPersonWithRecordID(addressBook_, uniqueId);
- if (ref) {
- person = [GTMABPerson recordWithRecord:ref];
- }
- return person;
-}
-
-- (GTMABGroup *)groupForId:(ABRecordID)uniqueId {
- GTMABGroup *group = nil;
- ABRecordRef ref = ABAddressBookGetGroupWithRecordID(addressBook_, uniqueId);
- if (ref) {
- group = [GTMABGroup recordWithRecord:ref];
- }
- return group;
-}
-
-+ (NSString *)localizedLabel:(CFStringRef)label {
- return GTMCFAutorelease(ABAddressBookCopyLocalizedLabel(label));
-}
-
-@end
-
-@implementation GTMABRecord
-+ (id)recordWithRecord:(ABRecordRef)record {
- return [[[self alloc] initWithRecord:record] autorelease];
-}
-
-- (id)initWithRecord:(ABRecordRef)record {
- if ((self = [super init])) {
- if ([self class] == [GTMABRecord class]) {
- [self autorelease];
- [self doesNotRecognizeSelector:_cmd];
- }
- if (!record) {
- [self release];
- self = nil;
- } else {
- record_ = CFRetain(record);
- }
- }
- return self;
-}
-
-- (NSUInteger)hash {
- // This really isn't completely valid due to
- // 6203836 ABRecords hash to their address
- // but it's the best we can do without knowing what properties
- // are in a record, and we don't have an API for that.
- return CFHash(record_);
-}
-
-- (BOOL)isEqual:(id)object {
- // This really isn't completely valid due to
- // 6203836 ABRecords hash to their address
- // but it's the best we can do without knowing what properties
- // are in a record, and we don't have an API for that.
- return [object respondsToSelector:@selector(recordRef)]
- && CFEqual(record_, [object recordRef]);
-}
-
-- (void)dealloc {
- if (record_) {
- CFRelease(record_);
- }
- [super dealloc];
-}
-
-- (ABRecordRef)recordRef {
- return record_;
-}
-
-- (ABRecordID)recordID {
- return ABRecordGetRecordID(record_);
-}
-
-- (id)valueForProperty:(ABPropertyID)property {
- id value = GTMCFAutorelease(ABRecordCopyValue(record_, property));
- if (value) {
- if ([[self class] typeOfProperty:property] & kABMultiValueMask) {
- value = [[[GTMABMultiValue alloc] initWithMultiValue:value] autorelease];
- }
- }
- return value;
-}
-
-- (BOOL)setValue:(id)value forProperty:(ABPropertyID)property {
- if (!value) return NO;
- // We check the type here because of
- // Radar 6201046 ABRecordSetValue returns true even if you pass in a bad type
- // for a value
- TypeClassNameMap fullTypeMap[] = {
- { kABStringPropertyType, [NSString class] },
- { kABIntegerPropertyType, [NSNumber class] },
- { kABRealPropertyType, [NSNumber class] },
- { kABDateTimePropertyType, [NSDate class] },
- { kABDictionaryPropertyType, [NSDictionary class] },
- { kABMultiStringPropertyType, [GTMABMultiValue class] },
- { kABMultiRealPropertyType, [GTMABMultiValue class] },
- { kABMultiDateTimePropertyType, [GTMABMultiValue class] },
- { kABMultiDictionaryPropertyType, [GTMABMultiValue class] }
- };
- ABPropertyType type = [[self class] typeOfProperty:property];
- BOOL wasFound = NO;
- for (size_t i = 0; i < sizeof(fullTypeMap) / sizeof(TypeClassNameMap); ++i) {
- if (fullTypeMap[i].pType == type) {
- wasFound = YES;
- if (![[value class] isSubclassOfClass:fullTypeMap[i].class]) {
- return NO;
- }
- }
- }
- if (!wasFound) {
- return NO;
- }
- if (type & kABMultiValueMask) {
- value = (id)[value multiValueRef];
- }
- CFErrorRef cfError = nil;
- bool wasGood = ABRecordSetValue(record_, property, (CFTypeRef)value, &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (BOOL)removeValueForProperty:(ABPropertyID)property {
- CFErrorRef cfError = nil;
- // We check to see if the value is in the property because of:
- // Radar 6201005 ABRecordRemoveValue returns true for value that aren't
- // in the record
- id value = [self valueForProperty:property];
- bool wasGood = value && ABRecordRemoveValue(record_, property, &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (NSString *)compositeName {
- return GTMCFAutorelease(ABRecordCopyCompositeName(record_));
-}
-
-// COV_NF_START
-// Both of these methods are to be overridden by their subclasses
-+ (ABPropertyType)typeOfProperty:(ABPropertyID)property {
- [self doesNotRecognizeSelector:_cmd];
- return kABInvalidPropertyType;
-}
-
-+ (NSString *)localizedPropertyName:(ABPropertyID)property {
- [self doesNotRecognizeSelector:_cmd];
- return nil;
-}
-// COV_NF_END
-@end
-
-@implementation GTMABPerson
-
-+ (GTMABPerson *)personWithFirstName:(NSString *)first
- lastName:(NSString *)last {
- GTMABPerson *person = [[[self alloc] init] autorelease];
- if (person) {
- BOOL isGood = YES;
- if (first) {
- isGood = [person setValue:first forProperty:kABPersonFirstNameProperty];
- }
- if (isGood && last) {
- isGood = [person setValue:last forProperty:kABPersonLastNameProperty];
- }
- if (!isGood) {
- // COV_NF_START
- // Marked as NF because I don't know how to force an error
- person = nil;
- // COV_NF_END
- }
- }
- return person;
-}
-
-- (id)init {
- ABRecordRef person = ABPersonCreate();
- self = [super initWithRecord:person];
- if (person) {
- CFRelease(person);
- }
- return self;
-}
-
-- (BOOL)setImageData:(NSData *)data {
- CFErrorRef cfError = NULL;
- bool wasGood = NO;
- if (!data) {
- wasGood = ABPersonRemoveImageData([self recordRef], &cfError);
- } else {
- // We verify that the data is good because of:
- // Radar 6202868 ABPersonSetImageData should validate image data
- UIImage *image = [UIImage imageWithData:data];
- wasGood = image && ABPersonSetImageData([self recordRef],
- (CFDataRef)data, &cfError);
- }
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (UIImage *)image {
- return [UIImage imageWithData:[self imageData]];
-}
-
-- (BOOL)setImage:(UIImage *)image {
- NSData *data = UIImagePNGRepresentation(image);
- return [self setImageData:data];
-}
-
-- (NSData *)imageData {
- return GTMCFAutorelease(ABPersonCopyImageData([self recordRef]));
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"%@ %@ %@ %d",
- [self class],
- [self valueForProperty:kABPersonFirstNameProperty],
- [self valueForProperty:kABPersonLastNameProperty],
- [self recordID]];
-}
-
-+ (NSString *)localizedPropertyName:(ABPropertyID)property {
- return GTMCFAutorelease(ABPersonCopyLocalizedPropertyName(property));
-}
-
-+ (ABPersonCompositeNameFormat)compositeNameFormat {
- return ABPersonGetCompositeNameFormat();
-}
-
-+ (ABPropertyType)typeOfProperty:(ABPropertyID)property {
- return ABPersonGetTypeOfProperty(property);
-}
-@end
-
-@implementation GTMABGroup
-
-+ (GTMABGroup *)groupNamed:(NSString *)name {
- GTMABGroup *group = [[[self alloc] init] autorelease];
- if (group) {
- if (![group setValue:name forProperty:kABGroupNameProperty]) {
- // COV_NF_START
- // Can't get setValue to fail for me
- group = nil;
- // COV_NF_END
- }
- }
- return group;
-}
-
-- (id)init {
- ABRecordRef group = ABGroupCreate();
- self = [super initWithRecord:group];
- if (group) {
- CFRelease(group);
- }
- return self;
-}
-
-- (NSArray *)members {
- NSArray *people
- = GTMCFAutorelease(ABGroupCopyArrayOfAllMembers([self recordRef]));
- NSMutableArray *gtmPeople = [NSMutableArray arrayWithCapacity:[people count]];
- for (id person in people) {
- [gtmPeople addObject:[GTMABPerson recordWithRecord:(ABRecordRef)person]];
- }
- return gtmPeople;
-}
-
-- (BOOL)addMember:(GTMABPerson *)person {
- CFErrorRef cfError = nil;
- // We check for person because of
- // Radar 6202860 Passing nil person into ABGroupAddMember crashes
- bool wasGood = person && ABGroupAddMember([self recordRef],
- [person recordRef], &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-- (BOOL)removeMember:(GTMABPerson *)person {
- CFErrorRef cfError = nil;
- // We check for person because of
- // Radar 6202860 Passing nil person into ABGroupAddMember crashes
- // (I know this is remove, but it crashes there too)
- bool wasGood = person && ABGroupRemoveMember([self recordRef],
- [person recordRef], &cfError);
- if (cfError) {
- // COV_NF_START
- _GTMDevLog(@"Error in [%@ %@]: %@",
- [self class], NSStringFromSelector(_cmd), cfError);
- CFRelease(cfError);
- // COV_NF_END
- }
- return wasGood ? YES : NO;
-}
-
-+ (ABPropertyType)typeOfProperty:(ABPropertyID)property {
- ABPropertyType type = kABInvalidPropertyType;
- if (property == kABGroupNameProperty) {
- type = kABStringPropertyType;
- }
- return type;
-}
-
-+ (NSString *)localizedPropertyName:(ABPropertyID)property {
- NSString *name = kGTMABUnknownPropertyName;
- if (property == kABGroupNameProperty) {
- name = NSLocalizedStringFromTable(@"Name",
- @"GTMABAddressBook",
- @"name property");
- }
- return name;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"%@ %@ %d",
- [self class],
- [self valueForProperty:kABGroupNameProperty],
- [self recordID]];
-}
-@end
-
-@implementation GTMABMultiValue
-- (id)init {
- // Call super init and release so we don't leak
- [[super init] autorelease];
- [self doesNotRecognizeSelector:_cmd];
- return nil; // COV_NF_LINE
-}
-
-- (id)initWithMultiValue:(ABMultiValueRef)multiValue {
- if ((self = [super init])) {
- if (!multiValue) {
- [self release];
- self = nil;
- } else {
- multiValue_ = CFRetain(multiValue);
- }
- }
- return self;
-}
-
-- (id)copyWithZone:(NSZone *)zone {
- return [[GTMABMultiValue alloc] initWithMultiValue:multiValue_];
-}
-
-- (id)mutableCopyWithZone:(NSZone *)zone {
- return [[GTMABMutableMultiValue alloc] initWithMultiValue:multiValue_];
-}
-
-- (NSUInteger)hash {
- // I'm implementing hash instead of using CFHash(multiValue_) because
- // 6203854 ABMultiValues hash to their address
- NSUInteger count = [self count];
- NSUInteger hash = 0;
- for (NSUInteger i = 0; i < count; ++i) {
- NSString *label = [self labelAtIndex:i];
- id value = [self valueAtIndex:i];
- hash += [label hash];
- hash += [value hash];
- }
- return hash;
-}
-
-- (BOOL)isEqual:(id)object {
- // I'm implementing isEqual instea of using CFEquals(multiValue,...) because
- // 6203854 ABMultiValues hash to their address
- // and it appears CFEquals just calls through to hash to compare them.
- BOOL isEqual = NO;
- if ([object respondsToSelector:@selector(multiValueRef)]) {
- isEqual = multiValue_ == [object multiValueRef];
- if (!isEqual) {
- NSUInteger count = [self count];
- NSUInteger objCount = [object count];
- isEqual = count == objCount;
- for (NSUInteger i = 0; isEqual && i < count; ++i) {
- NSString *label = [self labelAtIndex:i];
- NSString *objLabel = [object labelAtIndex:i];
- isEqual = [label isEqual:objLabel];
- if (isEqual) {
- id value = [self valueAtIndex:i];
- id objValue = [object valueAtIndex:i];
- isEqual = [value isEqual:objValue];
- }
- }
- }
- }
- return isEqual;
-}
-
-- (void)dealloc {
- if (multiValue_) {
- CFRelease(multiValue_);
- }
- [super dealloc];
-}
-
-- (ABMultiValueRef)multiValueRef {
- return multiValue_;
-}
-
-- (NSUInteger)count {
- return ABMultiValueGetCount(multiValue_);
-}
-
-- (id)valueAtIndex:(NSUInteger)idx {
- id value = nil;
- if (idx < [self count]) {
- value = GTMCFAutorelease(ABMultiValueCopyValueAtIndex(multiValue_, idx));
- ABPropertyType type = [self propertyType];
- if (type == kABIntegerPropertyType
- || type == kABRealPropertyType
- || type == kABDictionaryPropertyType) {
- // This is because of
- // 6208390 Integer and real values don't work in ABMultiValueRefs
- // Apparently they forget to add a ref count on int, real and
- // dictionary values in ABMultiValueCopyValueAtIndex, although they do
- // remember them for all other types.
- // Once they fix this, this will lead to a leak, but I figure the leak
- // is better than the crash. Our unittests will test to make sure that
- // this is the case, and once we find a system that has this fixed, we
- // can conditionalize this code. Look for testRadar6208390 in
- // GTMABAddressBookTest.m
- // Also, search for 6208390 below and fix the fast enumerator to actually
- // be somewhat performant when this is fixed.
- [value retain];
- }
- }
- return value;
-}
-
-- (NSString *)labelAtIndex:(NSUInteger)idx {
- NSString *label = nil;
- if (idx < [self count]) {
- label = GTMCFAutorelease(ABMultiValueCopyLabelAtIndex(multiValue_, idx));
- }
- return label;
-}
-
-- (ABMultiValueIdentifier)identifierAtIndex:(NSUInteger)idx {
- ABMultiValueIdentifier identifier = kABMultiValueInvalidIdentifier;
- if (idx < [self count]) {
- identifier = ABMultiValueGetIdentifierAtIndex(multiValue_, idx);
- }
- return identifier;
-}
-
-- (NSUInteger)indexForIdentifier:(ABMultiValueIdentifier)identifier {
- NSUInteger idx = ABMultiValueGetIndexForIdentifier(multiValue_, identifier);
- return idx == (NSUInteger)kCFNotFound ? (NSUInteger)NSNotFound : idx;
-}
-
-- (ABPropertyType)propertyType {
- return ABMultiValueGetPropertyType(multiValue_);
-}
-
-- (id)valueForIdentifier:(ABMultiValueIdentifier)identifier {
- return [self valueAtIndex:[self indexForIdentifier:identifier]];
-}
-
-- (NSString *)labelForIdentifier:(ABMultiValueIdentifier)identifier {
- return [self labelAtIndex:[self indexForIdentifier:identifier]];
-}
-
-- (unsigned long*)mutations {
- // We just need some constant non-zero value here so fast enumeration works.
- // Dereferencing self should give us the isa which will stay constant
- // over the enumeration.
- return (unsigned long*)self;
-}
-
-- (NSEnumerator *)valueEnumerator {
- return [GTMABMultiValueEnumerator valueEnumeratorFor:self];
-}
-
-- (NSEnumerator *)labelEnumerator {
- return [GTMABMultiValueEnumerator labelEnumeratorFor:self];
-}
-
-@end
-
-@implementation GTMABMutableMultiValue
-+ (id)valueWithPropertyType:(ABPropertyType)type {
- return [[[self alloc] initWithPropertyType:type] autorelease];
-}
-
-- (id)initWithPropertyType:(ABPropertyType)type {
- ABMutableMultiValueRef ref = nil;
- if (type != kABInvalidPropertyType) {
- ref = ABMultiValueCreateMutable(type);
- }
- self = [super initWithMultiValue:ref];
- if (ref) {
- CFRelease(ref);
- }
- return self;
-}
-
-- (id)initWithMultiValue:(ABMultiValueRef)multiValue {
- ABMutableMultiValueRef ref = nil;
- if (multiValue) {
- ref = ABMultiValueCreateMutableCopy(multiValue);
- }
- self = [super initWithMultiValue:ref];
- if (ref) {
- CFRelease(ref);
- }
- return self;
-}
-
-- (id)initWithMutableMultiValue:(ABMutableMultiValueRef)multiValue {
- return [super initWithMultiValue:multiValue];
-}
-
-- (BOOL)checkValueType:(id)value {
- BOOL isGood = NO;
- if (value) {
- TypeClassNameMap singleValueTypeMap[] = {
- { kABStringPropertyType, [NSString class] },
- { kABIntegerPropertyType, [NSNumber class] },
- { kABRealPropertyType, [NSNumber class] },
- { kABDateTimePropertyType, [NSDate class] },
- { kABDictionaryPropertyType, [NSDictionary class] },
- };
- ABPropertyType type = [self propertyType];
- for (size_t i = 0;
- i < sizeof(singleValueTypeMap) / sizeof(TypeClassNameMap); ++i) {
- if (singleValueTypeMap[i].pType == type) {
- if ([[value class] isSubclassOfClass:singleValueTypeMap[i].class]) {
- isGood = YES;
- break;
- }
- }
- }
- }
- return isGood;
-}
-
-- (ABMultiValueIdentifier)addValue:(id)value withLabel:(CFStringRef)label {
- ABMultiValueIdentifier identifier = kABMultiValueInvalidIdentifier;
- // We check label and value here because of
- // radar 6202827 Passing nil info ABMultiValueAddValueAndLabel causes crash
- if (!label
- || ![self checkValueType:value]
- || !ABMultiValueAddValueAndLabel(multiValue_,
- value,
- label,
- &identifier)) {
- identifier = kABMultiValueInvalidIdentifier;
- } else {
- mutations_++;
- }
- return identifier;
-}
-
-- (ABMultiValueIdentifier)insertValue:(id)value
- withLabel:(CFStringRef)label
- atIndex:(NSUInteger)idx {
- ABMultiValueIdentifier identifier = kABMultiValueInvalidIdentifier;
- // We perform a check here to ensure that we don't get bitten by
- // Radar 6202807 ABMultiValueInsertValueAndLabelAtIndex allows you to insert
- // values past end
- NSUInteger count = [self count];
- // We check label and value here because of
- // radar 6202827 Passing nil info ABMultiValueAddValueAndLabel causes crash
- if (idx > count
- || !label
- || ![self checkValueType:value]
- || !ABMultiValueInsertValueAndLabelAtIndex(multiValue_,
- value,
- label,
- idx,
- &identifier)) {
- identifier = kABMultiValueInvalidIdentifier;
- } else {
- mutations_++;
- }
- return identifier;
-}
-
-- (BOOL)removeValueAndLabelAtIndex:(NSUInteger)idx {
- BOOL isGood = NO;
- NSUInteger count = [self count];
- if (idx < count) {
- if (ABMultiValueRemoveValueAndLabelAtIndex(multiValue_,
- idx)) {
- mutations_++;
- isGood = YES;
- }
- }
- return isGood;
-}
-
-- (BOOL)replaceValueAtIndex:(NSUInteger)idx withValue:(id)value {
- BOOL isGood = NO;
- NSUInteger count = [self count];
- if (idx < count && [self checkValueType:value]) {
- if (ABMultiValueReplaceValueAtIndex(multiValue_,
- value, idx)) {
- mutations_++;
- isGood = YES;
- }
- }
- return isGood;
-}
-
-- (BOOL)replaceLabelAtIndex:(NSUInteger)idx withLabel:(CFStringRef)label{
- BOOL isGood = NO;
- NSUInteger count = [self count];
- if (idx < count) {
- if (ABMultiValueReplaceLabelAtIndex(multiValue_,
- label,
- idx)) {
- mutations_++;
- isGood = YES;
- }
- }
- return isGood;
-}
-
-- (unsigned long*)mutations {
- return &mutations_;
-}
-@end
-
-
-@implementation GTMABMultiValueEnumerator
-
-+ (id)valueEnumeratorFor:(GTMABMultiValue*)enumeree {
- return [[[self alloc] initWithEnumeree:enumeree useLabels:NO] autorelease];
-}
-
-+ (id)labelEnumeratorFor:(GTMABMultiValue*)enumeree {
- return [[[self alloc] initWithEnumeree:enumeree useLabels:YES] autorelease];
-}
-
-- (id)initWithEnumeree:(GTMABMultiValue*)enumeree useLabels:(BOOL)useLabels {
- if ((self = [super init])) {
- if (enumeree) {
- enumeree_ = [enumeree retain];
- useLabels_ = useLabels;
- } else {
- // COV_NF_START
- // Since this is a private class where the enumeree creates us
- // there is no way we should ever get here.
- [self release];
- self = nil;
- // COV_NF_END
- }
- }
- return self;
-}
-
-- (void)dealloc {
- [enumeree_ release];
- [super dealloc];
-}
-
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
- objects:(id *)stackbuf
- count:(NSUInteger)len {
- NSUInteger i;
- if (!ref_) {
- count_ = [enumeree_ count];
- ref_ = [enumeree_ multiValueRef];
- }
-
- for (i = 0; state->state < count_ && i < len; ++i, ++state->state) {
- if (useLabels_) {
- stackbuf[i] = GTMCFAutorelease(ABMultiValueCopyLabelAtIndex(ref_,
- state->state));
- } else {
- // Yes this is slow, but necessary in light of radar 6208390
- // Once this is fixed we can go to something similar to the label
- // case which should speed stuff up again. Hopefully anybody who wants
- // real performance is willing to move down to the C API anyways.
- stackbuf[i] = [enumeree_ valueAtIndex:state->state];
- }
- }
-
- state->itemsPtr = stackbuf;
- state->mutationsPtr = [enumeree_ mutations];
- return i;
-}
-
-- (id)nextObject {
- id value = nil;
- if (!ref_) {
- count_ = [enumeree_ count];
- mutations_ = *[enumeree_ mutations];
- ref_ = [enumeree_ multiValueRef];
-
- }
- if (mutations_ != *[enumeree_ mutations]) {
- NSString *reason = [NSString stringWithFormat:@"*** Collection <%@> was "
- "mutated while being enumerated", enumeree_];
- [[NSException exceptionWithName:NSGenericException
- reason:reason
- userInfo:nil] raise];
- }
- if (index_ < count_) {
- if (useLabels_) {
- value = GTMCFAutorelease(ABMultiValueCopyLabelAtIndex(ref_,
- index_));
- } else {
- // Yes this is slow, but necessary in light of radar 6208390
- // Once this is fixed we can go to something similar to the label
- // case which should speed stuff up again. Hopefully anybody who wants
- // real performance is willing to move down to the C API anyways.
- value = [enumeree_ valueAtIndex:index_];
- }
- index_ += 1;
- }
- return value;
-}
-@end
-
diff --git a/iPhone/GTMABAddressBook.strings b/iPhone/GTMABAddressBook.strings
deleted file mode 100644
index b5e010e..0000000
--- a/iPhone/GTMABAddressBook.strings
+++ /dev/null
Binary files differ
diff --git a/iPhone/GTMABAddressBookTest.m b/iPhone/GTMABAddressBookTest.m
deleted file mode 100644
index 17a3096..0000000
--- a/iPhone/GTMABAddressBookTest.m
+++ /dev/null
@@ -1,608 +0,0 @@
-//
-// GTMAddressBookTest.m
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-#import "GTMSenTestCase.h"
-#import "GTMABAddressBook.h"
-
-@interface GTMABAddressBookTest : GTMTestCase {
- @private
- GTMABAddressBook *book_;
-}
-@end
-
-
-@implementation GTMABAddressBookTest
-- (void)setUp {
- // Create a book forcing it out of it's autorelease pool.
- // I force it out of the release pool, so that we will see any errors
- // for it immediately at teardown, and it will be clear which release
- // caused us problems.
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- book_ = [[GTMABAddressBook addressBook] retain];
- [pool release];
- STAssertNotNil(book_, nil);
- STAssertFalse([book_ hasUnsavedChanges], nil);
-}
-
-- (void)tearDown {
- [book_ release];
-}
-
-- (void)testGenericAddressBook {
- STAssertEqualObjects([GTMABAddressBook localizedLabel:kABHomeLabel],
- @"home",
- nil);
- STAssertThrows([GTMABRecord recordWithRecord:nil], nil);
-}
-
-- (void)testAddingAndRemovingPerson {
- // Create a person
- GTMABPerson *person = [GTMABPerson personWithFirstName:@"Bart"
- lastName:@"Simpson"];
- STAssertNotNil(person, nil);
-
- // Add person
- NSArray *people = [book_ people];
- STAssertFalse([people containsObject:person], nil);
- STAssertTrue([book_ addRecord:person], nil);
-
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- people = [book_ people];
- STAssertNotNil(people, nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200703: ABAddressBookAddRecord doesn't add an item to the people
- // array until it's saved
- // We will check to make sure it stays broken ;-)
- STAssertFalse([people containsObject:person], nil);
-
- // Save book_
- STAssertTrue([book_ save], nil);
- people = [book_ people];
- STAssertNotNil(people, nil);
- STAssertTrue([people containsObject:person], nil);
-
- ABRecordID recordID = [person recordID];
- STAssertNotEquals(recordID, kABRecordInvalidID, nil);
-
- GTMABRecord *record = [book_ personForId:recordID];
- STAssertEqualObjects(record, person, nil);
-
- // Remove person
- STAssertTrue([book_ removeRecord:person], nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- // Normally this next line would be STAssertFalse, however due to
- // Radar 6200703: ABAddressBookAddRecord doesn't add an item to the people
- // array until it's saved
- // We will check to make sure it stays broken ;-)
- STAssertTrue([people containsObject:person], nil);
-
- // Save Book
- STAssertTrue([book_ save], nil);
- people = [book_ people];
- STAssertFalse([book_ hasUnsavedChanges], nil);
- STAssertFalse([people containsObject:person], nil);
- record = [book_ personForId:recordID];
- STAssertNil(record, nil);
-
- // Revert book_
- STAssertTrue([book_ addRecord:person], nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- [book_ revert];
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- // Bogus data
- STAssertFalse([book_ addRecord:nil], nil);
- STAssertFalse([book_ removeRecord:nil], nil);
-
- STAssertNotNULL([book_ addressBookRef], nil);
-
-}
-
-- (void)testAddingAndRemovingGroup {
- // Create a group
- GTMABGroup *group = [GTMABGroup groupNamed:@"Test"];
- STAssertNotNil(group, nil);
-
- // Add group
- NSArray *groups = [book_ groups];
- STAssertFalse([groups containsObject:group], nil);
- STAssertTrue([book_ addRecord:group], nil);
-
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- groups = [book_ groups];
- STAssertNotNil(groups, nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200703: ABAddressBookAddRecord doesn't add an item to the groups
- // array until it's saved
- // We will check to make sure it stays broken ;-)
- STAssertFalse([groups containsObject:group], nil);
-
- // Save book_
- STAssertTrue([book_ save], nil);
- groups = [book_ groups];
- STAssertNotNil(groups, nil);
- STAssertTrue([groups containsObject:group], nil);
-
- ABRecordID recordID = [group recordID];
- STAssertNotEquals(recordID, kABRecordInvalidID, nil);
-
- GTMABRecord *record = [book_ groupForId:recordID];
- STAssertEqualObjects(record, group, nil);
-
- // Remove group
- STAssertTrue([book_ removeRecord:group], nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- // Normally this next line would be STAssertFalse, however due to
- // Radar 6200703: ABAddressBookAddRecord doesn't add an item to the groups
- // array until it's saved
- // We will check to make sure it stays broken ;-)
- STAssertTrue([groups containsObject:group], nil);
-
- // Save Book
- STAssertTrue([book_ save], nil);
- groups = [book_ groups];
- STAssertFalse([book_ hasUnsavedChanges], nil);
- STAssertFalse([groups containsObject:group], nil);
- record = [book_ groupForId:recordID];
- STAssertNil(record, nil);
-
- // Revert book_
- STAssertTrue([book_ addRecord:group], nil);
- // Normally this next line would be STAssertTrue, however due to
- // Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
- // We will check to make sure it stays broken ;-)
- STAssertFalse([book_ hasUnsavedChanges], nil);
-
- [book_ revert];
- STAssertFalse([book_ hasUnsavedChanges], nil);
-}
-
-- (void)testPerson {
- GTMABPerson *person = [[[GTMABPerson alloc] initWithRecord:nil] autorelease];
- STAssertNil(person, nil);
- person = [GTMABPerson personWithFirstName:@"Bart"
- lastName:nil];
- STAssertNotNil(person, nil);
- STAssertEqualObjects([person compositeName], @"Bart", nil);
- NSString *firstName = [person valueForProperty:kABPersonFirstNameProperty];
- STAssertEqualObjects(firstName, @"Bart", nil);
- NSString *lastName = [person valueForProperty:kABPersonLastNameProperty];
- STAssertNil(lastName, nil);
- STAssertTrue([person removeValueForProperty:kABPersonFirstNameProperty], nil);
- STAssertFalse([person removeValueForProperty:kABPersonFirstNameProperty], nil);
- STAssertFalse([person removeValueForProperty:kABPersonLastNameProperty], nil);
- STAssertFalse([person setValue:nil forProperty:kABPersonFirstNameProperty], nil);
- STAssertFalse([person setValue:[NSNumber numberWithInt:1]
- forProperty:kABPersonFirstNameProperty], nil);
- STAssertFalse([person setValue:@"Bart"
- forProperty:kABPersonBirthdayProperty], nil);
-
- ABPropertyType property
- = [GTMABPerson typeOfProperty:kABPersonLastNameProperty];
- STAssertEquals(property, (ABPropertyType)kABStringPropertyType, nil);
-
- NSString *string
- = [GTMABPerson localizedPropertyName:kABPersonLastNameProperty];
- STAssertEqualObjects(string, @"Last", nil);
-
- string = [GTMABPerson localizedPropertyName:kABRecordInvalidID];
- STAssertEqualObjects(string, kGTMABUnknownPropertyName, nil);
-
- string = [person description];
- STAssertNotNil(string, nil);
-
- ABPersonCompositeNameFormat format = [GTMABPerson compositeNameFormat];
- STAssertTrue(format == kABPersonCompositeNameFormatFirstNameFirst ||
- format == kABPersonCompositeNameFormatLastNameFirst, nil);
-
- NSData *data = [person imageData];
- STAssertNil(data, nil);
- STAssertTrue([person setImageData:nil], nil);
- data = [person imageData];
- STAssertNil(data, nil);
- UIImage *image = [UIImage imageNamed:@"phone.png"];
- STAssertNotNil(image, nil);
- data = UIImagePNGRepresentation(image);
- STAssertTrue([person setImageData:data], nil);
- NSData *data2 = [person imageData];
- STAssertEqualObjects(data, data2, nil);
- STAssertTrue([person setImageData:nil], nil);
- data = [person imageData];
- STAssertNil(data, nil);
-
- STAssertTrue([person setImage:image], nil);
- UIImage *image2 = [person image];
- STAssertNotNil(image2, nil);
- STAssertEqualObjects(UIImagePNGRepresentation(image),
- UIImagePNGRepresentation(image2), nil);
-
- person = [GTMABPerson personWithFirstName:@"Bart"
- lastName:@"Simpson"];
-
- data = [NSData dataWithBytes:"a" length:1];
- STAssertFalse([person setImageData:data], nil);
-
- GTMABMutableMultiValue *value
- = [GTMABMutableMultiValue valueWithPropertyType:kABStringPropertyType];
- STAssertNotNil(value, nil);
- STAssertNotEquals([value addValue:@"222-222-2222"
- withLabel:kABHomeLabel],
- kABMultiValueInvalidIdentifier, nil);
- STAssertNotEquals([value addValue:@"333-333-3333"
- withLabel:kABWorkLabel],
- kABMultiValueInvalidIdentifier, nil);
- STAssertTrue([person setValue:value forProperty:kABPersonPhoneProperty], nil);
- id value2 = [person valueForProperty:kABPersonPhoneProperty];
- STAssertNotNil(value2, nil);
- STAssertEqualObjects(value, value2, nil);
- STAssertEquals([value hash], [value2 hash], nil);
- STAssertNotEquals([person hash], (NSUInteger)0, nil);
-}
-
-- (void)testGroup {
- GTMABGroup *group = [[[GTMABGroup alloc] initWithRecord:nil] autorelease];
- STAssertNil(group, nil);
- group = [GTMABGroup groupNamed:@"TestGroup"];
- STAssertNotNil(group, nil);
- STAssertEqualObjects([group compositeName], @"TestGroup", nil);
- NSString *name = [group valueForProperty:kABGroupNameProperty];
- STAssertEqualObjects(name, @"TestGroup", nil);
- NSString *lastName = [group valueForProperty:kABPersonLastNameProperty];
- STAssertNil(lastName, nil);
- STAssertTrue([group removeValueForProperty:kABGroupNameProperty], nil);
- STAssertFalse([group removeValueForProperty:kABGroupNameProperty], nil);
- STAssertFalse([group removeValueForProperty:kABPersonLastNameProperty], nil);
- STAssertFalse([group setValue:nil forProperty:kABGroupNameProperty], nil);
- STAssertFalse([group setValue:[NSNumber numberWithInt:1]
- forProperty:kABGroupNameProperty], nil);
- STAssertFalse([group setValue:@"Bart"
- forProperty:kABPersonBirthdayProperty], nil);
-
- ABPropertyType property = [GTMABGroup typeOfProperty:kABGroupNameProperty];
- STAssertEquals(property, (ABPropertyType)kABStringPropertyType, nil);
-
- property = [GTMABGroup typeOfProperty:kABPersonLastNameProperty];
- STAssertEquals(property, (ABPropertyType)kABInvalidPropertyType, nil);
-
- NSString *string = [GTMABGroup localizedPropertyName:kABGroupNameProperty];
- STAssertEqualObjects(string, @"Name", nil);
-
- string = [GTMABGroup localizedPropertyName:kABPersonLastNameProperty];
- STAssertEqualObjects(string, kGTMABUnknownPropertyName, nil);
-
- string = [GTMABGroup localizedPropertyName:kABRecordInvalidID];
- STAssertEqualObjects(string, kGTMABUnknownPropertyName, nil);
-
- string = [group description];
- STAssertNotNil(string, nil);
-
- // Adding and removing members
- group = [GTMABGroup groupNamed:@"TestGroup2"];
- NSArray *members = [group members];
- STAssertEquals([members count], (NSUInteger)0, @"Members: %@", members);
-
- STAssertFalse([group addMember:nil], nil);
-
- members = [group members];
- STAssertEquals([members count], (NSUInteger)0, @"Members: %@", members);
-
- GTMABPerson *person = [GTMABPerson personWithFirstName:@"Bart"
- lastName:@"Simpson"];
- STAssertNotNil(person, nil);
- STAssertTrue([book_ addRecord:person], nil);
- STAssertTrue([book_ save], nil);
- STAssertTrue([group addMember:person], nil);
- STAssertTrue([book_ addRecord:group], nil);
- STAssertTrue([book_ save], nil);
- members = [group members];
- STAssertEquals([members count], (NSUInteger)1, @"Members: %@", members);
- STAssertTrue([group removeMember:person], nil);
- STAssertFalse([group removeMember:person], nil);
- STAssertFalse([group removeMember:nil], nil);
- STAssertTrue([book_ removeRecord:group], nil);
- STAssertTrue([book_ removeRecord:person], nil);
- STAssertTrue([book_ save], nil);
-}
-
-
-- (void)testMultiValues {
- STAssertThrows([[GTMABMultiValue alloc] init], nil);
- STAssertThrows([[GTMABMutableMultiValue alloc] init], nil);
- GTMABMultiValue *value = [[GTMABMultiValue alloc] initWithMultiValue:nil];
- STAssertNil(value, nil);
- GTMABMutableMultiValue *mutValue
- = [GTMABMutableMultiValue valueWithPropertyType:kABInvalidPropertyType];
- STAssertNil(mutValue, nil);
- mutValue
- = [[[GTMABMutableMultiValue alloc]
- initWithMutableMultiValue:nil] autorelease];
- STAssertNil(mutValue, nil);
- mutValue
- = [[[GTMABMutableMultiValue alloc]
- initWithMultiValue:nil] autorelease];
- STAssertNil(mutValue, nil);
- const ABPropertyType types[] = {
- kABStringPropertyType,
- kABIntegerPropertyType,
- kABRealPropertyType,
- kABDateTimePropertyType,
- kABDictionaryPropertyType,
- kABMultiStringPropertyType,
- kABMultiIntegerPropertyType,
- kABMultiRealPropertyType,
- kABMultiDateTimePropertyType,
- kABMultiDictionaryPropertyType
- };
- for (size_t i = 0; i < sizeof(types) / sizeof(ABPropertyType); ++i) {
- mutValue = [GTMABMutableMultiValue valueWithPropertyType:types[i]];
- STAssertNotNil(mutValue, nil);
- // Oddly the Apple APIs allow you to create a mutable multi value with
- // either a property type of kABFooPropertyType or kABMultiFooPropertyType
- // and apparently you get back basically the same thing. However if you
- // ask a type that you created with kABMultiFooPropertyType for it's type
- // it returns just kABFooPropertyType.
- STAssertEquals([mutValue propertyType],
- types[i] & ~kABMultiValueMask, nil);
- }
- mutValue = [GTMABMutableMultiValue valueWithPropertyType:kABStringPropertyType];
- STAssertNotNil(mutValue, nil);
- value = [[mutValue copy] autorelease];
- STAssertEqualObjects([value class], [GTMABMultiValue class], nil);
- mutValue = [[value mutableCopy] autorelease];
- STAssertEqualObjects([mutValue class], [GTMABMutableMultiValue class], nil);
- STAssertEquals([mutValue count], (NSUInteger)0, nil);
- STAssertNil([mutValue valueAtIndex:0], nil);
- STAssertNil([mutValue labelAtIndex:0], nil);
- STAssertEquals([mutValue identifierAtIndex:0],
- kABMultiValueInvalidIdentifier, nil);
- STAssertEquals([mutValue propertyType],
- (ABPropertyType)kABStringPropertyType, nil);
- ABMultiValueIdentifier ident = [mutValue addValue:nil
- withLabel:kABHomeLabel];
- STAssertEquals(ident, kABMultiValueInvalidIdentifier, nil);
- ident = [mutValue addValue:@"val1"
- withLabel:nil];
- STAssertEquals(ident, kABMultiValueInvalidIdentifier, nil);
- ident = [mutValue insertValue:@"val1"
- withLabel:nil
- atIndex:0];
- STAssertEquals(ident, kABMultiValueInvalidIdentifier, nil);
- ident = [mutValue insertValue:nil
- withLabel:kABHomeLabel
- atIndex:0];
- STAssertEquals(ident, kABMultiValueInvalidIdentifier, nil);
- ident = [mutValue addValue:@"val1"
- withLabel:kABHomeLabel];
- STAssertNotEquals(ident, kABMultiValueInvalidIdentifier, nil);
- ABMultiValueIdentifier identCheck = [mutValue identifierAtIndex:0];
- STAssertEquals(ident, identCheck, nil);
- NSUInteger idx = [mutValue indexForIdentifier:ident];
- STAssertEquals(idx, (NSUInteger)0, nil);
- STAssertTrue([mutValue replaceLabelAtIndex:0
- withLabel:kABWorkLabel], nil);
- STAssertFalse([mutValue replaceLabelAtIndex:10
- withLabel:kABWorkLabel], nil);
- STAssertTrue([mutValue replaceValueAtIndex:0
- withValue:@"newVal1"], nil);
- STAssertFalse([mutValue replaceValueAtIndex:10
- withValue:@"newVal1"], nil);
-
- STAssertEqualObjects([mutValue valueForIdentifier:ident], @"newVal1", nil);
- STAssertEqualObjects([mutValue labelForIdentifier:ident],
- (NSString *)kABWorkLabel, nil);
-
- ABMultiValueIdentifier ident2 = [mutValue insertValue:@"val2"
- withLabel:kABOtherLabel
- atIndex:0];
- STAssertNotEquals(ident2, kABMultiValueInvalidIdentifier, nil);
- STAssertNotEquals(ident2, ident, nil);
- ABMultiValueIdentifier ident3 = [mutValue insertValue:@"val3"
- withLabel:kABPersonPhoneMainLabel
- atIndex:10];
- STAssertEquals(ident3, kABMultiValueInvalidIdentifier, nil);
- NSUInteger idx3 = [mutValue indexForIdentifier:ident3];
- STAssertEquals(idx3, (NSUInteger)NSNotFound, nil);
- STAssertTrue([mutValue removeValueAndLabelAtIndex:1], nil);
- STAssertFalse([mutValue removeValueAndLabelAtIndex:1], nil);
-
- NSUInteger idx4
- = [mutValue indexForIdentifier:kABMultiValueInvalidIdentifier];
- STAssertEquals(idx4, (NSUInteger)NSNotFound, nil);
-
- STAssertNotNULL([mutValue multiValueRef], nil);
-
- // Enumerator test
- mutValue = [GTMABMutableMultiValue valueWithPropertyType:kABIntegerPropertyType];
- STAssertNotNil(mutValue, nil);
- for (int i = 0; i < 100; i++) {
- NSString *label = [NSString stringWithFormat:@"label %d", i];
- NSNumber *val = [NSNumber numberWithInt:i];
- STAssertNotEquals([mutValue addValue:val
- withLabel:(CFStringRef)label],
- kABMultiValueInvalidIdentifier, nil);
- }
- int count = 0;
- for (NSString *label in [mutValue labelEnumerator]) {
- NSString *testLabel = [NSString stringWithFormat:@"label %d", count++];
- STAssertEqualObjects(label, testLabel, nil);
- }
- count = 0;
- value = [[mutValue copy] autorelease];
- for (NSNumber *val in [value valueEnumerator]) {
- STAssertEqualObjects(val, [NSNumber numberWithInt:count++], nil);
- }
-
- // Test messing with the values while we're enumerating them
- NSEnumerator *labelEnum = [mutValue labelEnumerator];
- NSEnumerator *valueEnum = [mutValue valueEnumerator];
- STAssertNotNil(labelEnum, nil);
- STAssertNotNil(valueEnum, nil);
- STAssertNotNil([labelEnum nextObject], nil);
- STAssertNotNil([valueEnum nextObject], nil);
- STAssertTrue([mutValue removeValueAndLabelAtIndex:0], nil);
- STAssertThrows([labelEnum nextObject], nil);
- STAssertThrows([valueEnum nextObject], nil);
-
- // Test messing with the values while we're fast enumerating them
- // Should throw an exception on the second access.
- BOOL exceptionThrown = NO;
- // Start at one because we removed index 0 above.
- count = 1;
- @try {
- for (NSString *label in [mutValue labelEnumerator]) {
- NSString *testLabel = [NSString stringWithFormat:@"label %d", count++];
- STAssertEqualObjects(label, testLabel, nil);
- STAssertTrue([mutValue removeValueAndLabelAtIndex:50], nil);
- }
- } @catch(NSException *e) {
- STAssertEqualObjects([e name], NSGenericException, @"Got %@ instead", e);
- STAssertEquals(count, 2,
- @"Should have caught it on the second access");
- exceptionThrown = YES;
- } // COV_NF_LINE - because we always catch, this brace doesn't get exec'd
- STAssertTrue(exceptionThrown, @"We should have thrown an exception"
- @" because the values under the enumerator were modified");
-
-}
-
-- (void)testRadar6208390 {
- ABPropertyType types[] = {
- kABStringPropertyType,
- kABIntegerPropertyType,
- kABRealPropertyType,
- kABDateTimePropertyType,
- kABDictionaryPropertyType
- };
- for (size_t j = 0; j < sizeof(types) / sizeof(ABPropertyType); ++j) {
- ABPropertyType type = types[j];
- ABMultiValueRef ref = ABMultiValueCreateMutable(type);
- STAssertNotNULL(ref, nil);
- NSString *label = [[NSString alloc] initWithString:@"label"];
- STAssertNotNil(label, nil);
- id val = nil;
- switch (type) {
- case kABDictionaryPropertyType:
- val = [[NSDictionary alloc] initWithObjectsAndKeys:@"1", @"1", nil];
- break;
-
- case kABStringPropertyType:
- val = [[NSString alloc] initWithFormat:@"value %d"];
- break;
-
- case kABIntegerPropertyType:
- case kABRealPropertyType:
- val = [[NSNumber alloc] initWithInt:143];
- break;
-
- case kABDateTimePropertyType:
- val = [[NSDate alloc] init];
- break;
- }
- STAssertNotNil(val,
- @"Testing type %d, %@", type, val);
- NSUInteger firstRetainCount = [val retainCount];
- STAssertNotEquals(firstRetainCount,
- (NSUInteger)0,
- @"Testing type %d, %@", type, val);
-
- ABMultiValueIdentifier identifier;
- STAssertTrue(ABMultiValueAddValueAndLabel(ref,
- val,
- (CFStringRef)label,
- &identifier),
- @"Testing type %d, %@", type, val);
- NSUInteger secondRetainCount = [val retainCount];
- STAssertEquals(firstRetainCount + 1,
- secondRetainCount,
- @"Testing type %d, %@", type, val);
- [label release];
- [val release];
- NSUInteger thirdRetainCount = [val retainCount];
- STAssertEquals(firstRetainCount,
- thirdRetainCount,
- @"Testing type %d, %@", type, val);
-
- id oldVal = val;
- val = (id)ABMultiValueCopyValueAtIndex(ref, 0);
- NSUInteger fourthRetainCount = [val retainCount];
-
- // kABDictionaryPropertyTypes appear to do an actual copy, so the retain
- // count checking trick won't work. We only check the retain count if
- // we didn't get a new version.
- if (val == oldVal) {
- if (type == kABIntegerPropertyType
- || type == kABRealPropertyType) {
- // We are verifying that yes indeed 6208390 is still broken
- STAssertEquals(fourthRetainCount,
- thirdRetainCount,
- @"Testing type %d, %@. If you see this error it may "
- @"be time to update the code to change retain behaviors"
- @"with this os version", type, val);
- } else {
- STAssertEquals(fourthRetainCount,
- thirdRetainCount + 1,
- @"Testing type %d, %@", type, val);
- [val release];
- }
- } else {
- [val release];
- }
- CFRelease(ref);
- }
-}
-
-// Globals used by testRadar6240394.
-static ABPropertyID gGTMTestID;
-static const ABPropertyID *gGTMTestIDPtr;
-
-void __attribute__((constructor))SetUpIDForTestRadar6240394(void) {
- // These must be set up BEFORE ABAddressBookCreate is called.
- gGTMTestID = kABPersonLastNameProperty;
- gGTMTestIDPtr = &kABPersonLastNameProperty;
-}
-
-- (void)testRadar6240394 {
- // As of iPhone SDK 2.1, the property IDs aren't initialized until
- // ABAddressBookCreate is actually called. They will return zero until
- // then. Logged as radar 6240394.
- STAssertEquals(gGTMTestID, 0, @"If this isn't zero, Apple has fixed 6240394");
- (void)ABAddressBookCreate();
- STAssertEquals(*gGTMTestIDPtr, kABPersonLastNameProperty,
- @"If this doesn't work, something else has broken");
-}
-@end