1
/*******************************************************************************
2
* Copyright (c) 2009 Progress Software, Inc.
3
* Copyright (c) 2008 IBM Corporation and others.
5
* All rights reserved. This program and the accompanying materials
6
* are made available under the terms of the Eclipse Public License v1.0
7
* which accompanies this distribution, and is available at
8
* http://www.eclipse.org/legal/epl-v10.html
10
*******************************************************************************/
11
package org.fusesource.hawtjni.generator;
13
import java.io.BufferedInputStream;
14
import java.io.ByteArrayOutputStream;
16
import java.io.FileInputStream;
17
import java.io.IOException;
18
import java.io.InputStream;
19
import java.io.InputStreamReader;
20
import java.io.PrintStream;
21
import java.util.ArrayList;
22
import java.util.Collections;
23
import java.util.Comparator;
24
import java.util.HashMap;
25
import java.util.Iterator;
28
import java.util.StringTokenizer;
29
import java.util.TreeMap;
30
import java.util.TreeSet;
32
import javax.xml.parsers.DocumentBuilderFactory;
34
import org.fusesource.hawtjni.generator.HawtJNI.UsageException;
35
import org.fusesource.hawtjni.generator.util.FileSupport;
36
import org.w3c.dom.Document;
37
import org.w3c.dom.Element;
38
import org.w3c.dom.NamedNodeMap;
39
import org.w3c.dom.Node;
40
import org.w3c.dom.NodeList;
41
import org.xml.sax.InputSource;
45
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
47
public class MacGenerator {
50
String outputDir, mainClassName;
51
String delimiter = System.getProperty("line.separator");
54
public MacGenerator() {
57
static void list(File path, ArrayList<String> list) {
60
File[] frameworks = path.listFiles();
61
if (frameworks == null)
63
for (int i = 0; i < frameworks.length; i++) {
64
File file = frameworks[i];
65
String name = file.getName();
66
int index = name.lastIndexOf(".");
68
String xml = file.getAbsolutePath() + "/Resources/BridgeSupport/" + name.substring(0, index) + "Full.bridgesupport";
69
if (new File(xml).exists()) {
76
int getLevel(Node node) {
78
while (node != null) {
80
node = node.getParentNode();
85
void merge(Document document, Document extraDocument) {
86
if (extraDocument == null)
89
/* Build a lookup table for extraDocument */
90
HashMap<String, Node> extras = new HashMap<String, Node>();
91
buildLookup(extraDocument, extras);
94
* Merge attributes on existing elements building a lookup table for
97
HashMap<String, Node> lookup = new HashMap<String, Node>();
98
merge(document, extras, lookup);
101
* Merge new elements. Extras at this point contains only elements that
102
* were not found in the document.
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);
109
return (arg0).getNodeName().compareTo((arg1).getNodeName());
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()))
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++) {
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());
136
lookup.put(getKey(element), element);
140
public void generate(ProgressMonitor progress) throws UsageException {
141
if (progress != null) {
142
progress.setTotal(3);
143
progress.setMessage("extra attributes...");
145
generateExtraAttributes();
146
if (progress != null) {
148
progress.setMessage(mainClassName);
151
if (progress != null) {
153
progress.setMessage("classes...");
156
if (progress != null) {
158
progress.setMessage("Done.");
163
String fixDelimiter(String str) {
164
if (delimiter.equals("\n"))
166
int index = 0, length = str.length();
167
StringBuffer buffer = new StringBuffer();
168
while (index != -1) {
170
index = str.indexOf('\n', start);
172
buffer.append(str.substring(start, length));
174
buffer.append(str.substring(start, index));
175
buffer.append(delimiter);
179
return buffer.toString();
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();
187
boolean isStatic = isStatic(method);
190
Node returnNode = getReturnNode(method.getChildNodes());
191
if (getType(returnNode).equals("void"))
193
String returnType = "", returnType64 = "";
194
if (returnNode != null) {
195
String type = returnType = getJavaType(returnNode), type64 = returnType64 = getJavaType64(returnNode);
197
if (!type.equals(type64)) {
206
String methodName = sel;
207
if (isUnique(method, methods)) {
208
int index = methodName.indexOf(":");
210
methodName = methodName.substring(0, index);
212
// TODO improve this selector
213
methodName = methodName.replaceAll(":", "_");
215
methodName = "static_" + methodName;
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();
227
String type = getJavaType(param), type64 = getJavaType64(param);
229
if (!type.equals(type64)) {
236
String paramName = paramAttributes.getNamedItem("name").getNodeValue();
237
if (paramName.length() == 0)
238
paramName = "arg" + paramAttributes.getNamedItem("index").getNodeValue();
239
if (paramName.equals("boolean"))
246
if (returnNode != null && isStruct(returnNode)) {
249
out(" result = new ");
253
out("\tOS.objc_msgSend_stret(result, ");
254
} else if (returnNode != null && isBoolean(returnNode)) {
256
out("OS.objc_msgSend_bool(");
257
} else if (returnNode != null && isFloatingPoint(returnNode)) {
259
if (returnType.equals("float"))
261
out("OS.objc_msgSend_fpret(");
262
} else if (returnNode != null && isObject(returnNode)) {
263
out("\tint /*long*/ result = OS.objc_msgSend(");
265
if (returnNode != null) {
267
if ((returnType.equals("int") && returnType64.equals("int")) || !returnType.equals("int")) {
272
if (returnType.equals("int") && returnType64.equals("int")) {
278
out("OS.objc_msgSend(");
287
out(getSelConst(sel));
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();
296
String paramName = paramAttributes.getNamedItem("name").getNodeValue();
297
if (paramName.length() == 0)
298
paramName = "arg" + paramAttributes.getNamedItem("index").getNodeValue();
299
if (paramName.equals("boolean"))
301
if (isObject(param)) {
314
if (returnNode != null && isObject(returnNode)) {
315
if (!isStatic && returnType.equals(className)) {
316
out("\treturn result == this.id ? this : (result != 0 ? new ");
318
out("(result) : null);");
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")) {
328
out("(result) : null;");
331
} else if (returnNode != null && isStruct(returnNode)) {
332
out("\treturn result;");
341
void generateExtraMethods(String className) {
342
/* Empty constructor */
352
/* pointer constructor */
355
out("(int /*long*/ id) {");
362
/* object constructor */
372
/* NSObject helpers */
373
if (className.equals("NSObject")) {
374
out("public NSObject alloc() {");
376
out("\tthis.id = OS.objc_msgSend(objc_getClass(), OS.sel_alloc);");
378
out("\treturn this;");
384
/* NSString helpers */
385
if (className.equals("NSString")) {
386
/* Get java string */
387
out("public String getString() {");
389
out("\tchar[] buffer = new char[(int)/*64*/length()];");
391
out("\tgetCharacters(buffer);");
393
out("\treturn new String(buffer);");
398
/* create NSString */
399
out("public NSString initWithString(String str) {");
401
out("\tchar[] buffer = new char[str.length()];");
403
out("\tstr.getChars(0, buffer.length, buffer, 0);");
405
out("\treturn initWithCharacters(buffer, buffer.length);");
410
out("public static NSString stringWith(String str) {");
412
out("\tchar[] buffer = new char[str.length()];");
414
out("\tstr.getChars(0, buffer.length, buffer, 0);");
416
out("\treturn stringWithCharacters(buffer, buffer.length);");
424
static class NodeEntry {
425
private final Node parent;
426
private final ArrayList<Node> children;
428
public NodeEntry(Node parent, ArrayList<Node> children) {
429
this.parent = parent;
430
this.children = children;
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)
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);
448
methods = new ArrayList<Node>();
449
classes.put(name, new NodeEntry(node, methods));
451
methods = clazz.children;
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)) {
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);
472
while (!superclass.equals("id")) {
474
superclass = getSuperclassName(classes.get(superclass).parent);
479
public int compare(NodeEntry arg0, NodeEntry arg1) {
480
return getHierarchyLevel(arg0.parent) - getHierarchyLevel(arg1.parent);
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)) {
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();
503
Node name = attributes.getNamedItem("name");
504
if (name.getNodeValue().equals("NSObject")) {
512
void generateClasses() {
513
TreeMap<String, NodeEntry> classes = getGeneratedClasses();
514
copyClassMethodsDown(classes);
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);
521
// out(fixDelimiter(metaData.getCopyright()));
523
String className = iterator.next();
524
NodeEntry clazz = classes.get(className);
525
Node node = clazz.parent;
526
ArrayList<Node> methods = clazz.children;
528
String packageName = getPackageName(mainClassName);
533
out("public class ");
536
out(getSuperclassName(node));
540
generateExtraMethods(className);
541
generateMethods(className, methods);
545
String fileName = outputDir + packageName.replace('.', '/') + "/" + className + ".java";
548
if (out.size() > 0) {
549
FileSupport.write(out.toByteArray(), new File(fileName));
551
} catch (Exception e) {
552
System.out.println("Problem");
553
e.printStackTrace(System.out);
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()))
565
saveExtraAttributes(xmls[x], document);
569
void generateMainClass() {
570
ByteArrayOutputStream out = new ByteArrayOutputStream();
571
this.out = new PrintStream(out);
573
String header = "", footer = "";
574
String fileName = outputDir + mainClassName.replace('.', '/') + ".java";
575
FileInputStream is = null;
577
InputStreamReader input = new InputStreamReader(new BufferedInputStream(is = new FileInputStream(fileName)));
578
StringBuffer str = new StringBuffer();
579
char[] buffer = new char[4096];
581
while ((read = input.read(buffer)) != -1) {
582
str.append(buffer, 0, read);
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) {
594
} catch (IOException e) {
602
out("/** Custom callbacks */");
604
generateCustomCallbacks();
606
out("/** Classes */");
608
generateClassesConst();
610
out("/** Protocols */");
612
generateProtocolsConst();
614
out("/** Selectors */");
616
generateSelectorsConst();
618
out("/** Constants */");
622
out("/** Globals */");
626
out("/** Functions */");
631
out("/** Super Sends */");
637
generateSends(false);
639
generateStructNatives();
645
if (out.size() > 0) {
646
FileSupport.write(out.toByteArray(), new File(fileName));
649
} catch (Exception e) {
650
System.out.println("Problem");
651
e.printStackTrace(System.out);
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)
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));
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());
685
xmls = array.toArray(new String[array.size()]);
690
void saveExtraAttributes(String xmlPath, Document document) {
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));
707
} catch (Exception e) {
708
System.out.println("Problem");
709
e.printStackTrace(System.out);
713
public void setOutputDir(String dir) {
715
if (!dir.endsWith("\\") && !dir.endsWith("/")) {
719
this.outputDir = dir;
722
public void setXmls(String[] xmls) {
724
this.documents = null;
727
public void setMainClass(String mainClassName) {
728
this.mainClassName = mainClassName;
731
Document getDocument(String xmlPath) {
733
InputStream is = null;
734
if (xmlPath.indexOf(File.separatorChar) == -1)
735
is = getClass().getResourceAsStream(xmlPath);
737
is = new BufferedInputStream(new FileInputStream(xmlPath));
739
return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(is));
740
} catch (Exception e) {
741
// e.printStackTrace();
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" };
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" };
762
return new String[0];
765
public String getFileName(String xmlPath) {
766
File file = new File(xmlPath);
767
return file.getName();
770
String getKey(Node node) {
771
StringBuffer buffer = new StringBuffer();
772
while (node != null) {
773
if (buffer.length() > 0)
775
String name = node.getNodeName();
776
StringBuffer key = new StringBuffer(name);
777
Node nameAttrib = getIDAttribute(node);
778
if (nameAttrib != null) {
780
key.append(nameAttrib.getNodeValue());
782
NamedNodeMap attributes = node.getAttributes();
783
if (attributes != null) {
784
boolean isStatic = attributes.getNamedItem("class_method") != null;
786
key.append("-static");
788
buffer.append(key.reverse());
789
node = node.getParentNode();
792
return buffer.toString();
795
public Node getIDAttribute(Node node) {
796
NamedNodeMap attributes = node.getAttributes();
797
if (attributes == 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)
808
public String[] getIDAttributeNames() {
809
return new String[] { "name", "selector", "path", };
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);
821
Node extra = extras.remove(key);
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());
833
merge(childNode, extras, docLookup);
837
void out(String str) {
838
PrintStream out = this.out;
845
PrintStream out = this.out;
851
void generateConstants() {
852
for (int x = 0; x < xmls.length; x++) {
853
Document document = documents[x];
854
if (document == null)
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())) {
861
NamedNodeMap attributes = node.getAttributes();
862
String constName = attributes.getNamedItem("name").getNodeValue();
863
out("/** @method flags=const */");
865
out("public static final native ");
866
String type = getType(node), type64 = getType64(node);
868
if (!type.equals(type64)) {
877
if (attributes.getNamedItem("declared_type").getNodeValue().equals("NSString*")) {
878
out("public static final NSString ");
880
out(" = new NSString(");
891
void generateEnums() {
892
for (int x = 0; x < xmls.length; x++) {
893
Document document = documents[x];
894
if (document == null)
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())) {
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) {
911
Integer.parseInt(value);
913
} catch (NumberFormatException e) {
918
out(attributes.getNamedItem("name").getNodeValue());
921
if (isLong && !value.endsWith("L"))
932
boolean getGen(Node node) {
933
NamedNodeMap attributes = node.getAttributes();
934
if (attributes == null)
936
Node gen = attributes.getNamedItem("hawtjni_gen");
937
return gen != null && !gen.getNodeValue().equals("false");
940
boolean getGenSuper(Node node) {
941
NamedNodeMap attributes = node.getAttributes();
942
if (attributes == null)
944
Node gen = attributes.getNamedItem("hawtjni_gen_super_msgSend");
945
return gen != null && !gen.getNodeValue().equals("false");
948
boolean getGenCallback(Node node) {
949
NamedNodeMap attributes = node.getAttributes();
950
if (attributes == null)
952
Node gen = attributes.getNamedItem("hawtjni_gen_custom_callback");
953
return gen != null && !gen.getNodeValue().equals("false");
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");
962
boolean isStruct(Node node) {
963
NamedNodeMap attributes = node.getAttributes();
964
String code = attributes.getNamedItem("type").getNodeValue();
965
return code.startsWith("{");
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");
974
boolean isObject(Node node) {
975
NamedNodeMap attributes = node.getAttributes();
976
String code = attributes.getNamedItem("type").getNodeValue();
977
return code.equals("@");
980
boolean isBoolean(Node node) {
981
NamedNodeMap attributes = node.getAttributes();
982
String code = attributes.getNamedItem("type").getNodeValue();
983
return code.equals("B");
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);
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);
1009
int index = methodName.indexOf(":");
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(":");
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);
1031
if (signature.equals(otherSignature)) {
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)
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())) {
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();
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*/ ");
1071
out("sel_registerName(\"");
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)
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());
1092
out("/** Sizeof natives */");
1094
for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) {
1095
String struct = iterator.next();
1096
out("public static final native int ");
1102
out("/** Memmove natives */");
1105
for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) {
1106
String struct = iterator.next();
1109
out(" * @param dest cast=(void *),flags=no_in critical");
1111
out(" * @param src cast=(void *),flags=critical");
1112
// out(" * @param src cast=(void *),flags=no_out critical");
1116
out("public static final native void memmove(");
1117
out("int /*long*/ dest, ");
1119
out(" src, int /*long*/ size);");
1123
out(" * @param dest cast=(void *),flags=no_in critical");
1125
out(" * @param src cast=(void *),flags=critical");
1126
// out(" * @param src cast=(void *),flags=no_out critical");
1130
out("public static final native void memmove(");
1132
out(" dest, int /*long*/ src, int /*long*/ size);");
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");
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");
1151
} else if (returnNode != null && isBoolean(returnNode)) {
1152
buffer.append("boolean ");
1153
buffer.append(superCall ? "objc_msgSendSuper_bool" : "objc_msgSend_bool");
1157
buffer.append("long");
1160
buffer.append("int /*long*/");
1162
buffer.append("int");
1166
buffer.append(superCall ? "objc_msgSendSuper" : "objc_msgSend");
1171
buffer.append("objc_super superId, long sel");
1174
buffer.append("objc_super superId, int /*long*/ sel");
1176
buffer.append("objc_super superId, int sel");
1181
buffer.append("long id, long sel");
1184
buffer.append("int /*long*/ id, int /*long*/ sel");
1186
buffer.append("int id, int sel");
1190
NodeList params = method.getChildNodes();
1191
boolean first = false;
1193
for (int k = 0; k < params.getLength(); k++) {
1194
Node param = params.item(k);
1195
if ("arg".equals(param.getNodeName())) {
1197
buffer.append(", ");
1198
if (isStruct(param)) {
1199
buffer.append(getJavaType(param));
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("*/");
1210
buffer.append(" arg");
1211
buffer.append(String.valueOf(count++));
1214
buffer.append(");");
1215
return buffer.toString();
1218
String getCType(Node node) {
1219
NamedNodeMap attributes = node.getAttributes();
1220
return attributes.getNamedItem("declared_type").getNodeValue();
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())) {
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)
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);
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);
1278
String nativeMth = key.replaceAll(":", "_");
1279
out("/** @method callback_types=");
1280
Node returnNode = getReturnNode(method.getChildNodes());
1281
out(returnNode == null ? "void" : getCType(returnNode));
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));
1291
out(",callback_flags=");
1292
out(returnNode != null && isStruct(returnNode) ? "struct" : "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");
1303
out("public static final native int /*long*/ CALLBACK_");
1305
out("(int /*long*/ func);");
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)
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);
1330
if (set64.get(code64) == null) {
1331
set64.put(code64, method);
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);
1347
set64.remove(tagCode);
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);
1356
for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) {
1357
String key = iterator.next();
1358
all.put(key, set.get(key));
1360
for (Iterator<String> iterator = set64.keySet().iterator(); iterator.hasNext();) {
1361
String key = iterator.next();
1362
all.put(key, set64.get(key));
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>();
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");
1380
if (tags.size() > 0) {
1384
out(" @method flags=cast");
1385
if (tags.size() > 0)
1387
for (String tag : tags) {
1393
out(key.toString());
1398
String getSelConst(String sel) {
1399
return "sel_" + sel.replaceAll(":", "_");
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)
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())) {
1413
NamedNodeMap attributes = node.getAttributes();
1414
String name = attributes.getNamedItem("name").getNodeValue();
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*/ ");
1426
out("objc_getClass(\"");
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)
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())) {
1444
NamedNodeMap attributes = node.getAttributes();
1445
String name = attributes.getNamedItem("name").getNodeValue();
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*/ ");
1457
out("objc_getProtocol(\"");
1464
String getPackageName(String className) {
1465
int dot = mainClassName.lastIndexOf('.');
1468
return mainClassName.substring(0, dot);
1471
String getClassName(String className) {
1472
int dot = mainClassName.lastIndexOf('.');
1474
return mainClassName;
1475
return mainClassName.substring(dot + 1);
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())) {
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);
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();
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);
1512
String getType(String code, NamedNodeMap attributes, boolean is64) {
1513
if (code.equals("c"))
1515
if (code.equals("i"))
1517
if (code.equals("s"))
1519
if (code.equals("l"))
1521
if (code.equals("q"))
1523
if (code.equals("C"))
1525
if (code.equals("I"))
1527
if (code.equals("S"))
1529
if (code.equals("L"))
1531
if (code.equals("Q"))
1533
if (code.equals("f"))
1535
if (code.equals("d"))
1537
if (code.equals("B"))
1539
if (code.equals("v"))
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();
1554
return "BAD " + code;
1557
String getJNIType(Node node) {
1558
NamedNodeMap attributes = node.getAttributes();
1559
String code = attributes.getNamedItem("type").getNodeValue();
1560
if (code.equals("c"))
1562
if (code.equals("i"))
1564
if (code.equals("s"))
1566
if (code.equals("l"))
1568
if (code.equals("q"))
1570
if (code.equals("C"))
1572
if (code.equals("I"))
1574
if (code.equals("S"))
1576
if (code.equals("L"))
1578
if (code.equals("Q"))
1580
if (code.equals("f"))
1582
if (code.equals("d"))
1584
if (code.equals("B"))
1586
if (code.equals("v"))
1588
if (code.equals("*"))
1590
if (code.equals("@"))
1592
if (code.equals("#"))
1594
if (code.equals(":"))
1596
if (code.startsWith("^"))
1598
if (code.startsWith("["))
1599
return "BAD " + code;
1600
if (code.startsWith("{")) {
1601
return "BAD " + code;
1603
if (code.startsWith("("))
1604
return "BAD " + code;
1605
return "BAD " + code;
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);
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();
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);
1632
String getJavaType(String code, NamedNodeMap attributes, boolean is64) {
1633
if (code.equals("c"))
1635
if (code.equals("i"))
1637
if (code.equals("s"))
1639
if (code.equals("l"))
1641
if (code.equals("q"))
1643
if (code.equals("C"))
1645
if (code.equals("I"))
1647
if (code.equals("S"))
1649
if (code.equals("L"))
1651
if (code.equals("Q"))
1653
if (code.equals("f"))
1655
if (code.equals("d"))
1657
if (code.equals("B"))
1659
if (code.equals("v"))
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('*');
1673
type = type.substring(0, index);
1674
index = type.indexOf('<');
1676
type = type.substring(0, index);
1679
if (code.startsWith("{")) {
1680
return attributes.getNamedItem("declared_type").getNodeValue().trim();
1682
return "BAD " + code;
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());
1691
return result.toArray(new String[result.size()]);
1694
void generateFunctions() {
1695
for (int x = 0; x < xmls.length; x++) {
1696
Document document = documents[x];
1697
if (document == null)
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())) {
1704
NamedNodeMap attributes = node.getAttributes();
1705
String name = attributes.getNamedItem("name").getNodeValue();
1706
NodeList params = node.getChildNodes();
1708
for (int j = 0; j < params.getLength(); j++) {
1709
Node param = params.item(j);
1710
if ("arg".equals(param.getNodeName())) {
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();
1723
out(paramAttributes.getNamedItem("name").getNodeValue());
1724
if (isStruct(param)) {
1725
out(" flags=struct");
1728
Node declaredType = paramAttributes.getNamedItem("declared_type");
1729
String cast = declaredType.getNodeValue();
1730
if (!cast.startsWith("("))
1733
if (!cast.endsWith(")"))
1743
out("public static final native ");
1744
Node returnNode = getReturnNode(node.getChildNodes());
1745
if (returnNode != null) {
1746
String type = getType(returnNode), type64 = getType64(returnNode);
1748
if (!type.equals(type64)) {
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();
1768
String type = getType(param), type64 = getType64(param);
1770
if (!type.equals(type64)) {
1776
out(paramAttributes.getNamedItem("name").getNodeValue());
1779
generateVariadics(node);
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(), ",");
1799
varCount = Integer.parseInt(variadicCount.getNodeValue());
1800
} catch (NumberFormatException e) {
1802
for (int j = 0; j < varCount; j++) {
1804
if (types != null && types.length > j && !types[j].equals("*")) {
1806
} else if (types != null && types[types.length - 1].equals("*")) {
1807
out(types[types.length - 2]);
1809
out("int /*long*/");
1817
public static void main(String[] args) {
1819
MacGenerator gen = new MacGenerator();
1821
gen.setOutputDir("../org.eclipse.hawtjni/Eclipse SWT PI/cocoa/");
1822
gen.setMainClass("org.eclipse.hawtjni.internal.cocoa.OS");
1824
} catch (Throwable e) {
1825
e.printStackTrace();