Index: third_party/protobuf/objectivec/GPBWellKnownTypes.m |
diff --git a/third_party/protobuf/objectivec/GPBWellKnownTypes.m b/third_party/protobuf/objectivec/GPBWellKnownTypes.m |
index fe02f5de11e24d04d309e19e8659541730f3c5ee..ed798a2e4b69998d83ca02c928cc971155d5c52c 100644 |
--- a/third_party/protobuf/objectivec/GPBWellKnownTypes.m |
+++ b/third_party/protobuf/objectivec/GPBWellKnownTypes.m |
@@ -32,10 +32,15 @@ |
// the static library. If these were compiled separately, the category methods |
// below would be stripped by the linker. |
-#import "google/protobuf/Timestamp.pbobjc.m" |
-#import "google/protobuf/Duration.pbobjc.m" |
#import "GPBWellKnownTypes.h" |
+#import "GPBUtilities_PackagePrivate.h" |
+ |
+NSString *const GPBWellKnownTypesErrorDomain = |
+ GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain); |
+ |
+static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/"; |
+ |
static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds, |
int32_t nanos) { |
return seconds + (NSTimeInterval)nanos / 1e9; |
@@ -50,6 +55,30 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, |
return (int32_t)nanos; |
} |
+static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) { |
+ if (typeURLPrefix.length == 0) { |
+ return fullName; |
+ } |
+ |
+ if ([typeURLPrefix hasSuffix:@"/"]) { |
+ return [typeURLPrefix stringByAppendingString:fullName]; |
+ } |
+ |
+ return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName]; |
+} |
+ |
+static NSString *ParseTypeFromURL(NSString *typeURLString) { |
+ NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch]; |
+ if ((range.location == NSNotFound) || |
+ (NSMaxRange(range) == typeURLString.length)) { |
+ return nil; |
+ } |
+ NSString *result = [typeURLString substringFromIndex:range.location + 1]; |
+ return result; |
+} |
+ |
+#pragma mark - GPBTimestamp |
+ |
@implementation GPBTimestamp (GBPWellKnownTypes) |
- (instancetype)initWithDate:(NSDate *)date { |
@@ -89,6 +118,8 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, |
@end |
+#pragma mark - GPBDuration |
+ |
@implementation GPBDuration (GBPWellKnownTypes) |
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { |
@@ -115,3 +146,105 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, |
} |
@end |
+ |
+#pragma mark - GPBAny |
+ |
+@implementation GPBAny (GBPWellKnownTypes) |
+ |
++ (instancetype)anyWithMessage:(GPBMessage *)message |
+ error:(NSError **)errorPtr { |
+ return [self anyWithMessage:message |
+ typeURLPrefix:kTypePrefixGoogleApisCom |
+ error:errorPtr]; |
+} |
+ |
++ (instancetype)anyWithMessage:(GPBMessage *)message |
+ typeURLPrefix:(NSString *)typeURLPrefix |
+ error:(NSError **)errorPtr { |
+ return [[[self alloc] initWithMessage:message |
+ typeURLPrefix:typeURLPrefix |
+ error:errorPtr] autorelease]; |
+} |
+ |
+- (instancetype)initWithMessage:(GPBMessage *)message |
+ error:(NSError **)errorPtr { |
+ return [self initWithMessage:message |
+ typeURLPrefix:kTypePrefixGoogleApisCom |
+ error:errorPtr]; |
+} |
+ |
+- (instancetype)initWithMessage:(GPBMessage *)message |
+ typeURLPrefix:(NSString *)typeURLPrefix |
+ error:(NSError **)errorPtr { |
+ self = [self init]; |
+ if (self) { |
+ if (![self packWithMessage:message |
+ typeURLPrefix:typeURLPrefix |
+ error:errorPtr]) { |
+ [self release]; |
+ self = nil; |
+ } |
+ } |
+ return self; |
+} |
+ |
+- (BOOL)packWithMessage:(GPBMessage *)message |
+ error:(NSError **)errorPtr { |
+ return [self packWithMessage:message |
+ typeURLPrefix:kTypePrefixGoogleApisCom |
+ error:errorPtr]; |
+} |
+ |
+- (BOOL)packWithMessage:(GPBMessage *)message |
+ typeURLPrefix:(NSString *)typeURLPrefix |
+ error:(NSError **)errorPtr { |
+ NSString *fullName = [message descriptor].fullName; |
+ if (fullName.length == 0) { |
+ if (errorPtr) { |
+ *errorPtr = |
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain |
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL |
+ userInfo:nil]; |
+ } |
+ return NO; |
+ } |
+ if (errorPtr) { |
+ *errorPtr = nil; |
+ } |
+ self.typeURL = BuildTypeURL(typeURLPrefix, fullName); |
+ self.value = message.data; |
+ return YES; |
+} |
+ |
+- (GPBMessage *)unpackMessageClass:(Class)messageClass |
+ error:(NSError **)errorPtr { |
+ NSString *fullName = [messageClass descriptor].fullName; |
+ if (fullName.length == 0) { |
+ if (errorPtr) { |
+ *errorPtr = |
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain |
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL |
+ userInfo:nil]; |
+ } |
+ return nil; |
+ } |
+ |
+ NSString *expectedFullName = ParseTypeFromURL(self.typeURL); |
+ if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) { |
+ if (errorPtr) { |
+ *errorPtr = |
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain |
+ code:GPBWellKnownTypesErrorCodeTypeURLMismatch |
+ userInfo:nil]; |
+ } |
+ return nil; |
+ } |
+ |
+ // Any is proto3, which means no extensions, so this assumes anything put |
+ // within an any also won't need extensions. A second helper could be added |
+ // if needed. |
+ return [messageClass parseFromData:self.value |
+ error:errorPtr]; |
+} |
+ |
+@end |