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 }