001 /*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
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 simpleName = clazz.getSimpleName();
108 output(simpleName);
109 output("_FID_CACHE ");
110 output(simpleName);
111 outputln("Fc;");
112 }
113
114 void generateBlankMacros(JNIClass clazz) {
115
116 if (clazz.getConditional()==null) {
117 return;
118 }
119
120 String simpleName = clazz.getSimpleName();
121 outputln("#else");
122 output("#define cache");
123 output(simpleName);
124 outputln("Fields(a,b)");
125 output("#define get");
126 output(simpleName);
127 outputln("Fields(a,b,c) NULL");
128 output("#define set");
129 output(simpleName);
130 outputln("Fields(a,b,c)");
131 }
132
133 void generatePrototypes(JNIClass clazz) {
134 String clazzName = clazz.getNativeName();
135 String simpleName = clazz.getSimpleName();
136 output("void cache");
137 output(simpleName);
138 outputln("Fields(JNIEnv *env, jobject lpObject);");
139 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
140 output("struct ");
141 }
142 output(clazzName);
143 output(" *get");
144 output(simpleName);
145 output("Fields(JNIEnv *env, jobject lpObject, ");
146 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
147 output("struct ");
148 }
149 output(clazzName);
150 outputln(" *lpStruct);");
151 output("void set");
152 output(simpleName);
153 output("Fields(JNIEnv *env, jobject lpObject, ");
154 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
155 output("struct ");
156 }
157 output(clazzName);
158 outputln(" *lpStruct);");
159 }
160
161 void generateFIDsStructure(JNIClass clazz) {
162 String simpleName = clazz.getSimpleName();
163 output("typedef struct ");
164 output(simpleName);
165 outputln("_FID_CACHE {");
166 outputln("\tint cached;");
167 outputln("\tjclass clazz;");
168 output("\tjfieldID ");
169 List<JNIField> fields = clazz.getDeclaredFields();
170 boolean first = true;
171 for (JNIField field : fields) {
172 if (ignoreField(field))
173 continue;
174 if (!first)
175 output(", ");
176 output(field.getName());
177 first = false;
178 }
179 outputln(";");
180 output("} ");
181 output(simpleName);
182 outputln("_FID_CACHE;");
183 }
184
185 void generateCacheFunction(JNIClass clazz) {
186 String simpleName = clazz.getSimpleName();
187 String clazzName = clazz.getNativeName();
188 output("void cache");
189 output(simpleName);
190 outputln("Fields(JNIEnv *env, jobject lpObject)");
191 outputln("{");
192 output("\tif (");
193 output(simpleName);
194 outputln("Fc.cached) return;");
195 JNIClass superclazz = clazz.getSuperclass();
196 if (!superclazz.getName().equals("java.lang.Object")) {
197 String superName = superclazz.getSimpleName();
198 output("\tcache");
199 output(superName);
200 outputln("Fields(env, lpObject);");
201 }
202 output("\t");
203 output(simpleName);
204 if (isCPP) {
205 if (GLOBAL_REF) {
206 output("Fc.clazz = (jclass)env->NewGlobalRef(env->GetObjectClass(lpObject));");
207 } else {
208 output("Fc.clazz = env->GetObjectClass(lpObject);");
209 }
210 } else {
211 if (GLOBAL_REF) {
212 output("Fc.clazz = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, lpObject));");
213 } else {
214 output("Fc.clazz = (*env)->GetObjectClass(env, lpObject);");
215 }
216 }
217 outputln();
218 List<JNIField> fields = clazz.getDeclaredFields();
219 for (JNIField field : fields) {
220 if (ignoreField(field))
221 continue;
222 output("\t");
223 output(simpleName);
224 output("Fc.");
225 output(field.getName());
226 if (isCPP) {
227 output(" = env->GetFieldID(");
228 } else {
229 output(" = (*env)->GetFieldID(env, ");
230 }
231 output(simpleName);
232 output("Fc.clazz, \"");
233 output(field.getName());
234 JNIType type = field.getType(), type64 = field.getType64();
235 output("\", ");
236 if (type.equals(type64))
237 output("\"");
238 output(type.getTypeSignature(!type.equals(type64)));
239 if (type.equals(type64))
240 output("\"");
241 outputln(");");
242 }
243 output("\t");
244 output(simpleName);
245 outputln("Fc.cached = 1;");
246 outputln("}");
247 }
248
249 void generateGetFields(JNIClass clazz) {
250 JNIClass superclazz = clazz.getSuperclass();
251 String clazzName = clazz.getNativeName();
252 String superName = superclazz.getNativeName();
253 if (!superclazz.getName().equals("java.lang.Object")) {
254 /*
255 * Windows exception - cannot call get/set function of super class
256 * in this case
257 */
258 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) {
259 output("\tget");
260 output(superName);
261 output("Fields(env, lpObject, (");
262 output(superName);
263 outputln(" *)lpStruct);");
264 } else {
265 generateGetFields(superclazz);
266 }
267 }
268 List<JNIField> fields = clazz.getDeclaredFields();
269 for (JNIField field : fields) {
270 if (ignoreField(field))
271 continue;
272 String conditional = field.getConditional();
273 if (conditional!=null) {
274 outputln("#if "+conditional);
275 }
276 JNIType type = field.getType(), type64 = field.getType64();
277 String simpleName = type.getSimpleName();
278 String accessor = field.getAccessor();
279 if (accessor == null || accessor.length() == 0)
280 accessor = field.getName();
281 if (type.isPrimitive()) {
282 output("\tlpStruct->");
283 output(accessor);
284 output(" = ");
285 output(field.getCast());
286 if( field.isPointer() ) {
287 output("(intptr_t)");
288 }
289 if (isCPP) {
290 output("env->Get");
291 } else {
292 output("(*env)->Get");
293 }
294 output(type.getTypeSignature1(!type.equals(type64)));
295 if (isCPP) {
296 output("Field(lpObject, ");
297 } else {
298 output("Field(env, lpObject, ");
299 }
300 output(field.getDeclaringClass().getSimpleName());
301 output("Fc.");
302 output(field.getName());
303 output(");");
304 } else if (type.isArray()) {
305 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
306 if (componentType.isPrimitive()) {
307 outputln("\t{");
308 output("\t");
309 output(type.getTypeSignature2(!type.equals(type64)));
310 output(" lpObject1 = (");
311 output(type.getTypeSignature2(!type.equals(type64)));
312 if (isCPP) {
313 output(")env->GetObjectField(lpObject, ");
314 } else {
315 output(")(*env)->GetObjectField(env, lpObject, ");
316 }
317 output(field.getDeclaringClass().getSimpleName());
318 output("Fc.");
319 output(field.getName());
320 outputln(");");
321 if (isCPP) {
322 output("\tenv->Get");
323 } else {
324 output("\t(*env)->Get");
325 }
326 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
327 if (isCPP) {
328 output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->");
329 } else {
330 output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->");
331 }
332 output(accessor);
333 output(")");
334 if (!componentType.isType("byte")) {
335 output(" / sizeof(");
336 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
337 output(")");
338 }
339 output(", (");
340 output(type.getTypeSignature4(!type.equals(type64), false));
341 output(")lpStruct->");
342 output(accessor);
343 outputln(");");
344 output("\t}");
345 } else {
346 throw new Error("not done");
347 }
348 } else {
349 outputln("\t{");
350 if (isCPP) {
351 output("\tjobject lpObject1 = env->GetObjectField(lpObject, ");
352 } else {
353 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, ");
354 }
355 output(field.getDeclaringClass().getSimpleName());
356 output("Fc.");
357 output(field.getName());
358 outputln(");");
359 output("\tif (lpObject1 != NULL) get");
360 output(simpleName);
361 output("Fields(env, lpObject1, &lpStruct->");
362 output(accessor);
363 outputln(");");
364 output("\t}");
365 }
366 outputln();
367 if (conditional!=null) {
368 outputln("#endif");
369 }
370 }
371 }
372
373 void generateGetFunction(JNIClass clazz) {
374 String clazzName = clazz.getNativeName();
375 String simpleName = clazz.getSimpleName();
376 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
377 output("struct ");
378 }
379 output(clazzName);
380 output(" *get");
381 output(simpleName);
382 output("Fields(JNIEnv *env, jobject lpObject, ");
383 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
384 output("struct ");
385 }
386 output(clazzName);
387 outputln(" *lpStruct)");
388 outputln("{");
389 output("\tif (!");
390 output(simpleName);
391 output("Fc.cached) cache");
392 output(simpleName);
393 outputln("Fields(env, lpObject);");
394 if( clazz.getFlag(ClassFlag.ZERO_OUT) ) {
395 outputln("memset(lpStruct, 0, sizeof(struct "+clazzName+"));");
396 }
397 generateGetFields(clazz);
398 outputln("\treturn lpStruct;");
399 outputln("}");
400 }
401
402 void generateSetFields(JNIClass clazz) {
403 JNIClass superclazz = clazz.getSuperclass();
404 String clazzName = clazz.getNativeName();
405 String superName = superclazz.getNativeName();
406 if (!superclazz.getName().equals("java.lang.Object")) {
407 /*
408 * Windows exception - cannot call get/set function of super class
409 * in this case
410 */
411 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) {
412 output("\tset");
413 output(superName);
414 output("Fields(env, lpObject, (");
415 output(superName);
416 outputln(" *)lpStruct);");
417 } else {
418 generateSetFields(superclazz);
419 }
420 }
421 List<JNIField> fields = clazz.getDeclaredFields();
422 for (JNIField field : fields) {
423 if (ignoreField(field))
424 continue;
425 String conditional = field.getConditional();
426 if (conditional!=null) {
427 outputln("#if "+conditional);
428 }
429 JNIType type = field.getType(), type64 = field.getType64();
430 boolean allowConversion = !type.equals(type64);
431
432 String simpleName = type.getSimpleName();
433 String accessor = field.getAccessor();
434 if (accessor == null || accessor.length() == 0)
435 accessor = field.getName();
436 if (type.isPrimitive()) {
437 if (isCPP) {
438 output("\tenv->Set");
439 } else {
440 output("\t(*env)->Set");
441 }
442 output(type.getTypeSignature1(allowConversion));
443 if (isCPP) {
444 output("Field(lpObject, ");
445 } else {
446 output("Field(env, lpObject, ");
447 }
448 output(field.getDeclaringClass().getSimpleName());
449 output("Fc.");
450 output(field.getName());
451 output(", ");
452 output("("+type.getTypeSignature2(allowConversion)+")");
453 if( field.isPointer() ) {
454 output("(intptr_t)");
455 }
456 output("lpStruct->"+accessor);
457 output(");");
458 } else if (type.isArray()) {
459 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
460 if (componentType.isPrimitive()) {
461 outputln("\t{");
462 output("\t");
463 output(type.getTypeSignature2(allowConversion));
464 output(" lpObject1 = (");
465 output(type.getTypeSignature2(allowConversion));
466 if (isCPP) {
467 output(")env->GetObjectField(lpObject, ");
468 } else {
469 output(")(*env)->GetObjectField(env, lpObject, ");
470 }
471 output(field.getDeclaringClass().getSimpleName());
472 output("Fc.");
473 output(field.getName());
474 outputln(");");
475 if (isCPP) {
476 output("\tenv->Set");
477 } else {
478 output("\t(*env)->Set");
479 }
480 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
481 if (isCPP) {
482 output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->");
483 } else {
484 output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->");
485 }
486 output(accessor);
487 output(")");
488 if (!componentType.isType("byte")) {
489 output(" / sizeof(");
490 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
491 output(")");
492 }
493 output(", (");
494 output(type.getTypeSignature4(allowConversion, false));
495 output(")lpStruct->");
496 output(accessor);
497 outputln(");");
498 output("\t}");
499 } else {
500 throw new Error("not done");
501 }
502 } else {
503 outputln("\t{");
504 if (isCPP) {
505 output("\tjobject lpObject1 = env->GetObjectField(lpObject, ");
506 } else {
507 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, ");
508 }
509 output(field.getDeclaringClass().getSimpleName());
510 output("Fc.");
511 output(field.getName());
512 outputln(");");
513 output("\tif (lpObject1 != NULL) set");
514 output(simpleName);
515 output("Fields(env, lpObject1, &lpStruct->");
516 output(accessor);
517 outputln(");");
518 output("\t}");
519 }
520 outputln();
521 if (conditional!=null) {
522 outputln("#endif");
523 }
524 }
525 }
526
527 void generateSetFunction(JNIClass clazz) {
528 String clazzName = clazz.getNativeName();
529 String simpleName = clazz.getSimpleName();
530 output("void set");
531 output(simpleName);
532 output("Fields(JNIEnv *env, jobject lpObject, ");
533 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) {
534 output("struct ");
535 }
536 output(clazzName);
537 outputln(" *lpStruct)");
538 outputln("{");
539 output("\tif (!");
540 output(simpleName);
541 output("Fc.cached) cache");
542 output(simpleName);
543 outputln("Fields(env, lpObject);");
544 generateSetFields(clazz);
545 outputln("}");
546 }
547
548 void generateFunctions(JNIClass clazz) {
549 generateCacheFunction(clazz);
550 outputln();
551 generateGetFunction(clazz);
552 outputln();
553 generateSetFunction(clazz);
554 }
555
556 boolean ignoreField(JNIField field) {
557 int mods = field.getModifiers();
558 return field.ignore() || ((mods & Modifier.FINAL) != 0) || ((mods & Modifier.STATIC) != 0);
559 }
560
561 }