generators: Remove dependency on protos strutil.h

The strutil.h header is not part of the protobuf API
and is removed from later version of protobuf.
Use base::StringUtils instead. Change is reasonably
safe as it affects only tools used at build-time
(the protobuf generators).

Bug: 140126865
Test: check 0-diff in out/xxx/gen/
Change-Id: Iacd1340183e92a6d10f0d033de16bc75ed39013d
diff --git a/Android.bp b/Android.bp
index 73cbcec..5d6e701 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3689,6 +3689,23 @@
 cc_binary_host {
   name: "perfetto_src_ipc_protoc_plugin_ipc_plugin___gn_standalone_toolchain_gcc_like_host_",
   srcs: [
+    "src/base/event_fd.cc",
+    "src/base/file_utils.cc",
+    "src/base/metatrace.cc",
+    "src/base/paged_memory.cc",
+    "src/base/pipe.cc",
+    "src/base/string_splitter.cc",
+    "src/base/string_utils.cc",
+    "src/base/string_view.cc",
+    "src/base/temp_file.cc",
+    "src/base/thread_checker.cc",
+    "src/base/thread_task_runner.cc",
+    "src/base/time.cc",
+    "src/base/unix_task_runner.cc",
+    "src/base/uuid.cc",
+    "src/base/virtual_destructors.cc",
+    "src/base/waitable_event.cc",
+    "src/base/watchdog_posix.cc",
     "src/ipc/protoc_plugin/ipc_plugin.cc",
   ],
   shared_libs: [
@@ -3791,6 +3808,23 @@
 cc_binary_host {
   name: "perfetto_src_protozero_protoc_plugin_protozero_plugin___gn_standalone_toolchain_gcc_like_host_",
   srcs: [
+    "src/base/event_fd.cc",
+    "src/base/file_utils.cc",
+    "src/base/metatrace.cc",
+    "src/base/paged_memory.cc",
+    "src/base/pipe.cc",
+    "src/base/string_splitter.cc",
+    "src/base/string_utils.cc",
+    "src/base/string_view.cc",
+    "src/base/temp_file.cc",
+    "src/base/thread_checker.cc",
+    "src/base/thread_task_runner.cc",
+    "src/base/time.cc",
+    "src/base/unix_task_runner.cc",
+    "src/base/uuid.cc",
+    "src/base/virtual_destructors.cc",
+    "src/base/waitable_event.cc",
+    "src/base/watchdog_posix.cc",
     "src/protozero/protoc_plugin/protozero_plugin.cc",
   ],
   shared_libs: [
diff --git a/BUILD b/BUILD
index d74fa36..63f5d79 100644
--- a/BUILD
+++ b/BUILD
@@ -270,6 +270,64 @@
 cc_binary(
     name = "src_protozero_protoc_plugin_protozero_plugin",
     srcs = [
+        "include/perfetto/base/build_config.h",
+        "include/perfetto/base/build_configs/bazel/perfetto_build_flags.h",
+        "include/perfetto/base/compiler.h",
+        "include/perfetto/base/copyable_ptr.h",
+        "include/perfetto/base/export.h",
+        "include/perfetto/base/logging.h",
+        "include/perfetto/base/task_runner.h",
+        "include/perfetto/base/time.h",
+        "include/perfetto/ext/base/circular_queue.h",
+        "include/perfetto/ext/base/container_annotations.h",
+        "include/perfetto/ext/base/event_fd.h",
+        "include/perfetto/ext/base/file_utils.h",
+        "include/perfetto/ext/base/hash.h",
+        "include/perfetto/ext/base/lookup_set.h",
+        "include/perfetto/ext/base/metatrace.h",
+        "include/perfetto/ext/base/metatrace_events.h",
+        "include/perfetto/ext/base/no_destructor.h",
+        "include/perfetto/ext/base/optional.h",
+        "include/perfetto/ext/base/paged_memory.h",
+        "include/perfetto/ext/base/pipe.h",
+        "include/perfetto/ext/base/proc_utils.h",
+        "include/perfetto/ext/base/scoped_file.h",
+        "include/perfetto/ext/base/small_set.h",
+        "include/perfetto/ext/base/string_splitter.h",
+        "include/perfetto/ext/base/string_utils.h",
+        "include/perfetto/ext/base/string_view.h",
+        "include/perfetto/ext/base/string_writer.h",
+        "include/perfetto/ext/base/temp_file.h",
+        "include/perfetto/ext/base/thread_annotations.h",
+        "include/perfetto/ext/base/thread_checker.h",
+        "include/perfetto/ext/base/thread_task_runner.h",
+        "include/perfetto/ext/base/thread_utils.h",
+        "include/perfetto/ext/base/unix_socket.h",
+        "include/perfetto/ext/base/unix_task_runner.h",
+        "include/perfetto/ext/base/utils.h",
+        "include/perfetto/ext/base/uuid.h",
+        "include/perfetto/ext/base/waitable_event.h",
+        "include/perfetto/ext/base/watchdog.h",
+        "include/perfetto/ext/base/watchdog_noop.h",
+        "include/perfetto/ext/base/watchdog_posix.h",
+        "include/perfetto/ext/base/weak_ptr.h",
+        "src/base/event_fd.cc",
+        "src/base/file_utils.cc",
+        "src/base/metatrace.cc",
+        "src/base/paged_memory.cc",
+        "src/base/pipe.cc",
+        "src/base/string_splitter.cc",
+        "src/base/string_utils.cc",
+        "src/base/string_view.cc",
+        "src/base/temp_file.cc",
+        "src/base/thread_checker.cc",
+        "src/base/thread_task_runner.cc",
+        "src/base/time.cc",
+        "src/base/unix_task_runner.cc",
+        "src/base/uuid.cc",
+        "src/base/virtual_destructors.cc",
+        "src/base/waitable_event.cc",
+        "src/base/watchdog_posix.cc",
         "src/protozero/protoc_plugin/protozero_plugin.cc",
     ],
     deps = [
diff --git a/include/perfetto/ext/base/string_utils.h b/include/perfetto/ext/base/string_utils.h
index 3220a69..21a7555 100644
--- a/include/perfetto/ext/base/string_utils.h
+++ b/include/perfetto/ext/base/string_utils.h
@@ -31,6 +31,12 @@
                  const std::string& delim);
 std::vector<std::string> SplitString(const std::string& text,
                                      const std::string& delimiter);
+std::string StripPrefix(const std::string& str, const std::string& prefix);
+std::string StripSuffix(const std::string& str, const std::string& suffix);
+std::string ToUpper(const std::string& str);
+std::string StripChars(const std::string& str,
+                       const std::string& chars,
+                       char replacement);
 
 }  // namespace base
 }  // namespace perfetto
diff --git a/src/base/string_utils.cc b/src/base/string_utils.cc
index e5b7c4e..fa4d646 100644
--- a/src/base/string_utils.cc
+++ b/src/base/string_utils.cc
@@ -16,6 +16,8 @@
 
 #include "perfetto/ext/base/string_utils.h"
 
+#include <string.h>
+
 #include <algorithm>
 
 #include "perfetto/base/logging.h"
@@ -64,7 +66,8 @@
   size_t next;
   for (;;) {
     next = std::min(text.find(delimiter, start), text.size());
-    output.emplace_back(&text[start], next - start);
+    if (next > start)
+      output.emplace_back(&text[start], next - start);
     start = next + delimiter.size();
     if (start >= text.size())
       break;
@@ -72,5 +75,34 @@
   return output;
 }
 
+std::string StripPrefix(const std::string& str, const std::string& prefix) {
+  return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
+}
+
+std::string StripSuffix(const std::string& str, const std::string& suffix) {
+  return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
+                               : str;
+}
+
+std::string ToUpper(const std::string& str) {
+  // Don't use toupper(), it depends on the locale.
+  std::string res(str);
+  auto end = res.end();
+  for (auto c = res.begin(); c != end; ++c)
+    *c = ('a' <= *c && *c <= 'z') ? (*c += 'A' - 'a') : *c;
+  return res;
+}
+
+std::string StripChars(const std::string& str,
+                       const std::string& chars,
+                       char replacement) {
+  std::string res(str);
+  const char* start = res.c_str();
+  const char* remove = chars.c_str();
+  for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
+    res[static_cast<uintptr_t>(c - start)] = replacement;
+  return res;
+}
+
 }  // namespace base
 }  // namespace perfetto
diff --git a/src/base/string_utils_unittest.cc b/src/base/string_utils_unittest.cc
index 58d0262..ea9ac01 100644
--- a/src/base/string_utils_unittest.cc
+++ b/src/base/string_utils_unittest.cc
@@ -55,15 +55,38 @@
 }
 
 TEST(StringUtilsTest, SplitString) {
-  EXPECT_THAT(SplitString("", ":"), ElementsAre(""));
+  EXPECT_THAT(SplitString("", ":"), ElementsAre());
   EXPECT_THAT(SplitString("a:b:c", ":"), ElementsAre("a", "b", "c"));
   EXPECT_THAT(SplitString("a::b::c", "::"), ElementsAre("a", "b", "c"));
+  EXPECT_THAT(SplitString("::::a::b::::c::", "::"), ElementsAre("a", "b", "c"));
   EXPECT_THAT(SplitString("abc", ":"), ElementsAre("abc"));
   EXPECT_THAT(SplitString("abc", "::"), ElementsAre("abc"));
   EXPECT_THAT(SplitString("abc", ":"), ElementsAre("abc"));
   EXPECT_THAT(SplitString("abc", "::"), ElementsAre("abc"));
 }
 
