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