Browse Source

Resolved a conflict

Vladimir Moskva 9 năm trước cách đây
mục cha
commit
5caf516976
43 tập tin đã thay đổi với 649 bổ sung85 xóa
  1. 12 12
      WORKSPACE
  2. 1 1
      appveyor.bat
  3. 1 0
      appveyor.yml
  4. 4 0
      cmake/CMakeLists.txt
  5. 10 10
      gmock.BUILD
  6. 1 0
      objectivec/DevTools/compile_testing_protos.sh
  7. 1 1
      objectivec/GPBBootstrap.h
  8. 9 0
      objectivec/GPBDescriptor.h
  9. 113 1
      objectivec/GPBDescriptor.m
  10. 5 0
      objectivec/GPBDescriptor_PackagePrivate.h
  11. 125 0
      objectivec/GPBWellKnownTypes.h
  12. 135 0
      objectivec/GPBWellKnownTypes.m
  13. 29 0
      objectivec/Tests/GPBDescriptorTests.m
  14. 1 0
      objectivec/Tests/GPBUnittestProtos.m
  15. 56 0
      objectivec/Tests/GPBWellKnownTypesTest.m
  16. 1 1
      objectivec/google/protobuf/Any.pbobjc.h
  17. 1 0
      objectivec/google/protobuf/Any.pbobjc.m
  18. 1 1
      objectivec/google/protobuf/Api.pbobjc.h
  19. 1 0
      objectivec/google/protobuf/Api.pbobjc.m
  20. 1 1
      objectivec/google/protobuf/Duration.pbobjc.h
  21. 1 0
      objectivec/google/protobuf/Duration.pbobjc.m
  22. 1 1
      objectivec/google/protobuf/Empty.pbobjc.h
  23. 1 0
      objectivec/google/protobuf/Empty.pbobjc.m
  24. 1 1
      objectivec/google/protobuf/FieldMask.pbobjc.h
  25. 1 0
      objectivec/google/protobuf/FieldMask.pbobjc.m
  26. 1 1
      objectivec/google/protobuf/SourceContext.pbobjc.h
  27. 1 0
      objectivec/google/protobuf/SourceContext.pbobjc.m
  28. 1 1
      objectivec/google/protobuf/Struct.pbobjc.h
  29. 1 0
      objectivec/google/protobuf/Struct.pbobjc.m
  30. 1 1
      objectivec/google/protobuf/Timestamp.pbobjc.h
  31. 1 0
      objectivec/google/protobuf/Timestamp.pbobjc.m
  32. 1 1
      objectivec/google/protobuf/Type.pbobjc.h
  33. 1 0
      objectivec/google/protobuf/Type.pbobjc.m
  34. 1 1
      objectivec/google/protobuf/Wrappers.pbobjc.h
  35. 1 0
      objectivec/google/protobuf/Wrappers.pbobjc.m
  36. 44 10
      protobuf.bzl
  37. 5 0
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  38. 25 13
      src/google/protobuf/compiler/objectivec/objectivec_file.cc
  39. 21 13
      src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
  40. 4 0
      src/google/protobuf/compiler/objectivec/objectivec_helpers.h
  41. 13 0
      src/google/protobuf/compiler/objectivec/objectivec_message.cc
  42. 6 6
      src/google/protobuf/compiler/subprocess.cc
  43. 8 8
      src/google/protobuf/testing/file.cc

+ 12 - 12
WORKSPACE

