2
0

Sharing on Facebook, Twitter and Google+

[FIXED]     Font of navbar.
[FIXED]     A few compile fixes.
[IMPROVED]  Made properties nonatomic.
[ADDED]     Support for facebook, twitter and google+ sharing.
This commit is contained in:
Maarten Billemont
2012-08-25 12:38:29 +02:00
parent b9ccee398e
commit 5e7b6ed60e
131 changed files with 24758 additions and 26 deletions

View File

@@ -0,0 +1,25 @@
/* Copyright (c) 2012 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>
NSData *GTLDecodeBase64(NSString *base64Str);
NSString *GTLEncodeBase64(NSData *data);
// "Web-safe" encoding substitutes - and _ for + and / in the encoding table,
// per http://www.ietf.org/rfc/rfc4648.txt section 5.
NSData *GTLDecodeWebSafeBase64(NSString *base64Str);
NSString *GTLEncodeWebSafeBase64(NSData *data);

View File

@@ -0,0 +1,139 @@
/* Copyright (c) 2012 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 "GTLBase64.h"
// Based on Cyrus Najmabadi's elegent little encoder and decoder from
// http://www.cocoadev.com/index.pl?BaseSixtyFour
static char gStandardEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char gWebSafeEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
#pragma mark Encode
static NSString *EncodeBase64StringCommon(NSData *data, const char *table) {
if (data == nil) return nil;
const uint8_t* input = [data bytes];
NSUInteger length = [data length];
NSUInteger bufferSize = ((length + 2) / 3) * 4;
NSMutableData* buffer = [NSMutableData dataWithLength:bufferSize];
uint8_t *output = [buffer mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0;
for (NSUInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger idx = (i / 3) * 4;
output[idx + 0] = table[(value >> 18) & 0x3F];
output[idx + 1] = table[(value >> 12) & 0x3F];
output[idx + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[idx + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
NSString *result = [[[NSString alloc] initWithData:buffer
encoding:NSASCIIStringEncoding] autorelease];
return result;
}
NSString *GTLEncodeBase64(NSData *data) {
return EncodeBase64StringCommon(data, gStandardEncodingTable);
}
NSString *GTLEncodeWebSafeBase64(NSData *data) {
return EncodeBase64StringCommon(data, gWebSafeEncodingTable);
}
#pragma mark Decode
static void CreateDecodingTable(const char *encodingTable,
size_t encodingTableSize, char *decodingTable) {
memset(decodingTable, 0, 128);
for (unsigned int i = 0; i < encodingTableSize; i++) {
decodingTable[(unsigned int) encodingTable[i]] = i;
}
}
static NSData *DecodeBase64StringCommon(NSString *base64Str,
char *decodingTable) {
// The input string should be plain ASCII
const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding];
if (cString == nil) return nil;
NSUInteger inputLength = strlen(cString);
if (inputLength % 4 != 0) return nil;
if (inputLength == 0) return [NSData data];
while (inputLength > 0 && cString[inputLength - 1] == '=') {
inputLength--;
}
NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t *output = [data mutableBytes];
NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
char *table = decodingTable;
while (inputPoint < inputLength) {
int i0 = cString[inputPoint++];
int i1 = cString[inputPoint++];
int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0
int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A';
output[outputPoint++] = (table[i0] << 2) | (table[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((table[i1] & 0xF) << 4) | (table[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((table[i2] & 0x3) << 6) | table[i3];
}
}
return data;
}
NSData *GTLDecodeBase64(NSString *base64Str) {
static char decodingTable[128];
static BOOL hasInited = NO;
if (!hasInited) {
CreateDecodingTable(gStandardEncodingTable, sizeof(gStandardEncodingTable),
decodingTable);
hasInited = YES;
}
return DecodeBase64StringCommon(base64Str, decodingTable);
}
NSData *GTLDecodeWebSafeBase64(NSString *base64Str) {
static char decodingTable[128];
static BOOL hasInited = NO;
if (!hasInited) {
CreateDecodingTable(gWebSafeEncodingTable, sizeof(gWebSafeEncodingTable),
decodingTable);
hasInited = YES;
}
return DecodeBase64StringCommon(base64Str, decodingTable);
}

View File

@@ -0,0 +1,49 @@
/* Copyright (c) 2011 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.
*/
//
// GTLBatchQuery.h
//
#import "GTLQuery.h"
@interface GTLBatchQuery : NSObject <GTLQueryProtocol> {
@private
NSMutableArray *queries_;
NSMutableDictionary *requestIDMap_;
BOOL skipAuthorization_;
NSDictionary *additionalHTTPHeaders_;
}
// Queries included in this batch. Each query should have a unique requestID.
@property (retain) NSArray *queries;
// Clients may set this to YES to disallow authorization. Defaults to NO.
@property (assign) BOOL shouldSkipAuthorization;
// Any additional HTTP headers for this batch.
//
// These headers override the same keys from the service object's
// additionalHTTPHeaders.
@property (copy) NSDictionary *additionalHTTPHeaders;
+ (id)batchQuery;
+ (id)batchQueryWithQueries:(NSArray *)array;
- (void)addQuery:(GTLQuery *)query;
- (GTLQuery *)queryForRequestID:(NSString *)requestID;
@end

View File

@@ -0,0 +1,133 @@
/* Copyright (c) 2011 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.
*/
//
// GTLBatchQuery.m
//
#import "GTLBatchQuery.h"
@implementation GTLBatchQuery
@synthesize shouldSkipAuthorization = skipAuthorization_,
additionalHTTPHeaders = additionalHTTPHeaders_;
+ (id)batchQuery {
GTLBatchQuery *obj = [[[self alloc] init] autorelease];
return obj;
}
+ (id)batchQueryWithQueries:(NSArray *)queries {
GTLBatchQuery *obj = [self batchQuery];
obj.queries = queries;
return obj;
}
- (id)copyWithZone:(NSZone *)zone {
// Deep copy the list of queries
NSArray *copiesOfQueries = [[[NSArray alloc] initWithArray:self.queries
copyItems:YES] autorelease];
GTLBatchQuery *newBatch = [[[self class] allocWithZone:zone] init];
newBatch.queries = copiesOfQueries;
newBatch.shouldSkipAuthorization = self.shouldSkipAuthorization;
newBatch.additionalHTTPHeaders = self.additionalHTTPHeaders;
return newBatch;
}
- (void)dealloc {
[queries_ release];
[additionalHTTPHeaders_ release];
[requestIDMap_ release];
[super dealloc];
}
- (NSString *)description {
NSArray *queries = self.queries;
NSArray *methodNames = [queries valueForKey:@"methodName"];
NSArray *dedupedNames = [[NSSet setWithArray:methodNames] allObjects];
NSString *namesStr = [dedupedNames componentsJoinedByString:@","];
return [NSString stringWithFormat:@"%@ %p (queries:%lu methods:%@)",
[self class], self, (unsigned long) [queries count], namesStr];
}
#pragma mark -
- (BOOL)isBatchQuery {
return YES;
}
- (GTLUploadParameters *)uploadParameters {
// File upload is not supported for batches
return nil;
}
- (void)executionDidStop {
NSArray *queries = self.queries;
[queries makeObjectsPerformSelector:@selector(executionDidStop)];
}
- (GTLQuery *)queryForRequestID:(NSString *)requestID {
GTLQuery *result = [requestIDMap_ objectForKey:requestID];
if (result) return result;
// We've not before tried to look up a query, or the map is stale
[requestIDMap_ release];
requestIDMap_ = [[NSMutableDictionary alloc] init];
for (GTLQuery *query in queries_) {
[requestIDMap_ setObject:query forKey:query.requestID];
}
result = [requestIDMap_ objectForKey:requestID];
return result;
}
#pragma mark -
- (void)setQueries:(NSArray *)array {
#if DEBUG
for (id obj in array) {
GTLQuery *query = obj;
GTL_DEBUG_ASSERT([query isKindOfClass:[GTLQuery class]],
@"unexpected query class: %@", [obj class]);
GTL_DEBUG_ASSERT(query.uploadParameters == nil,
@"batch may not contain upload: %@", query);
}
#endif
[queries_ autorelease];
queries_ = [array mutableCopy];
}
- (NSArray *)queries {
return queries_;
}
- (void)addQuery:(GTLQuery *)query {
GTL_DEBUG_ASSERT([query isKindOfClass:[GTLQuery class]],
@"unexpected query class: %@", [query class]);
GTL_DEBUG_ASSERT(query.uploadParameters == nil,
@"batch may not contain upload: %@", query);
if (queries_ == nil) {
queries_ = [[NSMutableArray alloc] init];
}
[queries_ addObject:query];
}
@end

View File

@@ -0,0 +1,58 @@
/* Copyright (c) 2011 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.
*/
//
// GTLBatchResult.h
//
#import "GTLObject.h"
@interface GTLBatchResult : GTLObject <GTLBatchItemCreationProtocol> {
@private
NSMutableDictionary *successes_;
NSMutableDictionary *failures_;
}
// Dictionaries of results for all queries in the batch
//
// Dictionary keys are requestID strings; objects are results or
// GTLErrorObjects.
//
// For successes with no returned object (such as from delete operations),
// the object for the dictionary entry is NSNull.
//
//
// The original query for each result is available from the service ticket,
// for example
//
// NSDictionary *successes = batchResults.successes;
// for (NSString *requestID in successes) {
// GTLObject *obj = [successes objectForKey:requestID];
// GTLQuery *query = [ticket queryForRequestID:requestID];
// NSLog(@"Query %@ returned object %@", query, obj);
// }
//
// NSDictionary *failures = batchResults.failures;
// for (NSString *requestID in failures) {
// GTLErrorObject *errorObj = [failures objectForKey:requestID];
// GTLQuery *query = [ticket queryForRequestID:requestID];
// NSLog(@"Query %@ failed with error %@", query, errorObj);
// }
//
@property (retain) NSMutableDictionary *successes;
@property (retain) NSMutableDictionary *failures;
@end

View File

@@ -0,0 +1,92 @@
/* Copyright (c) 2011 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.
*/
//
// GTLBatchResult.m
//
#import "GTLBatchResult.h"
#import "GTLErrorObject.h"
@implementation GTLBatchResult
@synthesize successes = successes_,
failures = failures_;
- (id)copyWithZone:(NSZone *)zone {
GTLBatchResult* newObject = [super copyWithZone:zone];
newObject.successes = [[self.successes mutableCopyWithZone:zone] autorelease];
newObject.failures = [[self.failures mutableCopyWithZone:zone] autorelease];
return newObject;
}
- (void)dealloc {
[successes_ release];
[failures_ release];
[super dealloc];
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %p (successes:%lu failures:%lu)",
[self class], self,
(unsigned long) [self.successes count],
(unsigned long) [self.failures count]];
}
#pragma mark -
- (void)createItemsWithClassMap:(NSDictionary *)batchClassMap {
// This is called by GTLObject objectForJSON:defaultClass:
// JSON is defined to be a dictionary, but for batch results, it really
// is any array.
id json = self.JSON;
GTL_DEBUG_ASSERT([json isKindOfClass:[NSArray class]],
@"didn't get an array for the batch results");
NSArray *jsonArray = json;
NSMutableDictionary *successes = [NSMutableDictionary dictionary];
NSMutableDictionary *failures = [NSMutableDictionary dictionary];
for (NSMutableDictionary *rpcResponse in jsonArray) {
NSString *responseID = [rpcResponse objectForKey:@"id"];
NSMutableDictionary *errorJSON = [rpcResponse objectForKey:@"error"];
if (errorJSON) {
GTLErrorObject *errorObject = [GTLErrorObject objectWithJSON:errorJSON];
[failures setValue:errorObject forKey:responseID];
} else {
NSMutableDictionary *resultJSON = [rpcResponse objectForKey:@"result"];
NSDictionary *surrogates = self.surrogates;
Class defaultClass = [batchClassMap objectForKey:responseID];
id resultObject = [[self class] objectForJSON:resultJSON
defaultClass:defaultClass
surrogates:surrogates
batchClassMap:nil];
if (resultObject == nil) {
// methods like delete return no object
resultObject = [NSNull null];
}
[successes setValue:resultObject forKey:responseID];
}
}
self.successes = successes;
self.failures = failures;
}
@end

View File

