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