GBA002/Pods/GoogleAPIClientForREST/Source/Objects/GTLRDuration.m
Riley Testut 6cca0f244f Replaces frameworks with static libraries
As of iOS 13.3.1, apps installed with free developer accounts that contain embedded frameworks fail to launch. To work around this, we now link all dependencies via Cocoapods as static libraries.
2020-02-03 19:28:23 -08:00

223 lines
6.3 KiB
Objective-C

/* Copyright (c) 2016 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.
*/
#if !__has_feature(objc_arc)
#error "This file needs to be compiled with ARC enabled."
#endif
#import "GTLRDuration.h"
static const int32_t kNanosPerMillisecond = 1000000;
static const int32_t kNanosPerMicrosecond = 1000;
static const int32_t kNanosPerSecond = 1000000000;
static int32_t IntPow10(int x) {
int32_t result = 1;
for (int i = 0; i < x; ++i) {
result *= 10;
}
return result;
}
@implementation GTLRDuration
@dynamic timeInterval;
@synthesize seconds = _seconds,
nanos = _nanos,
jsonString = _jsonString;
+ (instancetype)durationWithSeconds:(int64_t)seconds nanos:(int32_t)nanos {
if (seconds < 0) {
if (nanos > 0) {
// secs was -, nanos was +
return nil;
}
} else if (seconds > 0) {
if (nanos < 0) {
// secs was +, nanos was -
return nil;
}
}
if ((nanos <= -kNanosPerSecond) || (nanos >= kNanosPerSecond)) {
// more than a seconds worth
return nil;
}
return [[self alloc] initWithSeconds:seconds nanos:nanos jsonString:NULL];
}
+ (instancetype)durationWithJSONString:(NSString *)jsonString {
// It has to end in "s", so it needs >1 character.
if (jsonString.length <= 1) {
return nil;
}
static NSCharacterSet *gNumberSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
gNumberSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
});
NSScanner* scanner = [NSScanner scannerWithString:jsonString];
// There should be no whitespace, so no skip characters.
[scanner setCharactersToBeSkipped:nil];
// Can start with a '-'.
BOOL isNeg = [scanner scanString:@"-" intoString:NULL];
int64_t seconds;
if (![scanner scanLongLong:&seconds]) {
return nil;
}
// Since the sign was manually scanned, seconds should be positive
// (i.e. no "--#" in the put).
if (seconds < 0) {
return nil;
}
// See if it has a ".[nanos]". Spec seems to say it is required, but play
// it safe and make it optional.
int32_t nanos = 0;
if ([scanner scanString:@"." intoString:NULL]) {
NSString *nanosStr;
if (![scanner scanCharactersFromSet:gNumberSet intoString:&nanosStr]) {
return nil;
}
// Ensure not too many digits (also ensure it is within range).
if (nanosStr.length > 9) {
return nil;
}
// Can use NSString's intValue since the character set was controlled.
nanos = [nanosStr intValue];
// Scale based on length.
nanos *= IntPow10(9 - (int)nanosStr.length);
}
// And must have the final 's'.
if (![scanner scanString:@"s" intoString:NULL]) {
return nil;
}
// Better be the end...
if (![scanner isAtEnd]) {
return nil;
}
if (isNeg) {
seconds = -seconds;
nanos = -nanos;
}
// Pass on the json string so it will be reflected back out as it came in
// (incase it had a different number of digits, etc).
return [[self alloc] initWithSeconds:seconds
nanos:nanos
jsonString:jsonString];
}
+ (instancetype)durationWithTimeInterval:(NSTimeInterval)timeInterval {
NSTimeInterval seconds;
NSTimeInterval nanos = modf(timeInterval, &seconds);
nanos *= (NSTimeInterval)kNanosPerSecond;
return [[self alloc] initWithSeconds:(int64_t)seconds
nanos:(int32_t)nanos
jsonString:NULL];
}
- (instancetype)init {
return [self initWithSeconds:0 nanos:0 jsonString:NULL];
}
- (instancetype)initWithSeconds:(int64_t)seconds
nanos:(int32_t)nanos
jsonString:(NSString *)jsonString {
self = [super init];
if (self) {
// Sanity asserts, the class methods should make sure this doesn't happen.
GTLR_DEBUG_ASSERT((((seconds <= 0) && (nanos <= 0)) ||
((seconds >= 0) && (nanos >= 0))),
@"Seconds and nanos must have the same sign (%lld & %d)",
seconds, nanos);
GTLR_DEBUG_ASSERT(((nanos < kNanosPerSecond) &&
(nanos > -kNanosPerSecond)),
@"Nanos is a second or more (%d)", nanos);
_seconds = seconds;
_nanos = nanos;
if (jsonString.length) {
_jsonString = [jsonString copy];
} else {
// Based off the JSON serialization code in protocol buffers
// ( https://github.com/google/protobuf/ ).
NSString *sign = @"";
if ((seconds < 0) || (nanos < 0)) {
sign = @"-";
seconds = -seconds;
nanos = -nanos;
}
int nanoDigts;
int32_t nanoDivider;
if (nanos % kNanosPerMillisecond == 0) {
nanoDigts = 3;
nanoDivider = kNanosPerMillisecond;
} else if (nanos % kNanosPerMicrosecond == 0) {
nanoDigts = 6;
nanoDivider = kNanosPerMicrosecond;
} else {
nanoDigts = 9;
nanoDivider = 1;
}
_jsonString = [NSString stringWithFormat:@"%@%lld.%0*ds",
sign, seconds, nanoDigts, (nanos / nanoDivider)];
}
}
return self;
}
- (NSTimeInterval)timeInterval {
NSTimeInterval result = self.seconds;
result += (NSTimeInterval)self.nanos / (NSTimeInterval)kNanosPerSecond;
return result;
}
- (id)copyWithZone:(NSZone *)zone {
// Object is immutable
return self;
}
- (BOOL)isEqual:(GTLRDuration *)other {
if (self == other) return YES;
if (![other isKindOfClass:[GTLRDuration class]]) return NO;
BOOL result = ((self.seconds == other.seconds) &&
(self.nanos == other.nanos));
return result;
}
- (NSUInteger)hash {
NSUInteger result = (NSUInteger)((self.seconds * 13) + self.nanos);
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %p: {%@}",
[self class], self, self.jsonString];
}
@end