@@ -0,0 +1,56 @@
/* Copyright (c) 2011 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.
*/
//
// GTLDateTime.h
//
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
@interface GTLDateTime : NSObject <NSCopying> {
NSDateComponents *dateComponents_;
NSInteger milliseconds_; // This is only for the fraction of a second 0-999
NSInteger offsetSeconds_; // may be NSUndefinedDateComponent
BOOL isUniversalTime_; // preserves "Z"
NSTimeZone *timeZone_; // specific time zone by name, if known
}
// Note: nil can be passed for time zone arguments when the time zone is not
// known.
+ (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str;
+ (GTLDateTime *)dateTimeWithDate:(NSDate *)date timeZone:(NSTimeZone *)tz;
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz;
- (void)setFromRFC3339String:(NSString *)str;
@property (nonatomic, readonly) NSDate *date;
@property (nonatomic, readonly) NSCalendar *calendar;
@property (nonatomic, readonly) NSString *RFC3339String;
@property (nonatomic, readonly) NSString *stringValue; // same as RFC3339String
@property (nonatomic, retain) NSTimeZone *timeZone;
@property (nonatomic, copy) NSDateComponents *dateComponents;
@property (nonatomic, assign) NSInteger milliseconds; // This is only for the fraction of a second 0-999
@property (nonatomic, assign) BOOL hasTime;
@property (nonatomic, assign) NSInteger offsetSeconds;
@property (nonatomic, assign, getter=isUniversalTime) BOOL universalTime;
- (void)setTimeZone:(NSTimeZone *)timeZone withOffsetSeconds:(NSInteger)val;
@end

View File

@@ -0,0 +1,422 @@
/* Copyright (c) 2011 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.
*/
//
// GTLDateTime.m
//
#import "GTLDateTime.h"
@implementation GTLDateTime
// A note about milliseconds_:
// RFC 3339 has support for fractions of a second. NSDateComponents is all
// NSInteger based, so it can't handle a fraction of a second. NSDate is
// built on NSTimeInterval so it has sub-millisecond precision. GTL takes
// the compromise of supporting the RFC's optional fractional second support
// by maintaining a number of milliseconds past what fits in the
// NSDateComponents. The parsing and string conversions will include
// 3 decimal digits (hence milliseconds). When going to a string, the decimal
// digits are only included if the milliseconds are non zero.
@dynamic date;
@dynamic calendar;
@dynamic RFC3339String;
@dynamic stringValue;
@dynamic timeZone;
@dynamic hasTime;
@synthesize dateComponents = dateComponents_,
milliseconds = milliseconds_,
offsetSeconds = offsetSeconds_,
universalTime = isUniversalTime_;
+ (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str {
if (str == nil) return nil;
GTLDateTime *result = [[[self alloc] init] autorelease];
[result setFromRFC3339String:str];
return result;
}
+ (GTLDateTime *)dateTimeWithDate:(NSDate *)date timeZone:(NSTimeZone *)tz {
if (date == nil) return nil;
GTLDateTime *result = [[[self alloc] init] autorelease];
[result setFromDate:date timeZone:tz];
return result;
}
- (void)dealloc {
[dateComponents_ release];
[timeZone_ release];
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone {
GTLDateTime *newObj = [[GTLDateTime alloc] init];
newObj.universalTime = self.isUniversalTime;
[newObj setTimeZone:self.timeZone withOffsetSeconds:self.offsetSeconds];
newObj.dateComponents = self.dateComponents;
newObj.milliseconds = self.milliseconds;
return newObj;
}
// until NSDateComponent implements isEqual, we'll use this
- (BOOL)doesDateComponents:(NSDateComponents *)dc1
equalDateComponents:(NSDateComponents *)dc2 {
return [dc1 era] == [dc2 era]
&& [dc1 year] == [dc2 year]
&& [dc1 month] == [dc2 month]
&& [dc1 day] == [dc2 day]
&& [dc1 hour] == [dc2 hour]
&& [dc1 minute] == [dc2 minute]
&& [dc1 second] == [dc2 second]
&& [dc1 week] == [dc2 week]
&& [dc1 weekday] == [dc2 weekday]
&& [dc1 weekdayOrdinal] == [dc2 weekdayOrdinal];
}
- (BOOL)isEqual:(GTLDateTime *)other {
if (self == other) return YES;
if (![other isKindOfClass:[GTLDateTime class]]) return NO;
BOOL areDateComponentsEqual = [self doesDateComponents:self.dateComponents
equalDateComponents:other.dateComponents];
NSTimeZone *tz1 = self.timeZone;
NSTimeZone *tz2 = other.timeZone;
BOOL areTimeZonesEqual = (tz1 == tz2 || (tz2 && [tz1 isEqual:tz2]));
return self.offsetSeconds == other.offsetSeconds
&& self.isUniversalTime == other.isUniversalTime
&& self.milliseconds == other.milliseconds
&& areDateComponentsEqual
&& areTimeZonesEqual;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %p: {%@}",
[self class], self, self.RFC3339String];
}
- (NSTimeZone *)timeZone {
if (timeZone_) {
return timeZone_;
}
if (self.isUniversalTime) {
NSTimeZone *ztz = [NSTimeZone timeZoneWithName:@"Universal"];
return ztz;
}
NSInteger offsetSeconds = self.offsetSeconds;
if (offsetSeconds != NSUndefinedDateComponent) {
NSTimeZone *tz = [NSTimeZone timeZoneForSecondsFromGMT:offsetSeconds];
return tz;
}
return nil;
}
- (void)setTimeZone:(NSTimeZone *)timeZone {
[timeZone_ release];
timeZone_ = [timeZone retain];
if (timeZone) {
NSInteger offsetSeconds = [timeZone secondsFromGMTForDate:self.date];
self.offsetSeconds = offsetSeconds;
} else {
self.offsetSeconds = NSUndefinedDateComponent;
}
}
- (void)setTimeZone:(NSTimeZone *)timeZone withOffsetSeconds:(NSInteger)val {
[timeZone_ release];
timeZone_ = [timeZone retain];
offsetSeconds_ = val;
}
- (NSCalendar *)calendar {
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSTimeZone *tz = self.timeZone;
if (tz) {
[cal setTimeZone:tz];
}
return cal;
}
- (NSDate *)date {
NSCalendar *cal = self.calendar;
NSDateComponents *dateComponents = self.dateComponents;
NSTimeInterval extraMillisecondsAsSeconds = 0.0;
if (!self.hasTime) {
// we're not keeping track of a time, but NSDate always is based on
// an absolute time. We want to avoid returning an NSDate where the
// calendar date appears different from what was used to create our
// date-time object.
//
// We'll make a copy of the date components, setting the time on our
// copy to noon GMT, since that ensures the date renders correctly for
// any time zone
NSDateComponents *noonDateComponents = [[dateComponents copy] autorelease];
[noonDateComponents setHour:12];
[noonDateComponents setMinute:0];
[noonDateComponents setSecond:0];
dateComponents = noonDateComponents;
NSTimeZone *gmt = [NSTimeZone timeZoneWithName:@"Universal"];
[cal setTimeZone:gmt];
} else {
// Add in the fractional seconds that don't fit into NSDateComponents.
extraMillisecondsAsSeconds = ((NSTimeInterval)self.milliseconds) / 1000.0;
}
NSDate *date = [cal dateFromComponents:dateComponents];
// Add in any milliseconds that didn't fit into the dateComponents.
if (extraMillisecondsAsSeconds > 0.0) {
#if GTL_IPHONE || (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5)
date = [date dateByAddingTimeInterval:extraMillisecondsAsSeconds];
#else
date = [date addTimeInterval:extraMillisecondsAsSeconds];
#endif
}
return date;
}
- (NSString *)stringValue {
return self.RFC3339String;
}
- (NSString *)RFC3339String {
NSDateComponents *dateComponents = self.dateComponents;
NSInteger offset = self.offsetSeconds;
NSString *timeString = @""; // timeString like "T15:10:46-08:00"
if (self.hasTime) {
NSString *timeOffsetString; // timeOffsetString like "-08:00"
if (self.isUniversalTime) {
timeOffsetString = @"Z";
} else if (offset == NSUndefinedDateComponent) {
// unknown offset is rendered as -00:00 per
// http://www.ietf.org/rfc/rfc3339.txt section 4.3
timeOffsetString = @"-00:00";
} else {
NSString *sign = @"+";
if (offset < 0) {
sign = @"-";
offset = -offset;
}
timeOffsetString = [NSString stringWithFormat:@"%@%02ld:%02ld",
sign, (long)(offset/(60*60)) % 24, (long)(offset / 60) % 60];
}
NSString *fractionalSecondsString = @"";
if (self.milliseconds > 0.0) {
fractionalSecondsString = [NSString stringWithFormat:@".%03ld", (long)self.milliseconds];
}
timeString = [NSString stringWithFormat:@"T%02ld:%02ld:%02ld%@%@",
(long)[dateComponents hour], (long)[dateComponents minute],
(long)[dateComponents second], fractionalSecondsString, timeOffsetString];
}
// full dateString like "2006-11-17T15:10:46-08:00"
NSString *dateString = [NSString stringWithFormat:@"%04ld-%02ld-%02ld%@",
(long)[dateComponents year], (long)[dateComponents month],
(long)[dateComponents day], timeString];
return dateString;
}
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz {
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
if (tz) {
[cal setTimeZone:tz];
}
NSUInteger const kComponentBits = (NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit
| NSSecondCalendarUnit);
NSDateComponents *components = [cal components:kComponentBits fromDate:date];
self.dateComponents = components;
// Extract the fractional seconds.
NSTimeInterval asTimeInterval = [date timeIntervalSince1970];
NSTimeInterval worker = asTimeInterval - trunc(asTimeInterval);
self.milliseconds = (NSInteger)round(worker * 1000.0);
self.universalTime = NO;
NSInteger offset = NSUndefinedDateComponent;
if (tz) {
offset = [tz secondsFromGMTForDate:date];
if (offset == 0 && [tz isEqualToTimeZone:[NSTimeZone timeZoneWithName:@"Universal"]]) {
self.universalTime = YES;
}
}
self.offsetSeconds = offset;
// though offset seconds are authoritative, we'll retain the time zone
// since we can't regenerate it reliably from just the offset
timeZone_ = [tz retain];
}
- (void)setFromRFC3339String:(NSString *)str {
NSInteger year = NSUndefinedDateComponent;
NSInteger month = NSUndefinedDateComponent;
NSInteger day = NSUndefinedDateComponent;
NSInteger hour = NSUndefinedDateComponent;
NSInteger minute = NSUndefinedDateComponent;
NSInteger sec = NSUndefinedDateComponent;
NSInteger milliseconds = 0;
double secDouble = -1.0;
NSString* sign = nil;
NSInteger offsetHour = 0;
NSInteger offsetMinute = 0;
if ([str length] > 0) {
NSScanner* scanner = [NSScanner scannerWithString:str];
// There should be no whitespace, so no skip characters.
[scanner setCharactersToBeSkipped:nil];
NSCharacterSet* dashSet = [NSCharacterSet characterSetWithCharactersInString:@"-"];
NSCharacterSet* tSet = [NSCharacterSet characterSetWithCharactersInString:@"Tt "];
NSCharacterSet* colonSet = [NSCharacterSet characterSetWithCharactersInString:@":"];
NSCharacterSet* plusMinusZSet = [NSCharacterSet characterSetWithCharactersInString:@"+-zZ"];
// for example, scan 2006-11-17T15:10:46-08:00
// or 2006-11-17T15:10:46Z
if (// yyyy-mm-dd
[scanner scanInteger:&year] &&
[scanner scanCharactersFromSet:dashSet intoString:NULL] &&
[scanner scanInteger:&month] &&
[scanner scanCharactersFromSet:dashSet intoString:NULL] &&
[scanner scanInteger:&day] &&
// Thh:mm:ss
[scanner scanCharactersFromSet:tSet intoString:NULL] &&
[scanner scanInteger:&hour] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] &&
[scanner scanInteger:&minute] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] &&
[scanner scanDouble:&secDouble]) {
// At this point we got secDouble, pull it apart.
sec = (NSInteger)secDouble;
double worker = secDouble - ((double)sec);
milliseconds = (NSInteger)round(worker * 1000.0);
// Finish parsing, now the offset info.
if (// Z or +hh:mm
[scanner scanCharactersFromSet:plusMinusZSet intoString:&sign] &&
[scanner scanInteger:&offsetHour] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] &&
[scanner scanInteger:&offsetMinute]) {
}
}
}
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setYear:year];
[dateComponents setMonth:month];
[dateComponents setDay:day];
[dateComponents setHour:hour];
[dateComponents setMinute:minute];
[dateComponents setSecond:sec];
self.dateComponents = dateComponents;
self.milliseconds = milliseconds;
// determine the offset, like from Z, or -08:00:00.0
self.timeZone = nil;
NSInteger totalOffset = NSUndefinedDateComponent;
self.universalTime = NO;
if ([sign caseInsensitiveCompare:@"Z"] == NSOrderedSame) {
self.universalTime = YES;
totalOffset = 0;
} else if (sign != nil) {
totalOffset = (60 * offsetMinute) + (60 * 60 * offsetHour);
if ([sign isEqual:@"-"]) {
if (totalOffset == 0) {
// special case: offset of -0.00 means undefined offset
totalOffset = NSUndefinedDateComponent;
} else {
totalOffset *= -1;
}
}
}
self.offsetSeconds = totalOffset;
}
- (BOOL)hasTime {
NSDateComponents *dateComponents = self.dateComponents;
BOOL hasTime = ([dateComponents hour] != NSUndefinedDateComponent
&& [dateComponents minute] != NSUndefinedDateComponent);
return hasTime;
}
- (void)setHasTime:(BOOL)shouldHaveTime {
// we'll set time values to zero or NSUndefinedDateComponent as appropriate
BOOL hadTime = self.hasTime;
if (shouldHaveTime && !hadTime) {
[dateComponents_ setHour:0];
[dateComponents_ setMinute:0];
[dateComponents_ setSecond:0];
milliseconds_ = 0;
offsetSeconds_ = NSUndefinedDateComponent;
isUniversalTime_ = NO;
} else if (hadTime && !shouldHaveTime) {
[dateComponents_ setHour:NSUndefinedDateComponent];
[dateComponents_ setMinute:NSUndefinedDateComponent];
[dateComponents_ setSecond:NSUndefinedDateComponent];
milliseconds_ = 0;
offsetSeconds_ = NSUndefinedDateComponent;
isUniversalTime_ = NO;
self.timeZone = nil;
}
}
@end

View File

@@ -0,0 +1,128 @@
/* Copyright (c) 2011 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.
*/
//
// GTLDefines.h
//
// Ensure Apple's conditionals we depend on are defined.
#import <TargetConditionals.h>
#import <AvailabilityMacros.h>
//
// The developer may choose to define these in the project:
//
// #define GTL_TARGET_NAMESPACE Xxx // preface all GTL class names with Xxx (recommended for building plug-ins)
// #define GTL_FOUNDATION_ONLY 1 // builds without AppKit or Carbon (default for iPhone builds)
// #define STRIP_GTM_FETCH_LOGGING 1 // omit http logging code (default for iPhone release builds)
//
// Mac developers may find GTL_SIMPLE_DESCRIPTIONS and STRIP_GTM_FETCH_LOGGING useful for
// reducing code size.
//
// Define later OS versions when building on earlier versions
#ifdef MAC_OS_X_VERSION_10_0
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
#endif
#ifdef GTL_TARGET_NAMESPACE
// prefix all GTL class names with GTL_TARGET_NAMESPACE for this target
#import "GTLTargetNamespace.h"
#endif
// Provide a common definition for externing constants/functions
#if defined(__cplusplus)
#define GTL_EXTERN extern "C"
#else
#define GTL_EXTERN extern
#endif
#if TARGET_OS_IPHONE // iPhone SDK
#define GTL_IPHONE 1
#endif
#if GTL_IPHONE
#define GTL_FOUNDATION_ONLY 1
#endif
//
// GTL_ASSERT is like NSAssert, but takes a variable number of arguments:
//
// GTL_ASSERT(condition, @"Problem in argument %@", argStr);
//
// GTL_DEBUG_ASSERT is similar, but compiles in only for debug builds
//
#ifndef GTL_ASSERT
// we directly invoke the NSAssert handler so we can pass on the varargs
#if !defined(NS_BLOCK_ASSERTIONS)
#define GTL_ASSERT(condition, ...) \
do { \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] \
handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ \
description:__VA_ARGS__]; \
} \
} while(0)
#else
#define GTL_ASSERT(condition, ...) do { } while (0)
#endif // !defined(NS_BLOCK_ASSERTIONS)
#endif // GTL_ASSERT
#ifndef GTL_DEBUG_ASSERT
#if DEBUG
#define GTL_DEBUG_ASSERT(condition, ...) GTL_ASSERT(condition, __VA_ARGS__)
#else
#define GTL_DEBUG_ASSERT(condition, ...) do { } while (0)
#endif
#endif
#ifndef GTL_DEBUG_LOG
#if DEBUG
#define GTL_DEBUG_LOG(...) NSLog(__VA_ARGS__)
#else
#define GTL_DEBUG_LOG(...) do { } while (0)
#endif
#endif
#ifndef STRIP_GTM_FETCH_LOGGING
#if GTL_IPHONE && !DEBUG
#define STRIP_GTM_FETCH_LOGGING 1
#else
#define STRIP_GTM_FETCH_LOGGING 0
#endif
#endif
// Some support for advanced clang static analysis functionality
// See http://clang-analyzer.llvm.org/annotations.html
#ifndef __has_feature // Optional.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_RETURNS_NOT_RETAINED
#if __has_feature(attribute_ns_returns_not_retained)
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#else
#define NS_RETURNS_NOT_RETAINED
#endif
#endif

View File

@@ -0,0 +1,45 @@
/* Copyright (c) 2011 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.
*/
//
// GTLErrorObject.h
//
#import "GTLObject.h"
@class GTLErrorObjectData;
@interface GTLErrorObject : GTLObject
@property (retain) NSNumber *code;
@property (retain) NSString *message;
@property (retain) NSArray *data; // of GTLErrorObjectData
// Convenience accessor for creating an NSError from a GTLErrorObject.
@property (readonly) NSError *foundationError;
// Convenience accessor for extracting the GTLErrorObject that was used to
// create an NSError.
//
// Returns nil if the error was not originally from a GTLErrorObject.
+ (GTLErrorObject *)underlyingObjectForError:(NSError *)foundationError;
@end
@interface GTLErrorObjectData : GTLObject
@property (retain) NSString *domain;
@property (retain) NSString *reason;
@property (retain) NSString *message;
@property (retain) NSString *location;
@end

View File

@@ -0,0 +1,78 @@
/* Copyright (c) 2011 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.
*/
//
// GTLErrorObject.m
//
#import "GTLErrorObject.h"
#import "GTLService.h"
@implementation GTLErrorObject
@dynamic code;
@dynamic message;
@dynamic data;
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map = [NSDictionary dictionaryWithObject:[GTLErrorObjectData class]
forKey:@"data"];
return map;
}
- (NSError *)foundationError {
NSMutableDictionary *userInfo;
// This structured GTLErrorObject will be available in the error's userInfo
// dictionary
userInfo = [NSMutableDictionary dictionaryWithObject:self
forKey:kGTLStructuredErrorKey];
NSString *reasonStr = self.message;
if (reasonStr) {
// We always store an error in the userInfo key "error"
[userInfo setObject:reasonStr
forKey:kGTLServerErrorStringKey];
// Store a user-readable "reason" to show up when an error is logged,
// in parentheses like NSError does it
NSString *parenthesized = [NSString stringWithFormat:@"(%@)", reasonStr];
[userInfo setObject:parenthesized
forKey:NSLocalizedFailureReasonErrorKey];
}
NSInteger code = [self.code integerValue];
NSError *error = [NSError errorWithDomain:kGTLJSONRPCErrorDomain
code:code
userInfo:userInfo];
return error;
}
+ (GTLErrorObject *)underlyingObjectForError:(NSError *)foundationError {
NSDictionary *userInfo = [foundationError userInfo];
GTLErrorObject *errorObj = [userInfo objectForKey:kGTLStructuredErrorKey];
return errorObj;
}
@end
@implementation GTLErrorObjectData
@dynamic domain;
@dynamic reason;
@dynamic message;
@dynamic location;
@end

View File

@@ -0,0 +1,35 @@
/* Copyright (c) 2011 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.
*/
#ifndef _GTLFRAMEWORK_H_
#define _GTLFRAMEWORK_H_
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
// Returns the version of the framework. Major and minor should
// match the bundle version in the Info.plist file.
//
// Pass NULL to ignore any of the parameters.
void GTLFrameworkVersion(NSUInteger* major, NSUInteger* minor, NSUInteger* release);
// Returns the version in @"a.b" or @"a.b.c" format
NSString *GTLFrameworkVersionString(void);
#endif

View File

@@ -0,0 +1,40 @@
/* Copyright (c) 2011 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.
*/
#include "GTLFramework.h"
void GTLFrameworkVersion(NSUInteger* major, NSUInteger* minor, NSUInteger* release) {
// version 2.0.0
if (major) *major = 2;
if (minor) *minor = 0;
if (release) *release = 0;
}
NSString *GTLFrameworkVersionString(void) {
NSUInteger major, minor, release;
NSString *libVersionString;
GTLFrameworkVersion(&major, &minor, &release);
// most library releases will have a release value of zero
if (release != 0) {
libVersionString = [NSString stringWithFormat:@"%d.%d.%d",
(int)major, (int)minor, (int)release];
} else {
libVersionString = [NSString stringWithFormat:@"%d.%d",
(int)major, (int)minor];
}
return libVersionString;
}

View File

@@ -0,0 +1,41 @@
/* Copyright (c) 2011 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.
*/
//
// GTLJSONParser.h
//
// This class is a thin wrapper around the JSON parser. It uses
// NSJSONSerialization when available, and SBJSON otherwise.
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
@interface GTLJSONParser : NSObject
+ (NSString*)stringWithObject:(id)value
humanReadable:(BOOL)humanReadable
error:(NSError**)error;
+ (NSData *)dataWithObject:(id)obj
humanReadable:(BOOL)humanReadable
error:(NSError**)error;
+ (id)objectWithString:(NSString *)jsonStr
error:(NSError **)error;
+ (id)objectWithData:(NSData *)jsonData
error:(NSError **)error;
@end

View File

