Added Android code
[wl-app.git] / iOS / Pods / Protobuf / objectivec / GPBWellKnownTypes.m
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2015 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Importing sources here to force the linker to include our category methods in
32 // the static library. If these were compiled separately, the category methods
33 // below would be stripped by the linker.
34
35 #import "GPBWellKnownTypes.h"
36
37 #import "GPBUtilities_PackagePrivate.h"
38
39 NSString *const GPBWellKnownTypesErrorDomain =
40     GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
41
42 static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
43
44 static NSTimeInterval TimeIntervalFromSecondsAndNanos(int64_t seconds,
45                                                       int32_t nanos) {
46   return seconds + (NSTimeInterval)nanos / 1e9;
47 }
48
49 static int32_t SecondsAndNanosFromTimeInterval(NSTimeInterval time,
50                                                int64_t *outSeconds,
51                                                BOOL nanosMustBePositive) {
52   NSTimeInterval seconds;
53   NSTimeInterval nanos = modf(time, &seconds);
54
55   if (nanosMustBePositive && (nanos < 0)) {
56     // Per Timestamp.proto, nanos is non-negative and "Negative second values with
57     // fractions must still have non-negative nanos values that count forward in
58     // time. Must be from 0 to 999,999,999 inclusive."
59     --seconds;
60     nanos = 1.0 + nanos;
61   }
62
63   nanos *= 1e9;
64   *outSeconds = (int64_t)seconds;
65   return (int32_t)nanos;
66 }
67
68 static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
69   if (typeURLPrefix.length == 0) {
70     return fullName;
71   }
72
73   if ([typeURLPrefix hasSuffix:@"/"]) {
74     return [typeURLPrefix stringByAppendingString:fullName];
75   }
76
77   return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
78 }
79
80 static NSString *ParseTypeFromURL(NSString *typeURLString) {
81   NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
82   if ((range.location == NSNotFound) ||
83       (NSMaxRange(range) == typeURLString.length)) {
84     return nil;
85   }
86   NSString *result = [typeURLString substringFromIndex:range.location + 1];
87   return result;
88 }
89
90 #pragma mark - GPBTimestamp
91
92 @implementation GPBTimestamp (GBPWellKnownTypes)
93
94 - (instancetype)initWithDate:(NSDate *)date {
95   return [self initWithTimeIntervalSince1970:date.timeIntervalSince1970];
96 }
97
98 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
99   if ((self = [super init])) {
100     int64_t seconds;
101     int32_t nanos = SecondsAndNanosFromTimeInterval(
102         timeIntervalSince1970, &seconds, YES);
103     self.seconds = seconds;
104     self.nanos = nanos;
105   }
106   return self;
107 }
108
109 - (NSDate *)date {
110   return [NSDate dateWithTimeIntervalSince1970:self.timeIntervalSince1970];
111 }
112
113 - (void)setDate:(NSDate *)date {
114   self.timeIntervalSince1970 = date.timeIntervalSince1970;
115 }
116
117 - (NSTimeInterval)timeIntervalSince1970 {
118   return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
119 }
120
121 - (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
122   int64_t seconds;
123   int32_t nanos =
124       SecondsAndNanosFromTimeInterval(timeIntervalSince1970, &seconds, YES);
125   self.seconds = seconds;
126   self.nanos = nanos;
127 }
128
129 @end
130
131 #pragma mark - GPBDuration
132
133 @implementation GPBDuration (GBPWellKnownTypes)
134
135 - (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval {
136   if ((self = [super init])) {
137     int64_t seconds;
138     int32_t nanos = SecondsAndNanosFromTimeInterval(
139         timeInterval, &seconds, NO);
140     self.seconds = seconds;
141     self.nanos = nanos;
142   }
143   return self;
144 }
145
146 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
147   return [self initWithTimeInterval:timeIntervalSince1970];
148 }
149
150 - (NSTimeInterval)timeInterval {
151   return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
152 }
153
154 - (void)setTimeInterval:(NSTimeInterval)timeInterval {
155   int64_t seconds;
156   int32_t nanos =
157       SecondsAndNanosFromTimeInterval(timeInterval, &seconds, NO);
158   self.seconds = seconds;
159   self.nanos = nanos;
160 }
161
162 - (NSTimeInterval)timeIntervalSince1970 {
163   return self.timeInterval;
164 }
165
166 - (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
167   self.timeInterval = timeIntervalSince1970;
168 }
169
170 @end
171
172 #pragma mark - GPBAny
173
174 @implementation GPBAny (GBPWellKnownTypes)
175
176 + (instancetype)anyWithMessage:(GPBMessage *)message
177                          error:(NSError **)errorPtr {
178   return [self anyWithMessage:message
179                 typeURLPrefix:kTypePrefixGoogleApisCom
180                         error:errorPtr];
181 }
182
183 + (instancetype)anyWithMessage:(GPBMessage *)message
184                  typeURLPrefix:(NSString *)typeURLPrefix
185                          error:(NSError **)errorPtr {
186   return [[[self alloc] initWithMessage:message
187                           typeURLPrefix:typeURLPrefix
188                                   error:errorPtr] autorelease];
189 }
190
191 - (instancetype)initWithMessage:(GPBMessage *)message
192                           error:(NSError **)errorPtr {
193   return [self initWithMessage:message
194                  typeURLPrefix:kTypePrefixGoogleApisCom
195                          error:errorPtr];
196 }
197
198 - (instancetype)initWithMessage:(GPBMessage *)message
199                   typeURLPrefix:(NSString *)typeURLPrefix
200                           error:(NSError **)errorPtr {
201   self = [self init];
202   if (self) {
203     if (![self packWithMessage:message
204                  typeURLPrefix:typeURLPrefix
205                          error:errorPtr]) {
206       [self release];
207       self = nil;
208     }
209   }
210   return self;
211 }
212
213 - (BOOL)packWithMessage:(GPBMessage *)message
214                   error:(NSError **)errorPtr {
215   return [self packWithMessage:message
216                  typeURLPrefix:kTypePrefixGoogleApisCom
217                          error:errorPtr];
218 }
219
220 - (BOOL)packWithMessage:(GPBMessage *)message
221           typeURLPrefix:(NSString *)typeURLPrefix
222                   error:(NSError **)errorPtr {
223   NSString *fullName = [message descriptor].fullName;
224   if (fullName.length == 0) {
225     if (errorPtr) {
226       *errorPtr =
227           [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
228                               code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
229                           userInfo:nil];
230     }
231     return NO;
232   }
233   if (errorPtr) {
234     *errorPtr = nil;
235   }
236   self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
237   self.value = message.data;
238   return YES;
239 }
240
241 - (GPBMessage *)unpackMessageClass:(Class)messageClass
242                              error:(NSError **)errorPtr {
243   NSString *fullName = [messageClass descriptor].fullName;
244   if (fullName.length == 0) {
245     if (errorPtr) {
246       *errorPtr =
247           [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
248                               code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
249                       userInfo:nil];
250     }
251     return nil;
252   }
253
254   NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
255   if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
256     if (errorPtr) {
257       *errorPtr =
258           [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
259                               code:GPBWellKnownTypesErrorCodeTypeURLMismatch
260                           userInfo:nil];
261     }
262     return nil;
263   }
264
265   // Any is proto3, which means no extensions, so this assumes anything put
266   // within an any also won't need extensions. A second helper could be added
267   // if needed.
268   return [messageClass parseFromData:self.value
269                                error:errorPtr];
270 }
271
272 @end