+TEST(StringUtilsTest, Strip) {
+  EXPECT_EQ(StripPrefix("abc", ""), "abc");
+  EXPECT_EQ(StripPrefix("abc", "a"), "bc");
+  EXPECT_EQ(StripPrefix("abc", "ab"), "c");
+  EXPECT_EQ(StripPrefix("abc", "abc"), "");
+  EXPECT_EQ(StripPrefix("abc", "abcd"), "abc");
+
+  EXPECT_EQ(StripSuffix("abc", ""), "abc");
+  EXPECT_EQ(StripSuffix("abc", "c"), "ab");
+  EXPECT_EQ(StripSuffix("abc", "bc"), "a");
+  EXPECT_EQ(StripSuffix("abc", "abc"), "");
+  EXPECT_EQ(StripSuffix("abc", "ebcd"), "abc");
+
+  EXPECT_EQ(StripChars("foobar", "", '_'), "foobar");
+  EXPECT_EQ(StripChars("foobar", "x", '_'), "foobar");
+  EXPECT_EQ(StripChars("foobar", "f", '_'), "_oobar");
+  EXPECT_EQ(StripChars("foobar", "o", '_'), "f__bar");
+  EXPECT_EQ(StripChars("foobar", "oa", '_'), "f__b_r");
+  EXPECT_EQ(StripChars("foobar", "fbr", '_'), "_oo_a_");
+  EXPECT_EQ(StripChars("foobar", "froab", '_'), "______");
+}
+
 }  // namespace
 }  // namespace base
 }  // namespace perfetto