@@ -0,0 +1,150 @@
/* Copyright (c) 2011 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.
*/
//
// GTLJSONParser.m
//
#import "GTLJSONParser.h"
// We can assume NSJSONSerialization is present on Mac OS X 10.7 and iOS 5
#if !defined(GTL_REQUIRES_NSJSONSERIALIZATION)
#if (!TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) || \
(TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000))
#define GTL_REQUIRES_NSJSONSERIALIZATION 1
#endif
#endif
// If GTMNSJSONSerialization is available, it is used for parsing and
// formatting JSON
#if !GTL_REQUIRES_NSJSONSERIALIZATION
@interface GTMNSJSONSerialization : NSObject
+ (NSData *)dataWithJSONObject:(id)obj options:(NSUInteger)opt error:(NSError **)error;
+ (id)JSONObjectWithData:(NSData *)data options:(NSUInteger)opt error:(NSError **)error;
@end
// As a fallback, SBJSON is used for parsing and formatting JSON
@interface GTLSBJSON
- (void)setHumanReadable:(BOOL)flag;
- (NSString*)stringWithObject:(id)value error:(NSError**)error;
- (id)objectWithString:(NSString*)jsonrep error:(NSError**)error;
@end
#endif // !GTL_REQUIRES_NSJSONSERIALIZATION
@implementation GTLJSONParser
#if DEBUG && !GTL_REQUIRES_NSJSONSERIALIZATION
// When compiling for iOS 4 compatibility, SBJSON must be available
+ (void)load {
Class writer = NSClassFromString(@"SBJsonWriter");
Class parser = NSClassFromString(@"SBJsonParser");
Class oldParser = NSClassFromString(@"SBJSON");
GTL_ASSERT((oldParser != Nil)
|| (writer != Nil && parser != Nil),
@"No parsing class found");
}
#endif // DEBUG && !GTL_REQUIRES_NSJSONSERIALIZATION
+ (NSString*)stringWithObject:(id)obj
humanReadable:(BOOL)humanReadable
error:(NSError**)error {
NSData *data = [self dataWithObject:obj
humanReadable:humanReadable
error:error];
if (data) {
NSString *jsonStr = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
return jsonStr;
}
return nil;
}
+ (NSData *)dataWithObject:(id)obj
humanReadable:(BOOL)humanReadable
error:(NSError**)error {
const NSUInteger kOpts = humanReadable ? (1UL << 0) : 0; // NSJSONWritingPrettyPrinted
#if GTL_REQUIRES_NSJSONSERIALIZATION
NSData *data = [NSJSONSerialization dataWithJSONObject:obj
options:kOpts
error:error];
return data;
#else
Class serializer = NSClassFromString(@"NSJSONSerialization");
if (serializer) {
NSData *data = [serializer dataWithJSONObject:obj
options:kOpts
error:error];
return data;
} else {
Class jsonWriteClass = NSClassFromString(@"SBJsonWriter");
if (!jsonWriteClass) {
jsonWriteClass = NSClassFromString(@"SBJSON");
}
if (error) *error = nil;
GTLSBJSON *writer = [[[jsonWriteClass alloc] init] autorelease];
[writer setHumanReadable:humanReadable];
NSString *jsonStr = [writer stringWithObject:obj
error:error];
NSData *data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
return data;
}
#endif
}
+ (id)objectWithString:(NSString *)jsonStr
error:(NSError **)error {
NSData *data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
return [self objectWithData:data
error:error];
}
+ (id)objectWithData:(NSData *)jsonData
error:(NSError **)error {
#if GTL_REQUIRES_NSJSONSERIALIZATION
NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:error];
return obj;
#else
Class serializer = NSClassFromString(@"NSJSONSerialization");
if (serializer) {
const NSUInteger kOpts = (1UL << 0); // NSJSONReadingMutableContainers
NSMutableDictionary *obj = [serializer JSONObjectWithData:jsonData
options:kOpts
error:error];
return obj;
} else {
Class jsonParseClass = NSClassFromString(@"SBJsonParser");
if (!jsonParseClass) {
jsonParseClass = NSClassFromString(@"SBJSON");
}
if (error) *error = nil;
GTLSBJSON *parser = [[[jsonParseClass alloc] init] autorelease];
NSString *jsonrep = [[[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding] autorelease];
id obj = [parser objectWithString:jsonrep
error:error];
return obj;
}
#endif
}
@end

View File

@@ -0,0 +1,180 @@
/* Copyright (c) 2011 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.
*/
//
// GTLObject.h
//
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
#import "GTLUtilities.h"
#import "GTLDateTime.h"
#undef _EXTERN
#undef _INITIALIZE_AS
#ifdef GTLOBJECT_DEFINE_GLOBALS
#define _EXTERN
#define _INITIALIZE_AS(x) =x
#else
#define _EXTERN extern
#define _INITIALIZE_AS(x)
#endif
@protocol GTLCollectionProtocol
@optional
@property (retain) NSArray *items;
@end
@protocol GTLBatchItemCreationProtocol
- (void)createItemsWithClassMap:(NSDictionary *)batchClassMap;
@end
@interface GTLObject : NSObject <NSCopying> {
@private
NSMutableDictionary *json_;
// Used when creating the subobjects from this one.
NSDictionary *surrogates_;
// Any complex object hung off this object goes into the cache so the
// next fetch will get the same object back instead of having to recreate
// it.
NSMutableDictionary *childCache_;
// Anything defined by the client; retained but not used internally; not
// copied by copyWithZone:
NSMutableDictionary *userProperties_;
}
@property (nonatomic, retain) NSMutableDictionary *JSON;
@property (nonatomic, retain) NSDictionary *surrogates;
@property (nonatomic, retain) NSMutableDictionary *userProperties;
///////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
// These methods are intended for users of the library
//
+ (id)object;
+ (id)objectWithJSON:(NSMutableDictionary *)dict;
- (id)copyWithZone:(NSZone *)zone;
- (NSString *)JSONString;
// generic access to json; also creates it if necessary
- (void)setJSONValue:(id)obj forKey:(NSString *)key;
- (id)JSONValueForKey:(NSString *)key;
// Returns the list of keys in this object's JSON that aren't listed as
// properties on the object.
- (NSArray *)additionalJSONKeys;
// Any keys in the JSON that aren't listed as @properties on the object
// are counted as "additional properties". These allow you to get/set them.
- (id)additionalPropertyForName:(NSString *)name;
- (void)setAdditionalProperty:(id)obj forName:(NSString *)name;
- (NSDictionary *)additionalProperties;
// User properties are supported for client convenience, but are not copied by
// copyWithZone. User Properties keys beginning with _ are reserved by the library.
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property
- (id)propertyForKey:(NSString *)key;
// userData is stored as a property with key "_userData"
- (void)setUserData:(id)obj;
- (id)userData;
// Makes a partial query-compatible string describing the fields present
// in this object. (Note: only the first element of any array is examined.)
//
// http://code.google.com/apis/tasks/v1/performance.html#partial
//
- (NSString *)fieldsDescription;
// Makes an object containing only the changes needed to do a partial update
// (patch), where the patch would be to change an object from the original
// to the receiver, such as
//
// GTLSomeObject *patchObject = [newVersion patchObjectFromOriginal:oldVersion];
//
// http://code.google.com/apis/tasks/v1/performance.html#patch
//
// NOTE: this method returns nil if there are no changes between the original
// and the receiver.
- (id)patchObjectFromOriginal:(GTLObject *)original;
// Method creating a null value to set object properties for patch queries that
// delete fields. Do not use this except when setting an object property for
// a patch query.
+ (id)nullValue;
///////////////////////////////////////////////////////////////////////////////
//
// Protected methods
//
// These methods are intended for subclasses of GTLObject
//
// class registration ("kind" strings) for subclasses
+ (Class)registeredObjectClassForKind:(NSString *)kind;
+ (void)registerObjectClassForKind:(NSString *)kind;
// creation of objects from a JSON dictionary
+ (GTLObject *)objectForJSON:(NSMutableDictionary *)json
defaultClass:(Class)defaultClass
surrogates:(NSDictionary *)surrogates
batchClassMap:(NSDictionary *)batchClassMap;
// property-to-key mapping (for JSON keys which are not used as method names)
+ (NSDictionary *)propertyToJSONKeyMap;
// property-to-Class mapping for array properties (to say what is in the array)
+ (NSDictionary *)arrayPropertyToClassMap;
// The default class for additional JSON keys
+ (Class)classForAdditionalProperties;
@end
// Collection objects with an "items" property should derive from GTLCollection
// object. This provides support for fast object enumeration and the
// itemAtIndex: convenience method.
//
// Subclasses must implement the items method dynamically.
@interface GTLCollectionObject : GTLObject <GTLCollectionProtocol, NSFastEnumeration>
// itemAtIndex: returns nil when the index exceeds the bounds of the items array
- (id)itemAtIndex:(NSUInteger)idx;
@end
@interface GTLCollectionObject (DynamicMethods)
- (NSArray *)items;
@end
// Base object use for when an service method directly returns an array instead
// of an object. Normally methods should return an object with an 'items'
// property, this exists for the methods not up to spec.
@interface GTLResultArray : GTLCollectionObject
// This method should only be called by subclasses.
- (NSArray *)itemsWithItemClass:(Class)itemClass;
@end

View File

