1 // Copyright (c) 2009-2021, Google LLC
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above copyright
9 //       notice, this list of conditions and the following disclaimer in the
10 //       documentation and/or other materials provided with the distribution.
11 //     * Neither the name of Google LLC nor the
12 //       names of its contributors may be used to endorse or promote products
13 //       derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
19 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include <memory>
27 
28 #include "google/protobuf/descriptor.upb.h"
29 #include "upb/reflection/def.hpp"
30 #include "upb/util/def_to_proto.h"
31 #include "upbc/common.h"
32 #include "upbc/file_layout.h"
33 #include "upbc/plugin.h"
34 
35 namespace upbc {
36 namespace {
37 
DefInitSymbol(upb::FileDefPtr file)38 std::string DefInitSymbol(upb::FileDefPtr file) {
39   return ToCIdent(file.name()) + "_upbdefinit";
40 }
41 
DefHeaderFilename(upb::FileDefPtr file)42 static std::string DefHeaderFilename(upb::FileDefPtr file) {
43   return StripExtension(file.name()) + ".upbdefs.h";
44 }
45 
DefSourceFilename(upb::FileDefPtr file)46 static std::string DefSourceFilename(upb::FileDefPtr file) {
47   return StripExtension(file.name()) + ".upbdefs.c";
48 }
49 
GenerateMessageDefAccessor(upb::MessageDefPtr d,Output & output)50 void GenerateMessageDefAccessor(upb::MessageDefPtr d, Output& output) {
51   output("UPB_INLINE const upb_MessageDef *$0_getmsgdef(upb_DefPool *s) {\n",
52          ToCIdent(d.full_name()));
53   output("  _upb_DefPool_LoadDefInit(s, &$0);\n", DefInitSymbol(d.file()));
54   output("  return upb_DefPool_FindMessageByName(s, \"$0\");\n", d.full_name());
55   output("}\n");
56   output("\n");
57 }
58 
WriteDefHeader(upb::FileDefPtr file,Output & output)59 void WriteDefHeader(upb::FileDefPtr file, Output& output) {
60   EmitFileWarning(file.name(), output);
61 
62   output(
63       "#ifndef $0_UPBDEFS_H_\n"
64       "#define $0_UPBDEFS_H_\n\n"
65       "#include \"upb/reflection/def.h\"\n"
66       "#include \"upb/reflection/def_pool_internal.h\"\n"
67       "#include \"upb/port/def.inc\"\n"
68       "#ifdef __cplusplus\n"
69       "extern \"C\" {\n"
70       "#endif\n\n",
71       ToPreproc(file.name()));
72 
73   output("#include \"upb/reflection/def.h\"\n");
74   output("\n");
75   output("#include \"upb/port/def.inc\"\n");
76   output("\n");
77 
78   output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file));
79   output("\n");
80 
81   for (auto msg : SortedMessages(file)) {
82     GenerateMessageDefAccessor(msg, output);
83   }
84 
85   output(
86       "#ifdef __cplusplus\n"
87       "}  /* extern \"C\" */\n"
88       "#endif\n"
89       "\n"
90       "#include \"upb/port/undef.inc\"\n"
91       "\n"
92       "#endif  /* $0_UPBDEFS_H_ */\n",
93       ToPreproc(file.name()));
94 }
95 
WriteDefSource(upb::FileDefPtr file,Output & output)96 void WriteDefSource(upb::FileDefPtr file, Output& output) {
97   EmitFileWarning(file.name(), output);
98 
99   output("#include \"upb/reflection/def.h\"\n");
100   output("#include \"$0\"\n", DefHeaderFilename(file));
101   output("#include \"$0\"\n", HeaderFilename(file));
102   output("\n");
103 
104   for (int i = 0; i < file.dependency_count(); i++) {
105     output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file.dependency(i)));
106   }
107 
108   upb::Arena arena;
109   google_protobuf_FileDescriptorProto* file_proto =
110       upb_FileDef_ToProto(file.ptr(), arena.ptr());
111   size_t serialized_size;
112   const char* serialized = google_protobuf_FileDescriptorProto_serialize(
113       file_proto, arena.ptr(), &serialized_size);
114   absl::string_view file_data(serialized, serialized_size);
115 
116   output("static const char descriptor[$0] = {", serialized_size);
117 
118   // C90 only guarantees that strings can be up to 509 characters, and some
119   // implementations have limits here (for example, MSVC only allows 64k:
120   // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1091.
121   // So we always emit an array instead of a string.
122   for (size_t i = 0; i < serialized_size;) {
123     for (size_t j = 0; j < 25 && i < serialized_size; ++i, ++j) {
124       output("'$0', ", absl::CEscape(file_data.substr(i, 1)));
125     }
126     output("\n");
127   }
128   output("};\n\n");
129 
130   output("static _upb_DefPool_Init *deps[$0] = {\n",
131          file.dependency_count() + 1);
132   for (int i = 0; i < file.dependency_count(); i++) {
133     output("  &$0,\n", DefInitSymbol(file.dependency(i)));
134   }
135   output("  NULL\n");
136   output("};\n");
137   output("\n");
138 
139   output("_upb_DefPool_Init $0 = {\n", DefInitSymbol(file));
140   output("  deps,\n");
141   output("  &$0,\n", FileLayoutName(file));
142   output("  \"$0\",\n", file.name());
143   output("  UPB_STRINGVIEW_INIT(descriptor, $0)\n", file_data.size());
144   output("};\n");
145 }
146 
GenerateFile(upb::FileDefPtr file,Plugin * plugin)147 void GenerateFile(upb::FileDefPtr file, Plugin* plugin) {
148   Output h_def_output;
149   WriteDefHeader(file, h_def_output);
150   plugin->AddOutputFile(DefHeaderFilename(file), h_def_output.output());
151 
152   Output c_def_output;
153   WriteDefSource(file, c_def_output);
154   plugin->AddOutputFile(DefSourceFilename(file), c_def_output.output());
155 }
156 
157 }  // namespace
158 }  // namespace upbc
159 
main(int argc,char ** argv)160 int main(int argc, char** argv) {
161   upbc::Plugin plugin;
162   if (!plugin.parameter().empty()) {
163     plugin.SetError(
164         absl::StrCat("Expected no parameters, got: ", plugin.parameter()));
165     return 0;
166   }
167   plugin.GenerateFiles(
168       [&](upb::FileDefPtr file) { upbc::GenerateFile(file, &plugin); });
169   return 0;
170 }
171