@@ -1,15 +1,15 @@
-new_http_archive(
-    name = "gmock_archive",
-    url = "https://googlemock.googlecode.com/files/gmock-1.7.0.zip",
-    sha256 = "26fcbb5925b74ad5fc8c26b0495dfc96353f4d553492eb97e85a8a6d2f43095b",
+new_git_repository(
+    name = "googletest",
     build_file = "gmock.BUILD",
+    remote = "https://github.com/google/googletest",
+    tag = "release-1.8.0",
 )
 
 new_http_archive(
     name = "six_archive",
-    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
-    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
     build_file = "six.BUILD",
+    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
+    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
 )
 
 bind(
@@ -19,12 +19,12 @@ bind(
 
 bind(
     name = "gtest",
-    actual = "@gmock_archive//:gtest",
+    actual = "@googletest//:gtest",
 )
 
 bind(
     name = "gtest_main",
-    actual = "@gmock_archive//:gtest_main",
+    actual = "@googletest//:gtest_main",
 )
 
 bind(
@@ -33,8 +33,8 @@ bind(
 )
 
 maven_jar(
-  name = "guava_maven",
-  artifact = "com.google.guava:guava:18.0",
+    name = "guava_maven",
+    artifact = "com.google.guava:guava:18.0",
 )
 
 bind(
@@ -43,8 +43,8 @@ bind(
 )
 
 maven_jar(
-  name = "gson_maven",
-  artifact = "com.google.code.gson:gson:2.3",
+    name = "gson_maven",
+    artifact = "com.google.code.gson:gson:2.3",
 )
 
 bind(

+ 1 - 1
appveyor.bat

@@ -10,7 +10,7 @@ goto :error
 echo Building C++
 mkdir build_msvc
 cd build_msvc
-cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
+cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% -Dprotobuf_UNICODE=%UNICODE% ../cmake
 msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
 cd %configuration%
 tests.exe || goto error

+ 1 - 0
appveyor.yml

@@ -11,6 +11,7 @@ environment:
   matrix:
     - language: cpp
       BUILD_DLL: ON
+      UNICODE: ON
 
     - language: csharp
 

+ 4 - 0
cmake/CMakeLists.txt

@@ -159,6 +159,10 @@ else (MSVC)
   set(LIB_PREFIX)
 endif (MSVC)
 
+if (protobuf_UNICODE)
+  add_definitions(-DUNICODE -D_UNICODE)
+endif (protobuf_UNICODE)
+
 include(libprotobuf-lite.cmake)
 include(libprotobuf.cmake)
 include(libprotoc.cmake)

+ 10 - 10
gmock.BUILD

@@ -1,19 +1,19 @@
 cc_library(
     name = "gtest",
     srcs = [
-        "gmock-1.7.0/gtest/src/gtest-all.cc",
-        "gmock-1.7.0/src/gmock-all.cc",
+        "googletest/src/gtest-all.cc",
+        "googlemock/src/gmock-all.cc",
     ],
     hdrs = glob([
-        "gmock-1.7.0/**/*.h",
-        "gmock-1.7.0/gtest/src/*.cc",
-        "gmock-1.7.0/src/*.cc",
+        "**/*.h",
+        "googletest/src/*.cc",
+        "googlemock/src/*.cc",
     ]),
     includes = [
-        "gmock-1.7.0",
-        "gmock-1.7.0/gtest",
-        "gmock-1.7.0/gtest/include",
-        "gmock-1.7.0/include",
+        "googlemock",
+        "googletest",
+        "googletest/include",
+        "googlemock/include",
     ],
     linkopts = ["-pthread"],
     visibility = ["//visibility:public"],
@@ -21,7 +21,7 @@ cc_library(
 
 cc_library(
     name = "gtest_main",
-    srcs = ["gmock-1.7.0/src/gmock_main.cc"],
+    srcs = ["googlemock/src/gmock_main.cc"],
     linkopts = ["-pthread"],
     visibility = ["//visibility:public"],
     deps = [":gtest"],

+ 1 - 0
objectivec/DevTools/compile_testing_protos.sh

@@ -93,6 +93,7 @@ compile_protos() {
 # sources can be generated from them.
 
 CORE_PROTO_FILES=(
+  src/google/protobuf/any_test.proto
   src/google/protobuf/unittest_arena.proto
   src/google/protobuf/unittest_custom_options.proto
   src/google/protobuf/unittest_enormous_descriptor.proto

+ 1 - 1
objectivec/GPBBootstrap.h

@@ -99,4 +99,4 @@
 // regenerated.
 //
 // Meant to be used internally by generated code.
-#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002

+ 9 - 0
objectivec/GPBDescriptor.h

@@ -81,6 +81,13 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
 @property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
 /** The class of this message. */
 @property(nonatomic, readonly) Class messageClass;
+/** Containing message descriptor if this message is nested, or nil otherwise. */
+@property(readonly, nullable) GPBDescriptor *containingType;
+/**
+ * Fully qualified name for this message (package.message). Can be nil if the
+ * value is unable to be computed.
+ */
+@property(readonly, nullable) NSString *fullName;
 
 /**
  * Gets the field for the given number.
@@ -118,6 +125,8 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
 
 /** The package declared in the proto file. */
 @property(nonatomic, readonly, copy) NSString *package;
+/** The objc prefix declared in the proto file. */
+@property(nonatomic, readonly, copy, nullable) NSString *objcPrefix;
 /** The syntax of the proto file. */
 @property(nonatomic, readonly) GPBFileSyntax syntax;
 

+ 113 - 1
objectivec/GPBDescriptor.m

@@ -42,8 +42,10 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
 
-// The address of this variable is used as a key for obj_getAssociatedObject.
+// The addresses of these variables are used as keys for objc_getAssociatedObject.
 static const char kTextFormatExtraValueKey = 0;
+static const char kParentClassNameValueKey = 0;
+static const char kClassNameSuffixKey = 0;
 
 // Utility function to generate selectors on the fly.
 static SEL SelFromStrings(const char *prefix, const char *middle,
@@ -215,10 +217,102 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
   extensionRangesCount_ = count;
 }
 
+- (void)setupContainingMessageClassName:(const char *)msgClassName {
+  // Note: Only fetch the class here, can't send messages to it because
+  // that could cause cycles back to this class within +initialize if
+  // two messages have each other in fields (i.e. - they build a graph).
+  NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName);
+  NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName];
+  objc_setAssociatedObject(self, &kParentClassNameValueKey,
+                           parentNameValue,
+                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setupMessageClassNameSuffix:(NSString *)suffix {
+  if (suffix.length) {
+    objc_setAssociatedObject(self, &kClassNameSuffixKey,
+                             suffix,
+                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+  }
+}
+
 - (NSString *)name {
   return NSStringFromClass(messageClass_);
 }
 
+- (GPBDescriptor *)containingType {
+  NSValue *parentNameValue =
+      objc_getAssociatedObject(self, &kParentClassNameValueKey);
+  if (!parentNameValue) {
+    return nil;
+  }
+  const char *parentName = [parentNameValue pointerValue];
+  Class parentClass = objc_getClass(parentName);
+  NSAssert(parentClass, @"Class %s not defined", parentName);
+  return [parentClass descriptor];
+}
+
+- (NSString *)fullName {
+  NSString *className = NSStringFromClass(self.messageClass);
+  GPBFileDescriptor *file = self.file;
+  NSString *objcPrefix = file.objcPrefix;
+  if (objcPrefix && ![className hasPrefix:objcPrefix]) {
+    NSAssert(0,
+             @"Class didn't have correct prefix? (%@ - %@)",
+             className, objcPrefix);
+    return nil;
+  }
+  GPBDescriptor *parent = self.containingType;
+
+  NSString *name = nil;
+  if (parent) {
+    NSString *parentClassName = NSStringFromClass(parent.messageClass);
+    // The generator will add _Class to avoid reserved words, drop it.
+    NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
+    if (suffix) {
+      if (![parentClassName hasSuffix:suffix]) {
+        NSAssert(0,
+                 @"ParentMessage class didn't have correct suffix? (%@ - %@)",
+                 className, suffix);
+        return nil;
+      }
+      parentClassName =
+          [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
+    }
+    NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
+    if (![className hasPrefix:parentPrefix]) {
+      NSAssert(0,
+               @"Class didn't have the correct parent name prefix? (%@ - %@)",
+               parentPrefix, className);
+      return nil;
+    }
+    name = [className substringFromIndex:parentPrefix.length];
+  } else {
+    name = [className substringFromIndex:objcPrefix.length];
+  }
+
+  // The generator will add _Class to avoid reserved words, drop it.
+  NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
+  if (suffix) {
+    if (![name hasSuffix:suffix]) {
+      NSAssert(0,
+               @"Message class didn't have correct suffix? (%@ - %@)",
+               name, suffix);
+      return nil;
+    }
+    name = [name substringToIndex:(name.length - suffix.length)];
+  }
+
+  NSString *prefix = (parent != nil ? parent.fullName : file.package);
+  NSString *result;
+  if (prefix.length > 0) {
+    result = [NSString stringWithFormat:@"%@.%@", prefix, name];
+  } else {
+    result = name;
+  }
+  return result;
+}
+
 - (id)copyWithZone:(NSZone *)zone {
 #pragma unused(zone)
   return [self retain];
@@ -255,12 +349,26 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
 
 @implementation GPBFileDescriptor {
   NSString *package_;
+  NSString *objcPrefix_;
   GPBFileSyntax syntax_;
 }
 
 @synthesize package = package_;
+@synthesize objcPrefix = objcPrefix_;
 @synthesize syntax = syntax_;
 
+- (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax {
+  self = [super init];
+  if (self) {
+    package_ = [package copy];
+    objcPrefix_ = [objcPrefix copy];
+    syntax_ = syntax;
+  }
+  return self;
+}
+
 - (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax {
   self = [super init];
@@ -273,6 +381,7 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
 
 - (void)dealloc {
   [package_ release];
+  [objcPrefix_ release];
   [super dealloc];
 }
 
@@ -416,6 +525,9 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
     // Extra type specific data.
     if (isMessage) {
       const char *className = coreDesc->dataTypeSpecific.className;
+      // Note: Only fetch the class here, can't send messages to it because
+      // that could cause cycles back to this class within +initialize if
+      // two messages have each other in fields (i.e. - they build a graph).
       msgClass_ = objc_getClass(className);
       NSAssert(msgClass_, @"Class %s not defined", className);
     } else if (dataType == GPBDataTypeEnum) {

+ 5 - 0
objectivec/GPBDescriptor_PackagePrivate.h

@@ -168,10 +168,15 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
       firstHasIndex:(int32_t)firstHasIndex;
 - (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
 - (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+- (void)setupContainingMessageClassName:(const char *)msgClassName;
+- (void)setupMessageClassNameSuffix:(NSString *)suffix;
 
 @end
 
 @interface GPBFileDescriptor ()
+- (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax;
 - (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax;
 @end

+ 125 - 0
objectivec/GPBWellKnownTypes.h

@@ -37,15 +37,32 @@
 #endif
 
 #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
+ #import <Protobuf/Any.pbobjc.h>
  #import <Protobuf/Duration.pbobjc.h>
  #import <Protobuf/Timestamp.pbobjc.h>
 #else
+ #import "google/protobuf/Any.pbobjc.h"
  #import "google/protobuf/Duration.pbobjc.h"
  #import "google/protobuf/Timestamp.pbobjc.h"
 #endif
 
 NS_ASSUME_NONNULL_BEGIN
 
+#pragma mark - Errors
+
+/** NSError domain used for errors. */
+extern NSString *const GPBWellKnownTypesErrorDomain;
+
+/** Error code for NSError with GPBWellKnownTypesErrorDomain. */
+typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
+  /** The type_url could not be computed for the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeFailedToComputeTypeURL = -100,
+  /** type_url in a Any doesn’t match that of the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeTypeURLMismatch = -101,
+};
+
+#pragma mark - GPBTimestamp
+
 /**
  * Category for GPBTimestamp to work with standard Foundation time/date types.
  **/
@@ -82,6 +99,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @end
 
+#pragma mark - GPBDuration
+
 /**
  * Category for GPBDuration to work with standard Foundation time type.
  **/
@@ -106,4 +125,110 @@ NS_ASSUME_NONNULL_BEGIN
 
 @end
 
+#pragma mark - GPBAny
+
+/**
+ * Category for GPBAny to help work with the message within the object.
+ **/
+@interface GPBAny (GBPWellKnownTypes)
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ * This uses type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                           typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+                  error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                  error:(NSError **)errorPtr;
+
+/**
+ * Unpacks the serialized message as if it was an instance of the given class.
+ *
+ * @note When checking type_url, the base URL is not checked, only the fully
+ *       qualified name.
+ *
+ * @param messageClass The class to use to deserialize the contained message.
+ * @param errorPtr     Pointer to an error that will be populated if something
+ *                     goes wrong.
+ *
+ * @return An instance of the given class populated with the contained data, or
+ *         nil on failure.
+ */
+- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
+                                      error:(NSError **)errorPtr;
+
+@end
+
 NS_ASSUME_NONNULL_END

+ 135 - 0
objectivec/GPBWellKnownTypes.m

@@ -34,6 +34,13 @@
 
 #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;
@@ -48,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 {
@@ -87,6 +118,8 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
 
 @end
 
+#pragma mark - GPBDuration
+
 @implementation GPBDuration (GBPWellKnownTypes)
 
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
@@ -113,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

+ 29 - 0
objectivec/Tests/GPBDescriptorTests.m

@@ -34,12 +34,41 @@
 
 #import "GPBDescriptor.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
 
 @interface DescriptorTests : GPBTestCase
 @end
 
 @implementation DescriptorTests
 
+- (void)testDescriptor_containingType {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertNil(testAllTypesDesc.containingType);
+  XCTAssertNotNil(nestedMessageDesc.containingType);
+  XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc);  // Ptr comparison
+}
+
+- (void)testDescriptor_fullName {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  XCTAssertEqualObjects(testAllTypesDesc.fullName, @"protobuf_unittest.TestAllTypes");
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertEqualObjects(nestedMessageDesc.fullName, @"protobuf_unittest.TestAllTypes.NestedMessage");
+
+  // Prefixes removed.
+  GPBDescriptor *descDesc = [GPBDescriptorProto descriptor];
+  XCTAssertEqualObjects(descDesc.fullName, @"google.protobuf.DescriptorProto");
+  GPBDescriptor *descExtRngDesc = [GPBDescriptorProto_ExtensionRange descriptor];
+  XCTAssertEqualObjects(descExtRngDesc.fullName, @"google.protobuf.DescriptorProto.ExtensionRange");
+
+  // Things that get "_Class" added.
+  GPBDescriptor *pointDesc = [Point_Class descriptor];
+  XCTAssertEqualObjects(pointDesc.fullName, @"protobuf_unittest.Point");
+  GPBDescriptor *pointRectDesc = [Point_Rect descriptor];
+  XCTAssertEqualObjects(pointRectDesc.fullName, @"protobuf_unittest.Point.Rect");
+}
+
 - (void)testFieldDescriptor {
   GPBDescriptor *descriptor = [TestAllTypes descriptor];
 

+ 1 - 0
objectivec/Tests/GPBUnittestProtos.m

@@ -36,6 +36,7 @@
 // a descriptor as it doesn't use the classes/enums.
 #import "google/protobuf/Descriptor.pbobjc.m"
 
+#import "google/protobuf/AnyTest.pbobjc.m"
 #import "google/protobuf/MapProto2Unittest.pbobjc.m"
 #import "google/protobuf/MapUnittest.pbobjc.m"
 #import "google/protobuf/Unittest.pbobjc.m"

+ 56 - 0
objectivec/Tests/GPBWellKnownTypesTest.m

@@ -32,6 +32,8 @@
 
 #import <XCTest/XCTest.h>
 
+#import "google/protobuf/AnyTest.pbobjc.h"
+
 // A basically random interval into the future for testing with.
 static const NSTimeInterval kFutureOffsetInterval = 15000;
 
@@ -99,4 +101,58 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
   [duration2 release];
 }
 
+- (void)testAnyHelpers {
+
+  // Set and extract covers most of the code.
+
+  TestAny *subMessage = [TestAny message];
+  subMessage.int32Value = 12345;
+  TestAny *message = [TestAny message];
+  NSError *err = nil;
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:&err];
+  XCTAssertNil(err);
+
+  NSData *data = message.data;
+  XCTAssertNotNil(data);
+
+  TestAny *message2 = [TestAny parseFromData:data error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(message2);
+  XCTAssertTrue(message2.hasAnyValue);
+
+  TestAny *subMessage2 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(subMessage2);
+  XCTAssertEqual(subMessage2.int32Value, 12345);
+
+  // NULL errorPtr in the two calls.
+
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:NULL];
+  NSData *data2 = message.data;
+  XCTAssertEqualObjects(data2, data);
+
+  TestAny *subMessage3 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:NULL];
+  XCTAssertNotNil(subMessage3);
+  XCTAssertEqualObjects(subMessage2, subMessage3);
+
+  // Try to extract wrong type.
+
+  GPBTimestamp *wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:&err];
+  XCTAssertNotNil(err);
+  XCTAssertNil(wrongMessage);
+  XCTAssertEqualObjects(err.domain, GPBWellKnownTypesErrorDomain);
+  XCTAssertEqual(err.code, GPBWellKnownTypesErrorCodeTypeURLMismatch);
+
+  wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:NULL];
+  XCTAssertNil(wrongMessage);
+}
+
 @end

+ 1 - 1
objectivec/google/protobuf/Any.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Any.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Api.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Api.pbobjc.m

@@ -45,6 +45,7 @@ static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Duration.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Duration.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Empty.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Empty.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/FieldMask.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/FieldMask.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/SourceContext.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/SourceContext.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Struct.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Struct.pbobjc.m

@@ -42,6 +42,7 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Timestamp.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Timestamp.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Type.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Type.pbobjc.m

@@ -45,6 +45,7 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 1 - 1
objectivec/google/protobuf/Wrappers.pbobjc.h

@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 

+ 1 - 0
objectivec/google/protobuf/Wrappers.pbobjc.m

@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;

+ 44 - 10
protobuf.bzl

@@ -62,9 +62,19 @@ def _proto_gen_impl(ctx):
   if ctx.attr.gen_py:
     args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
 
-  if ctx.executable.grpc_cpp_plugin:
-    args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path]
-    args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+  if ctx.executable.plugin:
+    plugin = ctx.executable.plugin
+    lang = ctx.attr.plugin_language
+    if not lang and plugin.basename.startswith('protoc-gen-'):
+      lang = plugin.basename[len('protoc-gen-'):]
+    if not lang:
+      fail("cannot infer the target language of plugin", "plugin_language")
+
+    outdir = ctx.var["GENDIR"] + "/" + gen_dir
+    if ctx.attr.plugin_options:
+      outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
+    args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)]
+    args += ["--%s_out=%s" % (lang, outdir)]
 
   if args:
     ctx.action(
@@ -72,6 +82,7 @@ def _proto_gen_impl(ctx):
         outputs=ctx.outputs.outs,
         arguments=args + import_flags + [s.path for s in srcs],
         executable=ctx.executable.protoc,
+        mnemonic="ProtoCompile",
     )
 
   return struct(
@@ -82,7 +93,7 @@ def _proto_gen_impl(ctx):
       ),
   )
 
-_proto_gen = rule(
+proto_gen = rule(
     attrs = {
         "srcs": attr.label_list(allow_files = True),
         "deps": attr.label_list(providers = ["proto"]),
@@ -93,11 +104,13 @@ _proto_gen = rule(
             single_file = True,
             mandatory = True,
         ),
-        "grpc_cpp_plugin": attr.label(
+        "plugin": attr.label(
             cfg = "host",
+            allow_files = True,
             executable = True,
-            single_file = True,
         ),
+        "plugin_language": attr.string(),
+        "plugin_options": attr.string_list(),
         "gen_cc": attr.bool(),
         "gen_py": attr.bool(),
         "outs": attr.output_list(),
@@ -105,6 +118,26 @@ _proto_gen = rule(
     output_to_genfiles = True,
     implementation = _proto_gen_impl,
 )
+"""Generates codes from Protocol Buffers definitions.
+
+This rule helps you to implement Skylark macros specific to the target
+language. You should prefer more specific `cc_proto_library `,
+`py_proto_library` and others unless you are adding such wrapper macros.
+
+Args:
+  srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
+    against.
+  deps: a list of dependency labels; must be other proto libraries.
+  includes: a list of include paths to .proto files.
+  protoc: the label of the protocol compiler to generate the sources.
+  plugin: the label of the protocol compiler plugin to be passed to the protocol
+    compiler.
+  plugin_language: the language of the generated sources
+  plugin_options: a list of options to be passed to the plugin
+  gen_cc: generates C++ sources in addition to the ones from the plugin. 
+  gen_py: generates Python sources in addition to the ones from the plugin.
+  outs: a list of labels of the expected outputs from the protocol compiler.
+"""
 
 def cc_proto_library(
         name,
@@ -150,7 +183,7 @@ def cc_proto_library(
   if internal_bootstrap_hack:
     # For pre-checked-in generated files, we add the internal_bootstrap_hack
     # which will skip the codegen action.
-    _proto_gen(
+    proto_gen(
         name=name + "_genproto",
         srcs=srcs,
         deps=[s + "_genproto" for s in deps],
@@ -170,13 +203,14 @@ def cc_proto_library(
 
   outs = _CcOuts(srcs, use_grpc_plugin)
 
-  _proto_gen(
+  proto_gen(
       name=name + "_genproto",
       srcs=srcs,
       deps=[s + "_genproto" for s in deps],
       includes=includes,
       protoc=protoc,
-      grpc_cpp_plugin=grpc_cpp_plugin,
+      plugin=grpc_cpp_plugin,
+      plugin_language="grpc",
       gen_cc=1,
       outs=outs,
       visibility=["//visibility:public"],
@@ -286,7 +320,7 @@ def py_proto_library(
   if include != None:
     includes = [include]
 
-  _proto_gen(
+  proto_gen(
       name=name + "_genproto",
       srcs=srcs,
       deps=[s + "_genproto" for s in deps],

+ 5 - 0
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -719,6 +719,11 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
   ExpectGenerated("test_generator", "", "foo.proto", "Foo");
 }
 
+TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
+  EXPECT_EQ("The system cannot find the file specified.\r\n",
+    Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+}
+
 #endif  // defined(_WIN32) || defined(__CYGWIN__)
 
 TEST_F(CommandLineInterfaceTest, PathLookup) {

+ 25 - 13
src/google/protobuf/compiler/objectivec/objectivec_file.cc

@@ -37,6 +37,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <algorithm> // std::find()
 #include <iostream>
 #include <sstream>
 
@@ -53,7 +54,7 @@ namespace {
 // This is also found in GPBBootstrap.h, and needs to be kept in sync.  It
 // is the version check done to ensure generated code works with the current
 // runtime being used.
-const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30002;
 
 const char* kHeaderExtension = ".pbobjc.h";
 
@@ -463,19 +464,22 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
 
   // File descriptor only needed if there are messages to use it.
   if (message_generators_.size() > 0) {
-    string syntax;
+    map<string, string> vars;
+    vars["root_class_name"] = root_class_name_;
+    vars["package"] = file_->package();
+    vars["objc_prefix"] = FileClassPrefix(file_);
     switch (file_->syntax()) {
       case FileDescriptor::SYNTAX_UNKNOWN:
-        syntax = "GPBFileSyntaxUnknown";
+        vars["syntax"] = "GPBFileSyntaxUnknown";
         break;
       case FileDescriptor::SYNTAX_PROTO2:
-        syntax = "GPBFileSyntaxProto2";
+        vars["syntax"] = "GPBFileSyntaxProto2";
         break;
       case FileDescriptor::SYNTAX_PROTO3:
-        syntax = "GPBFileSyntaxProto3";
+        vars["syntax"] = "GPBFileSyntaxProto3";
         break;
     }
-    printer->Print(
+    printer->Print(vars,
         "#pragma mark - $root_class_name$_FileDescriptor\n"
         "\n"
         "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
@@ -483,16 +487,24 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
         "  // about thread safety of the singleton.\n"
         "  static GPBFileDescriptor *descriptor = NULL;\n"
         "  if (!descriptor) {\n"
-        "    GPBDebugCheckRuntimeVersion();\n"
-        "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
-        "                                                     syntax:$syntax$];\n"
+        "    GPBDebugCheckRuntimeVersion();\n");
+    if (vars["objc_prefix"].size() > 0) {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                 objcPrefix:@\"$objc_prefix$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    } else {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    }
+    printer->Print(
         "  }\n"
         "  return descriptor;\n"
         "}\n"
-        "\n",
-        "root_class_name", root_class_name_,
-        "package", file_->package(),
-        "syntax", syntax);
+        "\n");
   }
 
   for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();

+ 21 - 13
src/google/protobuf/compiler/objectivec/objectivec_helpers.cc

@@ -210,10 +210,14 @@ const char* const kReservedWordList[] = {
 hash_set<string> kReservedWords =
     MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
 
-string SanitizeNameForObjC(const string& input, const string& extension) {
+string SanitizeNameForObjC(const string& input,
+                           const string& extension,
+                           string* out_suffix_added) {
   if (kReservedWords.count(input) > 0) {
+    if (out_suffix_added) *out_suffix_added = extension;
     return input + extension;
   }
+  if (out_suffix_added) out_suffix_added->clear();
   return input;
 }
 
@@ -336,6 +340,12 @@ string BaseFileName(const FileDescriptor* file) {
   return basename;
 }
 
+string FileClassPrefix(const FileDescriptor* file) {
+  // Default is empty string, no need to check has_objc_class_prefix.
+  string result = file->options().objc_class_prefix();
+  return result;
+}
+
 string FilePath(const FileDescriptor* file) {
   string output;
   string basename;
@@ -366,19 +376,13 @@ string FilePathBasename(const FileDescriptor* file) {
   return output;
 }
 
-string FileClassPrefix(const FileDescriptor* file) {
-  // Default is empty string, no need to check has_objc_class_prefix.
-  string result = file->options().objc_class_prefix();
-  return result;
-}
-
 string FileClassName(const FileDescriptor* file) {
   string name = FileClassPrefix(file);
   name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
   name += "Root";
   // There aren't really any reserved words that end in "Root", but playing
   // it safe and checking.
-  return SanitizeNameForObjC(name, "_RootClass");
+  return SanitizeNameForObjC(name, "_RootClass", NULL);
 }
 
 string ClassNameWorker(const Descriptor* descriptor) {
@@ -400,11 +404,15 @@ string ClassNameWorker(const EnumDescriptor* descriptor) {
 }
 
 string ClassName(const Descriptor* descriptor) {
+  return ClassName(descriptor, NULL);
+}
+
+string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
   // 1. Message names are used as is (style calls for CamelCase, trust it).
   // 2. Check for reserved word at the very end and then suffix things.
   string prefix = FileClassPrefix(descriptor->file());
   string name = ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(prefix + name, "_Class");
+  return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added);
 }
 
 string EnumName(const EnumDescriptor* descriptor) {
@@ -418,7 +426,7 @@ string EnumName(const EnumDescriptor* descriptor) {
   //    yields Fixed_Class, Fixed_Size.
   string name = FileClassPrefix(descriptor->file());
   name += ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(name, "_Enum");
+  return SanitizeNameForObjC(name, "_Enum", NULL);
 }
 
 string EnumValueName(const EnumValueDescriptor* descriptor) {
@@ -433,7 +441,7 @@ string EnumValueName(const EnumValueDescriptor* descriptor) {
   const string& name = class_name + "_" + value_str;
   // There aren't really any reserved words with an underscore and a leading
   // capital letter, but playing it safe and checking.
-  return SanitizeNameForObjC(name, "_Value");
+  return SanitizeNameForObjC(name, "_Value", NULL);
 }
 
 string EnumValueShortName(const EnumValueDescriptor* descriptor) {
@@ -470,7 +478,7 @@ string UnCamelCaseEnumShortName(const string& name) {
 string ExtensionMethodName(const FieldDescriptor* descriptor) {
   const string& name = NameFromFieldDescriptor(descriptor);
   const string& result = UnderscoresToCamelCase(name, false);
-  return SanitizeNameForObjC(result, "_Extension");
+  return SanitizeNameForObjC(result, "_Extension", NULL);
 }
 
 string FieldName(const FieldDescriptor* field) {
@@ -485,7 +493,7 @@ string FieldName(const FieldDescriptor* field) {
       result += "_p";
     }
   }
-  return SanitizeNameForObjC(result, "_p");
+  return SanitizeNameForObjC(result, "_p", NULL);
 }
 
 string FieldNameCapitalized(const FieldDescriptor* field) {

+ 4 - 0
src/google/protobuf/compiler/objectivec/objectivec_helpers.h

@@ -67,6 +67,9 @@ bool IsRetainedName(const string& name);
 // handling under ARC.
 bool IsInitName(const string& name);
 
+// Gets the objc_class_prefix.
+string FileClassPrefix(const FileDescriptor* file);
+
 // Gets the path of the file we're going to generate (sans the .pb.h
 // extension).  The path will be dependent on the objectivec package
 // declared in the proto package.
@@ -83,6 +86,7 @@ string FileClassName(const FileDescriptor* file);
 // These return the fully-qualified class name corresponding to the given
 // descriptor.
 string ClassName(const Descriptor* descriptor);
+string ClassName(const Descriptor* descriptor, string* out_suffix_added);
 string EnumName(const EnumDescriptor* descriptor);
 
 // Returns the fully-qualified name of the enum value corresponding to the

+ 13 - 0
src/google/protobuf/compiler/objectivec/objectivec_message.cc

@@ -580,6 +580,19 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
           "    [localDescriptor setupExtensionRanges:ranges\n"
           "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
     }
+    if (descriptor_->containing_type() != NULL) {
+      string parent_class_name = ClassName(descriptor_->containing_type());
+      printer->Print(
+          "    [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
+          "parent_name", parent_class_name);
+    }
+    string suffix_added;
+    ClassName(descriptor_, &suffix_added);
+    if (suffix_added.size() > 0) {
+      printer->Print(
+          "    [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
+          "suffix", suffix_added);
+    }
     printer->Print(
         "    NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
         "    descriptor = localDescriptor;\n"

+ 6 - 6
src/google/protobuf/compiler/subprocess.cc

@@ -261,12 +261,12 @@ string Subprocess::Win32ErrorMessage(DWORD error_code) {
   char* message;
 
   // WTF?
-  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                FORMAT_MESSAGE_FROM_SYSTEM |
-                FORMAT_MESSAGE_IGNORE_INSERTS,
-                NULL, error_code, 0,
-                (LPTSTR)&message,  // NOT A BUG!
-                0, NULL);
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                 FORMAT_MESSAGE_FROM_SYSTEM |
+                 FORMAT_MESSAGE_IGNORE_INSERTS,
+                 NULL, error_code, 0,
+                 (LPSTR)&message,  // NOT A BUG!
+                 0, NULL);
 
   string result = message;
   LocalFree(message);

+ 8 - 8
src/google/protobuf/testing/file.cc

@@ -141,12 +141,12 @@ void File::DeleteRecursively(const string& name,
 
 #ifdef _MSC_VER
   // This interface is so weird.
-  WIN32_FIND_DATA find_data;
-  HANDLE find_handle = FindFirstFile((name + "/*").c_str(), &find_data);
+  WIN32_FIND_DATAA find_data;
+  HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data);
   if (find_handle == INVALID_HANDLE_VALUE) {
     // Just delete it, whatever it is.
-    DeleteFile(name.c_str());
-    RemoveDirectory(name.c_str());
+    DeleteFileA(name.c_str());
+    RemoveDirectoryA(name.c_str());
     return;
   }
 
@@ -156,15 +156,15 @@ void File::DeleteRecursively(const string& name,
       string path = name + "/" + entry_name;
       if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
         DeleteRecursively(path, NULL, NULL);
-        RemoveDirectory(path.c_str());
+        RemoveDirectoryA(path.c_str());
       } else {
-        DeleteFile(path.c_str());
+        DeleteFileA(path.c_str());
       }
     }
-  } while(FindNextFile(find_handle, &find_data));
+  } while(FindNextFileA(find_handle, &find_data));
   FindClose(find_handle);
 
-  RemoveDirectory(name.c_str());
+  RemoveDirectoryA(name.c_str());
 #else
   // Use opendir()!  Yay!
   // lstat = Don't follow symbolic links.