@@ -0,0 +1,691 @@
/* Copyright (c) 2011 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.
*/
//
// GTLObject.m
//
#define GTLOBJECT_DEFINE_GLOBALS 1
#include <objc/runtime.h>
#import "GTLObject.h"
#import "GTLRuntimeCommon.h"
#import "GTLJSONParser.h"
static NSString *const kUserDataPropertyKey = @"_userData";
@interface GTLObject () <GTLRuntimeCommon>
+ (NSMutableArray *)allDeclaredProperties;
+ (NSArray *)allKnownKeys;
+ (NSArray *)fieldsElementsForJSON:(NSDictionary *)targetJSON;
+ (NSString *)fieldsDescriptionForJSON:(NSDictionary *)targetJSON;
+ (NSMutableDictionary *)patchDictionaryForJSON:(NSDictionary *)newJSON
fromOriginalJSON:(NSDictionary *)originalJSON;
@end
@implementation GTLObject
@synthesize JSON = json_,
surrogates = surrogates_,
userProperties = userProperties_;
+ (id)object {
return [[[self alloc] init] autorelease];
}
+ (id)objectWithJSON:(NSMutableDictionary *)dict {
GTLObject *obj = [self object];
obj.JSON = dict;
return obj;
}
+ (NSDictionary *)propertyToJSONKeyMap {
return nil;
}
+ (NSDictionary *)arrayPropertyToClassMap {
return nil;
}
+ (Class)classForAdditionalProperties {
return Nil;
}
- (BOOL)isEqual:(GTLObject *)other {
if (self == other) return YES;
if (other == nil) return NO;
// The objects should be the same class, or one should be a subclass of the
// other's class
if (![other isKindOfClass:[self class]]
&& ![self isKindOfClass:[other class]]) return NO;
// What we're not comparing here:
// properties
return GTL_AreEqualOrBothNil(json_, [other JSON]);
}
// By definition, for two objects to potentially be considered equal,
// they must have the same hash value. The hash is mostly ignored,
// but removeObjectsInArray: in Leopard does seem to check the hash,
// and NSObject's default hash method just returns the instance pointer.
// We'll define hash here for all of our GTLObjects.
- (NSUInteger)hash {
return (NSUInteger) (void *) [GTLObject class];
}
- (id)copyWithZone:(NSZone *)zone {
GTLObject* newObject = [[[self class] allocWithZone:zone] init];
CFPropertyListRef ref = CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
json_, kCFPropertyListMutableContainers);
GTL_DEBUG_ASSERT(ref != NULL, @"GTLObject: copy failed (probably a non-plist type in the JSON)");
newObject.JSON = [NSMakeCollectable(ref) autorelease];
newObject.surrogates = self.surrogates;
// What we're not copying:
// userProperties
return newObject;
}
- (NSString *)descriptionWithLocale:(id)locale {
return [self description];
}
- (void)dealloc {
[json_ release];
[surrogates_ release];
[childCache_ release];
[userProperties_ release];
[super dealloc];
}
#pragma mark JSON values
- (void)setJSONValue:(id)obj forKey:(NSString *)key {
NSMutableDictionary *dict = self.JSON;
if (dict == nil && obj != nil) {
dict = [NSMutableDictionary dictionaryWithCapacity:1];
self.JSON = dict;
}
[dict setValue:obj forKey:key];
}
- (id)JSONValueForKey:(NSString *)key {
id obj = [self.JSON objectForKey:key];
return obj;
}
- (NSString *)JSONString {
NSError *error = nil;
NSString *str = [GTLJSONParser stringWithObject:[self JSON]
humanReadable:YES
error:&error];
if (error) {
return [error description];
}
return str;
}
- (NSArray *)additionalJSONKeys {
NSArray *knownKeys = [[self class] allKnownKeys];
NSMutableArray *result = [NSMutableArray arrayWithArray:[json_ allKeys]];
[result removeObjectsInArray:knownKeys];
// Return nil instead of an empty array.
if ([result count] == 0) {
result = nil;
}
return result;
}
#pragma mark Partial - Fields
- (NSString *)fieldsDescription {
NSString *str = [GTLObject fieldsDescriptionForJSON:self.JSON];
return str;
}
+ (NSString *)fieldsDescriptionForJSON:(NSDictionary *)targetJSON {
// Internal routine: recursively generate a string field description
// by joining elements
NSArray *array = [self fieldsElementsForJSON:targetJSON];
NSString *str = [array componentsJoinedByString:@","];
return str;
}
+ (NSArray *)fieldsElementsForJSON:(NSDictionary *)targetJSON {
// Internal routine: recursively generate an array of field description
// element strings
NSMutableArray *resultFields = [NSMutableArray array];
// Sorting the dictionary keys gives us deterministic results when iterating
NSArray *sortedKeys = [[targetJSON allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
for (NSString *key in sortedKeys) {
// We'll build a comma-separated list of fields
id value = [targetJSON objectForKey:key];
if ([value isKindOfClass:[NSString class]]
|| [value isKindOfClass:[NSNumber class]]) {
// Basic type (string, number), so the key is what we want
[resultFields addObject:key];
} else if ([value isKindOfClass:[NSDictionary class]]) {
// Object (dictionary): "parent/child1,parent/child2,parent/child3"
NSArray *subElements = [self fieldsElementsForJSON:value];
for (NSString *subElem in subElements) {
NSString *prepended = [NSString stringWithFormat:@"%@/%@",
key, subElem];
[resultFields addObject:prepended];
}
} else if ([value isKindOfClass:[NSArray class]]) {
// Array; we'll generate from the first array entry:
// "parent(child1,child2,child3)"
//
// Open question: should this instead create the union of elements for
// all items in the array, rather than just get fields from the first
// array object?
if ([value count] > 0) {
id firstObj = [value objectAtIndex:0];
if ([firstObj isKindOfClass:[NSDictionary class]]) {
// An array of objects
NSString *contentsStr = [self fieldsDescriptionForJSON:firstObj];
NSString *encapsulated = [NSString stringWithFormat:@"%@(%@)",
key, contentsStr];
[resultFields addObject:encapsulated];
} else {
// An array of some basic type, or of arrays
[resultFields addObject:key];
}
}
} else {
GTL_ASSERT(0, @"GTLObject unknown field element for %@ (%@)",
key, NSStringFromClass([value class]));
}
}
return resultFields;
}
#pragma mark Partial - Patch
- (id)patchObjectFromOriginal:(GTLObject *)original {
id resultObj;
NSMutableDictionary *resultJSON = [GTLObject patchDictionaryForJSON:self.JSON
fromOriginalJSON:original.JSON];
if ([resultJSON count] > 0) {
resultObj = [[self class] objectWithJSON:resultJSON];
} else {
// Client apps should not attempt to patch with an object containing
// empty JSON
resultObj = nil;
}
return resultObj;
}
+ (NSMutableDictionary *)patchDictionaryForJSON:(NSDictionary *)newJSON
fromOriginalJSON:(NSDictionary *)originalJSON {
// Internal recursive routine to create an object suitable for
// our patch semantics
NSMutableDictionary *resultJSON = [NSMutableDictionary dictionary];
// Iterate through keys present in the old object
NSArray *originalKeys = [originalJSON allKeys];
for (NSString *key in originalKeys) {
id originalValue = [originalJSON objectForKey:key];
id newValue = [newJSON valueForKey:key];
if (newValue == nil) {
// There is no new value for this key, so set the value to NSNull
[resultJSON setValue:[NSNull null] forKey:key];
} else if (!GTL_AreEqualOrBothNil(originalValue, newValue)) {
// The values for this key differ
if ([originalValue isKindOfClass:[NSDictionary class]]
&& [newValue isKindOfClass:[NSDictionary class]]) {
// Both are objects; recurse
NSMutableDictionary *subDict = [self patchDictionaryForJSON:newValue
fromOriginalJSON:originalValue];
[resultJSON setValue:subDict forKey:key];
} else {
// They are non-object values; the new replaces the old. Per the
// documentation for patch, this replaces entire arrays.
[resultJSON setValue:newValue forKey:key];
}
} else {
// The values are the same; omit this key-value pair
}
}
// Iterate through keys present only in the new object, and add them to the
// result
NSMutableArray *newKeys = [NSMutableArray arrayWithArray:[newJSON allKeys]];
[newKeys removeObjectsInArray:originalKeys];
for (NSString *key in newKeys) {
id value = [newJSON objectForKey:key];
[resultJSON setValue:value forKey:key];
}
return resultJSON;
}
+ (id)nullValue {
return [NSNull null];
}
#pragma mark Additional Properties
- (id)additionalPropertyForName:(NSString *)name {
// Return the cached object, if any, before creating one.
id result = [self cacheChildForKey:name];
if (result != nil) {
return result;
}
Class defaultClass = [[self class] classForAdditionalProperties];
id jsonObj = [self JSONValueForKey:name];
BOOL shouldCache = NO;
if (jsonObj != nil) {
NSDictionary *surrogates = self.surrogates;
result = [GTLRuntimeCommon objectFromJSON:jsonObj
defaultClass:defaultClass
surrogates:surrogates
isCacheable:&shouldCache];
}
[self setCacheChild:(shouldCache ? result : nil)
forKey:name];
return result;
}
- (void)setAdditionalProperty:(id)obj forName:(NSString *)name {
BOOL shouldCache = NO;
Class defaultClass = [[self class] classForAdditionalProperties];
id json = [GTLRuntimeCommon jsonFromAPIObject:obj
expectedClass:defaultClass
isCacheable:&shouldCache];
[self setJSONValue:json forKey:name];
[self setCacheChild:(shouldCache ? obj : nil)
forKey:name];
}
- (NSDictionary *)additionalProperties {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *propertyNames = [self additionalJSONKeys];
for (NSString *name in propertyNames) {
id obj = [self additionalPropertyForName:name];
[result setObject:obj forKey:name];
}
return result;
}
#pragma mark Child Cache methods
// There is no property for childCache_ as there shouldn't be KVC/KVO
// support for it, it's an implementation detail.
- (void)setCacheChild:(id)obj forKey:(NSString *)key {
if (childCache_ == nil && obj != nil) {
childCache_ = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
obj, key, nil];
} else {
[childCache_ setValue:obj forKey:key];
}
}
- (id)cacheChildForKey:(NSString *)key {
id obj = [childCache_ objectForKey:key];
return obj;
}
#pragma mark userData and user properties
- (void)setUserData:(id)userData {
[self setProperty:userData forKey:kUserDataPropertyKey];
}
- (id)userData {
// be sure the returned pointer has the life of the autorelease pool,
// in case self is released immediately
return [[[self propertyForKey:kUserDataPropertyKey] retain] autorelease];
}
- (void)setProperty:(id)obj forKey:(NSString *)key {
if (obj == nil) {
// user passed in nil, so delete the property
[userProperties_ removeObjectForKey:key];
} else {
// be sure the property dictionary exists
if (userProperties_ == nil) {
self.userProperties = [NSMutableDictionary dictionary];
}
[userProperties_ setObject:obj forKey:key];
}
}
- (id)propertyForKey:(NSString *)key {
id obj = [userProperties_ objectForKey:key];
// be sure the returned pointer has the life of the autorelease pool,
// in case self is released immediately
return [[obj retain] autorelease];
}
#pragma mark Support methods
+ (NSMutableArray *)allDeclaredProperties {
NSMutableArray *array = [NSMutableArray array];
// walk from this class up the hierarchy to GTLObject
Class topClass = class_getSuperclass([GTLObject class]);
for (Class currClass = self;
currClass != topClass;
currClass = class_getSuperclass(currClass)) {
// step through this class's properties, and add the property names to the
// array
objc_property_t *properties = class_copyPropertyList(currClass, NULL);
if (properties) {
for (objc_property_t *prop = properties;
*prop != NULL;
++prop) {
const char *propName = property_getName(*prop);
// We only want dynamic properties; their attributes contain ",D".
const char *attr = property_getAttributes(*prop);
const char *dynamicMarker = strstr(attr, ",D");
if (dynamicMarker &&
(dynamicMarker[2] == 0 || dynamicMarker[2] == ',' )) {
[array addObject:[NSString stringWithUTF8String:propName]];
}
}
free(properties);
}
}
return array;
}
+ (NSArray *)allKnownKeys {
NSArray *allProps = [self allDeclaredProperties];
NSMutableArray *knownKeys = [NSMutableArray arrayWithArray:allProps];
NSDictionary *propMap = [GTLObject propertyToJSONKeyMapForClass:[self class]];
NSUInteger idx = 0;
for (NSString *propName in allProps) {
NSString *jsonKey = [propMap objectForKey:propName];
if (jsonKey) {
[knownKeys replaceObjectAtIndex:idx
withObject:jsonKey];
}
++idx;
}
return knownKeys;
}
- (NSString *)description {
// find the list of declared and otherwise known JSON keys for this class
NSArray *knownKeys = [[self class] allKnownKeys];
NSMutableString *descStr = [NSMutableString string];
NSString *spacer = @"";
for (NSString *key in json_) {
NSString *value = nil;
// show question mark for JSON keys not supported by a declared property:
// foo?:"Hi mom."
NSString *qmark = [knownKeys containsObject:key] ? @"" : @"?";
// determine property value to dislay
id rawValue = [json_ valueForKey:key];
if ([rawValue isKindOfClass:[NSDictionary class]]) {
// for dictionaries, show the list of keys:
// {key1,key2,key3}
NSString *subkeyList = [[rawValue allKeys] componentsJoinedByString:@","];
value = [NSString stringWithFormat:@"{%@}", subkeyList];
} else if ([rawValue isKindOfClass:[NSArray class]]) {
// for arrays, show the number of items in the array:
// [3]
value = [NSString stringWithFormat:@"[%lu]", (unsigned long)[rawValue count]];
} else if ([rawValue isKindOfClass:[NSString class]]) {
// for strings, show the string in quotes:
// "Hi mom."
value = [NSString stringWithFormat:@"\"%@\"", rawValue];
} else {
// for numbers, show just the number
value = [rawValue description];
}
[descStr appendFormat:@"%@%@%@:%@", spacer, key, qmark, value];
spacer = @" ";
}
NSString *str = [NSString stringWithFormat:@"%@ %p: {%@}",
[self class], self, descStr];
return str;
}
#pragma mark Class Registration
static NSMutableDictionary *gKindMap = nil;
+ (Class)registeredObjectClassForKind:(NSString *)kind {
Class resultClass = [gKindMap objectForKey:kind];
return resultClass;
}
+ (void)registerObjectClassForKind:(NSString *)kind {
// there's no autorelease pool in place at +load time, so we'll create our own
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (gKindMap == nil) {
gKindMap = [GTLUtilities newStaticDictionary];
}
Class selfClass = [self class];
#if DEBUG
// ensure this is a unique registration
if ([gKindMap objectForKey:kind] != nil ) {
GTL_DEBUG_LOG(@"%@ (%@) registration conflicts with %@",
selfClass, kind, [gKindMap objectForKey:kind]);
}
if ([[gKindMap allKeysForObject:selfClass] count] != 0) {
GTL_DEBUG_LOG(@"%@ (%@) registration conflicts with %@",
selfClass, kind, [gKindMap allKeysForObject:selfClass]);
}
#endif
[gKindMap setValue:selfClass forKey:kind];
// we drain here to keep the clang static analyzer quiet
[pool drain];
}
#pragma mark Object Instantiation
+ (GTLObject *)objectForJSON:(NSMutableDictionary *)json
defaultClass:(Class)defaultClass
surrogates:(NSDictionary *)surrogates
batchClassMap:(NSDictionary *)batchClassMap {
if ([json isEqual:[NSNull null]]) {
// no actual result, such as the response from a delete
return nil;
}
GTL_ASSERT([json count] != 0, @"Creating object from empty json");
if ([json count] == 0) return nil;
// Determine the class to instantiate, based on the original fetch
// request or by looking up "kind" string from the registration at
// +load time of GTLObject subclasses
//
// We're letting the dynamic kind override the default class so
// feeds of heterogenous entries can use the defaultClass as a
// fallback
Class classToCreate = defaultClass;
NSString *kind = nil;
if ([json isKindOfClass:[NSDictionary class]]) {
kind = [json valueForKey:@"kind"];
if ([kind isKindOfClass:[NSString class]] && [kind length] > 0) {
Class dynamicClass = [GTLObject registeredObjectClassForKind:kind];
if (dynamicClass) {
classToCreate = dynamicClass;
}
}
}
// Warn the developer that no specific class of GTLObject
// was requested with the fetch call, and no class is found
// compiled in to match the "kind" attribute of the JSON
// returned by the server
GTL_ASSERT(classToCreate != nil,
@"Could not find registered GTLObject subclass to "
"match JSON with kind \"%@\"", kind);
if (classToCreate == nil) {
classToCreate = [self class];
}
// See if the top-level class for the JSON is listed in the surrogates;
// if so, instantiate the surrogate class instead
Class baseSurrogate = [surrogates objectForKey:classToCreate];
if (baseSurrogate) {
classToCreate = baseSurrogate;
}
// now instantiate the GTLObject
GTLObject *parsedObject = [classToCreate object];
parsedObject.surrogates = surrogates;
parsedObject.JSON = json;
// it's time to instantiate inner items
if ([parsedObject conformsToProtocol:@protocol(GTLBatchItemCreationProtocol)]) {
id <GTLBatchItemCreationProtocol> batch =
(id <GTLBatchItemCreationProtocol>) parsedObject;
[batch createItemsWithClassMap:batchClassMap];
}
return parsedObject;
}
#pragma mark Runtime Utilities
static NSMutableDictionary *gJSONKeyMapCache = nil;
static NSMutableDictionary *gArrayPropertyToClassMapCache = nil;
+ (void)initialize {
// Note that initialize is guaranteed by the runtime to be called in a
// thread-safe manner
if (gJSONKeyMapCache == nil) {
gJSONKeyMapCache = [GTLUtilities newStaticDictionary];
}
if (gArrayPropertyToClassMapCache == nil) {
gArrayPropertyToClassMapCache = [GTLUtilities newStaticDictionary];
}
}
+ (NSDictionary *)propertyToJSONKeyMapForClass:(Class<GTLRuntimeCommon>)aClass {
NSDictionary *resultMap =
[GTLUtilities mergedClassDictionaryForSelector:@selector(propertyToJSONKeyMap)
startClass:aClass
ancestorClass:[GTLObject class]
cache:gJSONKeyMapCache];
return resultMap;
}
+ (NSDictionary *)arrayPropertyToClassMapForClass:(Class<GTLRuntimeCommon>)aClass {
NSDictionary *resultMap =
[GTLUtilities mergedClassDictionaryForSelector:@selector(arrayPropertyToClassMap)
startClass:aClass
ancestorClass:[GTLObject class]
cache:gArrayPropertyToClassMapCache];
return resultMap;
}
#pragma mark Runtime Support
+ (Class<GTLRuntimeCommon>)ancestorClass {
return [GTLObject class];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
BOOL resolved = [GTLRuntimeCommon resolveInstanceMethod:sel onClass:self];
if (resolved)
return YES;
return [super resolveInstanceMethod:sel];
}
@end
@implementation GTLCollectionObject
// Subclasses must implement the items method dynamically.
- (id)itemAtIndex:(NSUInteger)idx {
NSArray *items = [self performSelector:@selector(items)];
if (idx < [items count]) {
return [items objectAtIndex:idx];
}
return nil;
}
// NSFastEnumeration protocol
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id *)stackbuf
count:(NSUInteger)len {
NSArray *items = [self performSelector:@selector(items)];
NSUInteger result = [items countByEnumeratingWithState:state
objects:stackbuf
count:len];
return result;
}
@end
@implementation GTLResultArray
- (NSArray *)itemsWithItemClass:(Class)itemClass {
// Return the cached array before creating on demand.
NSString *cacheKey = @"result_array_items";
NSMutableArray *cachedArray = [self cacheChildForKey:cacheKey];
if (cachedArray != nil) {
return cachedArray;
}
NSArray *result = nil;
NSArray *array = (NSArray *)[self JSON];
if (array != nil) {
if ([array isKindOfClass:[NSArray class]]) {
NSDictionary *surrogates = self.surrogates;
result = [GTLRuntimeCommon objectFromJSON:array
defaultClass:itemClass
surrogates:surrogates
isCacheable:NULL];
} else {
#if DEBUG
if (![array isKindOfClass:[NSNull class]]) {
GTL_DEBUG_LOG(@"GTLObject: unexpected JSON: %@ should be an array, actually is a %@:\n%@",
NSStringFromClass([self class]),
NSStringFromClass([array class]),
array);
}
#endif
result = array;
}
}
[self setCacheChild:result forKey:cacheKey];
return result;
}
@end

View File

@@ -0,0 +1,36 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlus.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
#import "GTLPlusConstants.h"
#import "GTLPlusItemScope.h"
#import "GTLPlusMoment.h"
#import "GTLPlusPerson.h"
#import "GTLQueryPlus.h"
#import "GTLServicePlus.h"

View File

@@ -0,0 +1,46 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusConstants.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
#import <Foundation/Foundation.h>
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLDefines.h"
#else
#import "GTLDefines.h"
#endif
// Authorization scope
// Know who you are on Google
GTL_EXTERN NSString * const kGTLAuthScopePlusMe; // "https://www.googleapis.com/auth/plus.me"
// View and manage user activity information in Google+
GTL_EXTERN NSString * const kGTLAuthScopePlusMomentsWrite; // "https://www.googleapis.com/auth/plus.moments.write"
// View your email address
GTL_EXTERN NSString * const kGTLAuthScopePlusUserinfoEmail; // "https://www.googleapis.com/auth/userinfo.email"
// Collection
GTL_EXTERN NSString * const kGTLPlusCollectionVault; // "vault"

View File

@@ -0,0 +1,37 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusConstants.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
#import "GTLPlusConstants.h"
// Authorization scope
NSString * const kGTLAuthScopePlusMe = @"https://www.googleapis.com/auth/plus.me";
NSString * const kGTLAuthScopePlusMomentsWrite = @"https://www.googleapis.com/auth/plus.moments.write";
NSString * const kGTLAuthScopePlusUserinfoEmail = @"https://www.googleapis.com/auth/userinfo.email";
// Collection
NSString * const kGTLPlusCollectionVault = @"vault";

View File

@@ -0,0 +1,225 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusItemScope.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusItemScope (0 custom class methods, 55 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusItemScope;
// ----------------------------------------------------------------------------
//
// GTLPlusItemScope
//
@interface GTLPlusItemScope : GTLObject
// The subject matter of the content.
@property (retain) GTLPlusItemScope *about;
// An additional name for a Person, can be used for a middle name.
@property (retain) NSArray *additionalName; // of NSString
// Postal address.
@property (retain) GTLPlusItemScope *address;
// Address country.
@property (copy) NSString *addressCountry;
// Address locality.
@property (copy) NSString *addressLocality;
// Address region.
@property (copy) NSString *addressRegion;
// The encoding.
@property (retain) NSArray *associatedMedia; // of GTLPlusItemScope
// Number of attendees.
@property (retain) NSNumber *attendeeCount; // intValue
// A person attending the event.
@property (retain) NSArray *attendees; // of GTLPlusItemScope
// From http://schema.org/MusicRecording, the audio file.
@property (retain) GTLPlusItemScope *audio;
// The person who created this scope.
@property (retain) NSArray *author; // of GTLPlusItemScope
// Best possible rating value.
@property (copy) NSString *bestRating;
// Date of birth.
@property (copy) NSString *birthDate;
// From http://schema.org/MusicRecording, the artist that performed this
// recording.
@property (retain) GTLPlusItemScope *byArtist;
// The caption for this object.
@property (copy) NSString *caption;
// File size in (mega/kilo) bytes.
@property (copy) NSString *contentSize;
// Actual bytes of the media object, for example the image file or video file.
@property (copy) NSString *contentUrl;
// The list of contributors for this scope.
@property (retain) NSArray *contributor; // of GTLPlusItemScope
// The date this scope was created.
@property (copy) NSString *dateCreated;
// The date this scope was last modified.
@property (copy) NSString *dateModified;
// The initial date this scope was published.
@property (copy) NSString *datePublished;
// The string describing the content of this scope.
// Remapped to 'descriptionProperty' to avoid NSObject's 'description'.
@property (copy) NSString *descriptionProperty;
// The duration of the item (movie, audio recording, event, etc.) in ISO 8601
// date format.
@property (copy) NSString *duration;
// A URL pointing to a player for a specific video. In general, this is the
// information in the src element of an embed tag and should not be the same as
// the content of the loc tag.
@property (copy) NSString *embedUrl;
// The end date and time of the event (in ISO 8601 date format).
@property (copy) NSString *endDate;
// Family name. In the U.S., the last name of an Person. This can be used along
// with givenName instead of the Name property.
@property (copy) NSString *familyName;
// Gender of the person.
@property (copy) NSString *gender;
// Geo coordinates.
@property (retain) GTLPlusItemScope *geo;
// Given name. In the U.S., the first name of a Person. This can be used along
// with familyName instead of the Name property.
@property (copy) NSString *givenName;
// The height of the media object.
@property (copy) NSString *height;
// The id for this item scope.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// A url to the image for this scope.
@property (copy) NSString *image;
// From http://schema.org/MusicRecording, which album a song is in.
@property (retain) GTLPlusItemScope *inAlbum;
// Identifies this resource as an itemScope.
@property (copy) NSString *kind;
// Latitude.
@property (retain) NSNumber *latitude; // doubleValue
// The location of the event or organization.
@property (retain) GTLPlusItemScope *location;
// Longitude.
@property (retain) NSNumber *longitude; // doubleValue
// The name of this scope.
@property (copy) NSString *name;
// Property of http://schema.org/TVEpisode indicating which series the episode
// belongs to.
@property (retain) GTLPlusItemScope *partOfTVSeries;
// The main performer or performers of the event—for example, a presenter,
// musician, or actor.
@property (retain) NSArray *performers; // of GTLPlusItemScope
// Player type required—for example, Flash or Silverlight.
@property (copy) NSString *playerType;
// Postal code.
@property (copy) NSString *postalCode;
// Post office box number.
@property (copy) NSString *postOfficeBoxNumber;
// Rating value.
@property (copy) NSString *ratingValue;
// Review rating.
@property (retain) NSArray *reviewRating; // of GTLPlusItemScope
// The start date and time of the event (in ISO 8601 date format).
@property (copy) NSString *startDate;
// Street address.
@property (copy) NSString *streetAddress;
// Comment text, review text, etc.
@property (copy) NSString *text;
// Thumbnail image for an image or video.
@property (retain) GTLPlusItemScope *thumbnail;
// A url to a thumbnail image for this scope.
@property (copy) NSString *thumbnailUrl;
// The exchange traded instrument associated with a Corporation object. The
// tickerSymbol is expressed as an exchange and an instrument name separated by
// a space character. For the exchange component of the tickerSymbol attribute,
// we reccommend using the controlled vocaulary of Market Identifier Codes (MIC)
// specified in ISO15022.
@property (copy) NSString *tickerSymbol;
// The item type.
@property (copy) NSString *type;
// A url for this scope.
@property (copy) NSString *url;
// The width of the media object.
@property (copy) NSString *width;
// Worst possible rating value.
@property (copy) NSString *worstRating;
@end

View File

@@ -0,0 +1,78 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusItemScope.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusItemScope (0 custom class methods, 55 custom properties)
#import "GTLPlusItemScope.h"
// ----------------------------------------------------------------------------
//
// GTLPlusItemScope
//
@implementation GTLPlusItemScope
@dynamic about, additionalName, address, addressCountry, addressLocality,
addressRegion, associatedMedia, attendeeCount, attendees, audio,
author, bestRating, birthDate, byArtist, caption, contentSize,
contentUrl, contributor, dateCreated, dateModified, datePublished,
descriptionProperty, duration, embedUrl, endDate, familyName, gender,
geo, givenName, height, identifier, image, inAlbum, kind, latitude,
location, longitude, name, partOfTVSeries, performers, playerType,
postalCode, postOfficeBoxNumber, ratingValue, reviewRating, startDate,
streetAddress, text, thumbnail, thumbnailUrl, tickerSymbol, type, url,
width, worstRating;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"associated_media", @"associatedMedia",
@"description", @"descriptionProperty",
@"id", @"identifier",
nil];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString class], @"additionalName",
[GTLPlusItemScope class], @"associated_media",
[GTLPlusItemScope class], @"attendees",
[GTLPlusItemScope class], @"author",
[GTLPlusItemScope class], @"contributor",
[GTLPlusItemScope class], @"performers",
[GTLPlusItemScope class], @"reviewRating",
nil];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#itemScope"];
}
@end

