001 /*******************************************************************************
002 * Copyright (c) 2009 Progress Software, Inc.
003 * Copyright (c) 2004, 2007 IBM Corporation and others.
004 *
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 *******************************************************************************/
011 package org.fusesource.hawtjni.generator;
012
013 import java.lang.reflect.Modifier;
014 import java.util.ArrayList;
015 import java.util.List;
016
017 import org.fusesource.hawtjni.generator.model.JNIClass;
018 import org.fusesource.hawtjni.generator.model.JNIField;
019 import org.fusesource.hawtjni.generator.model.JNIType;
020 import org.fusesource.hawtjni.runtime.ClassFlag;
021
022 /**
023 *
024 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
025 */
026 public class StructsGenerator extends JNIGenerator {
027
028 boolean header;
029
030 static final boolean GLOBAL_REF = false;
031
032 public StructsGenerator(boolean header) {
033 this.header = header;
034 }
035
036 public void generateCopyright() {
037 outputln(fixDelimiter(getCopyright()));
038 }
039
040 public void generateIncludes() {
041 if (header) {
042 outputln("#include \""+getOutputName()+".h\"");
043 } else {
044 outputln("#include \""+getOutputName()+".h\"");
045 outputln("#include \"hawtjni.h\"");
046 outputln("#include \""+getOutputName()+"_structs.h\"");
047 }
048 outputln();
049 }
050
051 public void generate(JNIClass clazz) {
052 ArrayList<JNIField> fields = getStructFields(clazz);
053 if (fields.isEmpty())
054 return;
055 if (header) {
056 generateHeaderFile(clazz);
057 } else {
058 generateSourceFile(clazz);
059 }
060 }
061
062 private ArrayList<JNIField> getStructFields(JNIClass clazz) {
063 ArrayList<JNIField> rc = new ArrayList<JNIField>();
064 List<JNIField> fields = clazz.getDeclaredFields();
065 for (JNIField field : fields) {
066 int mods = field.getModifiers();
067 if ( (mods & Modifier.STATIC) == 0 && (mods & Modifier.TRANSIENT) == 0) {
068 rc.add(field);
069 }
070 }
071 return rc;
072 }
073
074 void generateHeaderFile(JNIClass clazz) {
075 generateSourceStart(clazz);
076 generatePrototypes(clazz);
077 generateBlankMacros(clazz);
078 generateSourceEnd(clazz);
079 outputln();
080 }
081
082 void generateSourceFile(JNIClass clazz) {
083 generateSourceStart(clazz);
084 generateFIDsStructure(clazz);
085 outputln();
086 generateGlobalVar(clazz);
087 outputln();
088 generateFunctions(clazz);
089 generateSourceEnd(clazz);
090 outputln();
091 }
092
093 void generateSourceStart(JNIClass clazz) {
094 String conditional = clazz.getConditional();
095 if (conditional!=null) {
096 outputln("#if "+conditional);
097 }
098 }
099
100 void generateSourceEnd(JNIClass clazz) {
101 if (clazz.getConditional()!=null) {
102 outputln("#endif");
103 }
104 }
105
106 void generateGlobalVar(JNIClass clazz) {
107 String clazzName = clazz.getSimpleName();
108 output(clazzName);
109 output("_FID_CACHE ");
110 output(clazzName);
111 outputln("Fc;");
112 }
113
114 void generateBlankMacros(JNIClass clazz) {
115
116 if (clazz.getConditional()==null) {
117 return;
118 }
119
120 String clazzName = clazz.getSimpleName();
121 outputln("#else");
122 output("#define cache");
123 output(clazzName);
124 outputln("Fields(a,b)");
125 output("#define get");
126 output(clazzName);
127 outputln("Fields(a,b,c) NULL");
128 output("#define set");
129 output(clazzName);
130 outputln("Fields(a,b,c)");
131 }
132
133 void generatePrototypes(JNIClass clazz) {
134 String clazzName = clazz.getSimpleName();
135 output("void cache");
136 output(clazzName);
137 outputln("Fields(JNIEnv *env, jobject lpObject);");
138 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
139 output("struct ");
140 }
141 output(clazzName);
142 output(" *get");
143 output(clazzName);
144 output("Fields(JNIEnv *env, jobject lpObject, ");
145 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
146 output("struct ");
147 }
148 output(clazzName);
149 outputln(" *lpStruct);");
150 output("void set");
151 output(clazzName);
152 output("Fields(JNIEnv *env, jobject lpObject, ");
153 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
154 output("struct ");
155 }
156 output(clazzName);
157 outputln(" *lpStruct);");
158 }
159
160 void generateFIDsStructure(JNIClass clazz) {
161 String clazzName = clazz.getSimpleName();
162 output("typedef struct ");
163 output(clazzName);
164 outputln("_FID_CACHE {");
165 outputln("\tint cached;");
166 outputln("\tjclass clazz;");
167 output("\tjfieldID ");
168 List<JNIField> fields = clazz.getDeclaredFields();
169 boolean first = true;
170 for (JNIField field : fields) {
171 if (ignoreField(field))
172 continue;
173 if (!first)
174 output(", ");
175 output(field.getName());
176 first = false;
177 }
178 outputln(";");
179 output("} ");
180 output(clazzName);
181 outputln("_FID_CACHE;");
182 }
183
184 void generateCacheFunction(JNIClass clazz) {
185 String clazzName = clazz.getSimpleName();
186 output("void cache");
187 output(clazzName);
188 outputln("Fields(JNIEnv *env, jobject lpObject)");
189 outputln("{");
190 output("\tif (");
191 output(clazzName);
192 outputln("Fc.cached) return;");
193 JNIClass superclazz = clazz.getSuperclass();
194 if (!superclazz.getName().equals("java.lang.Object")) {
195 String superName = superclazz.getSimpleName();
196 output("\tcache");
197 output(superName);
198 outputln("Fields(env, lpObject);");
199 }
200 output("\t");
201 output(clazzName);
202 if (isCPP) {
203 if (GLOBAL_REF) {
204 output("Fc.clazz = (jclass)env->NewGlobalRef(env->GetObjectClass(lpObject));");
205 } else {
206 output("Fc.clazz = env->GetObjectClass(lpObject);");
207 }
208 } else {
209 if (GLOBAL_REF) {
210 output("Fc.clazz = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, lpObject));");
211 } else {
212 output("Fc.clazz = (*env)->GetObjectClass(env, lpObject);");
213 }
214 }
215 outputln();
216 List<JNIField> fields = clazz.getDeclaredFields();
217 for (JNIField field : fields) {
218 if (ignoreField(field))
219 continue;
220 output("\t");
221 output(clazzName);
222 output("Fc.");
223 output(field.getName());
224 if (isCPP) {
225 output(" = env->GetFieldID(");
226 } else {
227 output(" = (*env)->GetFieldID(env, ");
228 }
229 output(clazzName);
230 output("Fc.clazz, \"");
231 output(field.getName());
232 JNIType type = field.getType(), type64 = field.getType64();
233 output("\", ");
234 if (type.equals(type64))
235 output("\"");
236 output(type.getTypeSignature(!type.equals(type64)));
237 if (type.equals(type64))
238 output("\"");
239 outputln(");");
240 }
241 output("\t");
242 output(clazzName);
243 outputln("Fc.cached = 1;");
244 outputln("}");
245 }
246
247 void generateGetFields(JNIClass clazz) {
248 JNIClass superclazz = clazz.getSuperclass();
249 String clazzName = clazz.getSimpleName();
250 String superName = superclazz.getSimpleName();
251 if (!superclazz.getName().equals("java.lang.Object")) {
252 /*
253 * Windows exception - cannot call get/set function of super class
254 * in this case
255 */
256 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) {
257 output("\tget");
258 output(superName);
259 output("Fields(env, lpObject, (");
260 output(superName);
261 outputln(" *)lpStruct);");
262 } else {
263 generateGetFields(superclazz);
264 }
265 }
266 List<JNIField> fields = clazz.getDeclaredFields();
267 for (JNIField field : fields) {
268 if (ignoreField(field))
269 continue;
270 String conditional = field.getConditional();
271 if (conditional!=null) {
272 outputln("#if "+conditional);
273 }
274 JNIType type = field.getType(), type64 = field.getType64();
275 String typeName = type.getSimpleName();
276 String accessor = field.getAccessor();
277 if (accessor == null || accessor.length() == 0)
278 accessor = field.getName();
279 if (type.isPrimitive()) {
280 output("\tlpStruct->");
281 output(accessor);
282 output(" = ");
283 output(field.getCast());
284 if( field.isPointer() ) {
285 output("(intptr_t)");
286 }
287 if (isCPP) {
288 output("env->Get");
289 } else {
290 output("(*env)->Get");
291 }
292 output(type.getTypeSignature1(!type.equals(type64)));
293 if (isCPP) {
294 output("Field(lpObject, ");
295 } else {
296 output("Field(env, lpObject, ");
297 }
298 output(field.getDeclaringClass().getSimpleName());
299 output("Fc.");
300 output(field.getName());
301 output(");");
302 } else if (type.isArray()) {
303 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
304 if (componentType.isPrimitive()) {
305 outputln("\t{");
306 output("\t");
307 output(type.getTypeSignature2(!type.equals(type64)));
308 output(" lpObject1 = (");
309 output(type.getTypeSignature2(!type.equals(type64)));
310 if (isCPP) {
311 output(")env->GetObjectField(lpObject, ");
312 } else {
313 output(")(*env)->GetObjectField(env, lpObject, ");
314 }
315 output(field.getDeclaringClass().getSimpleName());
316 output("Fc.");
317 output(field.getName());
318 outputln(");");
319 if (isCPP) {
320 output("\tenv->Get");
321 } else {
322 output("\t(*env)->Get");
323 }
324 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
325 if (isCPP) {
326 output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->");
327 } else {
328 output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->");
329 }
330 output(accessor);
331 output(")");
332 if (!componentType.isType("byte")) {
333 output(" / sizeof(");
334 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
335 output(")");
336 }
337 output(", (");
338 output(type.getTypeSignature4(!type.equals(type64), false));
339 output(")lpStruct->");
340 output(accessor);
341 outputln(");");
342 output("\t}");
343 } else {
344 throw new Error("not done");
345 }
346 } else {
347 outputln("\t{");
348 if (isCPP) {
349 output("\tjobject lpObject1 = env->GetObjectField(lpObject, ");
350 } else {
351 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, ");
352 }
353 output(field.getDeclaringClass().getSimpleName());
354 output("Fc.");
355 output(field.getName());
356 outputln(");");
357 output("\tif (lpObject1 != NULL) get");
358 output(typeName);
359 output("Fields(env, lpObject1, &lpStruct->");
360 output(accessor);
361 outputln(");");
362 output("\t}");
363 }
364 outputln();
365 if (conditional!=null) {
366 outputln("#endif");
367 }
368 }
369 }
370
371 void generateGetFunction(JNIClass clazz) {
372 String clazzName = clazz.getSimpleName();
373 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
374 output("struct ");
375 }
376 output(clazzName);
377 output(" *get");
378 output(clazzName);
379 output("Fields(JNIEnv *env, jobject lpObject, ");
380 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
381 output("struct ");
382 }
383 output(clazzName);
384 outputln(" *lpStruct)");
385 outputln("{");
386 output("\tif (!");
387 output(clazzName);
388 output("Fc.cached) cache");
389 output(clazzName);
390 outputln("Fields(env, lpObject);");
391 if( clazz.getFlag(ClassFlag.ZERO_OUT) ) {
392 outputln("memset(lpStruct, 0, sizeof(struct "+clazzName+"));");
393 }
394 generateGetFields(clazz);
395 outputln("\treturn lpStruct;");
396 outputln("}");
397 }
398
399 void generateSetFields(JNIClass clazz) {
400 JNIClass superclazz = clazz.getSuperclass();
401 String clazzName = clazz.getSimpleName();
402 String superName = superclazz.getSimpleName();
403 if (!superclazz.getName().equals("java.lang.Object")) {
404 /*
405 * Windows exception - cannot call get/set function of super class
406 * in this case
407 */
408 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) {
409 output("\tset");
410 output(superName);
411 output("Fields(env, lpObject, (");
412 output(superName);
413 outputln(" *)lpStruct);");
414 } else {
415 generateSetFields(superclazz);
416 }
417 }
418 List<JNIField> fields = clazz.getDeclaredFields();
419 for (JNIField field : fields) {
420 if (ignoreField(field))
421 continue;
422 String conditional = field.getConditional();
423 if (conditional!=null) {
424 outputln("#if "+conditional);
425 }
426 JNIType type = field.getType(), type64 = field.getType64();
427 boolean allowConversion = !type.equals(type64);
428
429 String typeName = type.getSimpleName();
430 String accessor = field.getAccessor();
431 if (accessor == null || accessor.length() == 0)
432 accessor = field.getName();
433 if (type.isPrimitive()) {
434 if (isCPP) {
435 output("\tenv->Set");
436 } else {
437 output("\t(*env)->Set");
438 }
439 output(type.getTypeSignature1(allowConversion));
440 if (isCPP) {
441 output("Field(lpObject, ");
442 } else {
443 output("Field(env, lpObject, ");
444 }
445 output(field.getDeclaringClass().getSimpleName());
446 output("Fc.");
447 output(field.getName());
448 output(", ");
449 output("("+type.getTypeSignature2(allowConversion)+")");
450 if( field.isPointer() ) {
451 output("(intptr_t)");
452 }
453 output("lpStruct->"+accessor);
454 output(");");
455 } else if (type.isArray()) {
456 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
457 if (componentType.isPrimitive()) {
458 outputln("\t{");
459 output("\t");
460 output(type.getTypeSignature2(allowConversion));
461 output(" lpObject1 = (");
462 output(type.getTypeSignature2(allowConversion));
463 if (isCPP) {
464 output(")env->GetObjectField(lpObject, ");
465 } else {
466 output(")(*env)->GetObjectField(env, lpObject, ");
467 }
468 output(field.getDeclaringClass().getSimpleName());
469 output("Fc.");
470 output(field.getName());
471 outputln(");");
472 if (isCPP) {
473 output("\tenv->Set");
474 } else {
475 output("\t(*env)->Set");
476 }
477 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
478 if (isCPP) {
479 output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->");
480 } else {
481 output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->");
482 }
483 output(accessor);
484 output(")");
485 if (!componentType.isType("byte")) {
486 output(" / sizeof(");
487 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
488 output(")");
489 }
490 output(", (");
491 output(type.getTypeSignature4(allowConversion, false));
492 output(")lpStruct->");
493 output(accessor);
494 outputln(");");
495 output("\t}");
496 } else {
497 throw new Error("not done");
498 }
499 } else {
500 outputln("\t{");
501 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, ");
502 output(field.getDeclaringClass().getSimpleName());
503 output("Fc.");
504 output(field.getName());
505 outputln(");");
506 output("\tif (lpObject1 != NULL) set");
507 output(typeName);
508 output("Fields(env, lpObject1, &lpStruct->");
509 output(accessor);
510 outputln(");");
511 output("\t}");
512 }
513 outputln();
514 if (conditional!=null) {
515 outputln("#endif");
516 }
517 }
518 }
519
520 void generateSetFunction(JNIClass clazz) {
521 String clazzName = clazz.getSimpleName();
522 output("void set");
523 output(clazzName);
524 output("Fields(JNIEnv *env, jobject lpObject, ");
525 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
526 output("struct ");
527 }
528 output(clazzName);
529 outputln(" *lpStruct)");
530 outputln("{");
531 output("\tif (!");
532 output(clazzName);
533 output("Fc.cached) cache");
534 output(clazzName);
535 outputln("Fields(env, lpObject);");
536 generateSetFields(clazz);
537 outputln("}");
538 }
539
540 void generateFunctions(JNIClass clazz) {
541 generateCacheFunction(clazz);
542 outputln();
543 generateGetFunction(clazz);
544 outputln();
545 generateSetFunction(clazz);
546 }
547
548 boolean ignoreField(JNIField field) {
549 int mods = field.getModifiers();
550 return ((mods & Modifier.PUBLIC) == 0) || ((mods & Modifier.FINAL) != 0) || ((mods & Modifier.STATIC) != 0);
551 }
552
553 }