754270601a
AIDL generates unnecessary "import" statements. These cause warnings within Eclipse when the default Eclipse warnings settings are used. This is inconvenient since the generated .java files are not editable. Some pesky organisations have a zero-warnings policy too, so there's no option but to fiddle with the Eclipse settings. This patch ensures that all usages of class names within the generated code are fully-qualified. In practice, they were nearly all fully-qualified already. And this patch also removes the generation of the import statements, since they are redundant if we're using fully-qualified names everywhere. This should fix issue 43 in the Google Code Android issues tracker. http://code.google.com/p/android/issues/detail?id=43 I would appreciate if somebody who knows exactly how 'aidl' works could confirm that there's no reason 'import' statements would have been necessary except for the bits I've fixed. (I think unqualified names were used much more frequently in early versions of aidl, which might explain why import statements are generated so eagerly).
654 lines
22 KiB
C++
654 lines
22 KiB
C++
#include "generate_java.h"
|
|
#include "AST.h"
|
|
#include "Type.h"
|
|
#include <string.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->QualifiedName();
|
|
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, "(android.os.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 ? "android.os.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;
|
|
}
|
|
|