View File

@@ -0,0 +1,79 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusMoment.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusMoment (0 custom class methods, 6 custom properties)
// GTLPlusMomentVerb (0 custom class methods, 1 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusItemScope;
@class GTLPlusMomentVerb;
// ----------------------------------------------------------------------------
//
// GTLPlusMoment
//
@interface GTLPlusMoment : GTLObject
// Identifies this resource as a moment.
@property (copy) NSString *kind;
// The object generated by performing the action on the item
@property (retain) GTLPlusItemScope *result;
// Timestamp of the action (when it occured) in RFC3339 format.
@property (retain) GTLDateTime *startDate;
// The object on which the action was performed
@property (retain) GTLPlusItemScope *target;
// The schema.org activity type
@property (copy) NSString *type;
// The action the user performed
@property (retain) GTLPlusMomentVerb *verb;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusMomentVerb
//
@interface GTLPlusMomentVerb : GTLObject
// Url name of the verb
@property (copy) NSString *url;
@end

View File

@@ -0,0 +1,58 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusMoment.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusMoment (0 custom class methods, 6 custom properties)
// GTLPlusMomentVerb (0 custom class methods, 1 custom properties)
#import "GTLPlusMoment.h"
#import "GTLPlusItemScope.h"
// ----------------------------------------------------------------------------
//
// GTLPlusMoment
//
@implementation GTLPlusMoment
@dynamic kind, result, startDate, target, type, verb;
+ (void)load {
[self registerObjectClassForKind:@"plus#moment"];
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusMomentVerb
//
@implementation GTLPlusMomentVerb
@dynamic url;
@end

View File

@@ -0,0 +1,285 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusPerson.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusPerson (0 custom class methods, 21 custom properties)
// GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonImage (0 custom class methods, 1 custom properties)
// GTLPlusPersonName (0 custom class methods, 6 custom properties)
// GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties)
// GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties)
// GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusPersonEmailsItem;
@class GTLPlusPersonImage;
@class GTLPlusPersonName;
@class GTLPlusPersonOrganizationsItem;
@class GTLPlusPersonPlacesLivedItem;
@class GTLPlusPersonUrlsItem;
// ----------------------------------------------------------------------------
//
// GTLPlusPerson
//
@interface GTLPlusPerson : GTLObject
// A short biography for this person.
@property (copy) NSString *aboutMe;
// The person's date of birth, represented as YYYY-MM-DD.
@property (copy) NSString *birthday;
// The current location for this person.
@property (copy) NSString *currentLocation;
// The name of this person, suitable for display.
@property (copy) NSString *displayName;
// A list of email addresses for this person.
@property (retain) NSArray *emails; // of GTLPlusPersonEmailsItem
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The person's gender. Possible values are:
// - "male" - Male gender.
// - "female" - Female gender.
// - "other" - Other.
@property (copy) NSString *gender;
// If "true", indicates that the person has installed the app that is making the
// request and has chosen to expose this install state to the caller. A value of
// "false" indicates that the install state cannot be determined (it is either
// not installed or the person has chosen to keep this information private).
@property (retain) NSNumber *hasApp; // boolValue
// The ID of this person.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The representation of the person's profile photo.
@property (retain) GTLPlusPersonImage *image;
// Identifies this resource as a person. Value: "plus#person".
@property (copy) NSString *kind;
// The languages spoken by this person.
@property (retain) NSArray *languagesSpoken; // of NSString
// An object representation of the individual components of a person's name.
@property (retain) GTLPlusPersonName *name;
// The nickname of this person.
@property (copy) NSString *nickname;
// Type of person within Google+. Possible values are:
// - "person" - represents an actual person.
// - "page" - represents a page.
@property (copy) NSString *objectType;
// A list of current or past organizations with which this person is associated.
@property (retain) NSArray *organizations; // of GTLPlusPersonOrganizationsItem
// A list of places where this person has lived.
@property (retain) NSArray *placesLived; // of GTLPlusPersonPlacesLivedItem
// The person's relationship status. Possible values are:
// - "single" - Person is single.
// - "in_a_relationship" - Person is in a relationship.
// - "engaged" - Person is engaged.
// - "married" - Person is married.
// - "its_complicated" - The relationship is complicated.
// - "open_relationship" - Person is in an open relationship.
// - "widowed" - Person is widowed.
// - "in_domestic_partnership" - Person is in a domestic partnership.
// - "in_civil_union" - Person is in a civil union.
@property (copy) NSString *relationshipStatus;
// The brief description (tagline) of this person.
@property (copy) NSString *tagline;
// The URL of this person's profile.
@property (copy) NSString *url;
// A list of URLs for this person.
@property (retain) NSArray *urls; // of GTLPlusPersonUrlsItem
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonEmailsItem
//
@interface GTLPlusPersonEmailsItem : GTLObject
// If "true", indicates this email address is the person's primary one.
@property (retain) NSNumber *primary; // boolValue
// The type of address. Possible values are:
// - "home" - Home email address.
// - "work" - Work email address.
// - "other" - Other.
@property (copy) NSString *type;
// The email address.
@property (copy) NSString *value;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonImage
//
@interface GTLPlusPersonImage : GTLObject
// The URL of the person's profile photo. To re-size the image and crop it to a
// square, append the query string ?sz=x, where x is the dimension in pixels of
// each side.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonName
//
@interface GTLPlusPersonName : GTLObject
// The family name (last name) of this person.
@property (copy) NSString *familyName;
// The full name of this person, including middle names, suffixes, etc.
@property (copy) NSString *formatted;
// The given name (first name) of this person.
@property (copy) NSString *givenName;
// The honorific prefixes (such as "Dr." or "Mrs.") for this person.
@property (copy) NSString *honorificPrefix;
// The honorific suffixes (such as "Jr.") for this person.
@property (copy) NSString *honorificSuffix;
// The middle name of this person.
@property (copy) NSString *middleName;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonOrganizationsItem
//
@interface GTLPlusPersonOrganizationsItem : GTLObject
// The department within the organization.
@property (copy) NSString *department;
// A short description of the person's role in this organization.
// Remapped to 'descriptionProperty' to avoid NSObject's 'description'.
@property (copy) NSString *descriptionProperty;
// The date the person left this organization.
@property (copy) NSString *endDate;
// The location of this organization.
@property (copy) NSString *location;
// The name of the organization.
@property (copy) NSString *name;
// If "true", indicates this organization is the person's primary one (typically
// interpreted as current one).
@property (retain) NSNumber *primary; // boolValue
// The date the person joined this organization.
@property (copy) NSString *startDate;
// The person's job title or role within the organization.
@property (copy) NSString *title;
// The type of organization. Possible values are:
// - "work" - Work.
// - "school" - School.
@property (copy) NSString *type;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonPlacesLivedItem
//
@interface GTLPlusPersonPlacesLivedItem : GTLObject
// If "true", this place of residence is this person's primary residence.
@property (retain) NSNumber *primary; // boolValue
// A place where this person has lived. For example: "Seattle, WA", "Near
// Toronto".
@property (copy) NSString *value;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonUrlsItem
//
@interface GTLPlusPersonUrlsItem : GTLObject
// If "true", this URL is the person's primary URL.
@property (retain) NSNumber *primary; // boolValue
// The type of URL. Possible values are:
// - "home" - URL for home.
// - "work" - URL for work.
// - "blog" - URL for blog.
// - "profile" - URL for profile.
// - "other" - Other.
@property (copy) NSString *type;
// The URL value.
@property (copy) NSString *value;
@end

View File

@@ -0,0 +1,145 @@
/* Copyright (c) 2012 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.
*/
//
// GTLPlusPerson.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLPlusPerson (0 custom class methods, 21 custom properties)
// GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonImage (0 custom class methods, 1 custom properties)
// GTLPlusPersonName (0 custom class methods, 6 custom properties)
// GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties)
// GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties)
// GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties)
#import "GTLPlusPerson.h"
// ----------------------------------------------------------------------------
//
// GTLPlusPerson
//
@implementation GTLPlusPerson
@dynamic aboutMe, birthday, currentLocation, displayName, emails, ETag, gender,
hasApp, identifier, image, kind, languagesSpoken, name, nickname,
objectType, organizations, placesLived, relationshipStatus, tagline,
url, urls;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"etag", @"ETag",
@"id", @"identifier",
nil];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
[GTLPlusPersonEmailsItem class], @"emails",
[NSString class], @"languagesSpoken",
[GTLPlusPersonOrganizationsItem class], @"organizations",
[GTLPlusPersonPlacesLivedItem class], @"placesLived",
[GTLPlusPersonUrlsItem class], @"urls",
nil];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#person"];
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonEmailsItem
//
@implementation GTLPlusPersonEmailsItem
@dynamic primary, type, value;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonImage
//
@implementation GTLPlusPersonImage
@dynamic url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonName
//
@implementation GTLPlusPersonName
@dynamic familyName, formatted, givenName, honorificPrefix, honorificSuffix,
middleName;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonOrganizationsItem
//
@implementation GTLPlusPersonOrganizationsItem
@dynamic department, descriptionProperty, endDate, location, name, primary,
startDate, title, type;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"description"
forKey:@"descriptionProperty"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonPlacesLivedItem
//
@implementation GTLPlusPersonPlacesLivedItem
@dynamic primary, value;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonUrlsItem
//
@implementation GTLPlusPersonUrlsItem
@dynamic primary, type, value;
@end

View File

@@ -0,0 +1,90 @@
/* Copyright (c) 2012 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.
*/
//
// GTLQueryPlus.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLQueryPlus (2 custom class methods, 4 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLQuery.h"
#else
#import "GTLQuery.h"
#endif
@class GTLPlusMoment;
@interface GTLQueryPlus : GTLQuery
//
// Parameters valid on all methods.
//
// Selector specifying which fields to include in a partial response.
@property (copy) NSString *fields;
//
// Method-specific parameters; see the comments below for more information.
//
@property (copy) NSString *collection;
@property (assign) BOOL debug;
@property (copy) NSString *userId;
#pragma mark -
#pragma mark "moments" methods
// These create a GTLQueryPlus object.
// Method: plus.moments.insert
// Record a user activity (e.g Bill watched a video on Youtube)
// Required:
// userId: The ID of the user to get activities for. The special value "me"
// can be used to indicate the authenticated user.
// collection: The collection to which to write moments.
// kGTLPlusCollectionVault: The default collection for writing new moments.
// Optional:
// debug: Return the moment as written. Should be used only for debugging.
// Authorization scope(s):
// kGTLAuthScopePlusMomentsWrite
// Fetches a GTLPlusMoment.
+ (id)queryForMomentsInsertWithObject:(GTLPlusMoment *)object
userId:(NSString *)userId
collection:(NSString *)collection;
#pragma mark -
#pragma mark "people" methods
// These create a GTLQueryPlus object.
// Method: plus.people.get
// Get a person's profile.
// Required:
// userId: The ID of the person to get the profile for. The special value "me"
// can be used to indicate the authenticated user.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// kGTLAuthScopePlusUserinfoEmail
// Fetches a GTLPlusPerson.
+ (id)queryForPeopleGetWithUserId:(NSString *)userId;
@end

View File

@@ -0,0 +1,72 @@
/* Copyright (c) 2012 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.
*/
//
// GTLQueryPlus.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLQueryPlus (2 custom class methods, 4 custom properties)
#import "GTLQueryPlus.h"
#import "GTLPlusMoment.h"
#import "GTLPlusPerson.h"
@implementation GTLQueryPlus
@dynamic collection, debug, fields, userId;
#pragma mark -
#pragma mark "moments" methods
// These create a GTLQueryPlus object.
+ (id)queryForMomentsInsertWithObject:(GTLPlusMoment *)object
userId:(NSString *)userId
collection:(NSString *)collection {
if (object == nil) {
GTL_DEBUG_ASSERT(object != nil, @"%@ got a nil object", NSStringFromSelector(_cmd));
return nil;
}
NSString *methodName = @"plus.moments.insert";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.bodyObject = object;
query.userId = userId;
query.collection = collection;
query.expectedObjectClass = [GTLPlusMoment class];
return query;
}
#pragma mark -
#pragma mark "people" methods
// These create a GTLQueryPlus object.
+ (id)queryForPeopleGetWithUserId:(NSString *)userId {
NSString *methodName = @"plus.people.get";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.userId = userId;
query.expectedObjectClass = [GTLPlusPerson class];
return query;
}
@end

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2012 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.
*/
//
// GTLServicePlus.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLServicePlus (0 custom class methods, 0 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLService.h"
#else
#import "GTLService.h"
#endif
@interface GTLServicePlus : GTLService
// No new methods
// Clients should create a standard query with any of the class methods in
// GTLQueryPlus.h. The query can the be sent with GTLService's execute methods,
//
// - (GTLServiceTicket *)executeQuery:(GTLQuery *)query
// completionHandler:(void (^)(GTLServiceTicket *ticket,
// id object, NSError *error))handler;
// or
// - (GTLServiceTicket *)executeQuery:(GTLQuery *)query
// delegate:(id)delegate
// didFinishSelector:(SEL)finishedSelector;
//
// where finishedSelector has a signature of:
//
// - (void)serviceTicket:(GTLServiceTicket *)ticket
// finishedWithObject:(id)object
// error:(NSError *)error;
//
// The object passed to the completion handler or delegate method
// is a subclass of GTLObject, determined by the query method executed.
@end

View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2012 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.
*/
//
// GTLServicePlus.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1moments)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// http://developers.google.com/+/api/
// Classes:
// GTLServicePlus (0 custom class methods, 0 custom properties)
#import "GTLPlus.h"
@implementation GTLServicePlus
#if DEBUG
// Method compiled in debug builds just to check that all the needed support
// classes are present at link time.
+ (NSArray *)checkClasses {
NSArray *classes = [NSArray arrayWithObjects:
[GTLQueryPlus class],
[GTLPlusItemScope class],
[GTLPlusMoment class],
[GTLPlusPerson class],
nil];
return classes;
}
#endif // DEBUG
- (id)init {
self = [super init];
if (self) {
// Version from discovery.
self.apiVersion = @"v1moments";
// From discovery. Where to send JSON-RPC.
// Turn off prettyPrint for this service to save bandwidth (especially on
// mobile). The fetcher logging will pretty print.
self.rpcURL = [NSURL URLWithString:@"https://www.googleapis.com/rpc?prettyPrint=false"];
}
return self;
}
@end

View File

