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 }