| #include "generate_java.h" | 
 | #include "AST.h" | 
 | #include "Type.h" | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 |  | 
 | // ================================================= | 
 | class VariableFactory | 
 | { | 
 | public: | 
 |     VariableFactory(const string& base); // base must be short | 
 |     Variable* Get(Type* type); | 
 |     Variable* Get(int index); | 
 | private: | 
 |     vector<Variable*> m_vars; | 
 |     string m_base; | 
 |     int m_index; | 
 | }; | 
 |  | 
 | VariableFactory::VariableFactory(const string& base) | 
 |     :m_base(base), | 
 |      m_index(0) | 
 | { | 
 | } | 
 |  | 
 | Variable* | 
 | VariableFactory::Get(Type* type) | 
 | { | 
 |     char name[100]; | 
 |     sprintf(name, "%s%d", m_base.c_str(), m_index); | 
 |     m_index++; | 
 |     Variable* v = new Variable(type, name); | 
 |     m_vars.push_back(v); | 
 |     return v; | 
 | } | 
 |  | 
 | Variable* | 
 | VariableFactory::Get(int index) | 
 | { | 
 |     return m_vars[index]; | 
 | } | 
 |  | 
 | // ================================================= | 
 | class StubClass : public Class | 
 | { | 
 | public: | 
 |     StubClass(Type* type, Type* interfaceType); | 
 |     virtual ~StubClass(); | 
 |  | 
 |     Variable* transact_code; | 
 |     Variable* transact_data; | 
 |     Variable* transact_reply; | 
 |     Variable* transact_flags; | 
 |     SwitchStatement* transact_switch; | 
 | private: | 
 |     void make_as_interface(Type* interfaceType); | 
 | }; | 
 |  | 
 | StubClass::StubClass(Type* type, Type* interfaceType) | 
 |     :Class() | 
 | { | 
 |     this->comment = "/** Local-side IPC implementation stub class. */"; | 
 |     this->modifiers = PUBLIC | ABSTRACT | STATIC; | 
 |     this->what = Class::CLASS; | 
 |     this->type = type; | 
 |     this->extends = BINDER_NATIVE_TYPE; | 
 |     this->interfaces.push_back(interfaceType); | 
 |  | 
 |     // descriptor | 
 |     Field* descriptor = new Field(STATIC | FINAL | PRIVATE, | 
 |                             new Variable(STRING_TYPE, "DESCRIPTOR")); | 
 |     descriptor->value = "\"" + interfaceType->QualifiedName() + "\""; | 
 |     this->elements.push_back(descriptor); | 
 |  | 
 |     // ctor | 
 |     Method* ctor = new Method; | 
 |         ctor->modifiers = PUBLIC; | 
 |         ctor->comment = "/** Construct the stub at attach it to the " | 
 |                         "interface. */"; | 
 |         ctor->name = "Stub"; | 
 |         ctor->statements = new StatementBlock; | 
 |     MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", | 
 |                             2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); | 
 |     ctor->statements->Add(attach); | 
 |     this->elements.push_back(ctor); | 
 |  | 
 |     // asInterface | 
 |     make_as_interface(interfaceType); | 
 |  | 
 |     // asBinder | 
 |     Method* asBinder = new Method; | 
 |         asBinder->modifiers = PUBLIC; | 
 |         asBinder->returnType = IBINDER_TYPE; | 
 |         asBinder->name = "asBinder"; | 
 |         asBinder->statements = new StatementBlock; | 
 |     asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); | 
 |     this->elements.push_back(asBinder); | 
 |  | 
 |     // onTransact | 
 |     this->transact_code = new Variable(INT_TYPE, "code"); | 
 |     this->transact_data = new Variable(PARCEL_TYPE, "data"); | 
 |     this->transact_reply = new Variable(PARCEL_TYPE, "reply"); | 
 |     this->transact_flags = new Variable(INT_TYPE, "flags"); | 
 |     Method* onTransact = new Method; | 
 |         onTransact->modifiers = PUBLIC; | 
 |         onTransact->returnType = BOOLEAN_TYPE; | 
 |         onTransact->name = "onTransact"; | 
 |         onTransact->parameters.push_back(this->transact_code); | 
 |         onTransact->parameters.push_back(this->transact_data); | 
 |         onTransact->parameters.push_back(this->transact_reply); | 
 |         onTransact->parameters.push_back(this->transact_flags); | 
 |         onTransact->statements = new StatementBlock; | 
 |         onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE); | 
 |     this->elements.push_back(onTransact); | 
 |     this->transact_switch = new SwitchStatement(this->transact_code); | 
 |  | 
 |     onTransact->statements->Add(this->transact_switch); | 
 |     MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4, | 
 |                                     this->transact_code, this->transact_data, | 
 |                                     this->transact_reply, this->transact_flags); | 
 |     onTransact->statements->Add(new ReturnStatement(superCall)); | 
 | } | 
 |  | 
 | StubClass::~StubClass() | 
 | { | 
 | } | 
 |  | 
 | void | 
 | StubClass::make_as_interface(Type *interfaceType) | 
 | { | 
 |     Variable* obj = new Variable(IBINDER_TYPE, "obj"); | 
 |  | 
 |     Method* m = new Method; | 
 |         m->comment = "/**\n * Cast an IBinder object into an "; | 
 |         m->comment += interfaceType->Name(); | 
 |         m->comment += " interface,\n"; | 
 |         m->comment += " * generating a proxy if needed.\n */"; | 
 |         m->modifiers = PUBLIC | STATIC; | 
 |         m->returnType = interfaceType; | 
 |         m->name = "asInterface"; | 
 |         m->parameters.push_back(obj); | 
 |         m->statements = new StatementBlock; | 
 |  | 
 |     IfStatement* ifstatement = new IfStatement(); | 
 |         ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); | 
 |         ifstatement->statements = new StatementBlock; | 
 |         ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); | 
 |     m->statements->Add(ifstatement); | 
 |  | 
 |     // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) | 
 |     MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); | 
 |     queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); | 
 |     IInterfaceType* iinType = new IInterfaceType(); | 
 |     Variable *iin = new Variable(iinType, "iin"); | 
 |     VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType); | 
 |     m->statements->Add(iinVd); | 
 |  | 
 |     // Ensure the instance type of the local object is as expected. | 
 |     // One scenario where this is needed is if another package (with a | 
 |     // different class loader) runs in the same process as the service. | 
 |  | 
 |     // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin; | 
 |     Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); | 
 |     Comparison* instOfCheck = new Comparison(iin, " instanceof ", | 
 |             new LiteralExpression(interfaceType->QualifiedName())); | 
 |     IfStatement* instOfStatement = new IfStatement(); | 
 |         instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); | 
 |         instOfStatement->statements = new StatementBlock; | 
 |         instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin))); | 
 |     m->statements->Add(instOfStatement); | 
 |  | 
 |     string proxyType = interfaceType->QualifiedName(); | 
 |     proxyType += ".Stub.Proxy"; | 
 |     NewExpression* ne = new NewExpression(NAMES.Find(proxyType)); | 
 |     ne->arguments.push_back(obj); | 
 |     m->statements->Add(new ReturnStatement(ne)); | 
 |  | 
 |     this->elements.push_back(m); | 
 | } | 
 |  | 
 |  | 
 |  | 
 | // ================================================= | 
 | class ProxyClass : public Class | 
 | { | 
 | public: | 
 |     ProxyClass(Type* type, InterfaceType* interfaceType); | 
 |     virtual ~ProxyClass(); | 
 |  | 
 |     Variable* mRemote; | 
 |     bool mOneWay; | 
 | }; | 
 |  | 
 | ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType) | 
 |     :Class() | 
 | { | 
 |     this->modifiers = PRIVATE | STATIC; | 
 |     this->what = Class::CLASS; | 
 |     this->type = type; | 
 |     this->interfaces.push_back(interfaceType); | 
 |  | 
 |     mOneWay = interfaceType->OneWay(); | 
 |  | 
 |     // IBinder mRemote | 
 |     mRemote = new Variable(IBINDER_TYPE, "mRemote"); | 
 |     this->elements.push_back(new Field(PRIVATE, mRemote)); | 
 |  | 
 |     // Proxy() | 
 |     Variable* remote = new Variable(IBINDER_TYPE, "remote"); | 
 |     Method* ctor = new Method; | 
 |         ctor->name = "Proxy"; | 
 |         ctor->statements = new StatementBlock; | 
 |         ctor->parameters.push_back(remote); | 
 |     ctor->statements->Add(new Assignment(mRemote, remote)); | 
 |     this->elements.push_back(ctor); | 
 |  | 
 |     // IBinder asBinder() | 
 |     Method* asBinder = new Method; | 
 |         asBinder->modifiers = PUBLIC; | 
 |         asBinder->returnType = IBINDER_TYPE; | 
 |         asBinder->name = "asBinder"; | 
 |         asBinder->statements = new StatementBlock; | 
 |     asBinder->statements->Add(new ReturnStatement(mRemote)); | 
 |     this->elements.push_back(asBinder); | 
 | } | 
 |  | 
 | ProxyClass::~ProxyClass() | 
 | { | 
 | } | 
 |  | 
 | // ================================================= | 
 | static string | 
 | gather_comments(extra_text_type* extra) | 
 | { | 
 |     string s; | 
 |     while (extra) { | 
 |         if (extra->which == SHORT_COMMENT) { | 
 |             s += extra->data; | 
 |         } | 
 |         else if (extra->which == LONG_COMMENT) { | 
 |             s += "/*"; | 
 |             s += extra->data; | 
 |             s += "*/"; | 
 |         } | 
 |         extra = extra->next; | 
 |     } | 
 |     return s; | 
 | } | 
 |  | 
 | static string | 
 | append(const char* a, const char* b) | 
 | { | 
 |     string s = a; | 
 |     s += b; | 
 |     return s; | 
 | } | 
 |  | 
 | static void | 
 | generate_new_array(Type* t, StatementBlock* addTo, Variable* v, | 
 |                             Variable* parcel) | 
 | { | 
 |     Variable* len = new Variable(INT_TYPE, v->name + "_length"); | 
 |     addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); | 
 |     IfStatement* lencheck = new IfStatement(); | 
 |     lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); | 
 |     lencheck->statements->Add(new Assignment(v, NULL_VALUE)); | 
 |     lencheck->elseif = new IfStatement(); | 
 |     lencheck->elseif->statements->Add(new Assignment(v, | 
 |                 new NewArrayExpression(t, len))); | 
 |     addTo->Add(lencheck); | 
 | } | 
 |  | 
 | static void | 
 | generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v, | 
 |                             Variable* parcel, int flags) | 
 | { | 
 |     if (v->dimension == 0) { | 
 |         t->WriteToParcel(addTo, v, parcel, flags); | 
 |     } | 
 |     if (v->dimension == 1) { | 
 |         t->WriteArrayToParcel(addTo, v, parcel, flags); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, | 
 |                             Variable* parcel) | 
 | { | 
 |     if (v->dimension == 0) { | 
 |         t->CreateFromParcel(addTo, v, parcel); | 
 |     } | 
 |     if (v->dimension == 1) { | 
 |         t->CreateArrayFromParcel(addTo, v, parcel); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, | 
 |                             Variable* parcel) | 
 | { | 
 |     if (v->dimension == 0) { | 
 |         t->ReadFromParcel(addTo, v, parcel); | 
 |     } | 
 |     if (v->dimension == 1) { | 
 |         t->ReadArrayFromParcel(addTo, v, parcel); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | generate_method(const method_type* method, Class* interface, | 
 |                     StubClass* stubClass, ProxyClass* proxyClass, int index) | 
 | { | 
 |     arg_type* arg; | 
 |     int i; | 
 |     bool hasOutParams = false; | 
 |  | 
 |     const bool oneway = proxyClass->mOneWay || method->oneway; | 
 |  | 
 |     // == the TRANSACT_ constant ============================================= | 
 |     string transactCodeName = "TRANSACTION_"; | 
 |     transactCodeName += method->name.data; | 
 |  | 
 |     char transactCodeValue[50]; | 
 |     sprintf(transactCodeValue, "(IBinder.FIRST_CALL_TRANSACTION + %d)", index); | 
 |  | 
 |     Field* transactCode = new Field(STATIC | FINAL, | 
 |                             new Variable(INT_TYPE, transactCodeName)); | 
 |     transactCode->value = transactCodeValue; | 
 |     stubClass->elements.push_back(transactCode); | 
 |  | 
 |     // == the declaration in the interface =================================== | 
 |     Method* decl = new Method; | 
 |         decl->comment = gather_comments(method->comments_token->extra); | 
 |         decl->modifiers = PUBLIC; | 
 |         decl->returnType = NAMES.Search(method->type.type.data); | 
 |         decl->returnTypeDimension = method->type.dimension; | 
 |         decl->name = method->name.data; | 
 |  | 
 |     arg = method->args; | 
 |     while (arg != NULL) { | 
 |         decl->parameters.push_back(new Variable( | 
 |                             NAMES.Search(arg->type.type.data), arg->name.data, | 
 |                             arg->type.dimension)); | 
 |         arg = arg->next; | 
 |     } | 
 |  | 
 |     decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE); | 
 |  | 
 |     interface->elements.push_back(decl); | 
 |  | 
 |     // == the stub method ==================================================== | 
 |  | 
 |     Case* c = new Case(transactCodeName); | 
 |  | 
 |     MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data); | 
 |  | 
 |     // interface token validation is the very first thing we do | 
 |     c->statements->Add(new MethodCall(stubClass->transact_data, | 
 |             "enforceInterface", 1, new LiteralExpression("DESCRIPTOR"))); | 
 |  | 
 |     // args | 
 |     VariableFactory stubArgs("_arg"); | 
 |     arg = method->args; | 
 |     while (arg != NULL) { | 
 |         Type* t = NAMES.Search(arg->type.type.data); | 
 |         Variable* v = stubArgs.Get(t); | 
 |         v->dimension = arg->type.dimension; | 
 |  | 
 |         c->statements->Add(new VariableDeclaration(v)); | 
 |  | 
 |         if (convert_direction(arg->direction.data) & IN_PARAMETER) { | 
 |             generate_create_from_parcel(t, c->statements, v, | 
 |                     stubClass->transact_data); | 
 |         } else { | 
 |             if (arg->type.dimension == 0) { | 
 |                 c->statements->Add(new Assignment( | 
 |                                                 v, new NewExpression(v->type))); | 
 |             } | 
 |             else if (arg->type.dimension == 1) { | 
 |                 generate_new_array(v->type, c->statements, v, | 
 |                         stubClass->transact_data); | 
 |             } | 
 |             else { | 
 |                 fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, | 
 |                         __LINE__); | 
 |             } | 
 |         } | 
 |  | 
 |         realCall->arguments.push_back(v); | 
 |  | 
 |         arg = arg->next; | 
 |     } | 
 |  | 
 |     // the real call | 
 |     Variable* _result = NULL; | 
 |     if (0 == strcmp(method->type.type.data, "void")) { | 
 |         c->statements->Add(realCall); | 
 |  | 
 |         if (!oneway) { | 
 |             // report that there were no exceptions | 
 |             MethodCall* ex = new MethodCall(stubClass->transact_reply, | 
 |                     "writeNoException", 0); | 
 |             c->statements->Add(ex); | 
 |         } | 
 |     } else { | 
 |         _result = new Variable(decl->returnType, "_result", | 
 |                                 decl->returnTypeDimension); | 
 |         c->statements->Add(new VariableDeclaration(_result, realCall)); | 
 |  | 
 |         if (!oneway) { | 
 |             // report that there were no exceptions | 
 |             MethodCall* ex = new MethodCall(stubClass->transact_reply, | 
 |                     "writeNoException", 0); | 
 |             c->statements->Add(ex); | 
 |         } | 
 |  | 
 |         // marshall the return value | 
 |         generate_write_to_parcel(decl->returnType, c->statements, _result, | 
 |                                     stubClass->transact_reply, | 
 |                                     Type::PARCELABLE_WRITE_RETURN_VALUE); | 
 |     } | 
 |  | 
 |     // out parameters | 
 |     i = 0; | 
 |     arg = method->args; | 
 |     while (arg != NULL) { | 
 |         Type* t = NAMES.Search(arg->type.type.data); | 
 |         Variable* v = stubArgs.Get(i++); | 
 |  | 
 |         if (convert_direction(arg->direction.data) & OUT_PARAMETER) { | 
 |             generate_write_to_parcel(t, c->statements, v, | 
 |                                 stubClass->transact_reply, | 
 |                                 Type::PARCELABLE_WRITE_RETURN_VALUE); | 
 |             hasOutParams = true; | 
 |         } | 
 |  | 
 |         arg = arg->next; | 
 |     } | 
 |  | 
 |     // return true | 
 |     c->statements->Add(new ReturnStatement(TRUE_VALUE)); | 
 |     stubClass->transact_switch->cases.push_back(c); | 
 |  | 
 |     // == the proxy method =================================================== | 
 |     Method* proxy = new Method; | 
 |         proxy->comment = gather_comments(method->comments_token->extra); | 
 |         proxy->modifiers = PUBLIC; | 
 |         proxy->returnType = NAMES.Search(method->type.type.data); | 
 |         proxy->returnTypeDimension = method->type.dimension; | 
 |         proxy->name = method->name.data; | 
 |         proxy->statements = new StatementBlock; | 
 |         arg = method->args; | 
 |         while (arg != NULL) { | 
 |             proxy->parameters.push_back(new Variable( | 
 |                             NAMES.Search(arg->type.type.data), arg->name.data, | 
 |                             arg->type.dimension)); | 
 |             arg = arg->next; | 
 |         } | 
 |         proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE); | 
 |     proxyClass->elements.push_back(proxy); | 
 |  | 
 |     // the parcels | 
 |     Variable* _data = new Variable(PARCEL_TYPE, "_data"); | 
 |     proxy->statements->Add(new VariableDeclaration(_data, | 
 |                                 new MethodCall(PARCEL_TYPE, "obtain"))); | 
 |     Variable* _reply = NULL; | 
 |     if (!oneway) { | 
 |         _reply = new Variable(PARCEL_TYPE, "_reply"); | 
 |         proxy->statements->Add(new VariableDeclaration(_reply, | 
 |                                     new MethodCall(PARCEL_TYPE, "obtain"))); | 
 |     } | 
 |  | 
 |     // the return value | 
 |     _result = NULL; | 
 |     if (0 != strcmp(method->type.type.data, "void")) { | 
 |         _result = new Variable(proxy->returnType, "_result", | 
 |                 method->type.dimension); | 
 |         proxy->statements->Add(new VariableDeclaration(_result)); | 
 |     } | 
 |  | 
 |     // try and finally | 
 |     TryStatement* tryStatement = new TryStatement(); | 
 |     proxy->statements->Add(tryStatement); | 
 |     FinallyStatement* finallyStatement = new FinallyStatement(); | 
 |     proxy->statements->Add(finallyStatement); | 
 |  | 
 |     // the interface identifier token: the DESCRIPTOR constant, marshalled as a string | 
 |     tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken", | 
 |             1, new LiteralExpression("DESCRIPTOR"))); | 
 |  | 
 |     // the parameters | 
 |     arg = method->args; | 
 |     while (arg != NULL) { | 
 |         Type* t = NAMES.Search(arg->type.type.data); | 
 |         Variable* v = new Variable(t, arg->name.data, arg->type.dimension); | 
 |         int dir = convert_direction(arg->direction.data); | 
 |         if (dir == OUT_PARAMETER && arg->type.dimension != 0) { | 
 |             IfStatement* checklen = new IfStatement(); | 
 |             checklen->expression = new Comparison(v, "==", NULL_VALUE); | 
 |             checklen->statements->Add(new MethodCall(_data, "writeInt", 1, | 
 |                         new LiteralExpression("-1"))); | 
 |             checklen->elseif = new IfStatement(); | 
 |             checklen->elseif->statements->Add(new MethodCall(_data, "writeInt", | 
 |                         1, new FieldVariable(v, "length"))); | 
 |             tryStatement->statements->Add(checklen); | 
 |         } | 
 |         else if (dir & IN_PARAMETER) { | 
 |             generate_write_to_parcel(t, tryStatement->statements, v, _data, 0); | 
 |         } | 
 |         arg = arg->next; | 
 |     } | 
 |  | 
 |     // the transact call | 
 |     MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4, | 
 |                             new LiteralExpression("Stub." + transactCodeName), | 
 |                             _data, _reply ? _reply : NULL_VALUE, | 
 |                             new LiteralExpression( | 
 |                                 oneway ? "IBinder.FLAG_ONEWAY" : "0")); | 
 |     tryStatement->statements->Add(call); | 
 |  | 
 |     // throw back exceptions. | 
 |     if (_reply) { | 
 |         MethodCall* ex = new MethodCall(_reply, "readException", 0); | 
 |         tryStatement->statements->Add(ex); | 
 |     } | 
 |  | 
 |     // returning and cleanup | 
 |     if (_reply != NULL) { | 
 |         if (_result != NULL) { | 
 |             generate_create_from_parcel(proxy->returnType, | 
 |                                     tryStatement->statements, _result, _reply); | 
 |         } | 
 |  | 
 |         // the out/inout parameters | 
 |         arg = method->args; | 
 |         while (arg != NULL) { | 
 |             Type* t = NAMES.Search(arg->type.type.data); | 
 |             Variable* v = new Variable(t, arg->name.data, arg->type.dimension); | 
 |             if (convert_direction(arg->direction.data) & OUT_PARAMETER) { | 
 |                 generate_read_from_parcel(t, tryStatement->statements, | 
 |                                             v, _reply); | 
 |             } | 
 |             arg = arg->next; | 
 |         } | 
 |  | 
 |         finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); | 
 |     } | 
 |     finallyStatement->statements->Add(new MethodCall(_data, "recycle")); | 
 |  | 
 |     if (_result != NULL) { | 
 |         proxy->statements->Add(new ReturnStatement(_result)); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) | 
 | { | 
 |     // the interface descriptor transaction handler | 
 |     Case* c = new Case("INTERFACE_TRANSACTION"); | 
 |     c->statements->Add(new MethodCall(stub->transact_reply, "writeString", | 
 |             1, new LiteralExpression("DESCRIPTOR"))); | 
 |     c->statements->Add(new ReturnStatement(TRUE_VALUE)); | 
 |     stub->transact_switch->cases.push_back(c); | 
 |  | 
 |     // and the proxy-side method returning the descriptor directly | 
 |     Method* getDesc = new Method; | 
 |     getDesc->modifiers = PUBLIC; | 
 |     getDesc->returnType = STRING_TYPE; | 
 |     getDesc->returnTypeDimension = 0; | 
 |     getDesc->name = "getInterfaceDescriptor"; | 
 |     getDesc->statements = new StatementBlock; | 
 |     getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); | 
 |     proxy->elements.push_back(getDesc); | 
 | } | 
 |  | 
 | static Class* | 
 | generate_interface_class(const interface_type* iface) | 
 | { | 
 |     InterfaceType* interfaceType = static_cast<InterfaceType*>( | 
 |         NAMES.Find(iface->package, iface->name.data)); | 
 |  | 
 |     // the interface class | 
 |     Class* interface = new Class; | 
 |         interface->comment = gather_comments(iface->comments_token->extra); | 
 |         interface->modifiers = PUBLIC; | 
 |         interface->what = Class::INTERFACE; | 
 |         interface->type = interfaceType; | 
 |         interface->interfaces.push_back(IINTERFACE_TYPE); | 
 |  | 
 |     // the stub inner class | 
 |     StubClass* stub = new StubClass( | 
 |         NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()), | 
 |         interfaceType); | 
 |     interface->elements.push_back(stub); | 
 |  | 
 |     // the proxy inner class | 
 |     ProxyClass* proxy = new ProxyClass( | 
 |         NAMES.Find(iface->package, | 
 |                          append(iface->name.data, ".Stub.Proxy").c_str()), | 
 |         interfaceType); | 
 |     stub->elements.push_back(proxy); | 
 |  | 
 |     // stub and proxy support for getInterfaceDescriptor() | 
 |     generate_interface_descriptors(stub, proxy); | 
 |  | 
 |     // all the declared methods of the interface | 
 |     int index = 0; | 
 |     interface_item_type* item = iface->interface_items; | 
 |     while (item != NULL) { | 
 |         if (item->item_type == METHOD_TYPE) { | 
 |             generate_method((method_type*)item, interface, stub, proxy, index); | 
 |         } | 
 |         item = item->next; | 
 |         index++; | 
 |     } | 
 |  | 
 |     return interface; | 
 | } | 
 |  | 
 | int | 
 | generate_java(const string& filename, const string& originalSrc, | 
 |                 interface_type* iface) | 
 | { | 
 |     Document* document = new Document; | 
 |         document->comment = ""; | 
 |         if (iface->package) document->package = iface->package; | 
 |         document->originalSrc = originalSrc; | 
 |         document->classes.push_back(generate_interface_class(iface)); | 
 |  | 
 | //    printf("outputting... filename=%s\n", filename.c_str()); | 
 |     FILE* to; | 
 |     if (filename == "-") { | 
 |         to = stdout; | 
 |     } else { | 
 |        /* open file in binary mode to ensure that the tool produces the | 
 |         * same output on all platforms !! | 
 |         */ | 
 |         to = fopen(filename.c_str(), "wb"); | 
 |         if (to == NULL) { | 
 |             fprintf(stderr, "unable to open %s for write\n", filename.c_str()); | 
 |             return 1; | 
 |         } | 
 |     } | 
 |  | 
 |     document->Write(to); | 
 |  | 
 |     fclose(to); | 
 |     return 0; | 
 | } | 
 |  |