diff --git a/src/ipc/protoc_plugin/BUILD.gn b/src/ipc/protoc_plugin/BUILD.gn
index 4478f60..535f53a 100644
--- a/src/ipc/protoc_plugin/BUILD.gn
+++ b/src/ipc/protoc_plugin/BUILD.gn
@@ -21,5 +21,6 @@
   deps = [
     "../../../gn:default_deps",
     "../../../gn:protoc_lib",
+    "../../../src/base",
   ]
 }
diff --git a/src/ipc/protoc_plugin/ipc_plugin.cc b/src/ipc/protoc_plugin/ipc_plugin.cc
index 064e4cd..f3a4372 100644
--- a/src/ipc/protoc_plugin/ipc_plugin.cc
+++ b/src/ipc/protoc_plugin/ipc_plugin.cc
@@ -20,13 +20,13 @@
 #include <string>
 
 #include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/compiler/plugin.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/stubs/strutil.h>
+
+#include "perfetto/ext/base/string_utils.h"
 
 namespace perfetto {
 namespace ipc {
@@ -35,13 +35,13 @@
 using google::protobuf::FileDescriptor;
 using google::protobuf::MethodDescriptor;
 using google::protobuf::ServiceDescriptor;
-using google::protobuf::Split;
-using google::protobuf::StripString;
-using google::protobuf::StripSuffixString;
-using google::protobuf::UpperString;
 using google::protobuf::compiler::GeneratorContext;
 using google::protobuf::io::Printer;
 using google::protobuf::io::ZeroCopyOutputStream;
+using perfetto::base::SplitString;
+using perfetto::base::StripChars;
+using perfetto::base::StripSuffix;
+using perfetto::base::ToUpper;
 
 static const char kBanner[] = "// DO NOT EDIT. Autogenerated by Perfetto IPC\n";
 
@@ -113,7 +113,7 @@
 )";
 
 std::string StripName(const FileDescriptor& file) {
-  return StripSuffixString(file.name(), ".proto");
+  return StripSuffix(file.name(), ".proto");
 }
 
 std::string GetStubName(const FileDescriptor& file) {
@@ -138,7 +138,7 @@
                            const ServiceDescriptor& svc,
                            Printer* printer) {
   printer->Print("\n");
-  std::vector<std::string> namespaces = Split(file.package(), ".");
+  std::vector<std::string> namespaces = SplitString(file.package(), ".");
   for (const std::string& ns : namespaces)
     printer->Print("namespace $ns$ {\n", "ns", ns);
 
@@ -185,7 +185,7 @@
                         Printer* printer) {
   printer->Print("\n");
 
-  std::vector<std::string> namespaces = Split(file.package(), ".");
+  std::vector<std::string> namespaces = SplitString(file.package(), ".");
   for (const std::string& ns : namespaces)
     printer->Print("namespace $ns$ {\n", "ns", ns);
 
@@ -251,9 +251,8 @@
   Printer h_printer(h_fstream.get(), '$');
   Printer cc_printer(cc_fstream.get(), '$');
 
-  std::string guard = file->package() + "_" + file->name() + "_H_";
-  UpperString(&guard);
-  StripString(&guard, ".-/\\", '_');
+  std::string guard = ToUpper(file->package() + "_" + file->name() + "_H_");
+  guard = StripChars(guard, ".-/\\", '_');
 
   h_printer.Print(kBanner);
   h_printer.Print("#ifndef $guard$\n#define $guard$\n\n", "guard", guard);
diff --git a/src/protozero/protoc_plugin/BUILD.gn b/src/protozero/protoc_plugin/BUILD.gn
index 9cec6b8..432abd8 100644
--- a/src/protozero/protoc_plugin/BUILD.gn
+++ b/src/protozero/protoc_plugin/BUILD.gn
@@ -21,5 +21,6 @@
   deps = [
     "../../../gn:default_deps",
     "../../../gn:protoc_lib",
+    "../../../src/base",
   ]
 }
diff --git a/src/protozero/protoc_plugin/protozero_plugin.cc b/src/protozero/protoc_plugin/protozero_plugin.cc
index 08d985f..c88e328 100644
--- a/src/protozero/protoc_plugin/protozero_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_plugin.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <limits>
 #include <map>
 #include <memory>
 #include <set>
@@ -24,7 +25,8 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/stubs/strutil.h>
+
+#include "perfetto/ext/base/string_utils.h"
 
 namespace protozero {
 namespace {
@@ -34,14 +36,14 @@
 using google::protobuf::EnumValueDescriptor;
 using google::protobuf::FieldDescriptor;
 using google::protobuf::FileDescriptor;
-using google::protobuf::Split;
-using google::protobuf::StripPrefixString;
-using google::protobuf::StripString;
-using google::protobuf::StripSuffixString;
-using google::protobuf::UpperString;
 using google::protobuf::compiler::GeneratorContext;
 using google::protobuf::io::Printer;
 using google::protobuf::io::ZeroCopyOutputStream;
+using perfetto::base::SplitString;
+using perfetto::base::StripChars;
+using perfetto::base::StripPrefix;
+using perfetto::base::StripSuffix;
+using perfetto::base::ToUpper;
 
 // Keep this value in sync with ProtoDecoder::kMaxDecoderFieldId. If they go out
 // of sync pbzero.h files will stop compiling, hitting the at() static_assert.
@@ -78,7 +80,7 @@
 };
 
 inline std::string ProtoStubName(const FileDescriptor* proto) {
-  return StripSuffixString(proto->name(), ".proto") + ".pbzero";
+  return StripSuffix(proto->name(), ".proto") + ".pbzero";
 }
 
 class GeneratorJob {
@@ -120,7 +122,7 @@
   template <class T>
   inline std::string GetDescriptorName(const T* descriptor) {
     if (!package_.empty()) {
-      return StripPrefixString(descriptor->full_name(), package_ + ".");
+      return StripPrefix(descriptor->full_name(), package_ + ".");
     } else {
       return descriptor->full_name();
     }
@@ -131,8 +133,7 @@
   // prohibited but not recommended in order to avoid name collisions.
   template <class T>
   inline std::string GetCppClassName(const T* descriptor, bool full = false) {
-    std::string name = GetDescriptorName(descriptor);
-    StripString(&name, ".", '_');
+    std::string name = StripChars(GetDescriptorName(descriptor), ".", '_');
     if (full)
       name = full_namespace_prefix_ + name;
     return name;
@@ -322,7 +323,7 @@
   void Preprocess() {
     // Package name maps to a series of namespaces.
     package_ = source_->package();
-    namespaces_ = Split(package_, ".");
+    namespaces_ = SplitString(package_, ".");
     if (!wrapper_namespace_.empty())
       namespaces_.push_back(wrapper_namespace_);
 
@@ -339,8 +340,8 @@
     std::string greeting =
         "// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.\n";
     std::string guard = package_ + "_" + source_->name() + "_H_";
-    UpperString(&guard);
-    StripString(&guard, ".-/\\", '_');
+    guard = ToUpper(guard);
+    guard = StripChars(guard, ".-/\\", '_');
 
     stub_h_->Print(
         "$greeting$\n"
@@ -827,8 +828,8 @@
   stub_cc_printer.Print("// Intentionally empty (crbug.com/998165)\n");
 
   // Parse additional options.
-  for (const std::string& option : Split(options, ",")) {
-    std::vector<std::string> option_pair = Split(option, "=");
+  for (const std::string& option : SplitString(options, ",")) {
+    std::vector<std::string> option_pair = SplitString(option, "=");
     job.SetOption(option_pair[0], option_pair[1]);
   }
 
diff --git a/tools/proto_to_cpp/proto_to_cpp.cc b/tools/proto_to_cpp/proto_to_cpp.cc
index 8bb103c..5e995f2 100644
--- a/tools/proto_to_cpp/proto_to_cpp.cc
+++ b/tools/proto_to_cpp/proto_to_cpp.cc
@@ -18,7 +18,6 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/util/field_comparator.h>
 #include <google/protobuf/util/message_differencer.h>
 
@@ -28,10 +27,16 @@
 #include <iostream>
 
 #include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
 
 using namespace google::protobuf;
 using namespace google::protobuf::compiler;
 using namespace google::protobuf::io;
+using perfetto::base::SplitString;
+using perfetto::base::StripChars;
+using perfetto::base::StripSuffix;
+using perfetto::base::ToUpper;
+
 static constexpr auto TYPE_MESSAGE = FieldDescriptor::TYPE_MESSAGE;
 
 namespace {
@@ -81,7 +86,7 @@
 };
 
 std::string GetProtoHeader(const FileDescriptor* proto_file) {
-  return StringReplace(proto_file->name(), ".proto", ".pb.h", false);
+  return StripSuffix(proto_file->name(), ".proto") + ".pb.h";
 }
 
 std::string GetFwdDeclType(const Descriptor* msg, bool with_namespace = false) {
@@ -92,7 +97,8 @@
     full_type.insert(0, par->name() + "_");
   }
   if (with_namespace) {
-    std::vector<std::string> namespaces = Split(msg->file()->package(), ".");
+    std::vector<std::string> namespaces =
+        SplitString(msg->file()->package(), ".");
     for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) {
       full_type.insert(0, *it + "::");
     }
@@ -153,18 +159,18 @@
 }
 
 std::string ProtoToCpp::GetHeaderPath(const FileDescriptor* proto_file) {
-  std::string basename = Split(proto_file->name(), "/").back();
-  return header_dir_ + "/" + StringReplace(basename, ".proto", ".h", false);
+  std::string basename = SplitString(proto_file->name(), "/").back();
+  return header_dir_ + "/" + StripSuffix(basename, ".proto") + ".h";
 }
 
 std::string ProtoToCpp::GetCppPath(const FileDescriptor* proto_file) {
-  std::string basename = Split(proto_file->name(), "/").back();
-  return cpp_dir_ + "/" + StringReplace(basename, ".proto", ".cc", false);
+  std::string basename = SplitString(proto_file->name(), "/").back();
+  return cpp_dir_ + "/" + StripSuffix(basename, ".proto") + ".cc";
 }
 
 std::string ProtoToCpp::GetIncludePath(const FileDescriptor* proto_file) {
-  std::string basename = Split(proto_file->name(), "/").back();
-  return include_path_ + "/" + StringReplace(basename, ".proto", ".h", false);
+  std::string basename = SplitString(proto_file->name(), "/").back();
+  return include_path_ + "/" + StripSuffix(basename, ".proto") + ".h";
 }
 
 std::string ProtoToCpp::GetCppType(const FieldDescriptor* field,
@@ -228,8 +234,8 @@
   Printer cpp_printer(&cpp_proto_ostr, '$');
 
   std::string include_guard = dst_header + "_";
-  UpperString(&include_guard);
-  StripString(&include_guard, ".-/\\", '_');
+  include_guard = ToUpper(include_guard);
+  include_guard = StripChars(include_guard, ".-/\\", '_');
   header_printer.Print(kHeader, "f", __FILE__, "p", src_proto);
   header_printer.Print("#ifndef $g$\n#define $g$\n\n", "g", include_guard);
   header_printer.Print("#include <stdint.h>\n");
@@ -278,7 +284,7 @@
 
   // Generate forward declarations in the header for proto types.
   header_printer.Print("// Forward declarations for protobuf types.\n");
-  std::vector<std::string> namespaces = Split(proto_file->package(), ".");
+  std::vector<std::string> namespaces = SplitString(proto_file->package(), ".");
   for (size_t i = 0; i < namespaces.size(); i++)
     header_printer.Print("namespace $n$ {\n", "n", namespaces[i]);
   for (int i = 0; i < proto_file->message_type_count(); i++)