@@ -0,0 +1,132 @@
/* Copyright (c) 2011 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.
*/
//
// GTLQuery.h
//
#import "GTLObject.h"
#import "GTLUploadParameters.h"
@protocol GTLQueryProtocol <NSObject, NSCopying>
- (BOOL)isBatchQuery;
- (BOOL)shouldSkipAuthorization;
- (void)executionDidStop;
- (NSDictionary *)additionalHTTPHeaders;
- (GTLUploadParameters *)uploadParameters;
@end
@protocol GTLQueryCollectionProtocol
@optional
@property (retain) NSString *pageToken;
@property (retain) NSNumber *startIndex;
@end
@class GTLServiceTicket;
@interface GTLQuery : NSObject <GTLQueryProtocol> {
@private
NSString *methodName_;
NSMutableDictionary *json_;
GTLObject *bodyObject_;
NSMutableDictionary *childCache_;
NSString *requestID_;
GTLUploadParameters *uploadParameters_;
NSDictionary *urlQueryParameters_;
NSDictionary *additionalHTTPHeaders_;
Class expectedObjectClass_;
BOOL skipAuthorization_;
#if NS_BLOCKS_AVAILABLE
void (^completionBlock_)(GTLServiceTicket *ticket, id object, NSError *error);
#elif !__LP64__
// Placeholders: for 32-bit builds, keep the size of the object's ivar section
// the same with and without blocks
id completionPlaceholder_;
#endif
}
// The rpc method name.
@property (readonly) NSString *methodName;
// The JSON dictionary of all the parameters set on this query.
@property (retain) NSMutableDictionary *JSON;
// The object set to be uploaded with the query.
@property (retain) GTLObject *bodyObject;
// Each query must have a request ID string. The user may replace the
// default assigned request ID with a custom string, provided that if
// used in a batch query, all request IDs in the batch must be unique.
@property (copy) NSString *requestID;
// For queries which support file upload, the MIME type and file handle
// or data must be provided.
@property (copy) GTLUploadParameters *uploadParameters;
// Any url query parameters to add to the query (useful for debugging with some
// services).
@property (copy) NSDictionary *urlQueryParameters;
// Any additional HTTP headers for this query. Not valid when this query
// is added to a batch.
//
// These headers override the same keys from the service object's
// additionalHTTPHeaders.
@property (copy) NSDictionary *additionalHTTPHeaders;
// The GTLObject subclass expected for results (used if the result doesn't
// include a kind attribute).
@property (assign) Class expectedObjectClass;
// Clients may set this to YES to disallow authorization. Defaults to NO.
@property (assign) BOOL shouldSkipAuthorization;
#if NS_BLOCKS_AVAILABLE
// Clients may provide an optional callback block to be called immediately
// before the executeQuery: callback.
//
// The completionBlock property is particularly useful for queries executed
// in a batch.
//
// Errors passed to the completionBlock will have an "underlying" GTLErrorObject
// when the server returned an error for this specific query:
//
// GTLErrorObject *errorObj = [GTLErrorObject underlyingObjectForError:error];
// if (errorObj) {
// // the server returned this error for this specific query
// } else {
// // the batch execution failed
// }
@property (copy) void (^completionBlock)(GTLServiceTicket *ticket, id object, NSError *error);
#endif
// methodName is the RPC method name to use.
+ (id)queryWithMethodName:(NSString *)methodName;
// methodName is the RPC method name to use.
- (id)initWithMethodName:(NSString *)method;
// If you need to set a parameter that is not listed as a property for a
// query class, you can do so via this api. If you need to clear it after
// setting, pass nil for obj.
- (void)setCustomParameter:(id)obj forKey:(NSString *)key;
// Auto-generated request IDs
+ (NSString *)nextRequestID;
// Methods for subclasses to override.
+ (NSDictionary *)parameterNameMap;
+ (NSDictionary *)arrayPropertyToClassMap;
@end

View File

@@ -0,0 +1,267 @@
/* Copyright (c) 2011 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.
*/
//
// GTLQuery.m
//
#include <objc/runtime.h>
#import "GTLQuery.h"
#import "GTLRuntimeCommon.h"
#import "GTLUtilities.h"
@interface GTLQuery () <GTLRuntimeCommon>
@end
@implementation GTLQuery
// Implementation Note: bodyObject could be done as a dynamic property and map
// it to the key "resource". But we expose the object on the ServiceTicket
// for developers, and so sending it through the plumbing already in the
// parameters and outside of that gets into a grey area. For requests sent
// via this class, we don't need to touch the JSON, but for developers that
// have to use the lower level apis for something we'd need to know to add
// it to the JSON.
@synthesize methodName = methodName_,
JSON = json_,
bodyObject = bodyObject_,
requestID = requestID_,
uploadParameters = uploadParameters_,
urlQueryParameters = urlQueryParameters_,
additionalHTTPHeaders = additionalHTTPHeaders_,
expectedObjectClass = expectedObjectClass_,
shouldSkipAuthorization = skipAuthorization_;
#if NS_BLOCKS_AVAILABLE
@synthesize completionBlock = completionBlock_;
#endif
+ (id)queryWithMethodName:(NSString *)methodName {
return [[[self alloc] initWithMethodName:methodName] autorelease];
}
- (id)initWithMethodName:(NSString *)methodName {
self = [super init];
if (self) {
requestID_ = [[[self class] nextRequestID] retain];
methodName_ = [methodName copy];
if ([methodName_ length] == 0) {
[self release];
self = nil;
}
}
return self;
}
- (void)dealloc {
[methodName_ release];
[json_ release];
[bodyObject_ release];
[childCache_ release];
[requestID_ release];
[uploadParameters_ release];
[urlQueryParameters_ release];
[additionalHTTPHeaders_ release];
#if NS_BLOCKS_AVAILABLE
[completionBlock_ release];
#endif
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone {
GTLQuery *query =
[[[self class] allocWithZone:zone] initWithMethodName:self.methodName];
if ([json_ count] > 0) {
// Deep copy the parameters
CFPropertyListRef ref = CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
json_, kCFPropertyListMutableContainers);
query.JSON = [NSMakeCollectable(ref) autorelease];
}
query.bodyObject = self.bodyObject;
query.requestID = self.requestID;
query.uploadParameters = self.uploadParameters;
query.urlQueryParameters = self.urlQueryParameters;
query.additionalHTTPHeaders = self.additionalHTTPHeaders;
query.expectedObjectClass = self.expectedObjectClass;
query.shouldSkipAuthorization = self.shouldSkipAuthorization;
#if NS_BLOCKS_AVAILABLE
query.completionBlock = self.completionBlock;
#endif
return query;
}
- (NSString *)description {
NSArray *keys = [self.JSON allKeys];
NSArray *params = [keys sortedArrayUsingSelector:@selector(compare:)];
NSString *paramsSummary = @"";
if ([params count] > 0) {
paramsSummary = [NSString stringWithFormat:@" params:(%@)",
[params componentsJoinedByString:@","]];
}
keys = [self.urlQueryParameters allKeys];
NSArray *urlQParams = [keys sortedArrayUsingSelector:@selector(compare:)];
NSString *urlQParamsSummary = @"";
if ([urlQParams count] > 0) {
urlQParamsSummary = [NSString stringWithFormat:@" urlQParams:(%@)",
[urlQParams componentsJoinedByString:@","]];
}
GTLObject *bodyObj = self.bodyObject;
NSString *bodyObjSummary = @"";
if (bodyObj != nil) {
bodyObjSummary = [NSString stringWithFormat:@" bodyObject:%@", [bodyObj class]];
}
NSString *uploadStr = @"";
GTLUploadParameters *uploadParams = self.uploadParameters;
if (uploadParams) {
uploadStr = [NSString stringWithFormat:@" %@", uploadParams];
}
return [NSString stringWithFormat:@"%@ %p: {method:%@%@%@%@%@}",
[self class], self, self.methodName,
paramsSummary, urlQParamsSummary, bodyObjSummary, uploadStr];
}
- (void)setCustomParameter:(id)obj forKey:(NSString *)key {
[self setJSONValue:obj forKey:key];
}
- (BOOL)isBatchQuery {
return NO;
}
- (void)executionDidStop {
#if NS_BLOCKS_AVAILABLE
self.completionBlock = nil;
#endif
}
+ (NSString *)nextRequestID {
static unsigned long lastRequestID = 0;
NSString *result;
@synchronized([GTLQuery class]) {
++lastRequestID;
result = [NSString stringWithFormat:@"gtl_%lu",
(unsigned long) lastRequestID];
}
return result;
}
#pragma mark GTLRuntimeCommon Support
- (void)setJSONValue:(id)obj forKey:(NSString *)key {
NSMutableDictionary *dict = self.JSON;
if (dict == nil && obj != nil) {
dict = [NSMutableDictionary dictionaryWithCapacity:1];
self.JSON = dict;
}
[dict setValue:obj forKey:key];
}
- (id)JSONValueForKey:(NSString *)key {
id obj = [self.JSON objectForKey:key];
return obj;
}
// There is no property for childCache_ as there shouldn't be KVC/KVO
// support for it, it's an implementation detail.
- (void)setCacheChild:(id)obj forKey:(NSString *)key {
if (childCache_ == nil && obj != nil) {
childCache_ =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:obj, key, nil];
} else {
[childCache_ setValue:obj forKey:key];
}
}
- (id)cacheChildForKey:(NSString *)key {
id obj = [childCache_ objectForKey:key];
return obj;
}
#pragma mark Methods for Subclasses to Override
+ (NSDictionary *)parameterNameMap {
return nil;
}
+ (NSDictionary *)arrayPropertyToClassMap {
return nil;
}
#pragma mark Runtime Utilities
static NSMutableDictionary *gParameterNameMapCache = nil;
static NSMutableDictionary *gArrayPropertyToClassMapCache = nil;
+ (void)initialize {
// note that initialize is guaranteed by the runtime to be called in a
// thread-safe manner
if (gParameterNameMapCache == nil) {
gParameterNameMapCache = [GTLUtilities newStaticDictionary];
}
if (gArrayPropertyToClassMapCache == nil) {
gArrayPropertyToClassMapCache = [GTLUtilities newStaticDictionary];
}
}
+ (NSDictionary *)propertyToJSONKeyMapForClass:(Class<GTLRuntimeCommon>)aClass {
NSDictionary *resultMap =
[GTLUtilities mergedClassDictionaryForSelector:@selector(parameterNameMap)
startClass:aClass
ancestorClass:[GTLQuery class]
cache:gParameterNameMapCache];
return resultMap;
}
+ (NSDictionary *)arrayPropertyToClassMapForClass:(Class<GTLRuntimeCommon>)aClass {
NSDictionary *resultMap =
[GTLUtilities mergedClassDictionaryForSelector:@selector(arrayPropertyToClassMap)
startClass:aClass
ancestorClass:[GTLQuery class]
cache:gArrayPropertyToClassMapCache];
return resultMap;
}
#pragma mark Runtime Support
- (NSDictionary *)surrogates {
// Stub method just needed for RumtimeCommon, query doesn't use surrogates.
return nil;
}
+ (Class<GTLRuntimeCommon>)ancestorClass {
return [GTLQuery class];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
BOOL resolved = [GTLRuntimeCommon resolveInstanceMethod:sel onClass:self];
if (resolved)
return YES;
return [super resolveInstanceMethod:sel];
}
@end

View File

