PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/com/netease/protocGenAs3/Main.java

https://code.google.com/p/protoc-gen-as3/
Java | 1392 lines | 1359 code | 22 blank | 11 comment | 196 complexity | 5f11069ee9080a4adc1c1607aa933b56 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // vim: fileencoding=utf-8 tabstop=4 shiftwidth=4
  2. // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved.
  3. //
  4. // Author: Yang Bo (pop.atry@gmail.com)
  5. //
  6. // Use, modification and distribution are subject to the "New BSD License"
  7. // as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
  8. package com.netease.protocGenAs3;
  9. import static google.protobuf.compiler.Plugin.*;
  10. import static com.google.protobuf.DescriptorProtos.*;
  11. import com.google.protobuf.*;
  12. import java.io.*;
  13. import java.util.*;
  14. import java.math.*;
  15. public final class Main {
  16. private static final String[] ACTIONSCRIPT_KEYWORDS = {
  17. "as", "break", "case", "catch", "class", "const", "continue", "default",
  18. "delete", "do", "else", "extends", "false", "finally", "for",
  19. "function", "if", "implements", "import", "in", "instanceof",
  20. "interface", "internal", "is", "native", "new", "null", "package",
  21. "private", "protected", "public", "return", "super", "switch", "this",
  22. "throw", "to", "true", "try", "typeof", "use", "var", "void", "while",
  23. "with"
  24. };
  25. private static final class Scope<Proto> {
  26. // ?? proto instanceOf Scope ???? Scope ???? Scope ???
  27. public final String fullName;
  28. public final Scope<?> parent;
  29. public final Proto proto;
  30. public final boolean export;
  31. public final HashMap<String, Scope<?>> children =
  32. new HashMap<String, Scope<?>>();
  33. private Scope<?> find(String[] pathElements, int i) {
  34. Scope<?> result = this;
  35. for (; i < pathElements.length; i++) {
  36. String name = pathElements[i];
  37. if (result.children.containsKey(name)) {
  38. result = result.children.get(name);
  39. } else {
  40. return null;
  41. }
  42. }
  43. while (result.proto instanceof Scope) {
  44. result = (Scope<?>)result.proto;
  45. }
  46. return result;
  47. }
  48. private Scope<?> getRoot() {
  49. Scope<?> scope = this;
  50. while (scope.parent != null) {
  51. scope = scope.parent;
  52. }
  53. return scope;
  54. }
  55. public Scope<?> find(String path) {
  56. String[] pathElements = path.split("\\.");
  57. if (pathElements[0].equals("")) {
  58. return getRoot().find(pathElements, 1);
  59. } else {
  60. for (Scope<?> scope = this; scope != null; scope = scope.parent) {
  61. Scope<?> result = scope.find(pathElements, 0);
  62. if (result != null) {
  63. return result;
  64. }
  65. }
  66. return null;
  67. }
  68. }
  69. private Scope<?> findOrCreate(String[] pathElements, int i) {
  70. Scope<?> scope = this;
  71. for (; i < pathElements.length; i++) {
  72. String name = pathElements[i];
  73. if (scope.children.containsKey(name)) {
  74. scope = scope.children.get(name);
  75. } else {
  76. Scope<Object> child =
  77. new Scope<Object>(scope, null, false, name);
  78. scope.children.put(name, child);
  79. scope = child;
  80. }
  81. }
  82. return scope;
  83. }
  84. public Scope<?> findOrCreate(String path) {
  85. String[] pathElements = path.split("\\.");
  86. if (pathElements[0].equals("")) {
  87. return getRoot().findOrCreate(pathElements, 1);
  88. } else {
  89. return findOrCreate(pathElements, 0);
  90. }
  91. }
  92. private Scope(Scope<?> parent, Proto proto, boolean export,
  93. String name) {
  94. this.parent = parent;
  95. this.proto = proto;
  96. this.export = export;
  97. if (parent == null || parent.fullName == null ||
  98. parent.fullName.equals("")) {
  99. fullName = name;
  100. } else {
  101. fullName = parent.fullName + '.' + name;
  102. }
  103. }
  104. public <ChildProto> Scope<ChildProto> addChild(
  105. String name, ChildProto proto, boolean export) {
  106. assert(name != null);
  107. assert(!name.equals(""));
  108. Scope<ChildProto> child =
  109. new Scope<ChildProto>(this, proto, export, name);
  110. if(children.containsKey(child)) {
  111. throw new IllegalArgumentException();
  112. }
  113. children.put(name, child);
  114. return child;
  115. }
  116. public static Scope<Object> root() {
  117. return new Scope<Object>(null, null, false, "");
  118. }
  119. }
  120. private static void addServiceToScope(Scope<?> scope,
  121. ServiceDescriptorProto sdp, boolean export) {
  122. scope.addChild(sdp.getName(), sdp, export);
  123. }
  124. private static void addExtensionToScope(Scope<?> scope,
  125. FieldDescriptorProto efdp, boolean export) {
  126. scope.addChild(efdp.getName().toUpperCase(), efdp, export);
  127. }
  128. private static void addEnumToScope(Scope<?> scope, EnumDescriptorProto edp,
  129. boolean export) {
  130. assert(edp.hasName());
  131. Scope<EnumDescriptorProto> enumScope =
  132. scope.addChild(edp.getName(), edp, export);
  133. for (EnumValueDescriptorProto evdp : edp.getValueList()) {
  134. Scope<EnumValueDescriptorProto> enumValueScope =
  135. enumScope.addChild(evdp.getName(), evdp, false);
  136. scope.addChild(evdp.getName(), enumValueScope, false);
  137. }
  138. }
  139. private static void addMessageToScope(Scope<?> scope, DescriptorProto dp,
  140. boolean export) {
  141. Scope<DescriptorProto> messageScope =
  142. scope.addChild(dp.getName(), dp, export);
  143. for (EnumDescriptorProto edp : dp.getEnumTypeList()) {
  144. addEnumToScope(messageScope, edp, export);
  145. }
  146. for (DescriptorProto nested: dp.getNestedTypeList()) {
  147. addMessageToScope(messageScope, nested, export);
  148. }
  149. }
  150. private static Scope<Object> buildScopeTree(CodeGeneratorRequest request) {
  151. Scope<Object> root = Scope.root();
  152. List<String> filesToGenerate = request.getFileToGenerateList();
  153. for (FileDescriptorProto fdp : request.getProtoFileList()) {
  154. Scope<?> packageScope = fdp.hasPackage() ?
  155. root.findOrCreate(fdp.getPackage()) : root;
  156. boolean export = filesToGenerate.contains(fdp.getName());
  157. for (ServiceDescriptorProto sdp : fdp.getServiceList()) {
  158. addServiceToScope(packageScope, sdp, export);
  159. }
  160. for (FieldDescriptorProto efdp : fdp.getExtensionList()) {
  161. addExtensionToScope(packageScope, efdp, export);
  162. }
  163. for (EnumDescriptorProto edp : fdp.getEnumTypeList()) {
  164. addEnumToScope(packageScope, edp, export);
  165. }
  166. for (DescriptorProto dp : fdp.getMessageTypeList()) {
  167. addMessageToScope(packageScope, dp, export);
  168. }
  169. }
  170. return root;
  171. }
  172. private static String getImportType(Scope<?> scope,
  173. FieldDescriptorProto fdp) {
  174. switch (fdp.getType()) {
  175. case TYPE_ENUM:
  176. case TYPE_MESSAGE:
  177. Scope<?> typeScope = scope.find(fdp.getTypeName());
  178. if (typeScope == null) {
  179. throw new IllegalArgumentException(
  180. fdp.getTypeName() + " not found.");
  181. }
  182. return typeScope.fullName;
  183. case TYPE_BYTES:
  184. return "flash.utils.ByteArray";
  185. default:
  186. return null;
  187. }
  188. }
  189. private static boolean isValueType(FieldDescriptorProto.Type type) {
  190. switch (type) {
  191. case TYPE_DOUBLE:
  192. case TYPE_FLOAT:
  193. case TYPE_INT32:
  194. case TYPE_FIXED32:
  195. case TYPE_BOOL:
  196. case TYPE_UINT32:
  197. case TYPE_SFIXED32:
  198. case TYPE_SINT32:
  199. case TYPE_ENUM:
  200. return true;
  201. default:
  202. return false;
  203. }
  204. }
  205. static final int VARINT = 0;
  206. static final int FIXED_64_BIT = 1;
  207. static final int LENGTH_DELIMITED = 2;
  208. static final int FIXED_32_BIT = 5;
  209. private static int getWireType(
  210. FieldDescriptorProto.Type type) {
  211. switch (type) {
  212. case TYPE_DOUBLE:
  213. case TYPE_FIXED64:
  214. case TYPE_SFIXED64:
  215. return FIXED_64_BIT;
  216. case TYPE_FLOAT:
  217. case TYPE_FIXED32:
  218. case TYPE_SFIXED32:
  219. return FIXED_32_BIT;
  220. case TYPE_INT32:
  221. case TYPE_SINT32:
  222. case TYPE_UINT32:
  223. case TYPE_BOOL:
  224. case TYPE_INT64:
  225. case TYPE_UINT64:
  226. case TYPE_SINT64:
  227. case TYPE_ENUM:
  228. return VARINT;
  229. case TYPE_STRING:
  230. case TYPE_MESSAGE:
  231. case TYPE_BYTES:
  232. return LENGTH_DELIMITED;
  233. default:
  234. throw new IllegalArgumentException();
  235. }
  236. }
  237. private static String getActionScript3WireType(
  238. FieldDescriptorProto.Type type) {
  239. switch (type) {
  240. case TYPE_DOUBLE:
  241. case TYPE_FIXED64:
  242. case TYPE_SFIXED64:
  243. return "FIXED_64_BIT";
  244. case TYPE_FLOAT:
  245. case TYPE_FIXED32:
  246. case TYPE_SFIXED32:
  247. return "FIXED_32_BIT";
  248. case TYPE_INT32:
  249. case TYPE_SINT32:
  250. case TYPE_UINT32:
  251. case TYPE_BOOL:
  252. case TYPE_INT64:
  253. case TYPE_UINT64:
  254. case TYPE_SINT64:
  255. case TYPE_ENUM:
  256. return "VARINT";
  257. case TYPE_STRING:
  258. case TYPE_MESSAGE:
  259. case TYPE_BYTES:
  260. return "LENGTH_DELIMITED";
  261. default:
  262. throw new IllegalArgumentException();
  263. }
  264. }
  265. private static String getActionScript3LogicType(Scope<?> scope,
  266. FieldDescriptorProto fdp) {
  267. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_ENUM) {
  268. Scope<?> typeScope = scope.find(fdp.getTypeName());
  269. if (typeScope == null) {
  270. throw new IllegalArgumentException(
  271. fdp.getTypeName() + " not found.");
  272. }
  273. if (typeScope == scope) {
  274. // workaround for mxmlc's bug.
  275. return typeScope.fullName.substring(
  276. typeScope.fullName.lastIndexOf('.') + 1);
  277. }
  278. return typeScope.fullName;
  279. } else {
  280. return getActionScript3Type(scope, fdp);
  281. }
  282. }
  283. private static String getActionScript3Type(Scope<?> scope,
  284. FieldDescriptorProto fdp) {
  285. switch (fdp.getType()) {
  286. case TYPE_DOUBLE:
  287. case TYPE_FLOAT:
  288. return "Number";
  289. case TYPE_INT32:
  290. case TYPE_SFIXED32:
  291. case TYPE_SINT32:
  292. case TYPE_ENUM:
  293. return "int";
  294. case TYPE_UINT32:
  295. case TYPE_FIXED32:
  296. return "uint";
  297. case TYPE_BOOL:
  298. return "Boolean";
  299. case TYPE_INT64:
  300. case TYPE_SFIXED64:
  301. case TYPE_SINT64:
  302. return "Int64";
  303. case TYPE_UINT64:
  304. case TYPE_FIXED64:
  305. return "UInt64";
  306. case TYPE_STRING:
  307. return "String";
  308. case TYPE_MESSAGE:
  309. Scope<?> typeScope = scope.find(fdp.getTypeName());
  310. if (typeScope == null) {
  311. throw new IllegalArgumentException(
  312. fdp.getTypeName() + " not found.");
  313. }
  314. if (typeScope == scope) {
  315. // workaround for mxmlc's bug.
  316. return typeScope.fullName.substring(
  317. typeScope.fullName.lastIndexOf('.') + 1);
  318. }
  319. return typeScope.fullName;
  320. case TYPE_BYTES:
  321. return "flash.utils.ByteArray";
  322. default:
  323. throw new IllegalArgumentException();
  324. }
  325. }
  326. private static void appendQuotedString(StringBuilder sb, String value) {
  327. sb.append('\"');
  328. for (int i = 0; i < value.length(); i++) {
  329. char c = value.charAt(i);
  330. switch (c) {
  331. case '\"':
  332. case '\\':
  333. sb.append('\\');
  334. sb.append(c);
  335. break;
  336. default:
  337. if (c >= 128 || Character.isISOControl(c)) {
  338. sb.append("\\u");
  339. sb.append(String.format("%04X", new Integer(c)));
  340. } else {
  341. sb.append(c);
  342. }
  343. }
  344. }
  345. sb.append('\"');
  346. }
  347. private static void appendDefaultValue(StringBuilder sb, Scope<?> scope,
  348. FieldDescriptorProto fdp) {
  349. String value = fdp.getDefaultValue();
  350. switch (fdp.getType()) {
  351. case TYPE_DOUBLE:
  352. case TYPE_FLOAT:
  353. if (value.equals("nan")) {
  354. sb.append("NaN");
  355. } else if (value.equals("inf")) {
  356. sb.append("Infinity");
  357. } else if (value.equals("-inf")) {
  358. sb.append("-Infinity");
  359. } else {
  360. sb.append(value);
  361. }
  362. break;
  363. case TYPE_UINT64:
  364. case TYPE_FIXED64:
  365. {
  366. long v = new BigInteger(value).longValue();
  367. sb.append("new UInt64(");
  368. sb.append(Long.toString(v & 0xFFFFFFFFL));
  369. sb.append(", ");
  370. sb.append(Long.toString((v >>> 32) & 0xFFFFFFFFL));
  371. sb.append(")");
  372. }
  373. break;
  374. case TYPE_INT64:
  375. case TYPE_SFIXED64:
  376. case TYPE_SINT64:
  377. {
  378. long v = Long.parseLong(value);
  379. sb.append("new Int64(");
  380. sb.append(Long.toString(v & 0xFFFFFFFFL));
  381. sb.append(", ");
  382. sb.append(Integer.toString((int)v >>> 32));
  383. sb.append(")");
  384. }
  385. break;
  386. case TYPE_INT32:
  387. case TYPE_FIXED32:
  388. case TYPE_SFIXED32:
  389. case TYPE_SINT32:
  390. case TYPE_UINT32:
  391. case TYPE_BOOL:
  392. sb.append(value);
  393. break;
  394. case TYPE_STRING:
  395. appendQuotedString(sb, value);
  396. break;
  397. case TYPE_ENUM:
  398. sb.append(scope.find(fdp.getTypeName()).
  399. children.get(value).fullName);
  400. break;
  401. case TYPE_BYTES:
  402. sb.append("stringToByteArray(");
  403. sb.append("\"");
  404. sb.append(value);
  405. sb.append("\")");
  406. break;
  407. default:
  408. throw new IllegalArgumentException();
  409. }
  410. }
  411. private static void appendLowerCamelCase(StringBuilder sb, String s) {
  412. if (Arrays.binarySearch(ACTIONSCRIPT_KEYWORDS, s) >= 0) {
  413. sb.append("__");
  414. }
  415. sb.append(Character.toLowerCase(s.charAt(0)));
  416. boolean upper = false;
  417. for (int i = 1; i < s.length(); i++) {
  418. char c = s.charAt(i);
  419. if (upper) {
  420. if (Character.isLowerCase(c)) {
  421. sb.append(Character.toUpperCase(c));
  422. upper = false;
  423. continue;
  424. } else {
  425. sb.append('_');
  426. }
  427. }
  428. upper = c == '_';
  429. if (!upper) {
  430. sb.append(c);
  431. }
  432. }
  433. }
  434. private static void appendUpperCamelCase(StringBuilder sb, String s) {
  435. sb.append(Character.toUpperCase(s.charAt(0)));
  436. boolean upper = false;
  437. for (int i = 1; i < s.length(); i++) {
  438. char c = s.charAt(i);
  439. if (upper) {
  440. if (Character.isLowerCase(c)) {
  441. sb.append(Character.toUpperCase(c));
  442. upper = false;
  443. continue;
  444. } else {
  445. sb.append('_');
  446. }
  447. }
  448. upper = c == '_';
  449. if (!upper) {
  450. sb.append(c);
  451. }
  452. }
  453. }
  454. private static void writeMessage(Scope<DescriptorProto> scope,
  455. StringBuilder content, StringBuilder initializerContent) {
  456. content.append("\timport com.netease.protobuf.*;\n");
  457. content.append("\tuse namespace com.netease.protobuf.used_by_generated_code;\n");
  458. content.append("\timport com.netease.protobuf.fieldDescriptors.*;\n");
  459. content.append("\timport flash.utils.Endian;\n");
  460. content.append("\timport flash.utils.IDataInput;\n");
  461. content.append("\timport flash.utils.IDataOutput;\n");
  462. content.append("\timport flash.utils.IExternalizable;\n");
  463. content.append("\timport flash.errors.IOError;\n");
  464. HashSet<String> importTypes = new HashSet<String>();
  465. for (FieldDescriptorProto efdp : scope.proto.getExtensionList()) {
  466. importTypes.add(scope.find(efdp.getExtendee()).fullName);
  467. if (efdp.getType().equals(FieldDescriptorProto.Type.TYPE_MESSAGE)) {
  468. importTypes.add(scope.find(efdp.getTypeName()).fullName);
  469. }
  470. String importType = getImportType(scope, efdp);
  471. if (importType != null) {
  472. importTypes.add(importType);
  473. }
  474. }
  475. for (FieldDescriptorProto fdp : scope.proto.getFieldList()) {
  476. String importType = getImportType(scope, fdp);
  477. if (importType != null) {
  478. importTypes.add(importType);
  479. }
  480. }
  481. for (String importType : importTypes) {
  482. content.append("\timport ");
  483. content.append(importType);
  484. content.append(";\n");
  485. }
  486. content.append("\t// @@protoc_insertion_point(imports)\n\n");
  487. String remoteClassAlias;
  488. if (scope.proto.hasOptions()) {
  489. if (scope.proto.getOptions().hasExtension(Options.as3AmfAlias)) {
  490. remoteClassAlias = scope.proto.getOptions().getExtension(Options.as3AmfAlias);
  491. } else if (scope.proto.getOptions().getExtension(Options.as3AmfAutoAlias)) {
  492. remoteClassAlias = scope.fullName;
  493. } else {
  494. remoteClassAlias = null;
  495. }
  496. if (remoteClassAlias != null) {
  497. content.append("\t[RemoteClass(alias=");
  498. appendQuotedString(content, remoteClassAlias);
  499. content.append(")]\n");
  500. }
  501. if (scope.proto.getOptions().getExtension(Options.as3Bindable)) {
  502. content.append("\t[Bindable]\n");
  503. }
  504. } else {
  505. remoteClassAlias = null;
  506. }
  507. content.append("\t// @@protoc_insertion_point(class_metadata)\n");
  508. content.append("\tpublic dynamic final class ");
  509. content.append(scope.proto.getName());
  510. content.append(" extends com.netease.protobuf.Message");
  511. if (remoteClassAlias != null) {
  512. content.append(" implements flash.utils.IExternalizable {\n");
  513. content.append("\t\tpublic final function writeExternal(output:flash.utils.IDataOutput):void {\n");
  514. content.append("\t\t\twriteDelimitedTo(output);\n");
  515. content.append("\t\t}\n\n");
  516. content.append("\t\tpublic final function readExternal(input:flash.utils.IDataInput):void {\n");
  517. content.append("\t\t\tmergeDelimitedFrom(input);\n");
  518. content.append("\t\t}\n\n");
  519. } else {
  520. content.append(" {\n");
  521. }
  522. if (scope.proto.getExtensionRangeCount() > 0) {
  523. content.append("\t\t[ArrayElementType(\"Function\")]\n");
  524. content.append("\t\tpublic static const extensionReadFunctions:Array = [];\n\n");
  525. }
  526. if (scope.proto.getExtensionCount() > 0) {
  527. initializerContent.append("import ");
  528. initializerContent.append(scope.fullName);
  529. initializerContent.append(";\n");
  530. initializerContent.append("void(");
  531. initializerContent.append(scope.fullName);
  532. initializerContent.append(");\n");
  533. }
  534. for (FieldDescriptorProto efdp : scope.proto.getExtensionList()) {
  535. if (efdp.getType() == FieldDescriptorProto.Type.TYPE_GROUP) {
  536. System.err.println("Warning: Group is not supported.");
  537. continue;
  538. }
  539. String extendee = scope.find(efdp.getExtendee()).fullName;
  540. content.append("\t\t/**\n\t\t * @private\n\t\t */\n");
  541. content.append("\t\tpublic static const ");
  542. content.append(efdp.getName().toUpperCase());
  543. content.append(":");
  544. appendFieldDescriptorClass(content, efdp);
  545. content.append(" = ");
  546. appendFieldDescriptor(content, scope, efdp);
  547. content.append(";\n\n");
  548. if (efdp.hasDefaultValue()) {
  549. content.append("\t\t");
  550. content.append(extendee);
  551. content.append(".prototype[");
  552. content.append(efdp.getName().toUpperCase());
  553. content.append("] = ");
  554. appendDefaultValue(content, scope, efdp);
  555. content.append(";\n\n");
  556. }
  557. appendExtensionReadFunction(content, "\t\t", scope, efdp);
  558. }
  559. int valueTypeCount = 0;
  560. for (FieldDescriptorProto fdp : scope.proto.getFieldList()) {
  561. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_GROUP) {
  562. System.err.println("Warning: Group is not supported.");
  563. continue;
  564. }
  565. content.append("\t\t/**\n\t\t * @private\n\t\t */\n");
  566. content.append("\t\tpublic static const ");
  567. content.append(fdp.getName().toUpperCase());
  568. content.append(":");
  569. appendFieldDescriptorClass(content, fdp);
  570. content.append(" = ");
  571. appendFieldDescriptor(content, scope, fdp);
  572. content.append(";\n\n");
  573. assert(fdp.hasLabel());
  574. switch (fdp.getLabel()) {
  575. case LABEL_OPTIONAL:
  576. content.append("\t\tprivate var ");
  577. content.append(fdp.getName());
  578. content.append("$field:");
  579. content.append(getActionScript3Type(scope, fdp));
  580. content.append(";\n\n");
  581. if (isValueType(fdp.getType())) {
  582. final int valueTypeId = valueTypeCount++;
  583. final int valueTypeField = valueTypeId / 32;
  584. final int valueTypeBit = valueTypeId % 32;
  585. if (valueTypeBit == 0) {
  586. content.append("\t\tprivate var hasField$");
  587. content.append(valueTypeField);
  588. content.append(":uint = 0;\n\n");
  589. }
  590. content.append("\t\tpublic function clear");
  591. appendUpperCamelCase(content, fdp.getName());
  592. content.append("():void {\n");
  593. content.append("\t\t\thasField$");
  594. content.append(valueTypeField);
  595. content.append(" &= 0x");
  596. content.append(Integer.toHexString(~(1 << valueTypeBit)));
  597. content.append(";\n");
  598. content.append("\t\t\t");
  599. content.append(fdp.getName());
  600. content.append("$field = new ");
  601. content.append(getActionScript3Type(scope, fdp));
  602. content.append("();\n");
  603. content.append("\t\t}\n\n");
  604. content.append("\t\tpublic function get has");
  605. appendUpperCamelCase(content, fdp.getName());
  606. content.append("():Boolean {\n");
  607. content.append("\t\t\treturn (hasField$");
  608. content.append(valueTypeField);
  609. content.append(" & 0x");
  610. content.append(Integer.toHexString(1 << valueTypeBit));
  611. content.append(") != 0;\n");
  612. content.append("\t\t}\n\n");
  613. content.append("\t\tpublic function set ");
  614. appendLowerCamelCase(content, fdp.getName());
  615. content.append("(value:");
  616. content.append(getActionScript3Type(scope, fdp));
  617. content.append("):void {\n");
  618. content.append("\t\t\thasField$");
  619. content.append(valueTypeField);
  620. content.append(" |= 0x");
  621. content.append(Integer.toHexString(1 << valueTypeBit));
  622. content.append(";\n");
  623. content.append("\t\t\t");
  624. content.append(fdp.getName());
  625. content.append("$field = value;\n");
  626. content.append("\t\t}\n\n");
  627. } else {
  628. content.append("\t\tpublic function clear");
  629. appendUpperCamelCase(content, fdp.getName());
  630. content.append("():void {\n");
  631. content.append("\t\t\t");
  632. content.append(fdp.getName());
  633. content.append("$field = null;\n");
  634. content.append("\t\t}\n\n");
  635. content.append("\t\tpublic function get has");
  636. appendUpperCamelCase(content, fdp.getName());
  637. content.append("():Boolean {\n");
  638. content.append("\t\t\treturn ");
  639. content.append(fdp.getName());
  640. content.append("$field != null;\n");
  641. content.append("\t\t}\n\n");
  642. content.append("\t\tpublic function set ");
  643. appendLowerCamelCase(content, fdp.getName());
  644. content.append("(value:");
  645. content.append(getActionScript3Type(scope, fdp));
  646. content.append("):void {\n");
  647. content.append("\t\t\t");
  648. content.append(fdp.getName());
  649. content.append("$field = value;\n");
  650. content.append("\t\t}\n\n");
  651. }
  652. content.append("\t\tpublic function get ");
  653. appendLowerCamelCase(content, fdp.getName());
  654. content.append("():");
  655. content.append(getActionScript3Type(scope, fdp));
  656. content.append(" {\n");
  657. if (fdp.hasDefaultValue()) {
  658. content.append("\t\t\tif(!has");
  659. appendUpperCamelCase(content, fdp.getName());
  660. content.append(") {\n");
  661. content.append("\t\t\t\treturn ");
  662. appendDefaultValue(content, scope, fdp);
  663. content.append(";\n");
  664. content.append("\t\t\t}\n");
  665. }
  666. content.append("\t\t\treturn ");
  667. content.append(fdp.getName());
  668. content.append("$field;\n");
  669. content.append("\t\t}\n\n");
  670. break;
  671. case LABEL_REQUIRED:
  672. content.append("\t\tpublic var ");
  673. appendLowerCamelCase(content, fdp.getName());
  674. content.append(":");
  675. content.append(getActionScript3Type(scope, fdp));
  676. if (fdp.hasDefaultValue()) {
  677. content.append(" = ");
  678. appendDefaultValue(content, scope, fdp);
  679. }
  680. content.append(";\n\n");
  681. break;
  682. case LABEL_REPEATED:
  683. content.append("\t\t[ArrayElementType(\"");
  684. content.append(getActionScript3Type(scope, fdp));
  685. content.append("\")]\n");
  686. content.append("\t\tpublic var ");
  687. appendLowerCamelCase(content, fdp.getName());
  688. content.append(":Array = [];\n\n");
  689. break;
  690. default:
  691. throw new IllegalArgumentException();
  692. }
  693. }
  694. content.append("\t\t/**\n\t\t * @private\n\t\t */\n\t\toverride com.netease.protobuf.used_by_generated_code final function writeToBuffer(output:com.netease.protobuf.WritingBuffer):void {\n");
  695. for (FieldDescriptorProto fdp : scope.proto.getFieldList()) {
  696. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_GROUP) {
  697. System.err.println("Warning: Group is not supported.");
  698. continue;
  699. }
  700. switch (fdp.getLabel()) {
  701. case LABEL_OPTIONAL:
  702. content.append("\t\t\tif (");
  703. content.append("has");
  704. appendUpperCamelCase(content, fdp.getName());
  705. content.append(") {\n");
  706. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.writeTag(output, com.netease.protobuf.WireType.");
  707. content.append(getActionScript3WireType(fdp.getType()));
  708. content.append(", ");
  709. content.append(Integer.toString(fdp.getNumber()));
  710. content.append(");\n");
  711. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.write$");
  712. content.append(fdp.getType().name());
  713. content.append("(output, ");
  714. content.append(fdp.getName());
  715. content.append("$field);\n");
  716. content.append("\t\t\t}\n");
  717. break;
  718. case LABEL_REQUIRED:
  719. content.append("\t\t\tcom.netease.protobuf.WriteUtils.writeTag(output, com.netease.protobuf.WireType.");
  720. content.append(getActionScript3WireType(fdp.getType()));
  721. content.append(", ");
  722. content.append(Integer.toString(fdp.getNumber()));
  723. content.append(");\n");
  724. content.append("\t\t\tcom.netease.protobuf.WriteUtils.write$");
  725. content.append(fdp.getType().name());
  726. content.append("(output, this.");
  727. appendLowerCamelCase(content, fdp.getName());
  728. content.append(");\n");
  729. break;
  730. case LABEL_REPEATED:
  731. if (fdp.hasOptions() && fdp.getOptions().getPacked()) {
  732. content.append("\t\t\tif (this.");
  733. appendLowerCamelCase(content, fdp.getName());
  734. content.append(" != null && this.");
  735. appendLowerCamelCase(content, fdp.getName());
  736. content.append(".length > 0) {\n");
  737. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.writeTag(output, com.netease.protobuf.WireType.LENGTH_DELIMITED, ");
  738. content.append(Integer.toString(fdp.getNumber()));
  739. content.append(");\n");
  740. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.writePackedRepeated(output, com.netease.protobuf.WriteUtils.write$");
  741. content.append(fdp.getType().name());
  742. content.append(", this.");
  743. appendLowerCamelCase(content, fdp.getName());
  744. content.append(");\n");
  745. content.append("\t\t\t}\n");
  746. } else {
  747. content.append("\t\t\tfor (var ");
  748. appendLowerCamelCase(content, fdp.getName());
  749. content.append("$index:uint = 0; ");
  750. appendLowerCamelCase(content, fdp.getName());
  751. content.append("$index < this.");
  752. appendLowerCamelCase(content, fdp.getName());
  753. content.append(".length; ++");
  754. appendLowerCamelCase(content, fdp.getName());
  755. content.append("$index) {\n");
  756. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.writeTag(output, com.netease.protobuf.WireType.");
  757. content.append(getActionScript3WireType(fdp.getType()));
  758. content.append(", ");
  759. content.append(Integer.toString(fdp.getNumber()));
  760. content.append(");\n");
  761. content.append("\t\t\t\tcom.netease.protobuf.WriteUtils.write$");
  762. content.append(fdp.getType().name());
  763. content.append("(output, this.");
  764. appendLowerCamelCase(content, fdp.getName());
  765. content.append("[");
  766. appendLowerCamelCase(content, fdp.getName());
  767. content.append("$index]);\n");
  768. content.append("\t\t\t}\n");
  769. }
  770. break;
  771. }
  772. }
  773. content.append("\t\t\tfor (var fieldKey:* in this) {\n");
  774. if (scope.proto.getExtensionRangeCount() > 0) {
  775. content.append("\t\t\t\tsuper.writeExtensionOrUnknown(output, fieldKey);\n");
  776. } else {
  777. content.append("\t\t\t\tsuper.writeUnknown(output, fieldKey);\n");
  778. }
  779. content.append("\t\t\t}\n");
  780. content.append("\t\t}\n\n");
  781. content.append("\t\t/**\n\t\t * @private\n\t\t */\n");
  782. content.append("\t\toverride com.netease.protobuf.used_by_generated_code final function readFromSlice(input:flash.utils.IDataInput, bytesAfterSlice:uint):void {\n");
  783. for (FieldDescriptorProto fdp : scope.proto.getFieldList()) {
  784. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_GROUP) {
  785. System.err.println("Warning: Group is not supported.");
  786. continue;
  787. }
  788. switch (fdp.getLabel()) {
  789. case LABEL_OPTIONAL:
  790. case LABEL_REQUIRED:
  791. content.append("\t\t\tvar ");
  792. content.append(fdp.getName());
  793. content.append("$count:uint = 0;\n");
  794. break;
  795. }
  796. }
  797. content.append("\t\t\twhile (input.bytesAvailable > bytesAfterSlice) {\n");
  798. content.append("\t\t\t\tvar tag:uint = com.netease.protobuf.ReadUtils.read$TYPE_UINT32(input);\n");
  799. content.append("\t\t\t\tswitch (tag >> 3) {\n");
  800. for (FieldDescriptorProto fdp : scope.proto.getFieldList()) {
  801. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_GROUP) {
  802. System.err.println("Warning: Group is not supported.");
  803. continue;
  804. }
  805. content.append("\t\t\t\tcase ");
  806. content.append(Integer.toString(fdp.getNumber()));
  807. content.append(":\n");
  808. switch (fdp.getLabel()) {
  809. case LABEL_OPTIONAL:
  810. case LABEL_REQUIRED:
  811. content.append("\t\t\t\t\tif (");
  812. content.append(fdp.getName());
  813. content.append("$count != 0) {\n");
  814. content.append("\t\t\t\t\t\tthrow new flash.errors.IOError('Bad data format: ");
  815. content.append(scope.proto.getName());
  816. content.append('.');
  817. appendLowerCamelCase(content, fdp.getName());
  818. content.append(" cannot be set twice.');\n");
  819. content.append("\t\t\t\t\t}\n");
  820. content.append("\t\t\t\t\t++");
  821. content.append(fdp.getName());
  822. content.append("$count;\n");
  823. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE) {
  824. content.append("\t\t\t\t\tthis.");
  825. appendLowerCamelCase(content, fdp.getName());
  826. content.append(" = new ");
  827. content.append(getActionScript3Type(scope, fdp));
  828. content.append("();\n");
  829. content.append("\t\t\t\t\tcom.netease.protobuf.ReadUtils.read$TYPE_MESSAGE(input, this.");
  830. appendLowerCamelCase(content, fdp.getName());
  831. content.append(");\n");
  832. } else {
  833. content.append("\t\t\t\t\tthis.");
  834. appendLowerCamelCase(content, fdp.getName());
  835. content.append(" = com.netease.protobuf.ReadUtils.read$");
  836. content.append(fdp.getType().name());
  837. content.append("(input);\n");
  838. }
  839. break;
  840. case LABEL_REPEATED:
  841. switch (fdp.getType()) {
  842. case TYPE_DOUBLE:
  843. case TYPE_FLOAT:
  844. case TYPE_BOOL:
  845. case TYPE_INT32:
  846. case TYPE_FIXED32:
  847. case TYPE_UINT32:
  848. case TYPE_SFIXED32:
  849. case TYPE_SINT32:
  850. case TYPE_INT64:
  851. case TYPE_FIXED64:
  852. case TYPE_UINT64:
  853. case TYPE_SFIXED64:
  854. case TYPE_SINT64:
  855. case TYPE_ENUM:
  856. content.append("\t\t\t\t\tif ((tag & 7) == com.netease.protobuf.WireType.LENGTH_DELIMITED) {\n");
  857. content.append("\t\t\t\t\t\tcom.netease.protobuf.ReadUtils.readPackedRepeated(input, com.netease.protobuf.ReadUtils.read$");
  858. content.append(fdp.getType().name());
  859. content.append(", this.");
  860. appendLowerCamelCase(content, fdp.getName());
  861. content.append(");\n");
  862. content.append("\t\t\t\t\t\tbreak;\n");
  863. content.append("\t\t\t\t\t}\n");
  864. }
  865. if (fdp.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE) {
  866. content.append("\t\t\t\t\tthis.");
  867. appendLowerCamelCase(content, fdp.getName());
  868. content.append(".push(");
  869. content.append("com.netease.protobuf.ReadUtils.read$TYPE_MESSAGE(input, ");
  870. content.append("new ");
  871. content.append(getActionScript3Type(scope, fdp));
  872. content.append("()));\n");
  873. } else {
  874. content.append("\t\t\t\t\tthis.");
  875. appendLowerCamelCase(content, fdp.getName());
  876. content.append(".push(com.netease.protobuf.ReadUtils.read$");
  877. content.append(fdp.getType().name());
  878. content.append("(input));\n");
  879. }
  880. break;
  881. }
  882. content.append("\t\t\t\t\tbreak;\n");
  883. }
  884. content.append("\t\t\t\tdefault:\n");
  885. if (scope.proto.getExtensionRangeCount() > 0) {
  886. content.append("\t\t\t\t\tsuper.readExtensionOrUnknown(extensionReadFunctions, input, tag);\n");
  887. } else {
  888. content.append("\t\t\t\t\tsuper.readUnknown(input, tag);\n");
  889. }
  890. content.append("\t\t\t\t\tbreak;\n");
  891. content.append("\t\t\t\t}\n");
  892. content.append("\t\t\t}\n");
  893. content.append("\t\t}\n\n");
  894. content.append("\t}\n");
  895. }
  896. private static void appendFieldDescriptorClass(StringBuilder content,
  897. FieldDescriptorProto fdp) {
  898. switch (fdp.getLabel()) {
  899. case LABEL_REQUIRED:
  900. case LABEL_OPTIONAL:
  901. break;
  902. case LABEL_REPEATED:
  903. content.append("Repeated");
  904. break;
  905. default:
  906. throw new IllegalArgumentException();
  907. }
  908. content.append("FieldDescriptor$");
  909. content.append(fdp.getType().name());
  910. }
  911. private static void appendFieldDescriptor(StringBuilder content,
  912. Scope<?> scope,
  913. FieldDescriptorProto fdp) {
  914. content.append("new ");
  915. appendFieldDescriptorClass(content, fdp);
  916. content.append("(");
  917. if (scope.parent == null) {
  918. appendQuotedString(content, fdp.getName());
  919. } else {
  920. appendQuotedString(content, scope.fullName + '.' + fdp.getName());
  921. }
  922. content.append(", ");
  923. if (fdp.hasExtendee()) {
  924. if (scope.proto instanceof DescriptorProto) {
  925. appendQuotedString(content, scope.fullName + '/' + fdp.getName().toUpperCase());
  926. } else {
  927. if (scope.parent == null) {
  928. appendQuotedString(content, fdp.getName().toUpperCase());
  929. } else {
  930. appendQuotedString(content, scope.fullName + '.' + fdp.getName().toUpperCase());
  931. }
  932. }
  933. } else {
  934. StringBuilder fieldName = new StringBuilder();
  935. appendLowerCamelCase(fieldName, fdp.getName());
  936. appendQuotedString(content, fieldName.toString());
  937. }
  938. content.append(", (");
  939. switch (fdp.getLabel()) {
  940. case LABEL_REQUIRED:
  941. case LABEL_OPTIONAL:
  942. content.append(Integer.toString(fdp.getNumber()));
  943. content.append(" << 3) | com.netease.protobuf.WireType.");
  944. content.append(getActionScript3WireType(fdp.getType()));
  945. break;
  946. case LABEL_REPEATED:
  947. if (fdp.hasOptions() && fdp.getOptions().getPacked()) {
  948. content.append(Integer.toString(fdp.getNumber()));
  949. content.append(" << 3) | com.netease.protobuf.WireType.LENGTH_DELIMITED");
  950. } else {
  951. content.append(Integer.toString(fdp.getNumber()));
  952. content.append(" << 3) | com.netease.protobuf.WireType.");
  953. content.append(getActionScript3WireType(fdp.getType()));
  954. }
  955. break;
  956. }
  957. switch (fdp.getType()) {
  958. case TYPE_MESSAGE:
  959. if (scope.proto instanceof DescriptorProto) {
  960. content.append(", function():Class { return ");
  961. content.append(getActionScript3LogicType(scope, fdp));
  962. content.append("; }");
  963. } else {
  964. content.append(", ");
  965. content.append(getActionScript3LogicType(scope, fdp));
  966. }
  967. break;
  968. case TYPE_ENUM:
  969. content.append(", ");
  970. content.append(getActionScript3LogicType(scope, fdp));
  971. break;
  972. }
  973. content.append(")");
  974. }
  975. private static void appendExtensionReadFunction(StringBuilder content,
  976. String tabs,
  977. Scope<?> scope,
  978. FieldDescriptorProto fdp) {
  979. String extendee = scope.find(fdp.getExtendee()).fullName;
  980. switch (fdp.getLabel()) {
  981. case LABEL_REQUIRED:
  982. case LABEL_OPTIONAL:
  983. content.append(tabs);
  984. content.append(extendee);
  985. content.append(".extensionReadFunctions[(");
  986. content.append(Integer.toString(fdp.getNumber()));
  987. content.append(" << 3) | com.netease.protobuf.WireType.");
  988. content.append(getActionScript3WireType(fdp.getType()));
  989. content.append("] = ");
  990. content.append(fdp.getName().toUpperCase());
  991. content.append(".read;\n\n");
  992. break;
  993. case LABEL_REPEATED:
  994. content.append(tabs);
  995. content.append(extendee);
  996. content.append(".extensionReadFunctions[(");
  997. content.append(Integer.toString(fdp.getNumber()));
  998. content.append(" << 3) | com.netease.protobuf.WireType.");
  999. content.append(getActionScript3WireType(fdp.getType()));
  1000. content.append("] = ");
  1001. content.append(fdp.getName().toUpperCase());
  1002. content.append(".readNonPacked;\n\n");
  1003. switch (fdp.getType()) {
  1004. case TYPE_MESSAGE:
  1005. case TYPE_BYTES:
  1006. case TYPE_STRING:
  1007. break;
  1008. default:
  1009. content.append(tabs);
  1010. content.append(extendee);
  1011. content.append(".extensionReadFunctions[(");
  1012. content.append(Integer.toString(fdp.getNumber()));
  1013. content.append(" << 3) | com.netease.protobuf.WireType.LENGTH_DELIMITED] = ");
  1014. content.append(fdp.getName().toUpperCase());
  1015. content.append(".readPacked;\n\n");
  1016. break;
  1017. }
  1018. break;
  1019. }
  1020. }
  1021. private static void writeExtension(Scope<FieldDescriptorProto> scope,
  1022. StringBuilder content, StringBuilder initializerContent) {
  1023. initializerContent.append("import ");
  1024. initializerContent.append(scope.fullName);
  1025. initializerContent.append(";\n");
  1026. initializerContent.append("void(");
  1027. initializerContent.append(scope.fullName);
  1028. initializerContent.append(");\n");
  1029. content.append("\timport com.netease.protobuf.*;\n");
  1030. content.append("\timport com.netease.protobuf.fieldDescriptors.*;\n");
  1031. String importType = getImportType(scope.parent, scope.proto);
  1032. if (importType != null) {
  1033. content.append("\timport ");
  1034. content.append(importType);
  1035. content.append(";\n");
  1036. }
  1037. String extendee = scope.parent.find(scope.proto.getExtendee()).fullName;
  1038. content.append("\timport ");
  1039. content.append(extendee);
  1040. content.append(";\n");
  1041. content.append("\t// @@protoc_insertion_point(imports)\n\n");
  1042. content.append("\t// @@protoc_insertion_point(constant_metadata)\n");
  1043. content.append("\t/**\n\t * @private\n\t */\n");
  1044. content.append("\tpublic const ");
  1045. content.append(scope.proto.getName().toUpperCase());
  1046. content.append(":");
  1047. appendFieldDescriptorClass(content, scope.proto);
  1048. content.append(" = ");
  1049. appendFieldDescriptor(content, scope.parent, scope.proto);
  1050. content.append(";\n\n");
  1051. if (scope.proto.hasDefaultValue()) {
  1052. content.append("\t");
  1053. content.append(extendee);
  1054. content.append(".prototype[");
  1055. content.append(scope.proto.getName().toUpperCase());
  1056. content.append("] = ");
  1057. appendDefaultValue(content, scope.parent, scope.proto);
  1058. content.append(";\n\n");
  1059. }
  1060. appendExtensionReadFunction(content, "\t", scope.parent, scope.proto);
  1061. }
  1062. private static void writeEnum(Scope<EnumDescriptorProto> scope,
  1063. StringBuilder content) {
  1064. content.append("\tpublic final class ");
  1065. content.append(scope.proto.getName());
  1066. content.append(" {\n");
  1067. for (EnumValueDescriptorProto evdp : scope.proto.getValueList()) {
  1068. content.append("\t\tpublic static const ");
  1069. content.append(evdp.getName());
  1070. content.append(":int = ");
  1071. content.append(evdp.getNumber());
  1072. content.append(";\n");
  1073. }
  1074. content.append("\t}\n");
  1075. }
  1076. @SuppressWarnings("unchecked")
  1077. private static void writeFile(Scope<?> scope, StringBuilder content,
  1078. StringBuilder initializerContent) {
  1079. content.append("package ");
  1080. content.append(scope.parent.fullName);
  1081. content.append(" {\n");
  1082. if (scope.proto instanceof DescriptorProto) {
  1083. writeMessage((Scope<DescriptorProto>)scope, content,
  1084. initializerContent);
  1085. } else if (scope.proto instanceof EnumDescriptorProto) {
  1086. writeEnum((Scope<EnumDescriptorProto>)scope, content);
  1087. } else if (scope.proto instanceof FieldDescriptorProto) {
  1088. Scope<FieldDescriptorProto> fdpScope =
  1089. (Scope<FieldDescriptorProto>)scope;
  1090. if (fdpScope.proto.getType() ==
  1091. FieldDescriptorProto.Type.TYPE_GROUP) {
  1092. System.err.println("Warning: Group is not supported.");
  1093. } else {
  1094. writeExtension(fdpScope, content, initializerContent);
  1095. }
  1096. } else {
  1097. throw new IllegalArgumentException();
  1098. }
  1099. content.append("}\n");
  1100. }
  1101. @SuppressWarnings("unchecked")
  1102. private static void writeFiles(Scope<?> root,
  1103. CodeGeneratorResponse.Builder responseBuilder,
  1104. StringBuilder initializerContent) {
  1105. for (Map.Entry<String, Scope<?>> entry : root.children.entrySet()) {
  1106. Scope<?> scope = entry.getValue();
  1107. if (scope.export) {
  1108. if (scope.proto instanceof ServiceDescriptorProto) {
  1109. ServiceDescriptorProto serviceProto = (ServiceDescriptorProto)scope.proto;
  1110. if (serviceProto.getOptions().getExtension(Options.as3ClientSideService) ||
  1111. serviceProto.getOptions().getExtension(Options.as3ServerSideService)) {
  1112. StringBuilder classContent = new StringBuilder();
  1113. writeServiceClass((Scope<ServiceDescriptorProto>)scope, classContent);
  1114. responseBuilder.addFile(
  1115. CodeGeneratorResponse.File.newBuilder().
  1116. setName(scope.fullName.replace('.', '/') + ".as").
  1117. setContent(classContent.toString()).
  1118. build()
  1119. );
  1120. StringBuilder interfaceContent = new StringBuilder();
  1121. writeServiceInterface((Scope<ServiceDescriptorProto>)scope, interfaceContent);
  1122. String[] servicePath = scope.fullName.split("\\.");
  1123. StringBuilder sb = new StringBuilder();
  1124. int i = 0;
  1125. for (; i < servicePath.length - 1; i++) {
  1126. sb.append(servicePath[i]);
  1127. sb.append('/');
  1128. }
  1129. sb.append('I');
  1130. sb.append(servicePath[i]);
  1131. sb.append(".as");
  1132. responseBuilder.addFile(
  1133. CodeGeneratorResponse.File.newBuilder().
  1134. setName(sb.toString()).
  1135. setContent(interfaceContent.toString()).
  1136. build()
  1137. );
  1138. }
  1139. }
  1140. else
  1141. {
  1142. StringBuilder content = new StringBuilder();
  1143. writeFile(scope, content, initializerContent);
  1144. responseBuilder.addFile(
  1145. CodeGeneratorResponse.File.newBuilder().
  1146. setName(scope.fullName.replace('.', '/') + ".as").
  1147. setContent(content.toString()).
  1148. build()
  1149. );
  1150. }
  1151. }
  1152. writeFiles(scope, responseBuilder, initializerContent);
  1153. }
  1154. }
  1155. private static void writeFiles(Scope<?> root,
  1156. CodeGeneratorResponse.Builder responseBuilder) {
  1157. StringBuilder initializerContent = new StringBuilder();
  1158. initializerContent.append("{\n");
  1159. writeFiles(root, responseBuilder, initializerContent);
  1160. initializerContent.append("}\n");
  1161. responseBuilder.addFile(
  1162. CodeGeneratorResponse.File.newBuilder().
  1163. setName("initializer.as.inc").
  1164. setContent(initializerContent.toString()).
  1165. build()
  1166. );
  1167. }
  1168. private static void writeServiceClass(Scope<ServiceDescriptorProto> scope,
  1169. StringBuilder content) {
  1170. content.append("package ");
  1171. content.append(scope.parent.fullName);
  1172. content.append(" {\n");
  1173. HashSet<String> importTypes = new HashSet<String>();
  1174. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1175. importTypes.add(scope.find(mdp.getInputType()).fullName);
  1176. if (scope.proto.getOptions().getExtension(Options.as3ClientSideService)) {
  1177. importTypes.add(scope.find(mdp.getOutputType()).fullName);
  1178. }
  1179. }
  1180. for (String importType : importTypes) {
  1181. content.append("\timport ");
  1182. content.append(importType);
  1183. content.append(";\n");
  1184. }
  1185. content.append("\timport google.protobuf.*;\n");
  1186. content.append("\timport flash.utils.*;\n");
  1187. content.append("\timport com.netease.protobuf.*;\n");
  1188. content.append("\t// @@protoc_insertion_point(imports)\n\n");
  1189. content.append("\tpublic final class ");
  1190. content.append(scope.proto.getName());
  1191. if (scope.proto.getOptions().getExtension(Options.as3ClientSideService)) {
  1192. content.append(" implements ");
  1193. content.append(scope.parent.fullName);
  1194. content.append(".I");
  1195. content.append(scope.proto.getName());
  1196. }
  1197. content.append(" {\n");
  1198. if (scope.proto.hasOptions()) {
  1199. content.append("\t\tpublic static const OPTIONS_BYTES:flash.utils.ByteArray = com.netease.protobuf.stringToByteArray(\"");
  1200. ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  1201. try {
  1202. scope.proto.getOptions().writeTo(buffer);
  1203. } catch (IOException e) {
  1204. throw new AssertionError("ByteArrayOutputStream should not throw IOException!", e);
  1205. }
  1206. for (byte b : buffer.toByteArray()) {
  1207. content.append("\\x");
  1208. content.append(Character.forDigit((b & 0xF0) >>> 4, 16));
  1209. content.append(Character.forDigit(b & 0x0F, 16));
  1210. }
  1211. content.append("\");\n\n");
  1212. content.append("\t\tpublic static function getOptions():google.protobuf.ServiceOptions\n");
  1213. content.append("\t\t{\n");
  1214. content.append("\t\t\tconst options:google.protobuf.ServiceOptions = new google.protobuf.ServiceOptions();\n");
  1215. content.append("\t\t\toptions.mergeFrom(OPTIONS_BYTES);\n\n");
  1216. content.append("\t\t\treturn options;\n");
  1217. content.append("\t\t}\n\n");
  1218. }
  1219. boolean hasMethodOptions = false;
  1220. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1221. if (mdp.hasOptions()) {
  1222. if (!hasMethodOptions) {
  1223. hasMethodOptions = true;
  1224. content.append("\t\tpublic static const OPTIONS_BYTES_BY_METHOD_NAME:Object =\n");
  1225. content.append("\t\t{\n");
  1226. } else {
  1227. content.append(",\n");
  1228. }
  1229. content.append("\t\t\t\"");
  1230. content.append(scope.fullName);
  1231. content.append(".");
  1232. content.append(mdp.getName());
  1233. content.append("\" : stringToByteArray(\"");
  1234. ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  1235. try {
  1236. mdp.getOptions().writeTo(buffer);
  1237. } catch (IOException e) {
  1238. throw new AssertionError("ByteArrayOutputStream should not throw IOException!", e);
  1239. }
  1240. for (byte b : buffer.toByteArray()) {
  1241. content.append("\\x");
  1242. content.append(Character.forDigit((b & 0xF0) >>> 4, 16));
  1243. content.append(Character.forDigit(b & 0x0F, 16));
  1244. }
  1245. content.append("\")");
  1246. }
  1247. }
  1248. if (hasMethodOptions) {
  1249. content.append("\n\t\t};\n\n");
  1250. }
  1251. if (scope.proto.getOptions().getExtension(Options.as3ServerSideService)) {
  1252. content.append("\t\tpublic static const REQUEST_CLASSES_BY_METHOD_NAME:Object =\n");
  1253. content.append("\t\t{\n");
  1254. boolean comma = false;
  1255. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1256. if (comma) {
  1257. content.append(",\n");
  1258. } else {
  1259. comma = true;
  1260. }
  1261. content.append("\t\t\t\"");
  1262. content.append(scope.fullName);
  1263. content.append(".");
  1264. content.append(mdp.getName());
  1265. content.append("\" : ");
  1266. content.append(scope.find(mdp.getInputType()).fullName);
  1267. }
  1268. content.append("\n\t\t};\n\n");
  1269. content.append("\t\tpublic static function callMethod(service:");
  1270. content.append(scope.parent.fullName);
  1271. content.append(".I");
  1272. content.append(scope.proto.getName());
  1273. content.append(", methodName:String, request:com.netease.protobuf.Message, responseHandler:Function):void {\n");
  1274. content.append("\t\t\tswitch (methodName) {\n");
  1275. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1276. content.append("\t\t\t\tcase \"");
  1277. content.append(scope.fullName);
  1278. content.append(".");
  1279. content.append(mdp.getName());
  1280. content.append("\":\n");
  1281. content.append("\t\t\t\t{\n");
  1282. content.append("\t\t\t\t\tservice.");
  1283. appendLowerCamelCase(content, mdp.getName());
  1284. content.append("(");
  1285. content.append(scope.find(mdp.getInputType()).fullName);
  1286. content.append("(request), responseHandler);\n");
  1287. content.append("\t\t\t\t\tbreak;\n");
  1288. content.append("\t\t\t\t}\n");
  1289. }
  1290. content.append("\t\t\t}\n");
  1291. content.append("\t\t}\n\n");
  1292. }
  1293. if (scope.proto.getOptions().getExtension(Options.as3ClientSideService)) {
  1294. content.append("\t\tpublic var sendFunction:Function;\n\n");
  1295. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1296. content.append("\t\tpublic function ");
  1297. appendLowerCamelCase(content, mdp.getName());
  1298. content.append("(request:");
  1299. content.append(scope.find(mdp.getInputType()).fullName);
  1300. content.append(", responseHandler:Function):void {\n");
  1301. content.append("\t\t\tsendFunction(\"");
  1302. content.append(scope.fullName);
  1303. content.append(".");
  1304. content.append(mdp.getName());
  1305. content.append("\", request, responseHandler, ");
  1306. content.append(scope.find(mdp.getOutputType()).fullName);
  1307. content.append(");\n");
  1308. content.append("\t\t}\n\n");
  1309. }
  1310. }
  1311. content.append("\t}\n");
  1312. content.append("}\n");
  1313. }
  1314. private static void writeServiceInterface(
  1315. Scope<ServiceDescriptorProto> scope,
  1316. StringBuilder content) {
  1317. content.append("package ");
  1318. content.append(scope.parent.fullName);
  1319. content.append(" {\n");
  1320. HashSet<String> importTypes = new HashSet<String>();
  1321. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1322. importTypes.add(scope.find(mdp.getInputType()).fullName);
  1323. }
  1324. for (String importType : importTypes) {
  1325. content.append("\timport ");
  1326. content.append(importType);
  1327. content.append(";\n");
  1328. }
  1329. content.append("\t// @@protoc_insertion_point(imports)\n\n");
  1330. content.append("\tpublic interface I");
  1331. content.append(scope.proto.getName());
  1332. content.append(" {\n");
  1333. content.append("\n\n");
  1334. for (MethodDescriptorProto mdp : scope.proto.getMethodList()) {
  1335. content.append("\t\tfunction ");
  1336. appendLowerCamelCase(content, mdp.getName());
  1337. content.append("(input:");
  1338. content.append(scope.find(mdp.getInputType()).fullName);
  1339. content.append(", done:Function):void;\n\n");
  1340. }
  1341. content.append("\t}\n");
  1342. content.append("}\n");
  1343. }
  1344. public static void main(String[] args) throws IOException {
  1345. ExtensionRegistry registry = ExtensionRegistry.newInstance();
  1346. Options.registerAllExtensions(registry);
  1347. CodeGeneratorRequest request = CodeGeneratorRequest.
  1348. parseFrom(System.in, registry);
  1349. CodeGeneratorResponse response;
  1350. try {
  1351. Scope<Object> root = buildScopeTree(request);
  1352. CodeGeneratorResponse.Builder responseBuilder =
  1353. CodeGeneratorResponse.newBuilder();
  1354. writeFiles(root, responseBuilder);
  1355. response = responseBuilder.build();
  1356. } catch (Exception e) {
  1357. // ?????? protoc ?????
  1358. StringWriter sw = new StringWriter();
  1359. PrintWriter pw = new PrintWriter(sw);
  1360. e.printStackTrace(pw);
  1361. pw.flush();
  1362. CodeGeneratorResponse.newBuilder().setError(sw.toString()).
  1363. build().writeTo(System.out);
  1364. System.out.flush();
  1365. return;
  1366. }
  1367. response.writeTo(System.out);
  1368. System.out.flush();
  1369. }
  1370. }