names.c 7.5 KB

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