001 /******************************************************************************* 002 * Copyright (C) 2009-2011 FuseSource Corp. 003 * Copyright (c) 2008 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.io.BufferedInputStream; 014 import java.io.ByteArrayOutputStream; 015 import java.io.File; 016 import java.io.FileInputStream; 017 import java.io.IOException; 018 import java.io.InputStream; 019 import java.io.InputStreamReader; 020 import java.io.PrintStream; 021 import java.util.ArrayList; 022 import java.util.Collections; 023 import java.util.Comparator; 024 import java.util.HashMap; 025 import java.util.Iterator; 026 import java.util.Map; 027 import java.util.Set; 028 import java.util.StringTokenizer; 029 import java.util.TreeMap; 030 import java.util.TreeSet; 031 032 import javax.xml.parsers.DocumentBuilderFactory; 033 034 import org.fusesource.hawtjni.generator.HawtJNI.UsageException; 035 import org.fusesource.hawtjni.generator.util.FileSupport; 036 import org.w3c.dom.Document; 037 import org.w3c.dom.Element; 038 import org.w3c.dom.NamedNodeMap; 039 import org.w3c.dom.Node; 040 import org.w3c.dom.NodeList; 041 import org.xml.sax.InputSource; 042 043 /** 044 * 045 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 046 */ 047 public class MacGenerator { 048 String[] xmls; 049 Document[] documents; 050 String outputDir, mainClassName; 051 String delimiter = System.getProperty("line.separator"); 052 PrintStream out; 053 054 public MacGenerator() { 055 } 056 057 static void list(File path, ArrayList<String> list) { 058 if (path == null) 059 return; 060 File[] frameworks = path.listFiles(); 061 if (frameworks == null) 062 return; 063 for (int i = 0; i < frameworks.length; i++) { 064 File file = frameworks[i]; 065 String name = file.getName(); 066 int index = name.lastIndexOf("."); 067 if (index != -1) { 068 String xml = file.getAbsolutePath() + "/Resources/BridgeSupport/" + name.substring(0, index) + "Full.bridgesupport"; 069 if (new File(xml).exists()) { 070 list.add(xml); 071 } 072 } 073 } 074 } 075 076 int getLevel(Node node) { 077 int level = 0; 078 while (node != null) { 079 level++; 080 node = node.getParentNode(); 081 } 082 return level; 083 } 084 085 void merge(Document document, Document extraDocument) { 086 if (extraDocument == null) 087 return; 088 089 /* Build a lookup table for extraDocument */ 090 HashMap<String, Node> extras = new HashMap<String, Node>(); 091 buildLookup(extraDocument, extras); 092 093 /* 094 * Merge attributes on existing elements building a lookup table for 095 * document 096 */ 097 HashMap<String, Node> lookup = new HashMap<String, Node>(); 098 merge(document, extras, lookup); 099 100 /* 101 * Merge new elements. Extras at this point contains only elements that 102 * were not found in the document. 103 */ 104 ArrayList<Node> sortedNodes = Collections.list(Collections.enumeration(extras.values())); 105 Collections.sort(sortedNodes, new Comparator<Node>() { 106 public int compare(Node arg0, Node arg1) { 107 int compare = getLevel(arg0) - getLevel(arg1); 108 if (compare == 0) { 109 return (arg0).getNodeName().compareTo((arg1).getNodeName()); 110 } 111 return compare; 112 } 113 }); 114 String delimiter = System.getProperty("line.separator"); 115 for (Iterator<Node> iterator = sortedNodes.iterator(); iterator.hasNext();) { 116 Node node = iterator.next(); 117 String name = node.getNodeName(); 118 if ("arg".equals(name) || "retval".equals(name)) { 119 if (!sortedNodes.contains(node.getParentNode())) 120 continue; 121 } 122 Node parent = lookup.get(getKey(node.getParentNode())); 123 Element element = document.createElement(node.getNodeName()); 124 String text = parent.getChildNodes().getLength() == 0 ? delimiter : ""; 125 for (int i = 0, level = getLevel(parent) - 1; i < level; i++) { 126 text += " "; 127 } 128 parent.appendChild(document.createTextNode(text)); 129 parent.appendChild(element); 130 parent.appendChild(document.createTextNode(delimiter)); 131 NamedNodeMap attributes = node.getAttributes(); 132 for (int j = 0, length = attributes.getLength(); j < length; j++) { 133 Node attr = (Node) attributes.item(j); 134 element.setAttribute(attr.getNodeName(), attr.getNodeValue()); 135 } 136 lookup.put(getKey(element), element); 137 } 138 } 139 140 public void generate(ProgressMonitor progress) throws UsageException { 141 if (progress != null) { 142 progress.setTotal(3); 143 progress.setMessage("extra attributes..."); 144 } 145 generateExtraAttributes(); 146 if (progress != null) { 147 progress.step(); 148 progress.setMessage(mainClassName); 149 } 150 generateMainClass(); 151 if (progress != null) { 152 progress.step(); 153 progress.setMessage("classes..."); 154 } 155 generateClasses(); 156 if (progress != null) { 157 progress.step(); 158 progress.setMessage("Done."); 159 } 160 } 161 162 163 String fixDelimiter(String str) { 164 if (delimiter.equals("\n")) 165 return str; 166 int index = 0, length = str.length(); 167 StringBuffer buffer = new StringBuffer(); 168 while (index != -1) { 169 int start = index; 170 index = str.indexOf('\n', start); 171 if (index == -1) { 172 buffer.append(str.substring(start, length)); 173 } else { 174 buffer.append(str.substring(start, index)); 175 buffer.append(delimiter); 176 index++; 177 } 178 } 179 return buffer.toString(); 180 } 181 182 void generateMethods(String className, ArrayList<Node> methods) { 183 for (Node method : methods) { 184 NamedNodeMap mthAttributes = method.getAttributes(); 185 String sel = mthAttributes.getNamedItem("selector").getNodeValue(); 186 out("public "); 187 boolean isStatic = isStatic(method); 188 if (isStatic) 189 out("static "); 190 Node returnNode = getReturnNode(method.getChildNodes()); 191 if (getType(returnNode).equals("void")) 192 returnNode = null; 193 String returnType = "", returnType64 = ""; 194 if (returnNode != null) { 195 String type = returnType = getJavaType(returnNode), type64 = returnType64 = getJavaType64(returnNode); 196 out(type); 197 if (!type.equals(type64)) { 198 out(" /*"); 199 out(type64); 200 out("*/"); 201 } 202 out(" "); 203 } else { 204 out("void "); 205 } 206 String methodName = sel; 207 if (isUnique(method, methods)) { 208 int index = methodName.indexOf(":"); 209 if (index != -1) 210 methodName = methodName.substring(0, index); 211 } else { 212 // TODO improve this selector 213 methodName = methodName.replaceAll(":", "_"); 214 if (isStatic) 215 methodName = "static_" + methodName; 216 } 217 out(methodName); 218 out("("); 219 NodeList params = method.getChildNodes(); 220 boolean first = true; 221 for (int k = 0; k < params.getLength(); k++) { 222 Node param = params.item(k); 223 if ("arg".equals(param.getNodeName())) { 224 NamedNodeMap paramAttributes = param.getAttributes(); 225 if (!first) 226 out(", "); 227 String type = getJavaType(param), type64 = getJavaType64(param); 228 out(type); 229 if (!type.equals(type64)) { 230 out(" /*"); 231 out(type64); 232 out("*/"); 233 } 234 first = false; 235 out(" "); 236 String paramName = paramAttributes.getNamedItem("name").getNodeValue(); 237 if (paramName.length() == 0) 238 paramName = "arg" + paramAttributes.getNamedItem("index").getNodeValue(); 239 if (paramName.equals("boolean")) 240 paramName = "b"; 241 out(paramName); 242 } 243 } 244 out(") {"); 245 outln(); 246 if (returnNode != null && isStruct(returnNode)) { 247 out("\t"); 248 out(returnType); 249 out(" result = new "); 250 out(returnType); 251 out("();"); 252 outln(); 253 out("\tOS.objc_msgSend_stret(result, "); 254 } else if (returnNode != null && isBoolean(returnNode)) { 255 out("\treturn "); 256 out("OS.objc_msgSend_bool("); 257 } else if (returnNode != null && isFloatingPoint(returnNode)) { 258 out("\treturn "); 259 if (returnType.equals("float")) 260 out("(float)"); 261 out("OS.objc_msgSend_fpret("); 262 } else if (returnNode != null && isObject(returnNode)) { 263 out("\tint /*long*/ result = OS.objc_msgSend("); 264 } else { 265 if (returnNode != null) { 266 out("\treturn "); 267 if ((returnType.equals("int") && returnType64.equals("int")) || !returnType.equals("int")) { 268 out("("); 269 out(returnType); 270 out(")"); 271 } 272 if (returnType.equals("int") && returnType64.equals("int")) { 273 out("/*64*/"); 274 } 275 } else { 276 out("\t"); 277 } 278 out("OS.objc_msgSend("); 279 } 280 if (isStatic) { 281 out("OS.class_"); 282 out(className); 283 } else { 284 out("this.id"); 285 } 286 out(", OS."); 287 out(getSelConst(sel)); 288 first = false; 289 for (int k = 0; k < params.getLength(); k++) { 290 Node param = params.item(k); 291 if ("arg".equals(param.getNodeName())) { 292 NamedNodeMap paramAttributes = param.getAttributes(); 293 if (!first) 294 out(", "); 295 first = false; 296 String paramName = paramAttributes.getNamedItem("name").getNodeValue(); 297 if (paramName.length() == 0) 298 paramName = "arg" + paramAttributes.getNamedItem("index").getNodeValue(); 299 if (paramName.equals("boolean")) 300 paramName = "b"; 301 if (isObject(param)) { 302 out(paramName); 303 out(" != null ? "); 304 out(paramName); 305 out(".id : 0"); 306 } else { 307 out(paramName); 308 } 309 } 310 } 311 out(")"); 312 out(";"); 313 outln(); 314 if (returnNode != null && isObject(returnNode)) { 315 if (!isStatic && returnType.equals(className)) { 316 out("\treturn result == this.id ? this : (result != 0 ? new "); 317 out(returnType); 318 out("(result) : null);"); 319 } else { 320 out("\treturn result != 0 ? new "); 321 NamedNodeMap attributes = returnNode.getAttributes(); 322 Node hawtjni_alloc = attributes.getNamedItem("hawtjni_alloc"); 323 if (hawtjni_alloc != null && hawtjni_alloc.getNodeValue().equals("true")) { 324 out(className); 325 } else { 326 out(returnType); 327 } 328 out("(result) : null;"); 329 } 330 outln(); 331 } else if (returnNode != null && isStruct(returnNode)) { 332 out("\treturn result;"); 333 outln(); 334 } 335 out("}"); 336 outln(); 337 outln(); 338 } 339 } 340 341 void generateExtraMethods(String className) { 342 /* Empty constructor */ 343 out("public "); 344 out(className); 345 out("() {"); 346 outln(); 347 out("\tsuper();"); 348 outln(); 349 out("}"); 350 outln(); 351 outln(); 352 /* pointer constructor */ 353 out("public "); 354 out(className); 355 out("(int /*long*/ id) {"); 356 outln(); 357 out("\tsuper(id);"); 358 outln(); 359 out("}"); 360 outln(); 361 outln(); 362 /* object constructor */ 363 out("public "); 364 out(className); 365 out("(id id) {"); 366 outln(); 367 out("\tsuper(id);"); 368 outln(); 369 out("}"); 370 outln(); 371 outln(); 372 /* NSObject helpers */ 373 if (className.equals("NSObject")) { 374 out("public NSObject alloc() {"); 375 outln(); 376 out("\tthis.id = OS.objc_msgSend(objc_getClass(), OS.sel_alloc);"); 377 outln(); 378 out("\treturn this;"); 379 outln(); 380 out("}"); 381 outln(); 382 outln(); 383 } 384 /* NSString helpers */ 385 if (className.equals("NSString")) { 386 /* Get java string */ 387 out("public String getString() {"); 388 outln(); 389 out("\tchar[] buffer = new char[(int)/*64*/length()];"); 390 outln(); 391 out("\tgetCharacters(buffer);"); 392 outln(); 393 out("\treturn new String(buffer);"); 394 outln(); 395 out("}"); 396 outln(); 397 outln(); 398 /* create NSString */ 399 out("public NSString initWithString(String str) {"); 400 outln(); 401 out("\tchar[] buffer = new char[str.length()];"); 402 outln(); 403 out("\tstr.getChars(0, buffer.length, buffer, 0);"); 404 outln(); 405 out("\treturn initWithCharacters(buffer, buffer.length);"); 406 outln(); 407 out("}"); 408 outln(); 409 outln(); 410 out("public static NSString stringWith(String str) {"); 411 outln(); 412 out("\tchar[] buffer = new char[str.length()];"); 413 outln(); 414 out("\tstr.getChars(0, buffer.length, buffer, 0);"); 415 outln(); 416 out("\treturn stringWithCharacters(buffer, buffer.length);"); 417 outln(); 418 out("}"); 419 outln(); 420 outln(); 421 } 422 } 423 424 static class NodeEntry { 425 private final Node parent; 426 private final ArrayList<Node> children; 427 428 public NodeEntry(Node parent, ArrayList<Node> children) { 429 this.parent = parent; 430 this.children = children; 431 } 432 } 433 434 TreeMap<String, NodeEntry> getGeneratedClasses() { 435 TreeMap<String, NodeEntry> classes = new TreeMap<String, NodeEntry>(); 436 for (int x = 0; x < xmls.length; x++) { 437 Document document = documents[x]; 438 if (document == null) 439 continue; 440 NodeList list = document.getDocumentElement().getChildNodes(); 441 for (int i = 0; i < list.getLength(); i++) { 442 Node node = list.item(i); 443 if ("class".equals(node.getNodeName()) && getGen(node)) { 444 ArrayList<Node> methods; 445 String name = node.getAttributes().getNamedItem("name").getNodeValue(); 446 NodeEntry clazz = classes.get(name); 447 if (clazz == null) { 448 methods = new ArrayList<Node>(); 449 classes.put(name, new NodeEntry(node, methods)); 450 } else { 451 methods = clazz.children; 452 } 453 NodeList methodList = node.getChildNodes(); 454 for (int j = 0; j < methodList.getLength(); j++) { 455 Node method = methodList.item(j); 456 if ("method".equals(method.getNodeName()) && getGen(method)) { 457 methods.add(method); 458 } 459 } 460 } 461 } 462 } 463 return classes; 464 } 465 466 void copyClassMethodsDown(final Map<String, NodeEntry> classes) { 467 ArrayList<NodeEntry> sortedClasses = Collections.list(Collections.enumeration(classes.values())); 468 Collections.sort(sortedClasses, new Comparator<NodeEntry>() { 469 int getHierarchyLevel(Node node) { 470 String superclass = getSuperclassName(node); 471 int level = 0; 472 while (!superclass.equals("id")) { 473 level++; 474 superclass = getSuperclassName(classes.get(superclass).parent); 475 } 476 return level; 477 } 478 479 public int compare(NodeEntry arg0, NodeEntry arg1) { 480 return getHierarchyLevel(arg0.parent) - getHierarchyLevel(arg1.parent); 481 } 482 }); 483 for (NodeEntry clazz : sortedClasses) { 484 Node node = (Node) clazz.parent; 485 ArrayList<Node> methods = (ArrayList<Node>) clazz.children; 486 NodeEntry superclass = classes.get(getSuperclassName(node)); 487 if (superclass != null) { 488 for (Node method : superclass.children) { 489 if (isStatic(method)) { 490 methods.add(method); 491 } 492 } 493 } 494 } 495 } 496 497 String getSuperclassName(Node node) { 498 NamedNodeMap attributes = node.getAttributes(); 499 Node superclass = attributes.getNamedItem("hawtjni_superclass"); 500 if (superclass != null) { 501 return superclass.getNodeValue(); 502 } else { 503 Node name = attributes.getNamedItem("name"); 504 if (name.getNodeValue().equals("NSObject")) { 505 return "id"; 506 } else { 507 return "NSObject"; 508 } 509 } 510 } 511 512 void generateClasses() { 513 TreeMap<String, NodeEntry> classes = getGeneratedClasses(); 514 copyClassMethodsDown(classes); 515 516 Set<String> classNames = classes.keySet(); 517 for (Iterator<String> iterator = classNames.iterator(); iterator.hasNext();) { 518 ByteArrayOutputStream out = new ByteArrayOutputStream(); 519 this.out = new PrintStream(out); 520 521 // out(fixDelimiter(metaData.getCopyright())); 522 523 String className = iterator.next(); 524 NodeEntry clazz = classes.get(className); 525 Node node = clazz.parent; 526 ArrayList<Node> methods = clazz.children; 527 out("package "); 528 String packageName = getPackageName(mainClassName); 529 out(packageName); 530 out(";"); 531 outln(); 532 outln(); 533 out("public class "); 534 out(className); 535 out(" extends "); 536 out(getSuperclassName(node)); 537 out(" {"); 538 outln(); 539 outln(); 540 generateExtraMethods(className); 541 generateMethods(className, methods); 542 out("}"); 543 outln(); 544 545 String fileName = outputDir + packageName.replace('.', '/') + "/" + className + ".java"; 546 try { 547 out.flush(); 548 if (out.size() > 0) { 549 FileSupport.write(out.toByteArray(), new File(fileName)); 550 } 551 } catch (Exception e) { 552 System.out.println("Problem"); 553 e.printStackTrace(System.out); 554 } 555 out = null; 556 } 557 } 558 559 void generateExtraAttributes() { 560 Document[] documents = getDocuments(); 561 for (int x = 0; x < xmls.length; x++) { 562 Document document = documents[x]; 563 if (document == null || !getGen(document.getDocumentElement())) 564 continue; 565 saveExtraAttributes(xmls[x], document); 566 } 567 } 568 569 void generateMainClass() { 570 ByteArrayOutputStream out = new ByteArrayOutputStream(); 571 this.out = new PrintStream(out); 572 573 String header = "", footer = ""; 574 String fileName = outputDir + mainClassName.replace('.', '/') + ".java"; 575 FileInputStream is = null; 576 try { 577 InputStreamReader input = new InputStreamReader(new BufferedInputStream(is = new FileInputStream(fileName))); 578 StringBuffer str = new StringBuffer(); 579 char[] buffer = new char[4096]; 580 int read; 581 while ((read = input.read(buffer)) != -1) { 582 str.append(buffer, 0, read); 583 } 584 String section = "/** This section is auto generated */"; 585 int start = str.indexOf(section) + section.length(); 586 int end = str.indexOf(section, start); 587 header = str.substring(0, start); 588 footer = str.substring(end); 589 } catch (IOException e) { 590 } finally { 591 try { 592 if (is != null) 593 is.close(); 594 } catch (IOException e) { 595 } 596 } 597 598 out(header); 599 outln(); 600 outln(); 601 602 out("/** Custom callbacks */"); 603 outln(); 604 generateCustomCallbacks(); 605 outln(); 606 out("/** Classes */"); 607 outln(); 608 generateClassesConst(); 609 outln(); 610 out("/** Protocols */"); 611 outln(); 612 generateProtocolsConst(); 613 outln(); 614 out("/** Selectors */"); 615 outln(); 616 generateSelectorsConst(); 617 outln(); 618 out("/** Constants */"); 619 outln(); 620 generateEnums(); 621 outln(); 622 out("/** Globals */"); 623 outln(); 624 generateConstants(); 625 outln(); 626 out("/** Functions */"); 627 outln(); 628 outln(); 629 generateFunctions(); 630 outln(); 631 out("/** Super Sends */"); 632 outln(); 633 generateSends(true); 634 outln(); 635 out("/** Sends */"); 636 outln(); 637 generateSends(false); 638 outln(); 639 generateStructNatives(); 640 641 outln(); 642 out(footer); 643 try { 644 out.flush(); 645 if (out.size() > 0) { 646 FileSupport.write(out.toByteArray(), new File(fileName)); 647 648 } 649 } catch (Exception e) { 650 System.out.println("Problem"); 651 e.printStackTrace(System.out); 652 } 653 } 654 655 public Document[] getDocuments() { 656 if (documents == null) { 657 String[] xmls = getXmls(); 658 documents = new Document[xmls.length]; 659 for (int i = 0; i < xmls.length; i++) { 660 String xmlPath = xmls[i]; 661 Document document = documents[i] = getDocument(xmlPath); 662 if (document == null) 663 continue; 664 if (mainClassName != null && outputDir != null) { 665 String packageName = getPackageName(mainClassName); 666 String extrasPath = outputDir + packageName.replace('.', '/') + "/" + getFileName(xmlPath) + ".extras"; 667 merge(document, getDocument(extrasPath)); 668 } 669 } 670 } 671 return documents; 672 } 673 674 public String[] getXmls() { 675 if (xmls == null || xmls.length == 0) { 676 ArrayList<String> array = new ArrayList<String>(); 677 list(new File("/System/Library/Frameworks"), array); 678 list(new File("/System/Library/Frameworks/CoreServices.framework/Frameworks"), array); 679 list(new File("/System/Library/Frameworks/ApplicationServices.framework/Frameworks"), array); 680 Collections.sort(array, new Comparator<String>() { 681 public int compare(String o1, String o2) { 682 return new File(o1).getName().compareTo(new File(o2).getName()); 683 } 684 }); 685 xmls = array.toArray(new String[array.size()]); 686 } 687 return xmls; 688 } 689 690 void saveExtraAttributes(String xmlPath, Document document) { 691 try { 692 String packageName = getPackageName(mainClassName); 693 String fileName = outputDir + packageName.replace('.', '/') + "/" + getFileName(xmlPath) + ".extras"; 694 ByteArrayOutputStream out = new ByteArrayOutputStream(); 695 DOMWriter writer = new DOMWriter(new PrintStream(out)); 696 String[] names = getIDAttributeNames(); 697 String[] filter = new String[names.length + 2]; 698 filter[0] = "class_method"; 699 filter[1] = "hawtjni_.*"; 700 System.arraycopy(names, 0, filter, 2, names.length); 701 writer.setAttributeFilter(filter); 702 writer.setNodeFilter("hawtjni_"); 703 writer.print(document); 704 if (out.size() > 0) { 705 FileSupport.write(out.toByteArray(), new File(fileName)); 706 } 707 } catch (Exception e) { 708 System.out.println("Problem"); 709 e.printStackTrace(System.out); 710 } 711 } 712 713 public void setOutputDir(String dir) { 714 if (dir != null) { 715 if (!dir.endsWith("\\") && !dir.endsWith("/")) { 716 dir += "/"; 717 } 718 } 719 this.outputDir = dir; 720 } 721 722 public void setXmls(String[] xmls) { 723 this.xmls = xmls; 724 this.documents = null; 725 } 726 727 public void setMainClass(String mainClassName) { 728 this.mainClassName = mainClassName; 729 } 730 731 Document getDocument(String xmlPath) { 732 try { 733 InputStream is = null; 734 if (xmlPath.indexOf(File.separatorChar) == -1) 735 is = getClass().getResourceAsStream(xmlPath); 736 if (is == null) 737 is = new BufferedInputStream(new FileInputStream(xmlPath)); 738 if (is != null) 739 return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(is)); 740 } catch (Exception e) { 741 // e.printStackTrace(); 742 } 743 return null; 744 } 745 746 public String[] getExtraAttributeNames(Node node) { 747 String name = node.getNodeName(); 748 if (name.equals("method")) { 749 return new String[] { "hawtjni_gen_super_msgSend", "hawtjni_gen_custom_callback" }; 750 } else if (name.equals("function")) { 751 NamedNodeMap attribs = node.getAttributes(); 752 if (attribs != null && attribs.getNamedItem("variadic") != null) { 753 return new String[] { "hawtjni_variadic_count", "hawtjni_variadic_java_types" }; 754 } 755 } else if (name.equals("class")) { 756 return new String[] { "hawtjni_superclass" }; 757 } else if (name.equals("retval")) { 758 return new String[] { "hawtjni_java_type", "hawtjni_java_type64", "hawtjni_alloc" }; 759 } else if (name.equals("arg")) { 760 return new String[] { "hawtjni_java_type", "hawtjni_java_type64" }; 761 } 762 return new String[0]; 763 } 764 765 public String getFileName(String xmlPath) { 766 File file = new File(xmlPath); 767 return file.getName(); 768 } 769 770 String getKey(Node node) { 771 StringBuffer buffer = new StringBuffer(); 772 while (node != null) { 773 if (buffer.length() > 0) 774 buffer.append("_"); 775 String name = node.getNodeName(); 776 StringBuffer key = new StringBuffer(name); 777 Node nameAttrib = getIDAttribute(node); 778 if (nameAttrib != null) { 779 key.append("-"); 780 key.append(nameAttrib.getNodeValue()); 781 } 782 NamedNodeMap attributes = node.getAttributes(); 783 if (attributes != null) { 784 boolean isStatic = attributes.getNamedItem("class_method") != null; 785 if (isStatic) 786 key.append("-static"); 787 } 788 buffer.append(key.reverse()); 789 node = node.getParentNode(); 790 } 791 buffer.reverse(); 792 return buffer.toString(); 793 } 794 795 public Node getIDAttribute(Node node) { 796 NamedNodeMap attributes = node.getAttributes(); 797 if (attributes == null) 798 return null; 799 String[] names = getIDAttributeNames(); 800 for (int i = 0; i < names.length; i++) { 801 Node nameAttrib = attributes.getNamedItem(names[i]); 802 if (nameAttrib != null) 803 return nameAttrib; 804 } 805 return null; 806 } 807 808 public String[] getIDAttributeNames() { 809 return new String[] { "name", "selector", "path", }; 810 } 811 812 void merge(Node node, HashMap<String, Node> extras, HashMap<String, Node> docLookup) { 813 NodeList list = node.getChildNodes(); 814 for (int i = 0; i < list.getLength(); i++) { 815 Node childNode = list.item(i); 816 if (childNode.getNodeType() == Node.ELEMENT_NODE) { 817 String key = getKey(childNode); 818 if (docLookup != null && docLookup.get(key) == null) { 819 docLookup.put(key, childNode); 820 } 821 Node extra = extras.remove(key); 822 if (extra != null) { 823 NamedNodeMap attributes = extra.getAttributes(); 824 for (int j = 0, length = attributes.getLength(); j < length; j++) { 825 Node attr = (Node) attributes.item(j); 826 String name = attr.getNodeName(); 827 if (name.startsWith("hawtjni_")) { 828 ((Element) childNode).setAttribute(name, attr.getNodeValue()); 829 } 830 } 831 } 832 } 833 merge(childNode, extras, docLookup); 834 } 835 } 836 837 void out(String str) { 838 PrintStream out = this.out; 839 if (out == null) 840 out = System.out; 841 out.print(str); 842 } 843 844 void outln() { 845 PrintStream out = this.out; 846 if (out == null) 847 out = System.out; 848 out.println(); 849 } 850 851 void generateConstants() { 852 for (int x = 0; x < xmls.length; x++) { 853 Document document = documents[x]; 854 if (document == null) 855 continue; 856 NodeList list = document.getDocumentElement().getChildNodes(); 857 for (int i = 0; i < list.getLength(); i++) { 858 Node node = list.item(i); 859 if ("constant".equals(node.getNodeName())) { 860 if (getGen(node)) { 861 NamedNodeMap attributes = node.getAttributes(); 862 String constName = attributes.getNamedItem("name").getNodeValue(); 863 out("/** @method flags=const */"); 864 outln(); 865 out("public static final native "); 866 String type = getType(node), type64 = getType64(node); 867 out(type); 868 if (!type.equals(type64)) { 869 out(" /*"); 870 out(type64); 871 out("*/"); 872 } 873 out(" "); 874 out(constName); 875 out("();"); 876 outln(); 877 if (attributes.getNamedItem("declared_type").getNodeValue().equals("NSString*")) { 878 out("public static final NSString "); 879 out(constName); 880 out(" = new NSString("); 881 out(constName); 882 out("());"); 883 outln(); 884 } 885 } 886 } 887 } 888 } 889 } 890 891 void generateEnums() { 892 for (int x = 0; x < xmls.length; x++) { 893 Document document = documents[x]; 894 if (document == null) 895 continue; 896 NodeList list = document.getDocumentElement().getChildNodes(); 897 for (int i = 0; i < list.getLength(); i++) { 898 Node node = list.item(i); 899 if ("enum".equals(node.getNodeName())) { 900 if (getGen(node)) { 901 NamedNodeMap attributes = node.getAttributes(); 902 Node valueNode = attributes.getNamedItem("value"); 903 if (valueNode != null) { 904 String value = valueNode.getNodeValue(); 905 out("public static final "); 906 boolean isLong = false; 907 if (value.indexOf('.') != -1) { 908 out("double "); 909 } else { 910 try { 911 Integer.parseInt(value); 912 out("int "); 913 } catch (NumberFormatException e) { 914 isLong = true; 915 out("long "); 916 } 917 } 918 out(attributes.getNamedItem("name").getNodeValue()); 919 out(" = "); 920 out(value); 921 if (isLong && !value.endsWith("L")) 922 out("L"); 923 out(";"); 924 outln(); 925 } 926 } 927 } 928 } 929 } 930 } 931 932 boolean getGen(Node node) { 933 NamedNodeMap attributes = node.getAttributes(); 934 if (attributes == null) 935 return false; 936 Node gen = attributes.getNamedItem("hawtjni_gen"); 937 return gen != null && !gen.getNodeValue().equals("false"); 938 } 939 940 boolean getGenSuper(Node node) { 941 NamedNodeMap attributes = node.getAttributes(); 942 if (attributes == null) 943 return false; 944 Node gen = attributes.getNamedItem("hawtjni_gen_super_msgSend"); 945 return gen != null && !gen.getNodeValue().equals("false"); 946 } 947 948 boolean getGenCallback(Node node) { 949 NamedNodeMap attributes = node.getAttributes(); 950 if (attributes == null) 951 return false; 952 Node gen = attributes.getNamedItem("hawtjni_gen_custom_callback"); 953 return gen != null && !gen.getNodeValue().equals("false"); 954 } 955 956 boolean isStatic(Node node) { 957 NamedNodeMap attributes = node.getAttributes(); 958 Node isStatic = attributes.getNamedItem("class_method"); 959 return isStatic != null && isStatic.getNodeValue().equals("true"); 960 } 961 962 boolean isStruct(Node node) { 963 NamedNodeMap attributes = node.getAttributes(); 964 String code = attributes.getNamedItem("type").getNodeValue(); 965 return code.startsWith("{"); 966 } 967 968 boolean isFloatingPoint(Node node) { 969 NamedNodeMap attributes = node.getAttributes(); 970 String code = attributes.getNamedItem("type").getNodeValue(); 971 return code.equals("f") || code.equals("d"); 972 } 973 974 boolean isObject(Node node) { 975 NamedNodeMap attributes = node.getAttributes(); 976 String code = attributes.getNamedItem("type").getNodeValue(); 977 return code.equals("@"); 978 } 979 980 boolean isBoolean(Node node) { 981 NamedNodeMap attributes = node.getAttributes(); 982 String code = attributes.getNamedItem("type").getNodeValue(); 983 return code.equals("B"); 984 } 985 986 void buildLookup(Node node, HashMap<String, Node> table) { 987 NodeList list = node.getChildNodes(); 988 for (int i = 0; i < list.getLength(); i++) { 989 Node childNode = list.item(i); 990 if (childNode.getNodeType() == Node.ELEMENT_NODE) { 991 String key = getKey(childNode); 992 if (table.get(key) == null) 993 table.put(key, childNode); 994 buildLookup(childNode, table); 995 } 996 } 997 } 998 999 boolean isUnique(Node method, ArrayList<Node> methods) { 1000 String methodName = method.getAttributes().getNamedItem("selector").getNodeValue(); 1001 String signature = ""; 1002 NodeList params = method.getChildNodes(); 1003 for (int k = 0; k < params.getLength(); k++) { 1004 Node param = params.item(k); 1005 if ("arg".equals(param.getNodeName())) { 1006 signature += getJavaType(param); 1007 } 1008 } 1009 int index = methodName.indexOf(":"); 1010 if (index != -1) 1011 methodName = methodName.substring(0, index); 1012 for (Node node : methods) { 1013 NamedNodeMap attributes = node.getAttributes(); 1014 Node otherSel = null; 1015 if (attributes != null) 1016 otherSel = attributes.getNamedItem("selector"); 1017 if (node != method && otherSel != null) { 1018 String otherName = otherSel.getNodeValue(); 1019 index = otherName.indexOf(":"); 1020 if (index != -1) 1021 otherName = otherName.substring(0, index); 1022 if (methodName.equals(otherName)) { 1023 NodeList otherParams = node.getChildNodes(); 1024 String otherSignature = ""; 1025 for (int k = 0; k < otherParams.getLength(); k++) { 1026 Node param = otherParams.item(k); 1027 if ("arg".equals(param.getNodeName())) { 1028 otherSignature += getJavaType(param); 1029 } 1030 } 1031 if (signature.equals(otherSignature)) { 1032 return false; 1033 } 1034 } 1035 } 1036 } 1037 return true; 1038 } 1039 1040 void generateSelectorsConst() { 1041 TreeSet<String> set = new TreeSet<String>(); 1042 for (int x = 0; x < xmls.length; x++) { 1043 Document document = documents[x]; 1044 if (document == null) 1045 continue; 1046 NodeList list = document.getDocumentElement().getChildNodes(); 1047 for (int i = 0; i < list.getLength(); i++) { 1048 Node node = list.item(i); 1049 if ("class".equals(node.getNodeName()) || "informal_protocol".equals(node.getNodeName())) { 1050 if (getGen(node)) { 1051 NodeList methods = node.getChildNodes(); 1052 for (int j = 0; j < methods.getLength(); j++) { 1053 Node method = methods.item(j); 1054 if (getGen(method)) { 1055 NamedNodeMap mthAttributes = method.getAttributes(); 1056 String sel = mthAttributes.getNamedItem("selector").getNodeValue(); 1057 set.add(sel); 1058 } 1059 } 1060 } 1061 } 1062 } 1063 } 1064 set.add("alloc"); 1065 for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { 1066 String sel = iterator.next(); 1067 String selConst = getSelConst(sel); 1068 out("public static final int /*long*/ "); 1069 out(selConst); 1070 out(" = "); 1071 out("sel_registerName(\""); 1072 out(sel); 1073 out("\");"); 1074 outln(); 1075 } 1076 } 1077 1078 void generateStructNatives() { 1079 TreeSet<String> set = new TreeSet<String>(); 1080 for (int x = 0; x < xmls.length; x++) { 1081 Document document = documents[x]; 1082 if (document == null) 1083 continue; 1084 NodeList list = document.getDocumentElement().getChildNodes(); 1085 for (int i = 0; i < list.getLength(); i++) { 1086 Node node = list.item(i); 1087 if ("struct".equals(node.getNodeName()) && getGen(node)) { 1088 set.add(getIDAttribute(node).getNodeValue()); 1089 } 1090 } 1091 } 1092 out("/** Sizeof natives */"); 1093 outln(); 1094 for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { 1095 String struct = iterator.next(); 1096 out("public static final native int "); 1097 out(struct); 1098 out("_sizeof();"); 1099 outln(); 1100 } 1101 outln(); 1102 out("/** Memmove natives */"); 1103 outln(); 1104 outln(); 1105 for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { 1106 String struct = iterator.next(); 1107 out("/**"); 1108 outln(); 1109 out(" * @param dest cast=(void *),flags=no_in critical"); 1110 outln(); 1111 out(" * @param src cast=(void *),flags=critical"); 1112 // out(" * @param src cast=(void *),flags=no_out critical"); 1113 outln(); 1114 out(" */"); 1115 outln(); 1116 out("public static final native void memmove("); 1117 out("int /*long*/ dest, "); 1118 out(struct); 1119 out(" src, int /*long*/ size);"); 1120 outln(); 1121 out("/**"); 1122 outln(); 1123 out(" * @param dest cast=(void *),flags=no_in critical"); 1124 outln(); 1125 out(" * @param src cast=(void *),flags=critical"); 1126 // out(" * @param src cast=(void *),flags=no_out critical"); 1127 outln(); 1128 out(" */"); 1129 outln(); 1130 out("public static final native void memmove("); 1131 out(struct); 1132 out(" dest, int /*long*/ src, int /*long*/ size);"); 1133 outln(); 1134 } 1135 } 1136 1137 String buildSend(Node method, boolean tags, boolean only64, boolean superCall) { 1138 Node returnNode = getReturnNode(method.getChildNodes()); 1139 StringBuffer buffer = new StringBuffer(); 1140 buffer.append("public static final native "); 1141 if (returnNode != null && isStruct(returnNode)) { 1142 buffer.append("void "); 1143 buffer.append(superCall ? "objc_msgSendSuper_stret" : "objc_msgSend_stret"); 1144 buffer.append("("); 1145 buffer.append(getJavaType(returnNode)); 1146 buffer.append(" result, "); 1147 } else if (returnNode != null && isFloatingPoint(returnNode)) { 1148 buffer.append("double "); 1149 buffer.append(superCall ? "objc_msgSendSuper_fpret" : "objc_msgSend_fpret"); 1150 buffer.append("("); 1151 } else if (returnNode != null && isBoolean(returnNode)) { 1152 buffer.append("boolean "); 1153 buffer.append(superCall ? "objc_msgSendSuper_bool" : "objc_msgSend_bool"); 1154 buffer.append("("); 1155 } else { 1156 if (only64) { 1157 buffer.append("long"); 1158 } else { 1159 if (tags) { 1160 buffer.append("int /*long*/"); 1161 } else { 1162 buffer.append("int"); 1163 } 1164 } 1165 buffer.append(" "); 1166 buffer.append(superCall ? "objc_msgSendSuper" : "objc_msgSend"); 1167 buffer.append("("); 1168 } 1169 if (superCall) { 1170 if (only64) { 1171 buffer.append("objc_super superId, long sel"); 1172 } else { 1173 if (tags) { 1174 buffer.append("objc_super superId, int /*long*/ sel"); 1175 } else { 1176 buffer.append("objc_super superId, int sel"); 1177 } 1178 } 1179 } else { 1180 if (only64) { 1181 buffer.append("long id, long sel"); 1182 } else { 1183 if (tags) { 1184 buffer.append("int /*long*/ id, int /*long*/ sel"); 1185 } else { 1186 buffer.append("int id, int sel"); 1187 } 1188 } 1189 } 1190 NodeList params = method.getChildNodes(); 1191 boolean first = false; 1192 int count = 0; 1193 for (int k = 0; k < params.getLength(); k++) { 1194 Node param = params.item(k); 1195 if ("arg".equals(param.getNodeName())) { 1196 if (!first) 1197 buffer.append(", "); 1198 if (isStruct(param)) { 1199 buffer.append(getJavaType(param)); 1200 } else { 1201 String type = getType(param), type64 = getType64(param); 1202 buffer.append(only64 ? type64 : type); 1203 if (!only64 && tags && !type.equals(type64)) { 1204 buffer.append(" /*"); 1205 buffer.append(type64); 1206 buffer.append("*/"); 1207 } 1208 } 1209 first = false; 1210 buffer.append(" arg"); 1211 buffer.append(String.valueOf(count++)); 1212 } 1213 } 1214 buffer.append(");"); 1215 return buffer.toString(); 1216 } 1217 1218 String getCType(Node node) { 1219 NamedNodeMap attributes = node.getAttributes(); 1220 return attributes.getNamedItem("declared_type").getNodeValue(); 1221 } 1222 1223 Node findNSObjectMethod(Node method) { 1224 NamedNodeMap methodAttributes = method.getAttributes(); 1225 String selector = methodAttributes.getNamedItem("selector").getNodeValue(); 1226 NodeList list = method.getParentNode().getParentNode().getChildNodes(); 1227 for (int i = 0; i < list.getLength(); i++) { 1228 Node cls = list.item(i); 1229 if ("class".equals(cls.getNodeName())) { 1230 NamedNodeMap classAttributes = cls.getAttributes(); 1231 if ("NSObject".equals(classAttributes.getNamedItem("name").getNodeValue())) { 1232 NodeList methods = cls.getChildNodes(); 1233 for (int j = 0; j < methods.getLength(); j++) { 1234 Node mth = methods.item(j); 1235 if ("method".equals(mth.getNodeName())) { 1236 NamedNodeMap mthAttributes = mth.getAttributes(); 1237 if (selector.equals(mthAttributes.getNamedItem("selector").getNodeValue())) { 1238 return mth; 1239 } 1240 } 1241 } 1242 } 1243 } 1244 } 1245 return null; 1246 } 1247 1248 void generateCustomCallbacks() { 1249 TreeMap<String, Node> set = new TreeMap<String, Node>(); 1250 for (int x = 0; x < xmls.length; x++) { 1251 Document document = documents[x]; 1252 if (document == null) 1253 continue; 1254 NodeList list = document.getDocumentElement().getChildNodes(); 1255 for (int i = 0; i < list.getLength(); i++) { 1256 Node node = list.item(i); 1257 if (("class".equals(node.getNodeName()) || "informal_protocol".equals(node.getNodeName())) && getGen(node)) { 1258 NodeList methods = node.getChildNodes(); 1259 for (int j = 0; j < methods.getLength(); j++) { 1260 Node method = methods.item(j); 1261 if ("method".equals(method.getNodeName()) && getGen(method) && getGenCallback(method)) { 1262 NamedNodeMap mthAttributes = method.getAttributes(); 1263 String sel = mthAttributes.getNamedItem("selector").getNodeValue(); 1264 set.put(sel, method); 1265 } 1266 } 1267 } 1268 } 1269 } 1270 for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { 1271 String key = iterator.next(); 1272 Node method = set.get(key); 1273 if ("informal_protocol".equals(method.getParentNode().getNodeName())) { 1274 method = findNSObjectMethod(method); 1275 if (method == null) 1276 continue; 1277 } 1278 String nativeMth = key.replaceAll(":", "_"); 1279 out("/** @method callback_types="); 1280 Node returnNode = getReturnNode(method.getChildNodes()); 1281 out(returnNode == null ? "void" : getCType(returnNode)); 1282 out(";id;SEL;"); 1283 NodeList params = method.getChildNodes(); 1284 for (int k = 0; k < params.getLength(); k++) { 1285 Node param = params.item(k); 1286 if ("arg".equals(param.getNodeName())) { 1287 out(getCType(param)); 1288 out(";"); 1289 } 1290 } 1291 out(",callback_flags="); 1292 out(returnNode != null && isStruct(returnNode) ? "struct" : "none"); 1293 out(";none;none;"); 1294 for (int k = 0; k < params.getLength(); k++) { 1295 Node param = params.item(k); 1296 if ("arg".equals(param.getNodeName())) { 1297 out(isStruct(param) ? "struct" : "none"); 1298 out(";"); 1299 } 1300 } 1301 out(" */"); 1302 outln(); 1303 out("public static final native int /*long*/ CALLBACK_"); 1304 out(nativeMth); 1305 out("(int /*long*/ func);"); 1306 outln(); 1307 } 1308 } 1309 1310 void generateSends(boolean superCall) { 1311 TreeMap<String, Node> set = new TreeMap<String, Node>(); 1312 TreeMap<String, Node> set64 = new TreeMap<String, Node>(); 1313 for (int x = 0; x < xmls.length; x++) { 1314 Document document = documents[x]; 1315 if (document == null) 1316 continue; 1317 NodeList list = document.getDocumentElement().getChildNodes(); 1318 for (int i = 0; i < list.getLength(); i++) { 1319 Node node = list.item(i); 1320 if ("class".equals(node.getNodeName()) && getGen(node)) { 1321 NodeList methods = node.getChildNodes(); 1322 for (int j = 0; j < methods.getLength(); j++) { 1323 Node method = methods.item(j); 1324 if ("method".equals(method.getNodeName()) && getGen(method) && (!superCall || getGenSuper(method))) { 1325 String code = buildSend(method, false, false, superCall); 1326 String code64 = buildSend(method, false, true, superCall); 1327 if (set.get(code) == null) { 1328 set.put(code, method); 1329 } 1330 if (set64.get(code64) == null) { 1331 set64.put(code64, method); 1332 } 1333 } 1334 } 1335 } 1336 } 1337 } 1338 outln(); 1339 TreeMap<String, Node> tagsSet = new TreeMap<String, Node>(); 1340 for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { 1341 String key = iterator.next(); 1342 Node method = set.get(key); 1343 String tagCode = buildSend(method, false, true, superCall); 1344 if (set64.get(tagCode) != null) { 1345 tagsSet.put(key, method); 1346 iterator.remove(); 1347 set64.remove(tagCode); 1348 } 1349 } 1350 TreeMap<String, Node> all = new TreeMap<String, Node>(); 1351 for (Iterator<String> iterator = tagsSet.keySet().iterator(); iterator.hasNext();) { 1352 String key = iterator.next(); 1353 Node method = tagsSet.get(key); 1354 all.put(buildSend(method, true, false, superCall), method); 1355 } 1356 for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { 1357 String key = iterator.next(); 1358 all.put(key, set.get(key)); 1359 } 1360 for (Iterator<String> iterator = set64.keySet().iterator(); iterator.hasNext();) { 1361 String key = iterator.next(); 1362 all.put(key, set64.get(key)); 1363 } 1364 for (Iterator<String> iterator = all.keySet().iterator(); iterator.hasNext();) { 1365 String key = iterator.next(); 1366 Node method = all.get(key); 1367 NodeList params = method.getChildNodes(); 1368 ArrayList<String> tags = new ArrayList<String>(); 1369 int count = 0; 1370 for (int k = 0; k < params.getLength(); k++) { 1371 Node param = params.item(k); 1372 if ("arg".equals(param.getNodeName())) { 1373 if (isStruct(param)) { 1374 tags.add(" * @param arg" + count + " flags=struct"); 1375 } 1376 count++; 1377 } 1378 } 1379 out("/**"); 1380 if (tags.size() > 0) { 1381 outln(); 1382 out(" *"); 1383 } 1384 out(" @method flags=cast"); 1385 if (tags.size() > 0) 1386 outln(); 1387 for (String tag : tags) { 1388 out(tag); 1389 outln(); 1390 } 1391 out(" */"); 1392 outln(); 1393 out(key.toString()); 1394 outln(); 1395 } 1396 } 1397 1398 String getSelConst(String sel) { 1399 return "sel_" + sel.replaceAll(":", "_"); 1400 } 1401 1402 void generateClassesConst() { 1403 TreeSet<String> set = new TreeSet<String>(); 1404 for (int x = 0; x < xmls.length; x++) { 1405 Document document = documents[x]; 1406 if (document == null) 1407 continue; 1408 NodeList list = document.getDocumentElement().getChildNodes(); 1409 for (int i = 0; i < list.getLength(); i++) { 1410 Node node = list.item(i); 1411 if ("class".equals(node.getNodeName())) { 1412 if (getGen(node)) { 1413 NamedNodeMap attributes = node.getAttributes(); 1414 String name = attributes.getNamedItem("name").getNodeValue(); 1415 set.add(name); 1416 } 1417 } 1418 } 1419 } 1420 for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { 1421 String cls = iterator.next(); 1422 String clsConst = "class_" + cls; 1423 out("public static final int /*long*/ "); 1424 out(clsConst); 1425 out(" = "); 1426 out("objc_getClass(\""); 1427 out(cls); 1428 out("\");"); 1429 outln(); 1430 } 1431 } 1432 1433 void generateProtocolsConst() { 1434 TreeSet<String> set = new TreeSet<String>(); 1435 for (int x = 0; x < xmls.length; x++) { 1436 Document document = documents[x]; 1437 if (document == null) 1438 continue; 1439 NodeList list = document.getDocumentElement().getChildNodes(); 1440 for (int i = 0; i < list.getLength(); i++) { 1441 Node node = list.item(i); 1442 if ("informal_protocol".equals(node.getNodeName())) { 1443 if (getGen(node)) { 1444 NamedNodeMap attributes = node.getAttributes(); 1445 String name = attributes.getNamedItem("name").getNodeValue(); 1446 set.add(name); 1447 } 1448 } 1449 } 1450 } 1451 for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { 1452 String cls = iterator.next(); 1453 String clsConst = "protocol_" + cls; 1454 out("public static final int /*long*/ "); 1455 out(clsConst); 1456 out(" = "); 1457 out("objc_getProtocol(\""); 1458 out(cls); 1459 out("\");"); 1460 outln(); 1461 } 1462 } 1463 1464 String getPackageName(String className) { 1465 int dot = mainClassName.lastIndexOf('.'); 1466 if (dot == -1) 1467 return ""; 1468 return mainClassName.substring(0, dot); 1469 } 1470 1471 String getClassName(String className) { 1472 int dot = mainClassName.lastIndexOf('.'); 1473 if (dot == -1) 1474 return mainClassName; 1475 return mainClassName.substring(dot + 1); 1476 } 1477 1478 Node getReturnNode(NodeList list) { 1479 for (int j = 0; j < list.getLength(); j++) { 1480 Node node = list.item(j); 1481 if ("retval".equals(node.getNodeName())) { 1482 return node; 1483 } 1484 } 1485 return null; 1486 } 1487 1488 String getType(Node node) { 1489 NamedNodeMap attributes = node.getAttributes(); 1490 Node javaType = attributes.getNamedItem("hawtjni_java_type"); 1491 if (javaType != null) 1492 return javaType.getNodeValue(); 1493 String code = attributes.getNamedItem("type").getNodeValue(); 1494 return getType(code, attributes, false); 1495 } 1496 1497 String getType64(Node node) { 1498 NamedNodeMap attributes = node.getAttributes(); 1499 Node javaType = attributes.getNamedItem("hawtjni_java_type"); 1500 if (javaType != null) { 1501 Node javaType64 = attributes.getNamedItem("hawtjni_java_type64"); 1502 return javaType64 != null ? javaType64.getNodeValue() : javaType.getNodeValue(); 1503 } 1504 Node attrib = attributes.getNamedItem("type"); 1505 String code = attrib.getNodeValue(); 1506 Node attrib64 = attributes.getNamedItem("type64"); 1507 if (attrib64 != null) 1508 code = attrib64.getNodeValue(); 1509 return getType(code, attributes, true); 1510 } 1511 1512 String getType(String code, NamedNodeMap attributes, boolean is64) { 1513 if (code.equals("c")) 1514 return "byte"; 1515 if (code.equals("i")) 1516 return "int"; 1517 if (code.equals("s")) 1518 return "short"; 1519 if (code.equals("l")) 1520 return "int"; 1521 if (code.equals("q")) 1522 return "long"; 1523 if (code.equals("C")) 1524 return "byte"; 1525 if (code.equals("I")) 1526 return "int"; 1527 if (code.equals("S")) 1528 return "short"; 1529 if (code.equals("L")) 1530 return "int"; 1531 if (code.equals("Q")) 1532 return "long"; 1533 if (code.equals("f")) 1534 return "float"; 1535 if (code.equals("d")) 1536 return "double"; 1537 if (code.equals("B")) 1538 return "boolean"; 1539 if (code.equals("v")) 1540 return "void"; 1541 if (code.equals("*")) 1542 return is64 ? "long" : "int"; 1543 if (code.equals("@")) 1544 return is64 ? "long" : "int"; 1545 if (code.equals("#")) 1546 return is64 ? "long" : "int"; 1547 if (code.equals(":")) 1548 return is64 ? "long" : "int"; 1549 if (code.startsWith("^")) 1550 return is64 ? "long" : "int"; 1551 if (code.startsWith("{")) { 1552 return attributes.getNamedItem("declared_type").getNodeValue(); 1553 } 1554 return "BAD " + code; 1555 } 1556 1557 String getJNIType(Node node) { 1558 NamedNodeMap attributes = node.getAttributes(); 1559 String code = attributes.getNamedItem("type").getNodeValue(); 1560 if (code.equals("c")) 1561 return "B"; 1562 if (code.equals("i")) 1563 return "I"; 1564 if (code.equals("s")) 1565 return "S"; 1566 if (code.equals("l")) 1567 return "I"; 1568 if (code.equals("q")) 1569 return "J"; 1570 if (code.equals("C")) 1571 return "B"; 1572 if (code.equals("I")) 1573 return "I"; 1574 if (code.equals("S")) 1575 return "S"; 1576 if (code.equals("L")) 1577 return "I"; 1578 if (code.equals("Q")) 1579 return "J"; 1580 if (code.equals("f")) 1581 return "F"; 1582 if (code.equals("d")) 1583 return "D"; 1584 if (code.equals("B")) 1585 return "Z"; 1586 if (code.equals("v")) 1587 return "V"; 1588 if (code.equals("*")) 1589 return "I"; 1590 if (code.equals("@")) 1591 return "I"; 1592 if (code.equals("#")) 1593 return "I"; 1594 if (code.equals(":")) 1595 return "I"; 1596 if (code.startsWith("^")) 1597 return "I"; 1598 if (code.startsWith("[")) 1599 return "BAD " + code; 1600 if (code.startsWith("{")) { 1601 return "BAD " + code; 1602 } 1603 if (code.startsWith("(")) 1604 return "BAD " + code; 1605 return "BAD " + code; 1606 } 1607 1608 String getJavaType(Node node) { 1609 NamedNodeMap attributes = node.getAttributes(); 1610 Node javaType = attributes.getNamedItem("hawtjni_java_type"); 1611 if (javaType != null) 1612 return javaType.getNodeValue().trim(); 1613 String code = attributes.getNamedItem("type").getNodeValue(); 1614 return getJavaType(code, attributes, false); 1615 } 1616 1617 String getJavaType64(Node node) { 1618 NamedNodeMap attributes = node.getAttributes(); 1619 Node javaType = attributes.getNamedItem("hawtjni_java_type"); 1620 if (javaType != null) { 1621 Node javaType64 = attributes.getNamedItem("hawtjni_java_type64"); 1622 return javaType64 != null ? javaType64.getNodeValue() : javaType.getNodeValue(); 1623 } 1624 Node attrib = attributes.getNamedItem("type"); 1625 String code = attrib.getNodeValue(); 1626 Node attrib64 = attributes.getNamedItem("type64"); 1627 if (attrib64 != null) 1628 code = attrib64.getNodeValue(); 1629 return getJavaType(code, attributes, true); 1630 } 1631 1632 String getJavaType(String code, NamedNodeMap attributes, boolean is64) { 1633 if (code.equals("c")) 1634 return "byte"; 1635 if (code.equals("i")) 1636 return "int"; 1637 if (code.equals("s")) 1638 return "short"; 1639 if (code.equals("l")) 1640 return "int"; 1641 if (code.equals("q")) 1642 return "long"; 1643 if (code.equals("C")) 1644 return "byte"; 1645 if (code.equals("I")) 1646 return "int"; 1647 if (code.equals("S")) 1648 return "short"; 1649 if (code.equals("L")) 1650 return "int"; 1651 if (code.equals("Q")) 1652 return "long"; 1653 if (code.equals("f")) 1654 return "float"; 1655 if (code.equals("d")) 1656 return "double"; 1657 if (code.equals("B")) 1658 return "boolean"; 1659 if (code.equals("v")) 1660 return "void"; 1661 if (code.equals("*")) 1662 return is64 ? "long" : "int"; 1663 if (code.equals("#")) 1664 return is64 ? "long" : "int"; 1665 if (code.equals(":")) 1666 return is64 ? "long" : "int"; 1667 if (code.startsWith("^")) 1668 return is64 ? "long" : "int"; 1669 if (code.equals("@")) { 1670 String type = attributes.getNamedItem("declared_type").getNodeValue(); 1671 int index = type.indexOf('*'); 1672 if (index != -1) 1673 type = type.substring(0, index); 1674 index = type.indexOf('<'); 1675 if (index != -1) 1676 type = type.substring(0, index); 1677 return type.trim(); 1678 } 1679 if (code.startsWith("{")) { 1680 return attributes.getNamedItem("declared_type").getNodeValue().trim(); 1681 } 1682 return "BAD " + code; 1683 } 1684 1685 static String[] split(String str, String separator) { 1686 StringTokenizer tk = new StringTokenizer(str, separator); 1687 ArrayList<Object> result = new ArrayList<Object>(); 1688 while (tk.hasMoreElements()) { 1689 result.add(tk.nextElement()); 1690 } 1691 return result.toArray(new String[result.size()]); 1692 } 1693 1694 void generateFunctions() { 1695 for (int x = 0; x < xmls.length; x++) { 1696 Document document = documents[x]; 1697 if (document == null) 1698 continue; 1699 NodeList list = document.getDocumentElement().getChildNodes(); 1700 for (int i = 0; i < list.getLength(); i++) { 1701 Node node = list.item(i); 1702 if ("function".equals(node.getNodeName())) { 1703 if (getGen(node)) { 1704 NamedNodeMap attributes = node.getAttributes(); 1705 String name = attributes.getNamedItem("name").getNodeValue(); 1706 NodeList params = node.getChildNodes(); 1707 int count = 0; 1708 for (int j = 0; j < params.getLength(); j++) { 1709 Node param = params.item(j); 1710 if ("arg".equals(param.getNodeName())) { 1711 count++; 1712 } 1713 } 1714 if (count > 0) { 1715 out("/**"); 1716 outln(); 1717 } 1718 for (int j = 0; j < params.getLength(); j++) { 1719 Node param = params.item(j); 1720 if ("arg".equals(param.getNodeName())) { 1721 NamedNodeMap paramAttributes = param.getAttributes(); 1722 out(" * @param "); 1723 out(paramAttributes.getNamedItem("name").getNodeValue()); 1724 if (isStruct(param)) { 1725 out(" flags=struct"); 1726 } else { 1727 out(" cast="); 1728 Node declaredType = paramAttributes.getNamedItem("declared_type"); 1729 String cast = declaredType.getNodeValue(); 1730 if (!cast.startsWith("(")) 1731 out("("); 1732 out(cast); 1733 if (!cast.endsWith(")")) 1734 out(")"); 1735 } 1736 outln(); 1737 } 1738 } 1739 if (count > 0) { 1740 out(" */"); 1741 outln(); 1742 } 1743 out("public static final native "); 1744 Node returnNode = getReturnNode(node.getChildNodes()); 1745 if (returnNode != null) { 1746 String type = getType(returnNode), type64 = getType64(returnNode); 1747 out(type); 1748 if (!type.equals(type64)) { 1749 out(" /*"); 1750 out(type64); 1751 out("*/"); 1752 } 1753 out(" "); 1754 } else { 1755 out("void "); 1756 } 1757 out(name); 1758 out("("); 1759 params = node.getChildNodes(); 1760 boolean first = true; 1761 for (int j = 0; j < params.getLength(); j++) { 1762 Node param = params.item(j); 1763 if ("arg".equals(param.getNodeName())) { 1764 NamedNodeMap paramAttributes = param.getAttributes(); 1765 if (!first) 1766 out(", "); 1767 first = false; 1768 String type = getType(param), type64 = getType64(param); 1769 out(type); 1770 if (!type.equals(type64)) { 1771 out(" /*"); 1772 out(type64); 1773 out("*/"); 1774 } 1775 out(" "); 1776 out(paramAttributes.getNamedItem("name").getNodeValue()); 1777 } 1778 } 1779 generateVariadics(node); 1780 out(");"); 1781 outln(); 1782 } 1783 } 1784 } 1785 } 1786 } 1787 1788 void generateVariadics(Node node) { 1789 NamedNodeMap attributes = node.getAttributes(); 1790 Node variadicCount = attributes.getNamedItem("hawtjni_variadic_count"); 1791 if (variadicCount != null) { 1792 Node variadicTypes = attributes.getNamedItem("hawtjni_variadic_java_types"); 1793 String[] types = null; 1794 if (variadicTypes != null) { 1795 types = split(variadicTypes.getNodeValue(), ","); 1796 } 1797 int varCount = 0; 1798 try { 1799 varCount = Integer.parseInt(variadicCount.getNodeValue()); 1800 } catch (NumberFormatException e) { 1801 } 1802 for (int j = 0; j < varCount; j++) { 1803 out(", "); 1804 if (types != null && types.length > j && !types[j].equals("*")) { 1805 out(types[j]); 1806 } else if (types != null && types[types.length - 1].equals("*")) { 1807 out(types[types.length - 2]); 1808 } else { 1809 out("int /*long*/"); 1810 } 1811 out(" varArg"); 1812 out("" + j); 1813 } 1814 } 1815 } 1816 1817 public static void main(String[] args) { 1818 try { 1819 MacGenerator gen = new MacGenerator(); 1820 gen.setXmls(args); 1821 gen.setOutputDir("../org.eclipse.hawtjni/Eclipse SWT PI/cocoa/"); 1822 gen.setMainClass("org.eclipse.hawtjni.internal.cocoa.OS"); 1823 gen.generate(null); 1824 } catch (Throwable e) { 1825 e.printStackTrace(); 1826 } 1827 } 1828 }