001 /*******************************************************************************
002 * Copyright (c) 2009 Progress Software, Inc.
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 }