@@ -0,0 +1,57 @@
/* Copyright (c) 2011 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.
*/
//
// GTLRuntimeCommon.h
//
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
// This protocol and support class are an internal implementation detail so
// GTLObject and GTLQuery can share some code.
@protocol GTLRuntimeCommon <NSObject>
@required
// Get/Set properties
- (void)setJSONValue:(id)obj forKey:(NSString *)key;
- (id)JSONValueForKey:(NSString *)key;
// Child cache
- (void)setCacheChild:(id)obj forKey:(NSString *)key;
- (id)cacheChildForKey:(NSString *)key;
// Surrogate class mappings.
- (NSDictionary *)surrogates;
// Key map
+ (NSDictionary *)propertyToJSONKeyMapForClass:(Class<GTLRuntimeCommon>)aClass;
// Array item types
+ (NSDictionary *)arrayPropertyToClassMapForClass:(Class<GTLRuntimeCommon>)aClass;
// The parent class for dynamic support
+ (Class<GTLRuntimeCommon>)ancestorClass;
@end
@interface GTLRuntimeCommon : NSObject
// Wire things up.
+ (BOOL)resolveInstanceMethod:(SEL)sel onClass:(Class)onClass;
// Helpers
+ (id)objectFromJSON:(id)json
defaultClass:(Class)defaultClass
surrogates:(NSDictionary *)surrogates
isCacheable:(BOOL*)isCacheable;
+ (id)jsonFromAPIObject:(id)obj
expectedClass:(Class)expectedClass
isCacheable:(BOOL*)isCacheable;
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,592 @@
/* Copyright (c) 2011 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.
*/
//
// GTLService.h
//
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
#import "GTMHTTPFetcherService.h"
#import "GTLBatchQuery.h"
#import "GTLBatchResult.h"
#import "GTLDateTime.h"
#import "GTLErrorObject.h"
#import "GTLFramework.h"
#import "GTLJSONParser.h"
#import "GTLObject.h"
#import "GTLQuery.h"
#import "GTLUtilities.h"
#undef _EXTERN
#undef _INITIALIZE_AS
#ifdef GTLSERVICE_DEFINE_GLOBALS
#define _EXTERN
#define _INITIALIZE_AS(x) =x
#else
#define _EXTERN extern
#define _INITIALIZE_AS(x)
#endif
// Error domains
_EXTERN NSString* const kGTLServiceErrorDomain _INITIALIZE_AS(@"com.google.GTLServiceDomain");
enum {
kGTLErrorQueryResultMissing = -3000,
kGTLErrorWaitTimedOut = -3001
};
_EXTERN NSString* const kGTLJSONRPCErrorDomain _INITIALIZE_AS(@"com.google.GTLJSONRPCErrorDomain");
// We'll consistently store the server error string in the userInfo under
// this key
_EXTERN NSString* const kGTLServerErrorStringKey _INITIALIZE_AS(@"error");
_EXTERN Class const kGTLUseRegisteredClass _INITIALIZE_AS(nil);
_EXTERN NSUInteger const kGTLStandardUploadChunkSize _INITIALIZE_AS(NSUIntegerMax);
// When servers return us structured JSON errors, the NSError will
// contain a GTLErrorObject in the userInfo dictionary under the key
// kGTLStructuredErrorsKey
_EXTERN NSString* const kGTLStructuredErrorKey _INITIALIZE_AS(@"GTLStructuredError");
// When specifying an ETag for updating or deleting a single entry, use
// kGTLETagWildcard to tell the server to replace the current value
// unconditionally. Do not use this in entries in a batch feed.
_EXTERN NSString* const kGTLETagWildcard _INITIALIZE_AS(@"*");
// Notifications when parsing of a fetcher feed or entry begins or ends
_EXTERN NSString* const kGTLServiceTicketParsingStartedNotification _INITIALIZE_AS(@"kGTLServiceTicketParsingStartedNotification");
_EXTERN NSString* const kGTLServiceTicketParsingStoppedNotification _INITIALIZE_AS(@"kGTLServiceTicketParsingStoppedNotification");
@class GTLServiceTicket;
// Block types used for fetch callbacks
//
// These typedefs are not used in the header file method declarations
// since it's more useful when code sense expansions show the argument
// types rather than the typedefs
#if NS_BLOCKS_AVAILABLE
typedef void (^GTLServiceCompletionHandler)(GTLServiceTicket *ticket, id object, NSError *error);
typedef void (^GTLServiceUploadProgressBlock)(GTLServiceTicket *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength);
#else
typedef void *GTLServiceCompletionHandler;
typedef void *GTLServiceUploadProgressBlock;
#endif // NS_BLOCKS_AVAILABLE
#pragma mark -
//
// Service base class
//
@interface GTLService : NSObject {
@private
NSOperationQueue *parseQueue_;
NSString *userAgent_;
GTMHTTPFetcherService *fetcherService_;
NSString *userAgentAddition_;
NSMutableDictionary *serviceProperties_; // initial values for properties in future tickets
NSDictionary *surrogates_; // initial value for surrogates in future tickets
SEL uploadProgressSelector_; // optional
#if NS_BLOCKS_AVAILABLE
BOOL (^retryBlock_)(GTLServiceTicket *, BOOL, NSError *);
void (^uploadProgressBlock_)(GTLServiceTicket *ticket,
unsigned long long numberOfBytesRead,
unsigned long long dataLength);
#elif !__LP64__
// Placeholders: for 32-bit builds, keep the size of the object's ivar section
// the same with and without blocks
id retryPlaceholder_;
id uploadProgressPlaceholder_;
#endif
NSUInteger uploadChunkSize_; // zero when uploading via multi-part MIME http body
BOOL isRetryEnabled_; // user allows auto-retries
SEL retrySelector_; // optional; set with setServiceRetrySelector
NSTimeInterval maxRetryInterval_; // default to 600. seconds
BOOL shouldFetchNextPages_;
NSString *apiKey_;
BOOL isRESTDataWrapperRequired_;
NSString *apiVersion_;
NSURL *rpcURL_;
NSURL *rpcUploadURL_;
NSDictionary *urlQueryParameters_;
NSDictionary *additionalHTTPHeaders_;
}
#pragma mark Query Execution
// The finishedSelector has a signature matching:
//
// - (void)serviceTicket:(GTLServiceTicket *)ticket
// finishedWithObject:(GTLObject *)object
// error:(NSError *)error
//
// If an error occurs, the error parameter will be non-nil. Otherwise,
// the object parameter will point to a GTLObject, if any was returned by
// the fetch. (Delete fetches return no object, so the second parameter will
// be nil.)
//
// If the query object is a GTLBatchQuery, the object passed to the callback
// will be a GTLBatchResult
- (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
#if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
#endif
// Automatic page fetches
//
// Tickets can optionally do a sequence of fetches for queries where
// repeated requests with nextPageToken or nextStartIndex values is required to
// retrieve items of all pages of the response collection. The client's
// callback is invoked only when all items have been retrieved, or an error has
// occurred. During the fetch, the items accumulated so far are available from
// the ticket.
//
// Note that the final object may be a combination of multiple page responses
// so it may not be the same as if all results had been returned in a single
// page. Some fields of the response such as total item counts may reflect only
// the final page's values.
//
// Automatic page fetches will return an error if more than 25 page fetches are
// required. For debug builds, this will log a warning to the console when more
// than 2 page fetches occur, as a reminder that the query's maxResults
// parameter should probably be increased to specify more items returned per
// page.
//
// Default value is NO.
@property (nonatomic, assign) BOOL shouldFetchNextPages;
// Retrying; see comments on retry support at the top of GTMHTTPFetcher.
//
// Default value is NO.
@property (nonatomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
// Some services require a developer key for quotas and limits. Setting this
// will include it on all request sent to this service via a GTLQuery class.
@property (nonatomic, copy) NSString *APIKey;
// An authorizer adds user authentication headers to the request as needed.
@property (nonatomic, retain) id <GTMFetcherAuthorizationProtocol> authorizer;
// Retry selector is optional for retries.
//
// If present, it should have the signature:
// -(BOOL)ticket:(GTLServiceTicket *)ticket willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
// and return YES to cause a retry. Note that unlike the GTMHTTPFetcher retry
// selector, this selector's first argument is a ticket, not a fetcher.
@property (nonatomic, assign) SEL retrySelector;
#if NS_BLOCKS_AVAILABLE
@property (copy) BOOL (^retryBlock)(GTLServiceTicket *ticket, BOOL suggestedWillRetry, NSError *error);
#endif
@property (nonatomic, assign) NSTimeInterval maxRetryInterval;
//
// Fetches may be done using RPC or REST APIs, without creating
// a GTLQuery object
//
#pragma mark RPC Fetch Methods
//
// These methods may be used for RPC fetches without creating a GTLQuery object
//
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters
objectClass:(Class)objectClass
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters
insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
#if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters
objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters
insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
#endif
#pragma mark REST Fetch Methods
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
objectClass:(Class)objectClass
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchPublicObjectWithURL:(NSURL *)objectURL
objectClass:(Class)objectClass
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
- (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL
ETag:(NSString *)etagOrNil
delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector;
#if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
- (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
- (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
- (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL
ETag:(NSString *)etagOrNil
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler;
#endif
#pragma mark User Properties
// Properties and userData are supported for client convenience.
//
// Property keys beginning with _ are reserved by the library.
//
// The service properties dictionary is copied to become the initial property
// dictionary for each ticket.
- (void)setServiceProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property
- (id)servicePropertyForKey:(NSString *)key;
@property (nonatomic, copy) NSDictionary *serviceProperties;
// The service userData becomes the initial value for each future ticket's
// userData.
@property (nonatomic, retain) id serviceUserData;
#pragma mark Request Settings
// Set the surrogates to be used for future tickets. Surrogates are subclasses
// to be used instead of standard classes when creating objects from the JSON.
// For example, this code will make the framework generate objects
// using MyCalendarItemSubclass instead of GTLItemCalendar and
// MyCalendarEventSubclass instead of GTLItemCalendarEvent.
//
// NSDictionary *surrogates = [NSDictionary dictionaryWithObjectsAndKeys:
// [MyCalendarEntrySubclass class], [GTLItemCalendar class],
// [MyCalendarEventSubclass class], [GTLItemCalendarEvent class],
// nil];
// [calendarService setServiceSurrogates:surrogates];
//
@property (nonatomic, retain) NSDictionary *surrogates;
// On iOS 4 and later, the fetch may optionally continue in the background
// until finished or stopped by OS expiration.
//
// The default value is NO.
//
// For Mac OS X, background fetches are always supported, and this property
// is ignored.
@property (nonatomic, assign) BOOL shouldFetchInBackground;
// Run loop modes are used for scheduling NSURLConnections.
//
// The default value, nil, schedules connections using the current run
// loop mode. To use the service during a modal dialog, be sure to specify
// NSModalPanelRunLoopMode as one of the modes.
@property (nonatomic, retain) NSArray *runLoopModes;
// Applications needing an additional identifier in the server logs may specify
// one.
@property (nonatomic, copy) NSString *userAgentAddition;
// Applications have a default user-agent based on the application signature
// in the Info.plist settings. Most applications should not explicitly set
// this property.
@property (nonatomic, copy) NSString *userAgent;
// The request user agent includes the library and OS version appended to the
// base userAgent, along with the optional addition string.
@property (nonatomic, readonly) NSString *requestUserAgent;
// Applications may call requestForURL:httpMethod to get a request with the
// proper user-agent and ETag headers
//
// For http method, pass nil (for default GET method), POST, PUT, or DELETE
- (NSMutableURLRequest *)requestForURL:(NSURL *)url
ETag:(NSString *)etagOrNil
httpMethod:(NSString *)httpMethodOrNil;
// objectRequestForURL returns an NSMutableURLRequest for a JSON GTL object
//
// The object is the object being sent to the server, or nil;
// the http method may be nil for GET, or POST, PUT, DELETE
- (NSMutableURLRequest *)objectRequestForURL:(NSURL *)url
object:(GTLObject *)object
ETag:(NSString *)etag
httpMethod:(NSString *)httpMethod
isREST:(BOOL)isREST
additionalHeaders:(NSDictionary *)additionalHeaders
ticket:(GTLServiceTicket *)ticket;
// The queue used for parsing JSON responses (previously this property
// was called operationQueue)
@property (nonatomic, retain) NSOperationQueue *parseQueue;
// The fetcher service object issues the GTMHTTPFetcher instances
// for this API service
@property (nonatomic, retain) GTMHTTPFetcherService *fetcherService;
// Default storage for cookies is in the service object's fetchHistory.
//
// Apps that want to share cookies between all standalone fetchers and the
// service object may specify static application-wide cookie storage,
// kGTMHTTPFetcherCookieStorageMethodStatic.
@property (nonatomic, assign) NSInteger cookieStorageMethod;
// When sending REST style queries, should the payload be wrapped in a "data"
// element, and will the reply be wrapped in an "data" element.
@property (nonatomic, assign) BOOL isRESTDataWrapperRequired;
// Any url query parameters to add to urls (useful for debugging with some
// services).
@property (copy) NSDictionary *urlQueryParameters;
// Any extra http headers to set on requests for GTLObjects.
@property (copy) NSDictionary *additionalHTTPHeaders;
// The service API version.
@property (nonatomic, copy) NSString *apiVersion;
// The URL for sending RPC requests for this service.
@property (nonatomic, retain) NSURL *rpcURL;
// The URL for sending RPC requests which initiate file upload.
@property (nonatomic, retain) NSURL *rpcUploadURL;
// Set a non-zero value to enable uploading via chunked fetches
// (resumable uploads); typically this defaults to kGTLStandardUploadChunkSize
// for service subclasses that support chunked uploads
@property (nonatomic, assign) NSUInteger serviceUploadChunkSize;
// Service subclasses may specify their own default chunk size
+ (NSUInteger)defaultServiceUploadChunkSize;
// The service uploadProgressSelector becomes the initial value for each future
// ticket's uploadProgressSelector.
//
// The optional uploadProgressSelector will be called in the delegate as bytes
// are uploaded to the server. It should have a signature matching
//
// - (void)ticket:(GTLServiceTicket *)ticket
// hasDeliveredByteCount:(unsigned long long)numberOfBytesRead
// ofTotalByteCount:(unsigned long long)dataLength;
@property (nonatomic, assign) SEL uploadProgressSelector;
#if NS_BLOCKS_AVAILABLE
@property (copy) void (^uploadProgressBlock)(GTLServiceTicket *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength);
#endif
// Wait synchronously for fetch to complete (strongly discouraged)
//
// This just runs the current event loop until the fetch completes
// or the timout limit is reached. This may discard unexpected events
// that occur while spinning, so it's really not appropriate for use
// in serious applications.
//
// Returns true if an object was successfully fetched. If the wait
// timed out, returns false and the returned error is nil.
//
// The returned object or error, if any, will be already autoreleased
//
// This routine will likely be removed in some future releases of the library.
- (BOOL)waitForTicket:(GTLServiceTicket *)ticket
timeout:(NSTimeInterval)timeoutInSeconds
fetchedObject:(GTLObject **)outObjectOrNil
error:(NSError **)outErrorOrNil;
@end
#pragma mark -
//
// Ticket base class
//
@interface GTLServiceTicket : NSObject {
GTLService *service_;
NSMutableDictionary *ticketProperties_;
NSDictionary *surrogates_;
GTMHTTPFetcher *objectFetcher_;
SEL uploadProgressSelector_;
BOOL shouldFetchNextPages_;
BOOL isRetryEnabled_;
SEL retrySelector_;
NSTimeInterval maxRetryInterval_;
#if NS_BLOCKS_AVAILABLE
BOOL (^retryBlock_)(GTLServiceTicket *, BOOL, NSError *);
void (^uploadProgressBlock_)(GTLServiceTicket *ticket,
unsigned long long numberOfBytesRead,
unsigned long long dataLength);
#elif !__LP64__
// Placeholders: for 32-bit builds, keep the size of the object's ivar section
// the same with and without blocks
id retryPlaceholder_;
id uploadProgressPlaceholder_;
#endif
GTLObject *postedObject_;
GTLObject *fetchedObject_;
id<GTLQueryProtocol> executingQuery_;
id<GTLQueryProtocol> originalQuery_;
NSError *fetchError_;
BOOL hasCalledCallback_;
NSUInteger pagesFetchedCounter_;
NSString *apiKey_;
BOOL isREST_;
NSOperation *parseOperation_;
}
+ (id)ticketForService:(GTLService *)service;
- (id)initWithService:(GTLService *)service;
- (id)service;
#pragma mark Execution Control
// if cancelTicket is called, the fetch is stopped if it is in progress,
// the callbacks will not be called, and the ticket will no longer be useful
// (though the client must still release the ticket if it retained the ticket)
- (void)cancelTicket;
// chunked upload tickets may be paused
- (void)pauseUpload;
- (void)resumeUpload;
- (BOOL)isUploadPaused;
@property (nonatomic, retain) GTMHTTPFetcher *objectFetcher;
@property (nonatomic, assign) SEL uploadProgressSelector;
// Services which do not require an user authorization may require a developer
// API key for quota management
@property (nonatomic, copy) NSString *APIKey;
#pragma mark User Properties
// Properties and userData are supported for client convenience.
//
// Property keys beginning with _ are reserved by the library.
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property
- (id)propertyForKey:(NSString *)key;
@property (nonatomic, copy) NSDictionary *properties;
@property (nonatomic, retain) id userData;
#pragma mark Payload
@property (nonatomic, retain) GTLObject *postedObject;
@property (nonatomic, retain) GTLObject *fetchedObject;
@property (nonatomic, retain) id<GTLQueryProtocol> executingQuery; // Query currently being fetched by this ticket
@property (nonatomic, retain) id<GTLQueryProtocol> originalQuery; // Query used to create this ticket
- (GTLQuery *)queryForRequestID:(NSString *)requestID; // Returns the query from within the batch with the given id.
@property (nonatomic, retain) NSDictionary *surrogates;
#pragma mark Retry
@property (nonatomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
@property (nonatomic, assign) SEL retrySelector;
#if NS_BLOCKS_AVAILABLE
@property (copy) BOOL (^retryBlock)(GTLServiceTicket *ticket, BOOL suggestedWillRetry, NSError *error);
#endif
@property (nonatomic, assign) NSTimeInterval maxRetryInterval;
#pragma mark Status
@property (nonatomic, readonly) NSInteger statusCode; // server status from object fetch
@property (nonatomic, retain) NSError *fetchError;
@property (nonatomic, assign) BOOL hasCalledCallback;
#pragma mark Pagination
@property (nonatomic, assign) BOOL shouldFetchNextPages;
@property (nonatomic, assign) NSUInteger pagesFetchedCounter;
#pragma mark Upload
#if NS_BLOCKS_AVAILABLE
@property (copy) void (^uploadProgressBlock)(GTLServiceTicket *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength);
#endif
@end
// Category to provide opaque access to tickets stored in fetcher properties
@interface GTMHTTPFetcher (GTLServiceTicketAdditions)
- (id)ticket;
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
//
// Makes the value of GTL_TARGET_NAMESPACE a prefix for all GTL
// library class names
//
//
// To avoid global namespace issues, define GTL_TARGET_NAMESPACE to a short
// string in your target if you are using the GTL library in a shared-code
// environment like a plug-in.
//
// For example: -DGTL_TARGET_NAMESPACE=MyPlugin
//
//
// com.google.GTLFramework v. 2.0 (29 classes) 2011-10-25 19:25:36 -0700
//
#if defined(__OBJC__) && defined(GTL_TARGET_NAMESPACE)
#define _GTL_NS_SYMBOL_INNER(ns, symbol) ns ## _ ## symbol
#define _GTL_NS_SYMBOL_MIDDLE(ns, symbol) _GTL_NS_SYMBOL_INNER(ns, symbol)
#define _GTL_NS_SYMBOL(symbol) _GTL_NS_SYMBOL_MIDDLE(GTL_TARGET_NAMESPACE, symbol)
#define _GTL_NS_STRING_INNER(ns) #ns
#define _GTL_NS_STRING_MIDDLE(ns) _GTL_NS_STRING_INNER(ns)
#define GTL_TARGET_NAMESPACE_STRING _GTL_NS_STRING_MIDDLE(GTL_TARGET_NAMESPACE)
#define GTLBatchQuery _GTL_NS_SYMBOL(GTLBatchQuery)
#define GTLBatchResult _GTL_NS_SYMBOL(GTLBatchResult)
#define GTLCollectionObject _GTL_NS_SYMBOL(GTLCollectionObject)
#define GTLDateTime _GTL_NS_SYMBOL(GTLDateTime)
#define GTLErrorObject _GTL_NS_SYMBOL(GTLErrorObject)
#define GTLErrorObjectData _GTL_NS_SYMBOL(GTLErrorObjectData)
#define GTLJSONParser _GTL_NS_SYMBOL(GTLJSONParser)
#define GTLObject _GTL_NS_SYMBOL(GTLObject)
#define GTLQuery _GTL_NS_SYMBOL(GTLQuery)
#define GTLRuntimeCommon _GTL_NS_SYMBOL(GTLRuntimeCommon)
#define GTLService _GTL_NS_SYMBOL(GTLService)
#define GTLServiceTicket _GTL_NS_SYMBOL(GTLServiceTicket)
#define GTLUploadParameters _GTL_NS_SYMBOL(GTLUploadParameters)
#define GTLUtilities _GTL_NS_SYMBOL(GTLUtilities)
#define GTMCachedURLResponse _GTL_NS_SYMBOL(GTMCachedURLResponse)
#define GTMCookieStorage _GTL_NS_SYMBOL(GTMCookieStorage)
#define GTMGatherInputStream _GTL_NS_SYMBOL(GTMGatherInputStream)
#define GTMHTTPFetcher _GTL_NS_SYMBOL(GTMHTTPFetcher)
#define GTMHTTPFetcherService _GTL_NS_SYMBOL(GTMHTTPFetcherService)
#define GTMHTTPFetchHistory _GTL_NS_SYMBOL(GTMHTTPFetchHistory)
#define GTMHTTPUploadFetcher _GTL_NS_SYMBOL(GTMHTTPUploadFetcher)
#define GTMMIMEDocument _GTL_NS_SYMBOL(GTMMIMEDocument)
#define GTMMIMEPart _GTL_NS_SYMBOL(GTMMIMEPart)
#define GTMOAuth2Authentication _GTL_NS_SYMBOL(GTMOAuth2Authentication)
#define GTMOAuth2AuthorizationArgs _GTL_NS_SYMBOL(GTMOAuth2AuthorizationArgs)
#define GTMOAuth2SignIn _GTL_NS_SYMBOL(GTMOAuth2SignIn)
#define GTMOAuth2WindowController _GTL_NS_SYMBOL(GTMOAuth2WindowController)
#define GTMReadMonitorInputStream _GTL_NS_SYMBOL(GTMReadMonitorInputStream)
#define GTMURLCache _GTL_NS_SYMBOL(GTMURLCache)
#endif

View File

@@ -0,0 +1,57 @@
/* Copyright (c) 2011 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.
*/
//
// GTLUploadParameters.h
//
#import <Foundation/Foundation.h>
#import "GTLDefines.h"
@interface GTLUploadParameters : NSObject <NSCopying> {
@private
NSString *MIMEType_;
NSData *data_;
NSFileHandle *fileHandle_;
NSURL *uploadLocationURL_;
NSString *slug_;
BOOL shouldSendUploadOnly_;
}
// Uploading requires MIME type and one of
// - data to be uploaded
// - file handle for uploading
@property (copy) NSString *MIMEType;
@property (retain) NSData *data;
@property (retain) NSFileHandle *fileHandle;
// Resuming an in-progress upload is done with the upload location URL,
// and requires a file handle for uploading
@property (retain) NSURL *uploadLocationURL;
// Some services need a slug (filename) header
@property (copy) NSString *slug;
// Uploads may be done without a JSON body in the initial request
@property (assign) BOOL shouldSendUploadOnly;
+ (GTLUploadParameters *)uploadParametersWithData:(NSData *)data
MIMEType:(NSString *)mimeType;
+ (GTLUploadParameters *)uploadParametersWithFileHandle:(NSFileHandle *)fileHandle
MIMEType:(NSString *)mimeType;
@end

View File

@@ -0,0 +1,107 @@
/* Copyright (c) 2011 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.
*/
//
// GTLObject.m
//
#include <objc/runtime.h>
#import "GTLUploadParameters.h"
@implementation GTLUploadParameters
@synthesize MIMEType = MIMEType_,
data = data_,
fileHandle = fileHandle_,
uploadLocationURL = uploadLocationURL_,
slug = slug_,
shouldSendUploadOnly = shouldSendUploadOnly_;
+ (GTLUploadParameters *)uploadParametersWithData:(NSData *)data
MIMEType:(NSString *)mimeType {
GTLUploadParameters *params = [[[GTLUploadParameters alloc] init] autorelease];
params.data = data;
params.MIMEType = mimeType;
return params;
}
+ (GTLUploadParameters *)uploadParametersWithFileHandle:(NSFileHandle *)fileHandle
MIMEType:(NSString *)mimeType {
GTLUploadParameters *params = [[[GTLUploadParameters alloc] init] autorelease];
params.fileHandle = fileHandle;
params.MIMEType = mimeType;
return params;
}
- (id)copyWithZone:(NSZone *)zone {
GTLUploadParameters *newParams = [[[self class] allocWithZone:zone] init];
newParams.MIMEType = self.MIMEType;
newParams.data = self.data;
newParams.fileHandle = self.fileHandle;
newParams.uploadLocationURL = self.uploadLocationURL;
newParams.slug = self.slug;
newParams.shouldSendUploadOnly = self.shouldSendUploadOnly;
return newParams;
}
- (void)dealloc {
[MIMEType_ release];
[data_ release];
[fileHandle_ release];
[uploadLocationURL_ release];
[slug_ release];
[super dealloc];
}
- (NSString *)description {
NSMutableArray *array = [NSMutableArray array];
NSString *str = [NSString stringWithFormat:@"MIMEType:%@", MIMEType_];
[array addObject:str];
if (data_) {
str = [NSString stringWithFormat:@"data:%llu bytes",
(unsigned long long)[data_ length]];
[array addObject:str];
}
if (fileHandle_) {
str = [NSString stringWithFormat:@"fileHandle:%@", fileHandle_];
[array addObject:str];
}
if (uploadLocationURL_) {
str = [NSString stringWithFormat:@"uploadLocation:%@",
[uploadLocationURL_ absoluteString]];
[array addObject:str];
}
if (slug_) {
str = [NSString stringWithFormat:@"slug:%@", slug_];
[array addObject:str];
}
if (shouldSendUploadOnly_) {
[array addObject:@"shouldSendUploadOnly"];
}
NSString *descStr = [array componentsJoinedByString:@", "];
str = [NSString stringWithFormat:@"%@ %p: {%@}",
[self class], self, descStr];
return str;
}
@end

View File

@@ -0,0 +1,105 @@
/* Copyright (c) 2011 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>
#ifndef SKIP_GTL_DEFINES
#import "GTLDefines.h"
#endif
// helper functions for implementing isEqual:
BOOL GTL_AreEqualOrBothNil(id obj1, id obj2);
BOOL GTL_AreBoolsEqual(BOOL b1, BOOL b2);
// Helper to ensure a number is a number.
//
// The GoogleAPI servers will send numbers >53 bits as strings to avoid
// bugs in some JavaScript implementations. Work around this by catching
// the string and turning it back into a number.
NSNumber *GTL_EnsureNSNumber(NSNumber *num);
@interface GTLUtilities : NSObject
//
// String encoding
//
// URL encoding, different for parts of URLs and parts of URL parameters
//
// +stringByURLEncodingString just makes a string legal for a URL
//
// +stringByURLEncodingForURI also encodes some characters that are legal in
// URLs but should not be used in URIs,
// per http://bitworking.org/projects/atom/rfc5023.html#rfc.section.9.7
//
// +stringByURLEncodingStringParameter is like +stringByURLEncodingForURI but
// replaces space characters with + characters rather than percent-escaping them
//
+ (NSString *)stringByURLEncodingString:(NSString *)str;
+ (NSString *)stringByURLEncodingForURI:(NSString *)str;
+ (NSString *)stringByURLEncodingStringParameter:(NSString *)str;
// Percent-encoded UTF-8
+ (NSString *)stringByPercentEncodingUTF8ForString:(NSString *)str;
// Key-value coding searches in an array
//
// Utilities to get from an array objects having a known value (or nil)
// at a keyPath
+ (NSArray *)objectsFromArray:(NSArray *)sourceArray
withValue:(id)desiredValue
forKeyPath:(NSString *)keyPath;
+ (id)firstObjectFromArray:(NSArray *)sourceArray
withValue:(id)desiredValue
forKeyPath:(NSString *)keyPath;
//
// Version helpers
//
+ (NSComparisonResult)compareVersion:(NSString *)ver1 toVersion:(NSString *)ver2;
//
// URL builder
//
// If there are already query parameters on urlString, the new ones are simple
// appended after them.
+ (NSURL *)URLWithString:(NSString *)urlString
queryParameters:(NSDictionary *)queryParameters;
// Allocate a global dictionary
+ (NSMutableDictionary *)newStaticDictionary;
// Walk up the class tree merging dictionaries and return the result.
+ (NSDictionary *)mergedClassDictionaryForSelector:(SEL)selector
startClass:(Class)startClass
ancestorClass:(Class)ancestorClass
cache:(NSMutableDictionary *)cache;
//
// MIME Types
//
// Utility routine to convert a file path to the file's MIME type using
// Mac OS X's UTI database
#if !GTL_FOUNDATION_ONLY
+ (NSString *)MIMETypeForFileAtPath:(NSString *)path
defaultMIMEType:(NSString *)defaultType;
#endif
@end

View File

@@ -0,0 +1,376 @@
/* Copyright (c) 2011 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 "GTLUtilities.h"
#include <objc/runtime.h>
@implementation GTLUtilities
#pragma mark String encoding
// URL Encoding
+ (NSString *)stringByURLEncodingString:(NSString *)str {
NSString *result = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return result;
}
// NSURL's stringByAddingPercentEscapesUsingEncoding: does not escape
// some characters that should be escaped in URL parameters, like / and ?;
// we'll use CFURL to force the encoding of those
//
// Reference: http://www.ietf.org/rfc/rfc3986.txt
const CFStringRef kCharsToForceEscape = CFSTR("!*'();:@&=+$,/?%#[]");
+ (NSString *)stringByURLEncodingForURI:(NSString *)str {
NSString *resultStr = str;
CFStringRef originalString = (CFStringRef) str;
CFStringRef leaveUnescaped = NULL;
CFStringRef escapedStr;
escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
originalString,
leaveUnescaped,
kCharsToForceEscape,
kCFStringEncodingUTF8);
if (escapedStr) {
resultStr = [(id)CFMakeCollectable(escapedStr) autorelease];
}
return resultStr;
}
+ (NSString *)stringByURLEncodingStringParameter:(NSString *)str {
// For parameters, we'll explicitly leave spaces unescaped now, and replace
// them with +'s
NSString *resultStr = str;
CFStringRef originalString = (CFStringRef) str;
CFStringRef leaveUnescaped = CFSTR(" ");
CFStringRef escapedStr;
escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
originalString,
leaveUnescaped,
kCharsToForceEscape,
kCFStringEncodingUTF8);
if (escapedStr) {
NSMutableString *mutableStr = [NSMutableString stringWithString:(NSString *)escapedStr];
CFRelease(escapedStr);
// replace spaces with plusses
[mutableStr replaceOccurrencesOfString:@" "
withString:@"+"
options:0
range:NSMakeRange(0, [mutableStr length])];
resultStr = mutableStr;
}
return resultStr;
}
+ (NSString *)stringByPercentEncodingUTF8ForString:(NSString *)inputStr {
// Encode per http://bitworking.org/projects/atom/rfc5023.html#rfc.section.9.7
//
// This is used for encoding upload slug headers
//
// Step through the string as UTF-8, and replace characters outside 20..7E
// (and the percent symbol itself, 25) with percent-encodings
//
// We avoid creating an encoding string unless we encounter some characters
// that require it
const char* utf8 = [inputStr UTF8String];
if (utf8 == NULL) {
return nil;
}
NSMutableString *encoded = nil;
for (unsigned int idx = 0; utf8[idx] != '\0'; idx++) {
unsigned char currChar = utf8[idx];
if (currChar < 0x20 || currChar == 0x25 || currChar > 0x7E) {
if (encoded == nil) {
// Start encoding and catch up on the character skipped so far
encoded = [[[NSMutableString alloc] initWithBytes:utf8
length:idx
encoding:NSUTF8StringEncoding] autorelease];
}
// append this byte as a % and then uppercase hex
[encoded appendFormat:@"%%%02X", currChar];
} else {
// This character does not need encoding
//
// Encoded is nil here unless we've encountered a previous character
// that needed encoding
[encoded appendFormat:@"%c", currChar];
}
}
if (encoded) {
return encoded;
}
return inputStr;
}
#pragma mark Key-Value Coding Searches in an Array
+ (NSArray *)objectsFromArray:(NSArray *)sourceArray
withValue:(id)desiredValue
forKeyPath:(NSString *)keyPath {
// Step through all entries, get the value from
// the key path, and see if it's equal to the
// desired value
NSMutableArray *results = [NSMutableArray array];
for(id obj in sourceArray) {
id val = [obj valueForKeyPath:keyPath];
if (GTL_AreEqualOrBothNil(val, desiredValue)) {
// found a match; add it to the results array
[results addObject:obj];
}
}
return results;
}
+ (id)firstObjectFromArray:(NSArray *)sourceArray
withValue:(id)desiredValue
forKeyPath:(NSString *)keyPath {
for (id obj in sourceArray) {
id val = [obj valueForKeyPath:keyPath];
if (GTL_AreEqualOrBothNil(val, desiredValue)) {
// found a match; return it
return obj;
}
}
return nil;
}
#pragma mark Version helpers
// compareVersion compares two strings in 1.2.3.4 format
// missing fields are interpreted as zeros, so 1.2 = 1.2.0.0
+ (NSComparisonResult)compareVersion:(NSString *)ver1 toVersion:(NSString *)ver2 {
static NSCharacterSet* dotSet = nil;
if (dotSet == nil) {
dotSet = [[NSCharacterSet characterSetWithCharactersInString:@"."] retain];
}
if (ver1 == nil) ver1 = @"";
if (ver2 == nil) ver2 = @"";
NSScanner* scanner1 = [NSScanner scannerWithString:ver1];
NSScanner* scanner2 = [NSScanner scannerWithString:ver2];
[scanner1 setCharactersToBeSkipped:dotSet];
[scanner2 setCharactersToBeSkipped:dotSet];
int partA1 = 0, partA2 = 0, partB1 = 0, partB2 = 0;
int partC1 = 0, partC2 = 0, partD1 = 0, partD2 = 0;
if ([scanner1 scanInt:&partA1] && [scanner1 scanInt:&partB1]
&& [scanner1 scanInt:&partC1] && [scanner1 scanInt:&partD1]) {
}
if ([scanner2 scanInt:&partA2] && [scanner2 scanInt:&partB2]
&& [scanner2 scanInt:&partC2] && [scanner2 scanInt:&partD2]) {
}
if (partA1 != partA2) return ((partA1 < partA2) ? NSOrderedAscending : NSOrderedDescending);
if (partB1 != partB2) return ((partB1 < partB2) ? NSOrderedAscending : NSOrderedDescending);
if (partC1 != partC2) return ((partC1 < partC2) ? NSOrderedAscending : NSOrderedDescending);
if (partD1 != partD2) return ((partD1 < partD2) ? NSOrderedAscending : NSOrderedDescending);
return NSOrderedSame;
}
#pragma mark URL builder
+ (NSURL *)URLWithString:(NSString *)urlString
queryParameters:(NSDictionary *)queryParameters {
if ([urlString length] == 0) return nil;
NSString *fullURLString;
if ([queryParameters count] > 0) {
NSMutableArray *queryItems = [NSMutableArray arrayWithCapacity:[queryParameters count]];
// sort the custom parameter keys so that we have deterministic parameter
// order for unit tests
NSArray *queryKeys = [queryParameters allKeys];
NSArray *sortedQueryKeys = [queryKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
for (NSString *paramKey in sortedQueryKeys) {
NSString *paramValue = [queryParameters valueForKey:paramKey];
NSString *paramItem = [NSString stringWithFormat:@"%@=%@",
[self stringByURLEncodingStringParameter:paramKey],
[self stringByURLEncodingStringParameter:paramValue]];
[queryItems addObject:paramItem];
}
NSString *paramStr = [queryItems componentsJoinedByString:@"&"];
BOOL hasQMark = ([urlString rangeOfString:@"?"].location == NSNotFound);
char joiner = hasQMark ? '?' : '&';
fullURLString = [NSString stringWithFormat:@"%@%c%@",
urlString, joiner, paramStr];
} else {
fullURLString = urlString;
}
NSURL *result = [NSURL URLWithString:fullURLString];
return result;
}
#pragma mark Collections
+ (NSMutableDictionary *)newStaticDictionary {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
// make the dictionary ineligible for garbage collection
#if !GTL_IPHONE
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:dict];
#endif
return dict;
}
+ (NSDictionary *)mergedClassDictionaryForSelector:(SEL)selector
startClass:(Class)startClass
ancestorClass:(Class)ancestorClass
cache:(NSMutableDictionary *)cache {
NSDictionary *result;
@synchronized(cache) {
result = [cache objectForKey:startClass];
if (result == nil) {
// Collect the class's dictionary.
NSDictionary *classDict = [startClass performSelector:selector];
// Collect the parent class's merged dictionary.
NSDictionary *parentClassMergedDict;
if ([startClass isEqual:ancestorClass]) {
parentClassMergedDict = nil;
} else {
Class parentClass = class_getSuperclass(startClass);
parentClassMergedDict =
[GTLUtilities mergedClassDictionaryForSelector:selector
startClass:parentClass
ancestorClass:ancestorClass
cache:cache];
}
// Merge this class's into the parent's so things properly override.
NSMutableDictionary *mergeDict;
if (parentClassMergedDict != nil) {
mergeDict =
[NSMutableDictionary dictionaryWithDictionary:parentClassMergedDict];
} else {
mergeDict = [NSMutableDictionary dictionary];
}
if (classDict != nil) {
[mergeDict addEntriesFromDictionary:classDict];
}
// Make an immutable version.
result = [NSDictionary dictionaryWithDictionary:mergeDict];
// Save it.
[cache setObject:result forKey:(id<NSCopying>)startClass];
}
}
return result;
}
#pragma mark MIME Types
// Utility routine to convert a file path to the file's MIME type using
// Mac OS X's UTI database
#if !GTL_FOUNDATION_ONLY
+ (NSString *)MIMETypeForFileAtPath:(NSString *)path
defaultMIMEType:(NSString *)defaultType {
NSString *result = defaultType;
// Convert the path to an FSRef
FSRef fileFSRef;
Boolean isDirectory;
OSStatus err = FSPathMakeRef((UInt8 *) [path fileSystemRepresentation],
&fileFSRef, &isDirectory);
if (err == noErr) {
// Get the UTI (content type) for the FSRef
CFStringRef fileUTI;
err = LSCopyItemAttribute(&fileFSRef, kLSRolesAll, kLSItemContentType,
(CFTypeRef *)&fileUTI);
if (err == noErr) {
// Get the MIME type for the UTI
CFStringRef mimeTypeTag;
mimeTypeTag = UTTypeCopyPreferredTagWithClass(fileUTI,
kUTTagClassMIMEType);
if (mimeTypeTag) {
// Convert the CFStringRef to an autoreleased NSString
result = [(id)CFMakeCollectable(mimeTypeTag) autorelease];
}
CFRelease(fileUTI);
}
}
return result;
}
#endif
@end
// isEqual: has the fatal flaw that it doesn't deal well with the receiver
// being nil. We'll use this utility instead.
BOOL GTL_AreEqualOrBothNil(id obj1, id obj2) {
if (obj1 == obj2) {
return YES;
}
if (obj1 && obj2) {
BOOL areEqual = [obj1 isEqual:obj2];
return areEqual;
}
return NO;
}
BOOL GTL_AreBoolsEqual(BOOL b1, BOOL b2) {
// avoid comparison problems with boolean types by negating
// both booleans
return (!b1 == !b2);
}
NSNumber *GTL_EnsureNSNumber(NSNumber *num) {
if ([num isKindOfClass:[NSString class]]) {
NSDecimalNumber *reallyNum;
// Force the parse to use '.' as the number seperator.
static NSLocale *usLocale = nil;
@synchronized([GTLUtilities class]) {
if (usLocale == nil) {
usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
}
reallyNum = [NSDecimalNumber decimalNumberWithString:(NSString*)num
locale:(id)usLocale];
}
if (reallyNum != nil) {
num = reallyNum;
}
}
return num;
}