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 "finally", "fn", "for", "foreach", "function",
81 "if", "implements", "include", "include_once", "instanceof",
82 "global", "goto", "insteadof", "interface", "isset",
83 "list", "match", "namespace", "new", "object",
84 "or", "print", "private", "protected", "public",
85 "require", "require_once", "return", "static", "switch",
86 "throw", "trait", "try", "unset", "use",
87 "var", "while", "xor", "yield", "int",
88 "float", "bool", "string", "true", "false",
89 "null", "void", "iterable", NULL};
90
is_reserved_name(const char * name)91 bool is_reserved_name(const char* name) {
92 int i;
93 for (i = 0; kReservedNames[i]; i++) {
94 if (strcmp(kReservedNames[i], name) == 0) {
95 return true;
96 }
97 }
98 return false;
99 }
100
nolocale_tolower(char ch)101 static char nolocale_tolower(char ch) {
102 if (ch >= 'A' && ch <= 'Z') {
103 return ch - ('A' - 'a');
104 } else {
105 return ch;
106 }
107 }
108
nolocale_toupper(char ch)109 static char nolocale_toupper(char ch) {
110 if (ch >= 'a' && ch <= 'z') {
111 return ch - ('a' - 'A');
112 } else {
113 return ch;
114 }
115 }
116
is_reserved(const char * segment,int length)117 static bool is_reserved(const char *segment, int length) {
118 bool result;
119 char* lower = calloc(1, length + 1);
120 memcpy(lower, segment, length);
121 int i = 0;
122 while(lower[i]) {
123 lower[i] = nolocale_tolower(lower[i]);
124 i++;
125 }
126 lower[length] = 0;
127 result = is_reserved_name(lower);
128 free(lower);
129 return result;
130 }
131
fill_prefix(const char * segment,int length,const char * prefix_given,const char * package_name,stringsink * classname)132 static void fill_prefix(const char *segment, int length,
133 const char *prefix_given,
134 const char *package_name,
135 stringsink *classname) {
136 if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
137 stringsink_string(classname, prefix_given, strlen(prefix_given));
138 } else {
139 if (is_reserved(segment, length)) {
140 if (package_name != NULL &&
141 strcmp("google.protobuf", package_name) == 0) {
142 stringsink_string(classname, "GPB", 3);
143 } else {
144 stringsink_string(classname, "PB", 2);
145 }
146 }
147 }
148 }
149
fill_segment(const char * segment,int length,stringsink * classname,bool use_camel)150 static void fill_segment(const char *segment, int length,
151 stringsink *classname, bool use_camel) {
152 if (use_camel && (segment[0] < 'A' || segment[0] > 'Z')) {
153 char first = nolocale_toupper(segment[0]);
154 stringsink_string(classname, &first, 1);
155 stringsink_string(classname, segment + 1, length - 1);
156 } else {
157 stringsink_string(classname, segment, length);
158 }
159 }
160
fill_namespace(const char * package,const char * php_namespace,stringsink * classname)161 static void fill_namespace(const char *package, const char *php_namespace,
162 stringsink *classname) {
163 if (php_namespace != NULL) {
164 if (strlen(php_namespace) != 0) {
165 stringsink_string(classname, php_namespace, strlen(php_namespace));
166 stringsink_string(classname, "\\", 1);
167 }
168 } else if (package != NULL) {
169 int i = 0, j = 0;
170 size_t package_len = strlen(package);
171 while (i < package_len) {
172 j = i;
173 while (j < package_len && package[j] != '.') {
174 j++;
175 }
176 fill_prefix(package + i, j - i, "", package, classname);
177 fill_segment(package + i, j - i, classname, true);
178 stringsink_string(classname, "\\", 1);
179 i = j + 1;
180 }
181 }
182 }
183
fill_classname(const char * fullname,const char * package,const char * prefix,stringsink * classname)184 static void fill_classname(const char *fullname,
185 const char *package,
186 const char *prefix,
187 stringsink *classname) {
188 int classname_start = 0;
189 if (package != NULL) {
190 size_t package_len = strlen(package);
191 classname_start = package_len == 0 ? 0 : package_len + 1;
192 }
193 size_t fullname_len = strlen(fullname);
194
195 int i = classname_start, j;
196 while (i < fullname_len) {
197 j = i;
198 while (j < fullname_len && fullname[j] != '.') {
199 j++;
200 }
201 fill_prefix(fullname + i, j - i, prefix, package, classname);
202 fill_segment(fullname + i, j - i, classname, false);
203 if (j != fullname_len) {
204 stringsink_string(classname, "\\", 1);
205 }
206 i = j + 1;
207 }
208 }
209
GetPhpClassname(const upb_filedef * file,const char * fullname)210 char *GetPhpClassname(const upb_filedef *file, const char *fullname) {
211 // Prepend '.' to package name to make it absolute. In the 5 additional
212 // bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if
213 // given message is google.protobuf.Empty.
214 const char *package = upb_filedef_package(file);
215 const char *php_namespace = upb_filedef_phpnamespace(file);
216 const char *prefix = upb_filedef_phpprefix(file);
217 char *ret;
218 stringsink namesink;
219 stringsink_init(&namesink);
220
221 fill_namespace(package, php_namespace, &namesink);
222 fill_classname(fullname, package, prefix, &namesink);
223 stringsink_string(&namesink, "\0", 1);
224 ret = strdup(namesink.ptr);
225 stringsink_uninit(&namesink);
226 return ret;
227 }
228