Add android.util.proto package as an @TestApi.

The classes there add a way for the platform to write out
protocol buffers that doesn't require lots of small objects,
generate code, and extra copying.

Includes the plugin for protoc to generate the constants.

Test: proto cts tests

Change-Id: I6385c198cecda9ac6fa533151609e3ace341af01
diff --git a/tools/streaming_proto/main.cpp b/tools/streaming_proto/main.cpp
new file mode 100644
index 0000000..d286213
--- /dev/null
+++ b/tools/streaming_proto/main.cpp
@@ -0,0 +1,391 @@
+#include "Errors.h"
+
+#include "string_utils.h"
+
+#include "google/protobuf/compiler/plugin.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+#include "google/protobuf/text_format.h"
+
+#include <stdio.h>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <map>
+
+using namespace android::javastream_proto;
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace google::protobuf::io;
+using namespace std;
+
+const int FIELD_TYPE_SHIFT = 32;
+const uint64_t FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+
+const int FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
+
+
+/**
+ * See if this is the file for this request, and not one of the imported ones.
+ */
+static bool
+should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
+{
+    const int N = request.file_to_generate_size();
+    for (int i=0; i<N; i++) {
+        if (request.file_to_generate(i) == file) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * If the descriptor gives us a class name, use that. Otherwise make one up from
+ * the filename of the .proto file.
+ */
+static string
+make_outer_class_name(const FileDescriptorProto& file_descriptor)
+{
+    string name = file_descriptor.options().java_outer_classname();
+    if (name.size() == 0) {
+        name = to_camel_case(file_base_name(file_descriptor.name()));
+        if (name.size() == 0) {
+            ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE,
+                    "Unable to make an outer class name for file: %s",
+                    file_descriptor.name().c_str());
+            name = "Unknown";
+        }
+    }
+    return name;
+}
+
+/**
+ * Figure out the package name that we are generating.
+ */
+static string
+make_java_package(const FileDescriptorProto& file_descriptor) {
+    if (file_descriptor.options().has_java_package()) {
+        return file_descriptor.options().java_package();
+    } else {
+        return file_descriptor.package();
+    }
+}
+
+/**
+ * Figure out the name of the file we are generating.
+ */
+static string
+make_file_name(const FileDescriptorProto& file_descriptor)
+{
+    string const package = make_java_package(file_descriptor);
+    string result;
+    if (package.size() > 0) {
+        result = replace_string(package, '.', '/');
+        result += '/';
+    }
+
+    result += make_outer_class_name(file_descriptor);
+    result += ".java";
+
+    return result;
+}
+
+static string
+indent_more(const string& indent)
+{
+    return indent + "    ";
+}
+
+/**
+ * Write the constants for an enum.
+ */
+static void
+write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
+{
+    const int N = enu.value_size();
+    text << indent << "// enum " << enu.name() << endl;
+    for (int i=0; i<N; i++) {
+        const EnumValueDescriptorProto& value = enu.value(i);
+        text << indent << "public static final int "
+                << make_constant_name(value.name())
+                << " = " << value.number() << ";" << endl;
+    }
+    text << endl;
+}
+
+/**
+ * Get the string name for a field.
+ */
+static string
+get_proto_type(const FieldDescriptorProto& field)
+{
+    switch (field.type()) {
+        case FieldDescriptorProto::TYPE_DOUBLE:
+            return "double";
+        case FieldDescriptorProto::TYPE_FLOAT:
+            return "float";
+        case FieldDescriptorProto::TYPE_INT64:
+            return "int64";
+        case FieldDescriptorProto::TYPE_UINT64:
+            return "uint64";
+        case FieldDescriptorProto::TYPE_INT32:
+            return "int32";
+        case FieldDescriptorProto::TYPE_FIXED64:
+            return "fixed64";
+        case FieldDescriptorProto::TYPE_FIXED32:
+            return "fixed32";
+        case FieldDescriptorProto::TYPE_BOOL:
+            return "bool";
+        case FieldDescriptorProto::TYPE_STRING:
+            return "string";
+        case FieldDescriptorProto::TYPE_GROUP:
+            return "group<unsupported!>";
+        case FieldDescriptorProto::TYPE_MESSAGE:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_BYTES:
+            return "bytes";
+        case FieldDescriptorProto::TYPE_UINT32:
+            return "uint32";
+        case FieldDescriptorProto::TYPE_ENUM:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_SFIXED32:
+            return "sfixed32";
+        case FieldDescriptorProto::TYPE_SFIXED64:
+            return "sfixed64";
+        case FieldDescriptorProto::TYPE_SINT32:
+            return "sint32";
+        case FieldDescriptorProto::TYPE_SINT64:
+            return "sint64";
+        default:
+            // won't happen
+            return "void";
+    }
+}
+
+static uint64_t
+get_field_id(const FieldDescriptorProto& field)
+{
+    // Number
+    uint64_t result = (uint32_t)field.number();
+
+    // Type
+    switch (field.type()) {
+        case FieldDescriptorProto::TYPE_DOUBLE:
+            result |= FIELD_TYPE_DOUBLE;
+        case FieldDescriptorProto::TYPE_FLOAT:
+            result |= FIELD_TYPE_FLOAT;
+        case FieldDescriptorProto::TYPE_INT64:
+            result |= FIELD_TYPE_INT64;
+        case FieldDescriptorProto::TYPE_UINT64:
+            result |= FIELD_TYPE_UINT64;
+        case FieldDescriptorProto::TYPE_INT32:
+            result |= FIELD_TYPE_INT32;
+        case FieldDescriptorProto::TYPE_FIXED64:
+            result |= FIELD_TYPE_FIXED64;
+        case FieldDescriptorProto::TYPE_FIXED32:
+            result |= FIELD_TYPE_FIXED32;
+        case FieldDescriptorProto::TYPE_BOOL:
+            result |= FIELD_TYPE_BOOL;
+        case FieldDescriptorProto::TYPE_STRING:
+            result |= FIELD_TYPE_STRING;
+        case FieldDescriptorProto::TYPE_MESSAGE:
+            result |= FIELD_TYPE_OBJECT;
+        case FieldDescriptorProto::TYPE_BYTES:
+            result |= FIELD_TYPE_BYTES;
+        case FieldDescriptorProto::TYPE_UINT32:
+            result |= FIELD_TYPE_UINT32;
+        case FieldDescriptorProto::TYPE_ENUM:
+            result |= FIELD_TYPE_ENUM;
+        case FieldDescriptorProto::TYPE_SFIXED32:
+            result |= FIELD_TYPE_SFIXED32;
+        case FieldDescriptorProto::TYPE_SFIXED64:
+            result |= FIELD_TYPE_SFIXED64;
+        case FieldDescriptorProto::TYPE_SINT32:
+            result |= FIELD_TYPE_SINT32;
+        case FieldDescriptorProto::TYPE_SINT64:
+            result |= FIELD_TYPE_SINT64;
+        default:
+            ;
+    }
+
+    // Count
+    if (field.options().packed()) {
+        result |= FIELD_COUNT_PACKED;
+    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
+        result |= FIELD_COUNT_REPEATED;
+    } else {
+        result |= FIELD_COUNT_SINGLE;
+    }
+
+    return result;
+}
+
+/**
+ * Write a field.
+ */
+static void
+write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
+{
+    string optional_comment = field.label() == FieldDescriptorProto::LABEL_OPTIONAL
+            ? "optional " : "";
+    string repeated_comment = field.label() == FieldDescriptorProto::LABEL_REPEATED
+            ? "repeated " : "";
+    string proto_type = get_proto_type(field);
+    string packed_comment = field.options().packed()
+            ? " [packed=true]" : "";
+    text << indent << "// " << optional_comment << repeated_comment << proto_type << ' '
+            << field.name() << " = " << field.number() << packed_comment << ';' << endl;
+
+    text << indent << "public static final long " << make_constant_name(field.name()) << " = 0x";
+
+    ios::fmtflags fmt(text.flags());
+    text << setfill('0') << setw(16) << hex << get_field_id(field);
+    text.flags(fmt);
+
+    text << "L;" << endl;
+
+    text << endl;
+}
+
+/**
+ * Write a Message constants class.
+ */
+static void
+write_message(stringstream& text, const DescriptorProto& message, const string& indent)
+{
+    int N;
+    const string indented = indent_more(indent);
+
+    text << indent << "// message " << message.name() << endl;
+    text << indent << "public final class " << message.name() << " {" << endl;
+    text << endl;
+
+    // Enums
+    N = message.enum_type_size();
+    for (int i=0; i<N; i++) {
+        write_enum(text, message.enum_type(i), indented);
+    }
+
+    // Nested classes
+    N = message.nested_type_size();
+    for (int i=0; i<N; i++) {
+        write_message(text, message.nested_type(i), indented);
+    }
+
+    // Fields
+    N = message.field_size();
+    for (int i=0; i<N; i++) {
+        write_field(text, message.field(i), indented);
+    }
+
+    text << indent << "}" << endl;
+    text << endl;
+}
+
+/**
+ * Write the contents of a file.
+ */
+static void
+write_file(stringstream& text, const FileDescriptorProto& file_descriptor)
+{
+    string const package_name = make_java_package(file_descriptor);
+    string const outer_class_name = make_outer_class_name(file_descriptor);
+
+    text << "// Generated by protoc-gen-javastream. DO NOT MODIFY." << endl;
+    text << "// source: " << file_descriptor.name() << endl << endl;
+
+    if (package_name.size() > 0) {
+        if (package_name.size() > 0) {
+            text << "package " << package_name << ";" << endl;
+            text << endl;
+        }
+    }
+
+    // This bit of policy is android api rules specific: Raw proto classes
+    // must never be in the API, but they should all be available for testing.
+    text << "/** @hide */" << endl;
+    text << "@android.annotation.TestApi" << endl;
+
+    text << "public final class " << outer_class_name << " {" << endl;
+    text << endl;
+
+    int N;
+    const string indented = indent_more("");
+    
+    N = file_descriptor.enum_type_size();
+    for (int i=0; i<N; i++) {
+        write_enum(text, file_descriptor.enum_type(i), indented);
+    }
+
+    N = file_descriptor.message_type_size();
+    for (int i=0; i<N; i++) {
+        write_message(text, file_descriptor.message_type(i), indented);
+    }
+
+    text << "}" << endl;
+}
+
+/**
+ * Main.
+ */
+int
+main(int argc, char const*const* argv)
+{
+    (void)argc;
+    (void)argv;
+
+    GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+    CodeGeneratorRequest request;
+    CodeGeneratorResponse response;
+
+    // Read the request
+    request.ParseFromIstream(&cin);
+
+    // Build the files we need.
+    const int N = request.proto_file_size();
+    for (int i=0; i<N; i++) {
+        const FileDescriptorProto& file_descriptor = request.proto_file(i);
+        if (should_generate_for_file(request, file_descriptor.name())) {
+            // Generate the text
+            stringstream text;
+            write_file(text, file_descriptor);
+
+            // Put the text in the response
+            CodeGeneratorResponse::File* file_response = response.add_file();
+            file_response->set_name(make_file_name(file_descriptor));
+            file_response->set_content(text.str());
+
+            cerr << "writing file: " << file_response->name() << endl;
+        }
+    }
+
+    // If we had errors, don't write the response. Print the errors and exit.
+    if (ERRORS.HasErrors()) {
+        ERRORS.Print();
+        return 1;
+    }
+
+    // If we didn't have errors, write the response and exit happily.
+    response.SerializeToOstream(&cout);
+    return 0;
+}