• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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 #include "names.h"
32 
33 #include <stdlib.h>
34 
35 #include "protobuf.h"
36 
37 /* stringsink *****************************************************************/
38 
39 typedef struct {
40   char *ptr;
41   size_t len, size;
42 } stringsink;
43 
stringsink_string(stringsink * sink,const char * ptr,size_t len)44 static size_t stringsink_string(stringsink *sink, const char *ptr, size_t len) {
45   size_t new_size = sink->size;
46 
47   while (sink->len + len > new_size) {
48     new_size *= 2;
49   }
50 
51   if (new_size != sink->size) {
52     sink->ptr = realloc(sink->ptr, new_size);
53     sink->size = new_size;
54   }
55 
56   memcpy(sink->ptr + sink->len, ptr, len);
57   sink->len += len;
58 
59   return len;
60 }
61 
stringsink_init(stringsink * sink)62 static void stringsink_init(stringsink *sink) {
63   sink->size = 32;
64   sink->ptr = malloc(sink->size);
65   PBPHP_ASSERT(sink->ptr != NULL);
66   sink->len = 0;
67 }
68 
stringsink_uninit(stringsink * sink)69 static void stringsink_uninit(stringsink *sink) { free(sink->ptr); }
70 
71 /* def name -> classname ******************************************************/
72 
73 const char *const kReservedNames[] = {
74     "abstract",   "and",        "array",        "as",           "break",
75     "callable",   "case",       "catch",        "class",        "clone",
76     "const",      "continue",   "declare",      "default",      "die",
77     "do",         "echo",       "else",         "elseif",       "empty",
78     "enddeclare", "endfor",     "endforeach",   "endif",        "endswitch",
79     "endwhile",   "eval",       "exit",         "extends",      "final",
80     "for",        "foreach",    "function",     "global",       "goto",
81     "if",         "implements", "include",      "include_once", "instanceof",
82     "insteadof",  "interface",  "isset",        "list",         "namespace",
83     "new",        "or",         "print",        "private",      "protected",
84     "public",     "require",    "require_once", "return",       "static",
85     "switch",     "throw",      "trait",        "try",          "unset",
86     "use",        "var",        "while",        "xor",          "int",
87     "float",      "bool",       "string",       "true",         "false",
88     "null",       "void",       "iterable",     NULL};
89 
is_reserved_name(const char * name)90 bool is_reserved_name(const char* name) {
91   int i;
92   for (i = 0; kReservedNames[i]; i++) {
93     if (strcmp(kReservedNames[i], name) == 0) {
94       return true;
95     }
96   }
97   return false;
98 }
99 
nolocale_tolower(char ch)100 static char nolocale_tolower(char ch) {
101   if (ch >= 'A' && ch <= 'Z') {
102     return ch - ('A' - 'a');
103   } else {
104     return ch;
105   }
106 }
107 
nolocale_toupper(char ch)108 static char nolocale_toupper(char ch) {
109   if (ch >= 'a' && ch <= 'z') {
110     return ch - ('a' - 'A');
111   } else {
112     return ch;
113   }
114 }
115 
is_reserved(const char * segment,int length)116 static bool is_reserved(const char *segment, int length) {
117   bool result;
118   char* lower = calloc(1, length + 1);
119   memcpy(lower, segment, length);
120   int i = 0;
121   while(lower[i]) {
122     lower[i] = nolocale_tolower(lower[i]);
123     i++;
124   }
125   lower[length] = 0;
126   result = is_reserved_name(lower);
127   free(lower);
128   return result;
129 }
130 
fill_prefix(const char * segment,int length,const char * prefix_given,const char * package_name,stringsink * classname)131 static void fill_prefix(const char *segment, int length,
132                         const char *prefix_given,
133                         const char *package_name,
134                         stringsink *classname) {
135   if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
136     stringsink_string(classname, prefix_given, strlen(prefix_given));
137   } else {
138     if (is_reserved(segment, length)) {
139       if (package_name != NULL &&
140           strcmp("google.protobuf", package_name) == 0) {
141         stringsink_string(classname, "GPB", 3);
142       } else {
143         stringsink_string(classname, "PB", 2);
144       }
145     }
146   }
147 }
148 
fill_segment(const char * segment,int length,stringsink * classname,bool use_camel)149 static void fill_segment(const char *segment, int length,
150                          stringsink *classname, bool use_camel) {
151   if (use_camel && (segment[0] < 'A' || segment[0] > 'Z')) {
152     char first = nolocale_toupper(segment[0]);
153     stringsink_string(classname, &first, 1);
154     stringsink_string(classname, segment + 1, length - 1);
155   } else {
156     stringsink_string(classname, segment, length);
157   }
158 }
159 
fill_namespace(const char * package,const char * php_namespace,stringsink * classname)160 static void fill_namespace(const char *package, const char *php_namespace,
161                            stringsink *classname) {
162   if (php_namespace != NULL) {
163     if (strlen(php_namespace) != 0) {
164       stringsink_string(classname, php_namespace, strlen(php_namespace));
165       stringsink_string(classname, "\\", 1);
166     }
167   } else if (package != NULL) {
168     int i = 0, j = 0;
169     size_t package_len = strlen(package);
170     while (i < package_len) {
171       j = i;
172       while (j < package_len && package[j] != '.') {
173         j++;
174       }
175       fill_prefix(package + i, j - i, "", package, classname);
176       fill_segment(package + i, j - i, classname, true);
177       stringsink_string(classname, "\\", 1);
178       i = j + 1;
179     }
180   }
181 }
182 
fill_classname(const char * fullname,const char * package,const char * prefix,stringsink * classname)183 static void fill_classname(const char *fullname,
184                            const char *package,
185                            const char *prefix,
186                            stringsink *classname) {
187   int classname_start = 0;
188   if (package != NULL) {
189     size_t package_len = strlen(package);
190     classname_start = package_len == 0 ? 0 : package_len + 1;
191   }
192   size_t fullname_len = strlen(fullname);
193 
194   int i = classname_start, j;
195   while (i < fullname_len) {
196     j = i;
197     while (j < fullname_len && fullname[j] != '.') {
198       j++;
199     }
200     fill_prefix(fullname + i, j - i, prefix, package, classname);
201     fill_segment(fullname + i, j - i, classname, false);
202     if (j != fullname_len) {
203       stringsink_string(classname, "\\", 1);
204     }
205     i = j + 1;
206   }
207 }
208 
GetPhpClassname(const upb_filedef * file,const char * fullname)209 char *GetPhpClassname(const upb_filedef *file, const char *fullname) {
210   // Prepend '.' to package name to make it absolute. In the 5 additional
211   // bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if
212   // given message is google.protobuf.Empty.
213   const char *package = upb_filedef_package(file);
214   const char *php_namespace = upb_filedef_phpnamespace(file);
215   const char *prefix = upb_filedef_phpprefix(file);
216   char *ret;
217   stringsink namesink;
218   stringsink_init(&namesink);
219 
220   fill_namespace(package, php_namespace, &namesink);
221   fill_classname(fullname, package, prefix, &namesink);
222   stringsink_string(&namesink, "\0", 1);
223   ret = strdup(namesink.ptr);
224   stringsink_uninit(&namesink);
225   return ret;
226 }
227