From 9b943b254bd5ebd87954a6a52a99da7816c95027 Mon Sep 17 00:00:00 2001
From: David Raila <raila@illinois.edu>
Date: Wed, 16 Jul 2008 02:00:27 +0000
Subject: [PATCH] Fix bytes type setter to work with byte sequences with
 embedded NULLs.

Patch from Alkis Evlogimenos <alkis@evlogimenos.com>.
---
 .../protobuf/compiler/cpp/cpp_string_field.cc | 77 ++++++++++++++-----
 .../protobuf/compiler/cpp/cpp_unittest.cc     | 13 ++++
 src/google/protobuf/descriptor.pb.h           |  8 +-
 3 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index de59ac8..e74eb43 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -96,8 +96,14 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 
   printer->Print(variables_,
     "inline const ::std::string& $name$() const;\n"
-    "inline void set_$name$(const ::std::string& value);\n"
-    "inline void set_$name$(const char* value);\n");
+    "inline void set_$name$(const ::std::string& value);\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
+    printer->Print(variables_,
+      "inline void set_$name$(const char* value, size_t size);\n");
+  } else {
+    printer->Print(variables_,
+      "inline void set_$name$(const char* value);\n");
+  }
 
   printer->Print(variables_,
     "inline ::std::string* mutable_$name$();\n");
@@ -121,14 +127,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(value);\n"
-    "}\n"
-    "inline void $classname$::set_$name$(const char* value) {\n"
-    "  _set_bit($index$);\n"
-    "  if ($name$_ == &_default_$name$_) {\n"
-    "    $name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $name$_->assign(value);\n"
     "}\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
+    printer->Print(variables_,
+      "inline void $classname$::set_$name$(const char* value, size_t size) {\n"
+      "  _set_bit($index$);\n"
+      "  if ($name$_ == &_default_$name$_) {\n"
+      "    $name$_ = new ::std::string;\n"
+      "  }\n"
+      "  $name$_->assign(value, size);\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "inline void $classname$::set_$name$(const char* value) {\n"
+      "  _set_bit($index$);\n"
+      "  if ($name$_ == &_default_$name$_) {\n"
+      "    $name$_ = new ::std::string;\n"
+      "  }\n"
+      "  $name$_->assign(value);\n"
+      "}\n");
+  }
+
   printer->Print(variables_,
     "inline ::std::string* $classname$::mutable_$name$() {\n"
     "  _set_bit($index$);\n"
@@ -245,10 +265,18 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
     "inline const ::std::string& $name$(int index) const;\n"
     "inline ::std::string* mutable_$name$(int index);\n"
     "inline void set_$name$(int index, const ::std::string& value);\n"
-    "inline void set_$name$(int index, const char* value);\n"
     "inline ::std::string* add_$name$();\n"
-    "inline void add_$name$(const ::std::string& value);\n"
-    "inline void add_$name$(const char* value);\n");
+    "inline void add_$name$(const ::std::string& value);\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
+    printer->Print(variables_,
+      "inline void set_$name$(int index, const char* value, size_t size);\n"
+      "inline void add_$name$(const char* value, size_t size);\n");
+  } else {
+    printer->Print(variables_,
+      "inline void set_$name$(int index, const char* value);\n"
+      "inline void add_$name$(const char* value);\n");
+  }
 
   if (descriptor_->options().has_ctype()) {
     printer->Outdent();
@@ -277,18 +305,31 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, const char* value) {\n"
-    "  $name$_.Mutable(index)->assign(value);\n"
-    "}\n"
     "inline ::std::string* $classname$::add_$name$() {\n"
     "  return $name$_.Add();\n"
     "}\n"
     "inline void $classname$::add_$name$(const ::std::string& value) {\n"
     "  $name$_.Add()->assign(value);\n"
-    "}\n"
-    "inline void $classname$::add_$name$(const char* value) {\n"
-    "  $name$_.Add()->assign(value);\n"
     "}\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
+    printer->Print(variables_,
+      "inline void "
+      "$classname$::set_$name$(int index, const char* value, size_t size) {\n"
+      "  $name$_.Mutable(index)->assign(value, size);\n"
+      "}\n"
+      "inline void $classname$::add_$name$(const char* value, size_t size) {\n"
+      "  $name$_.Add()->assign(value, size);\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "inline void $classname$::set_$name$(int index, const char* value) {\n"
+      "  $name$_.Mutable(index)->assign(value);\n"
+      "}\n"
+      "inline void $classname$::add_$name$(const char* value) {\n"
+      "  $name$_.Add()->assign(value);\n"
+      "}\n");
+  }
 }
 
 void RepeatedStringFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 8253242..561a5ad 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -172,6 +172,19 @@ TEST(GeneratedMessageTest, Clear) {
             &message.optional_import_message());
 }
 
+TEST(GeneratedMessageTest, EmbeddedNullsInBytesCharStar) {
+  unittest::TestAllTypes message;
+
+  const char* value = "\0lalala\0\0";
+  message.set_optional_bytes(value, 9);
+  ASSERT_EQ(9, message.optional_bytes().size());
+  EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9));
+
+  message.add_repeated_bytes(value, 9);
+  ASSERT_EQ(9, message.repeated_bytes(0).size());
+  EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9));
+}
+
 TEST(GeneratedMessageTest, ClearOneField) {
   // Set every field to a unique value, then clear one value and insure that
   // only that one value is cleared.
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 892f92d..27994dd 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -174,9 +174,9 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
   inline const ::std::string& dependency(int index) const;
   inline ::std::string* mutable_dependency(int index);
   inline void set_dependency(int index, const ::std::string& value);
-  inline void set_dependency(int index, const char* value);
   inline ::std::string* add_dependency();
   inline void add_dependency(const ::std::string& value);
+  inline void set_dependency(int index, const char* value);
   inline void add_dependency(const char* value);
   
   // repeated .google.protobuf.DescriptorProto message_type = 4;
@@ -1835,15 +1835,15 @@ inline ::std::string* FileDescriptorProto::mutable_dependency(int index) {
 inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
   dependency_.Mutable(index)->assign(value);
 }
-inline void FileDescriptorProto::set_dependency(int index, const char* value) {
-  dependency_.Mutable(index)->assign(value);
-}
 inline ::std::string* FileDescriptorProto::add_dependency() {
   return dependency_.Add();
 }
 inline void FileDescriptorProto::add_dependency(const ::std::string& value) {
   dependency_.Add()->assign(value);
 }
+inline void FileDescriptorProto::set_dependency(int index, const char* value) {
+  dependency_.Mutable(index)->assign(value);
+}
 inline void FileDescriptorProto::add_dependency(const char* value) {
   dependency_.Add()->assign(value);
 }
-- 
GitLab