1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 // Copyright (c) 2008-2013, Dave Benson. All rights reserved.
36 //
37 // Redistribution and use in source and binary forms, with or without
38 // modification, are permitted provided that the following conditions are
39 // met:
40 //
41 // * Redistributions of source code must retain the above copyright
42 // notice, this list of conditions and the following disclaimer.
43 //
44 // * Redistributions in binary form must reproduce the above
45 // copyright notice, this list of conditions and the following disclaimer
46 // in the documentation and/or other materials provided with the
47 // distribution.
48 //
49 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
61 // Modified to implement C code by Dave Benson.
62
63 #include <algorithm>
64 #include <map>
65 #include <memory>
66 #include <protoc-c/c_message.h>
67 #include <protoc-c/c_enum.h>
68 #include <protoc-c/c_extension.h>
69 #include <protoc-c/c_helpers.h>
70 #include <google/protobuf/io/printer.h>
71 #include <google/protobuf/io/coded_stream.h>
72 #include <google/protobuf/wire_format.h>
73 #include <protobuf-c/protobuf-c.pb.h>
74
75 namespace google {
76 namespace protobuf {
77 namespace compiler {
78 namespace c {
79
80 // ===================================================================
81
MessageGenerator(const Descriptor * descriptor,const std::string & dllexport_decl)82 MessageGenerator::MessageGenerator(const Descriptor* descriptor,
83 const std::string& dllexport_decl)
84 : descriptor_(descriptor),
85 dllexport_decl_(dllexport_decl),
86 field_generators_(descriptor),
87 nested_generators_(new std::unique_ptr<MessageGenerator>[
88 descriptor->nested_type_count()]),
89 enum_generators_(new std::unique_ptr<EnumGenerator>[
90 descriptor->enum_type_count()]),
91 extension_generators_(new std::unique_ptr<ExtensionGenerator>[
92 descriptor->extension_count()]) {
93
94 for (int i = 0; i < descriptor->nested_type_count(); i++) {
95 nested_generators_[i].reset(
96 new MessageGenerator(descriptor->nested_type(i), dllexport_decl));
97 }
98
99 for (int i = 0; i < descriptor->enum_type_count(); i++) {
100 enum_generators_[i].reset(
101 new EnumGenerator(descriptor->enum_type(i), dllexport_decl));
102 }
103
104 for (int i = 0; i < descriptor->extension_count(); i++) {
105 extension_generators_[i].reset(
106 new ExtensionGenerator(descriptor->extension(i), dllexport_decl));
107 }
108 }
109
~MessageGenerator()110 MessageGenerator::~MessageGenerator() {}
111
112 void MessageGenerator::
GenerateStructTypedef(io::Printer * printer)113 GenerateStructTypedef(io::Printer* printer) {
114 printer->Print("typedef struct $classname$ $classname$;\n",
115 "classname", FullNameToC(descriptor_->full_name(), descriptor_->file()));
116
117 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
118 nested_generators_[i]->GenerateStructTypedef(printer);
119 }
120 }
121
122 void MessageGenerator::
GenerateEnumDefinitions(io::Printer * printer)123 GenerateEnumDefinitions(io::Printer* printer) {
124 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
125 nested_generators_[i]->GenerateEnumDefinitions(printer);
126 }
127
128 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
129 enum_generators_[i]->GenerateDefinition(printer);
130 }
131 }
132
133
134 void MessageGenerator::
GenerateStructDefinition(io::Printer * printer)135 GenerateStructDefinition(io::Printer* printer) {
136 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
137 nested_generators_[i]->GenerateStructDefinition(printer);
138 }
139
140 std::map<std::string, std::string> vars;
141 vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
142 vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
143 vars["ucclassname"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file());
144 vars["field_count"] = SimpleItoa(descriptor_->field_count());
145 if (dllexport_decl_.empty()) {
146 vars["dllexport"] = "";
147 } else {
148 vars["dllexport"] = dllexport_decl_ + " ";
149 }
150
151 // Generate the case enums for unions
152 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
153 const OneofDescriptor *oneof = descriptor_->oneof_decl(i);
154 vars["opt_comma"] = ",";
155
156 vars["oneofname"] = CamelToUpper(oneof->name());
157 vars["foneofname"] = FullNameToC(oneof->full_name(), oneof->file());
158
159 printer->Print("typedef enum {\n");
160 printer->Indent();
161 printer->Print(vars, "$ucclassname$__$oneofname$__NOT_SET = 0,\n");
162 for (int j = 0; j < oneof->field_count(); j++) {
163 const FieldDescriptor *field = oneof->field(j);
164 vars["fieldname"] = CamelToUpper(field->name());
165 vars["fieldnum"] = SimpleItoa(field->number());
166 bool isLast = j == oneof->field_count() - 1;
167 if (isLast) {
168 vars["opt_comma"] = "";
169 }
170 printer->Print(vars, "$ucclassname$__$oneofname$_$fieldname$ = $fieldnum$$opt_comma$\n");
171 }
172 printer->Print(vars, " PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE($ucclassname$__$oneofname$__CASE)\n");
173 printer->Outdent();
174 printer->Print(vars, "} $foneofname$Case;\n\n");
175 }
176
177 SourceLocation msgSourceLoc;
178 descriptor_->GetSourceLocation(&msgSourceLoc);
179 PrintComment (printer, msgSourceLoc.leading_comments);
180
181 const ProtobufCMessageOptions opt =
182 descriptor_->options().GetExtension(pb_c_msg);
183 vars["base"] = opt.base_field_name();
184
185 printer->Print(vars,
186 "struct $dllexport$ $classname$\n"
187 "{\n"
188 " ProtobufCMessage $base$;\n");
189
190 // Generate fields.
191 printer->Indent();
192 for (int i = 0; i < descriptor_->field_count(); i++) {
193 const FieldDescriptor *field = descriptor_->field(i);
194 if (field->containing_oneof() == NULL) {
195 SourceLocation fieldSourceLoc;
196 field->GetSourceLocation(&fieldSourceLoc);
197
198 PrintComment (printer, fieldSourceLoc.leading_comments);
199 PrintComment (printer, fieldSourceLoc.trailing_comments);
200 field_generators_.get(field).GenerateStructMembers(printer);
201 }
202 }
203
204 // Generate unions from oneofs.
205 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
206 const OneofDescriptor *oneof = descriptor_->oneof_decl(i);
207 vars["oneofname"] = CamelToLower(oneof->name());
208 vars["foneofname"] = FullNameToC(oneof->full_name(), oneof->file());
209
210 printer->Print(vars, "$foneofname$Case $oneofname$_case;\n");
211
212 printer->Print("union {\n");
213 printer->Indent();
214 for (int j = 0; j < oneof->field_count(); j++) {
215 const FieldDescriptor *field = oneof->field(j);
216 SourceLocation fieldSourceLoc;
217 field->GetSourceLocation(&fieldSourceLoc);
218
219 PrintComment (printer, fieldSourceLoc.leading_comments);
220 PrintComment (printer, fieldSourceLoc.trailing_comments);
221 field_generators_.get(field).GenerateStructMembers(printer);
222 }
223 printer->Outdent();
224 printer->Print(vars, "};\n");
225 }
226 printer->Outdent();
227
228 printer->Print(vars, "};\n");
229
230 for (int i = 0; i < descriptor_->field_count(); i++) {
231 const FieldDescriptor *field = descriptor_->field(i);
232 if (field->has_default_value()) {
233 field_generators_.get(field).GenerateDefaultValueDeclarations(printer);
234 }
235 }
236
237 printer->Print(vars, "#define $ucclassname$__INIT \\\n"
238 " { PROTOBUF_C_MESSAGE_INIT (&$lcclassname$__descriptor) \\\n ");
239 for (int i = 0; i < descriptor_->field_count(); i++) {
240 const FieldDescriptor *field = descriptor_->field(i);
241 if (field->containing_oneof() == NULL) {
242 printer->Print(", ");
243 field_generators_.get(field).GenerateStaticInit(printer);
244 }
245 }
246 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
247 const OneofDescriptor *oneof = descriptor_->oneof_decl(i);
248 vars["foneofname"] = FullNameToUpper(oneof->full_name(), oneof->file());
249 // Initialize the case enum
250 printer->Print(vars, ", $foneofname$__NOT_SET");
251 // Initialize the union
252 printer->Print(", {0}");
253 }
254 printer->Print(" }\n\n\n");
255
256 }
257
258 void MessageGenerator::
GenerateHelperFunctionDeclarations(io::Printer * printer,bool is_pack_deep,bool gen_pack,bool gen_init)259 GenerateHelperFunctionDeclarations(io::Printer* printer,
260 bool is_pack_deep,
261 bool gen_pack,
262 bool gen_init)
263 {
264 const ProtobufCMessageOptions opt =
265 descriptor_->options().GetExtension(pb_c_msg);
266
267 // Override parent settings, if needed
268 if (opt.has_gen_pack_helpers())
269 gen_pack = opt.gen_pack_helpers();
270 if (opt.has_gen_init_helpers())
271 gen_init = opt.gen_init_helpers();
272
273 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
274 bool nested_pack = !is_pack_deep ? opt.gen_pack_helpers() : gen_pack;
275 nested_generators_[i]->GenerateHelperFunctionDeclarations(printer, true,
276 nested_pack,
277 gen_init);
278 }
279
280 std::map<std::string, std::string> vars;
281 vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
282 vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
283 if (gen_init) {
284 printer->Print(vars,
285 "/* $classname$ methods */\n"
286 "void $lcclassname$__init\n"
287 " ($classname$ *message);\n"
288 );
289 }
290 if (gen_pack) {
291 printer->Print(vars,
292 "size_t $lcclassname$__get_packed_size\n"
293 " (const $classname$ *message);\n"
294 "size_t $lcclassname$__pack\n"
295 " (const $classname$ *message,\n"
296 " uint8_t *out);\n"
297 "size_t $lcclassname$__pack_to_buffer\n"
298 " (const $classname$ *message,\n"
299 " ProtobufCBuffer *buffer);\n"
300 "$classname$ *\n"
301 " $lcclassname$__unpack\n"
302 " (ProtobufCAllocator *allocator,\n"
303 " size_t len,\n"
304 " const uint8_t *data);\n"
305 "void $lcclassname$__free_unpacked\n"
306 " ($classname$ *message,\n"
307 " ProtobufCAllocator *allocator);\n"
308 );
309 }
310 }
311
312 void MessageGenerator::
GenerateDescriptorDeclarations(io::Printer * printer)313 GenerateDescriptorDeclarations(io::Printer* printer) {
314 printer->Print("extern const ProtobufCMessageDescriptor $name$__descriptor;\n",
315 "name", FullNameToLower(descriptor_->full_name(), descriptor_->file()));
316
317 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
318 nested_generators_[i]->GenerateDescriptorDeclarations(printer);
319 }
320
321 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
322 enum_generators_[i]->GenerateDescriptorDeclarations(printer);
323 }
324 }
GenerateClosureTypedef(io::Printer * printer)325 void MessageGenerator::GenerateClosureTypedef(io::Printer* printer)
326 {
327 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
328 nested_generators_[i]->GenerateClosureTypedef(printer);
329 }
330 std::map<std::string, std::string> vars;
331 vars["name"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
332 printer->Print(vars,
333 "typedef void (*$name$_Closure)\n"
334 " (const $name$ *message,\n"
335 " void *closure_data);\n");
336 }
337
338 static int
compare_pfields_by_number(const void * a,const void * b)339 compare_pfields_by_number (const void *a, const void *b)
340 {
341 const FieldDescriptor *pa = *(const FieldDescriptor **)a;
342 const FieldDescriptor *pb = *(const FieldDescriptor **)b;
343 if (pa->number() < pb->number()) return -1;
344 if (pa->number() > pb->number()) return +1;
345 return 0;
346 }
347
348 void MessageGenerator::
GenerateHelperFunctionDefinitions(io::Printer * printer,bool is_pack_deep,bool gen_pack,bool gen_init)349 GenerateHelperFunctionDefinitions(io::Printer* printer,
350 bool is_pack_deep,
351 bool gen_pack,
352 bool gen_init)
353 {
354 const ProtobufCMessageOptions opt =
355 descriptor_->options().GetExtension(pb_c_msg);
356
357 // Override parent settings, if needed
358 if (opt.has_gen_pack_helpers())
359 gen_pack = opt.gen_pack_helpers();
360 if (opt.has_gen_init_helpers())
361 gen_init = opt.gen_init_helpers();
362
363 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
364 bool nested_pack = !is_pack_deep ? opt.gen_pack_helpers() : gen_pack;
365 nested_generators_[i]->GenerateHelperFunctionDefinitions(printer, true,
366 nested_pack,
367 gen_init);
368 }
369
370 std::map<std::string, std::string> vars;
371 vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
372 vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
373 vars["ucclassname"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file());
374 vars["base"] = opt.base_field_name();
375 if (gen_init) {
376 printer->Print(vars,
377 "void $lcclassname$__init\n"
378 " ($classname$ *message)\n"
379 "{\n"
380 " static const $classname$ init_value = $ucclassname$__INIT;\n"
381 " *message = init_value;\n"
382 "}\n");
383 }
384 if (gen_pack) {
385 printer->Print(vars,
386 "size_t $lcclassname$__get_packed_size\n"
387 " (const $classname$ *message)\n"
388 "{\n"
389 " assert(message->$base$.descriptor == &$lcclassname$__descriptor);\n"
390 " return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n"
391 "}\n"
392 "size_t $lcclassname$__pack\n"
393 " (const $classname$ *message,\n"
394 " uint8_t *out)\n"
395 "{\n"
396 " assert(message->$base$.descriptor == &$lcclassname$__descriptor);\n"
397 " return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n"
398 "}\n"
399 "size_t $lcclassname$__pack_to_buffer\n"
400 " (const $classname$ *message,\n"
401 " ProtobufCBuffer *buffer)\n"
402 "{\n"
403 " assert(message->$base$.descriptor == &$lcclassname$__descriptor);\n"
404 " return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n"
405 "}\n"
406 "$classname$ *\n"
407 " $lcclassname$__unpack\n"
408 " (ProtobufCAllocator *allocator,\n"
409 " size_t len,\n"
410 " const uint8_t *data)\n"
411 "{\n"
412 " return ($classname$ *)\n"
413 " protobuf_c_message_unpack (&$lcclassname$__descriptor,\n"
414 " allocator, len, data);\n"
415 "}\n"
416 "void $lcclassname$__free_unpacked\n"
417 " ($classname$ *message,\n"
418 " ProtobufCAllocator *allocator)\n"
419 "{\n"
420 " if(!message)\n"
421 " return;\n"
422 " assert(message->$base$.descriptor == &$lcclassname$__descriptor);\n"
423 " protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n"
424 "}\n"
425 );
426 }
427 }
428
429 void MessageGenerator::
GenerateMessageDescriptor(io::Printer * printer,bool gen_init)430 GenerateMessageDescriptor(io::Printer* printer, bool gen_init) {
431 std::map<std::string, std::string> vars;
432 vars["fullname"] = descriptor_->full_name();
433 vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
434 vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
435 vars["shortname"] = ToCamel(descriptor_->name());
436 vars["n_fields"] = SimpleItoa(descriptor_->field_count());
437 vars["packagename"] = descriptor_->file()->package();
438
439 bool optimize_code_size = descriptor_->file()->options().has_optimize_for() &&
440 descriptor_->file()->options().optimize_for() ==
441 FileOptions_OptimizeMode_CODE_SIZE;
442
443 const ProtobufCMessageOptions opt =
444 descriptor_->options().GetExtension(pb_c_msg);
445 // Override parent settings, if needed
446 if (opt.has_gen_init_helpers())
447 gen_init = opt.gen_init_helpers();
448
449 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
450 nested_generators_[i]->GenerateMessageDescriptor(printer, gen_init);
451 }
452
453 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
454 enum_generators_[i]->GenerateEnumDescriptor(printer);
455 }
456
457 for (int i = 0; i < descriptor_->field_count(); i++) {
458 const FieldDescriptor *fd = descriptor_->field(i);
459 if (fd->has_default_value()) {
460 field_generators_.get(fd).GenerateDefaultValueImplementations(printer);
461 }
462 }
463
464 for (int i = 0; i < descriptor_->field_count(); i++) {
465 const FieldDescriptor *fd = descriptor_->field(i);
466 const ProtobufCFieldOptions opt = fd->options().GetExtension(pb_c_field);
467 if (fd->has_default_value()) {
468
469 bool already_defined = false;
470 vars["name"] = fd->name();
471 vars["lcname"] = CamelToLower(fd->name());
472 vars["maybe_static"] = "static ";
473 vars["field_dv_ctype_suffix"] = "";
474 vars["default_value"] = field_generators_.get(fd).GetDefaultValue();
475 switch (fd->cpp_type()) {
476 case FieldDescriptor::CPPTYPE_INT32:
477 vars["field_dv_ctype"] = "int32_t";
478 break;
479 case FieldDescriptor::CPPTYPE_INT64:
480 vars["field_dv_ctype"] = "int64_t";
481 break;
482 case FieldDescriptor::CPPTYPE_UINT32:
483 vars["field_dv_ctype"] = "uint32_t";
484 break;
485 case FieldDescriptor::CPPTYPE_UINT64:
486 vars["field_dv_ctype"] = "uint64_t";
487 break;
488 case FieldDescriptor::CPPTYPE_FLOAT:
489 vars["field_dv_ctype"] = "float";
490 break;
491 case FieldDescriptor::CPPTYPE_DOUBLE:
492 vars["field_dv_ctype"] = "double";
493 break;
494 case FieldDescriptor::CPPTYPE_BOOL:
495 vars["field_dv_ctype"] = "protobuf_c_boolean";
496 break;
497
498 case FieldDescriptor::CPPTYPE_MESSAGE:
499 // NOTE: not supported by protobuf
500 vars["maybe_static"] = "";
501 vars["field_dv_ctype"] = "{ ... }";
502 GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
503 break;
504 case FieldDescriptor::CPPTYPE_STRING:
505 if (fd->type() == FieldDescriptor::TYPE_BYTES || opt.string_as_bytes())
506 {
507 vars["field_dv_ctype"] = "ProtobufCBinaryData";
508 }
509 else /* STRING type */
510 {
511 already_defined = true;
512 vars["maybe_static"] = "";
513 vars["field_dv_ctype"] = "char";
514 vars["field_dv_ctype_suffix"] = "[]";
515 }
516 break;
517 case FieldDescriptor::CPPTYPE_ENUM:
518 {
519 const EnumValueDescriptor *vd = fd->default_value_enum();
520 vars["field_dv_ctype"] = FullNameToC(vd->type()->full_name(), vd->type()->file());
521 break;
522 }
523 default:
524 GOOGLE_LOG(DFATAL) << "Unknown CPPTYPE";
525 break;
526 }
527 if (!already_defined)
528 printer->Print(vars, "$maybe_static$const $field_dv_ctype$ $lcclassname$__$lcname$__default_value$field_dv_ctype_suffix$ = $default_value$;\n");
529 }
530 }
531
532 if ( descriptor_->field_count() ) {
533 printer->Print(vars,
534 "static const ProtobufCFieldDescriptor $lcclassname$__field_descriptors[$n_fields$] =\n"
535 "{\n");
536 printer->Indent();
537 const FieldDescriptor **sorted_fields = new const FieldDescriptor *[descriptor_->field_count()];
538 for (int i = 0; i < descriptor_->field_count(); i++) {
539 sorted_fields[i] = descriptor_->field(i);
540 }
541 qsort (sorted_fields, descriptor_->field_count(),
542 sizeof (const FieldDescriptor *),
543 compare_pfields_by_number);
544 for (int i = 0; i < descriptor_->field_count(); i++) {
545 const FieldDescriptor *field = sorted_fields[i];
546 field_generators_.get(field).GenerateDescriptorInitializer(printer);
547 }
548 printer->Outdent();
549 printer->Print(vars, "};\n");
550
551 if (!optimize_code_size) {
552 NameIndex *field_indices = new NameIndex [descriptor_->field_count()];
553 for (int i = 0; i < descriptor_->field_count(); i++) {
554 field_indices[i].name = sorted_fields[i]->name().c_str();
555 field_indices[i].index = i;
556 }
557 qsort (field_indices, descriptor_->field_count(), sizeof (NameIndex),
558 compare_name_indices_by_name);
559 printer->Print(vars, "static const unsigned $lcclassname$__field_indices_by_name[] = {\n");
560 for (int i = 0; i < descriptor_->field_count(); i++) {
561 vars["index"] = SimpleItoa(field_indices[i].index);
562 vars["name"] = field_indices[i].name;
563 printer->Print(vars, " $index$, /* field[$index$] = $name$ */\n");
564 }
565 printer->Print("};\n");
566 delete[] field_indices;
567 }
568
569 // create range initializers
570 int *values = new int[descriptor_->field_count()];
571 for (int i = 0; i < descriptor_->field_count(); i++) {
572 values[i] = sorted_fields[i]->number();
573 }
574 int n_ranges = WriteIntRanges(printer,
575 descriptor_->field_count(), values,
576 vars["lcclassname"] + "__number_ranges");
577 delete [] values;
578 delete [] sorted_fields;
579
580 vars["n_ranges"] = SimpleItoa(n_ranges);
581 } else {
582 /* MS compiler can't handle arrays with zero size and empty
583 * initialization list. Furthermore it is an extension of GCC only but
584 * not a standard. */
585 vars["n_ranges"] = "0";
586 printer->Print(vars,
587 "#define $lcclassname$__field_descriptors NULL\n"
588 "#define $lcclassname$__field_indices_by_name NULL\n"
589 "#define $lcclassname$__number_ranges NULL\n");
590 }
591
592 printer->Print(vars,
593 "const ProtobufCMessageDescriptor $lcclassname$__descriptor =\n"
594 "{\n"
595 " PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n");
596 if (optimize_code_size) {
597 printer->Print(" NULL,NULL,NULL,NULL, /* CODE_SIZE */\n");
598 } else {
599 printer->Print(vars,
600 " \"$fullname$\",\n"
601 " \"$shortname$\",\n"
602 " \"$classname$\",\n"
603 " \"$packagename$\",\n");
604 }
605 printer->Print(vars,
606 " sizeof($classname$),\n"
607 " $n_fields$,\n"
608 " $lcclassname$__field_descriptors,\n");
609 if (optimize_code_size) {
610 printer->Print(" NULL, /* CODE_SIZE */\n");
611 } else {
612 printer->Print(vars,
613 " $lcclassname$__field_indices_by_name,\n");
614 }
615 printer->Print(vars,
616 " $n_ranges$,"
617 " $lcclassname$__number_ranges,\n");
618 if (gen_init) {
619 printer->Print(vars,
620 " (ProtobufCMessageInit) $lcclassname$__init,\n");
621 } else {
622 printer->Print(vars,
623 " NULL, /* gen_init_helpers = false */\n");
624 }
625 printer->Print(vars,
626 " NULL,NULL,NULL /* reserved[123] */\n"
627 "};\n");
628 }
629
630 } // namespace c
631 } // namespace compiler
632 } // namespace protobuf
633 } // namespace google
634