/******************************************************************************* * Copyright (c) 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.tools.internal; import java.io.*; import java.util.*; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; import org.xml.sax.InputSource; @SuppressWarnings("unchecked") public class MacGenerator { String[] xmls; Document[] documents; String outputDir, outputLibDir, extrasDir, mainClassName; String delimiter = System.getProperty("line.separator"); boolean generate64Code; PrintWriter out; public static boolean BUILD_C_SOURCE = true; public static boolean GENERATE_ALLOC = true; public static boolean GENERATE_STRUCTS = false; public static boolean USE_SYSTEM_BRIDGE_FILES = false; static final char[] INT_LONG = "int /*long*/".toCharArray(); static final char[] INT_LONG_ARRAY = "int[] /*long[]*/".toCharArray(); static final char[] FLOAT_DOUBLE = "float /*double*/".toCharArray(); static final char[] FLOAT_DOUBLE_ARRAY = "float[] /*double[]*/".toCharArray(); static final char[] LONG_INT = "long /*int*/".toCharArray(); static final char[] LONG_INT_ARRAY = "long[] /*int[]*/".toCharArray(); static final char[] DOUBLE_FLOAT = "double /*float*/".toCharArray(); static final char[] DOUBLE_FLOAT_ARRAY = "double[] /*float[]*/".toCharArray(); public MacGenerator() { } static void list(File path, ArrayList<String> list) { if (path == null) return; File[] frameworks = path.listFiles(); if (frameworks == null) return; for (int i = 0; i < frameworks.length; i++) { File file = frameworks[i]; String name = file.getName(); int index = name.lastIndexOf("."); if (index != -1) { String xml = file.getAbsolutePath() + "/Resources/BridgeSupport/" + name.substring(0, index) + "Full.bridgesupport"; if (new File(xml).exists()) { list.add(xml); } } } } static int indexOf(final char[] toBeFound, final char[] array, final int start) { final int arrayLength = array.length; final int toBeFoundLength = toBeFound.length; if (toBeFoundLength > arrayLength || start < 0) return -1; if (toBeFoundLength == 0) return 0; if (toBeFoundLength == arrayLength) { for (int i = start; i < arrayLength; i++) { if (array[i] != toBeFound[i]) return -1; } return 0; } arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) { if (array[i] == toBeFound[0]) { for (int j = 1; j < toBeFoundLength; j++) { if (array[i + j] != toBeFound[j]) continue arrayLoop; } return i; } } return -1; } static boolean replace(char[] source, char[] src, char[] dest) { boolean changed = false; int start = 0; while (start < source.length) { int index = indexOf(src, source, start); if (index == -1) break; changed |= true; System.arraycopy(dest, 0, source, index, dest.length); start = index + 1; } return changed; } void output(String fileName, char[] source) { try { if (source.length > 0) { if (generate64Code) { replace(source, INT_LONG, LONG_INT); replace(source, INT_LONG_ARRAY, LONG_INT_ARRAY); replace(source, FLOAT_DOUBLE, DOUBLE_FLOAT); replace(source, FLOAT_DOUBLE_ARRAY, DOUBLE_FLOAT_ARRAY); } else { replace(source, LONG_INT, INT_LONG); replace(source, LONG_INT_ARRAY, INT_LONG_ARRAY); replace(source, DOUBLE_FLOAT, FLOAT_DOUBLE); replace(source, DOUBLE_FLOAT_ARRAY, FLOAT_DOUBLE_ARRAY); } ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintStream stream = new PrintStream(out); stream.print(source); stream.flush(); JNIGenerator.output(out.toByteArray(), fileName); } } catch (Exception e) { System.out.println("Problem"); e.printStackTrace(System.out); } } int getLevel(Node node) { int level = 0; while (node != null) { level++; node = node.getParentNode(); } return level; } void merge(Document document, Document extraDocument) { if (extraDocument == null) return; /* Build a lookup table for extraDocument */ HashMap<String, Node> extras = new HashMap<String, Node>(); buildLookup(extraDocument, extras); /* Merge attributes on existing elements building a lookup table for document */ HashMap<String, Node> lookup = new HashMap<String, Node>(); merge(document, extras, lookup); /* * Merge new elements. Extras at this point contains only elements that were * not found in the document. */ ArrayList<Node> sortedNodes = Collections.list(Collections.enumeration(extras.values())); Collections.sort(sortedNodes, new Comparator<Object>() { public int compare(Object arg0, Object arg1) { int compare = getLevel((Node)arg0) - getLevel((Node)arg1); if (compare == 0) { return ((Node)arg0).getNodeName().compareTo(((Node)arg1).getNodeName()); } return compare; } }); String delimiter = System.getProperty("line.separator"); for (Iterator<Node> iterator = sortedNodes.iterator(); iterator.hasNext();) { Node node = iterator.next(); String name = node.getNodeName(); if ("arg".equals(name) || "retval".equals(name)) { if (!sortedNodes.contains(node.getParentNode())) continue; } Node parent = lookup.get(getKey(node.getParentNode())); Element element = document.createElement(node.getNodeName()); String text = parent.getChildNodes().getLength() == 0 ? delimiter : ""; for (int i = 0, level = getLevel(parent) - 1; i < level; i++) { text += " "; } parent.appendChild(document.createTextNode(text)); parent.appendChild(element); parent.appendChild(document.createTextNode(delimiter)); NamedNodeMap attributes = node.getAttributes(); for (int j = 0, length = attributes.getLength(); j < length; j++) { Node attr = attributes.item(j); element.setAttribute(attr.getNodeName(), attr.getNodeValue()); } lookup.put(getKey(element), element); } } public void generate(ProgressMonitor progress) { if (progress != null) { progress.setTotal(BUILD_C_SOURCE ? 4 : 3); progress.setMessage("extra attributes..."); } generateExtraAttributes(); if (progress != null) { progress.step(); progress.setMessage(mainClassName); } generateMainClass(); if (progress != null) { progress.step(); progress.setMessage("classes..."); } generateClasses(); if (GENERATE_STRUCTS) { if (progress != null) { progress.step(); progress.setMessage("structs..."); } generateStructs(); } if (BUILD_C_SOURCE) { if (progress != null) { progress.step(); progress.setMessage("C source..."); } generateCSource(); } if (progress != null) { progress.step(); progress.setMessage("Done."); } } void generateCSource() { JNIGeneratorApp app = new JNIGeneratorApp(); String outputLibDir = this.outputLibDir != null ? this.outputLibDir : outputDir + "/library"; app.setMainClassName(mainClassName, outputLibDir, outputDir); app.generate(); } String fixDelimiter(String str) { if (delimiter.equals("\n")) return str; int index = 0, length = str.length(); StringBuffer buffer = new StringBuffer(); while (index != -1) { int start = index; index = str.indexOf('\n', start); if (index == -1) { buffer.append(str.substring(start, length)); } else { buffer.append(str.substring(start, index)); buffer.append(delimiter); index++; } } return buffer.toString(); } String getParamName(Node param, int i) { NamedNodeMap paramAttributes = param.getAttributes(); Node swtName = paramAttributes.getNamedItem("swt_param_name"); String paramName = ""; if (swtName != null) { paramName = swtName.getNodeValue(); } else { Node node = paramAttributes.getNamedItem("name"); if (node != null) paramName = node.getNodeValue(); } if (paramName.length() == 0) { Node node = paramAttributes.getNamedItem("index"); String index = "0"; if (node != null) { index = node.getNodeValue(); } else { index = String.valueOf(i); } paramName = "arg" + index; } if (paramName.equals("boolean")) paramName = "b"; return paramName; } void generateFields(String structName, ArrayList<?> fields) { for (Iterator<?> iterator = fields.iterator(); iterator.hasNext();) { Node field = (Node)iterator.next(); NamedNodeMap fieldAttributes = field.getAttributes(); String fieldName = fieldAttributes.getNamedItem("name").getNodeValue(); String type = getJavaType(field), type64 = getJavaType64(field); out("\t"); out("public "); out(type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } out(" "); out(fieldName); if (isStruct(field)) { out(" = new "); String clazz = fieldAttributes.getNamedItem("declared_type").getNodeValue(); out (clazz); out ("()"); } out(";"); outln(); } } void generateMethods(String className, ArrayList<?> methods) { for (Iterator<?> iterator = methods.iterator(); iterator.hasNext();) { Node method = (Node)iterator.next(); NamedNodeMap mthAttributes = method.getAttributes(); String sel = mthAttributes.getNamedItem("selector").getNodeValue(); if ("NSObject".equals(className)) { if ("alloc".equals(sel) || "dealloc".equals(sel)) continue; } out("public "); boolean isStatic = isStatic(method); if (isStatic) out("static "); Node returnNode = getReturnNode(method.getChildNodes()); if (getType(returnNode).equals("void")) returnNode = null; String returnType = "", returnType64 = ""; if (returnNode != null) { String type = returnType = getJavaType(returnNode), type64 = returnType64 = getJavaType64(returnNode); out(type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } out(" "); } else { out("void "); } String methodName = sel; if (isUnique(method, methods)) { int index = methodName.indexOf(":"); if (index != -1) methodName = methodName.substring(0, index); } else { //TODO improve this selector methodName = methodName.replaceAll(":", "_"); if (isStatic) methodName = "static_" + methodName; } out(methodName); out("("); NodeList params = method.getChildNodes(); boolean first = true; int argIndex = 0; for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { if (!first) out(", "); String type = getJavaType(param), type64 = getJavaType64(param); out( type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } first = false; out(" "); out(getParamName(param, argIndex++)); } } out(") {"); outln(); if (returnNode != null && isStruct(returnNode)) { out("\t"); out(returnType); out(" result = new "); out(returnType); out("();"); outln(); out("\tOS.objc_msgSend_stret(result, "); } else if (returnNode != null && isBoolean(returnNode)) { out("\treturn "); out("OS.objc_msgSend_bool("); } else if (returnNode != null && isFloatingPoint(returnNode)) { out("\treturn "); String type = getType(returnNode), type64 = getType64(returnNode); if (type.equals(type64) && type.equals("float")) { out("OS.objc_msgSend_floatret("); } else { if (returnType.equals("float")) out("(float /*double*/)"); out("OS.objc_msgSend_fpret("); } } else if (returnNode != null && isObject(returnNode)) { out("\tint /*long*/ result = OS.objc_msgSend("); } else { if (returnNode != null) { out("\treturn "); if ((returnType.equals("int") && returnType64.equals("int")) || !returnType.equals("int")) { out("("); out(returnType); out(")"); } if (returnType.equals("int") && returnType64.equals("int")) { out("/*64*/"); } } else { out("\t"); } out("OS.objc_msgSend("); } if (isStatic) { out("OS.class_"); out(className); } else { out("this.id"); } out(", OS."); out(getSelConst(sel)); first = false; argIndex = 0; for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { if (!first) out(", "); first = false; String paramName = getParamName(param, argIndex++); if (isObject(param)) { out(paramName); out(" != null ? "); out(paramName); out(".id : 0"); } else { out(paramName); } } } out(")"); out(";"); outln(); if (returnNode != null && isObject(returnNode)) { if (!isStatic && returnType.equals(className)) { out("\treturn result == this.id ? this : (result != 0 ? new "); out(returnType); out("(result) : null);"); } else { out("\treturn result != 0 ? new "); NamedNodeMap attributes = returnNode.getAttributes(); Node swt_alloc = attributes.getNamedItem("swt_alloc"); if (swt_alloc != null && swt_alloc.getNodeValue().equals("true")) { out(className); } else { out(returnType); } out("(result) : null;"); } outln(); } else if (returnNode != null && isStruct(returnNode)) { out("\treturn result;"); outln(); } out("}"); outln(); outln(); } } void generateExtraFields(String className) { /* sizeof field */ out("\t"); out("public static int sizeof = OS." + className + "_sizeof();"); outln(); if ("CGSize".equals(className)) { outln(); out("\tpublic String toString () {"); outln(); out("\t\treturn \"CGSize {\" + width + \" \" + height + \"}\";"); outln(); out("\t}"); outln(); } if ("CGRect".equals(className)) { outln(); out("\tpublic String toString () {"); outln(); out("\t\treturn \"CGRect {\" + origin.x + \" \" + origin.y + \" \" + size.width + \" \" + size.height + \"}\";"); outln(); out("\t}"); outln(); } if ("CGPoint".equals(className)) { outln(); out("\tpublic String toString () {"); outln(); out("\t\treturn \"CGPoint {\" + x + \" \" + y + \"}\";"); outln(); out("\t}"); outln(); } } void generateExtraMethods(String className) { /* Empty constructor */ out("public "); out(className); out("() {"); outln(); out("\tsuper();"); outln(); out("}"); outln(); outln(); /* pointer constructor */ out("public "); out(className); out("(int /*long*/ id) {"); outln(); out("\tsuper(id);"); outln(); out("}"); outln(); outln(); /* object constructor */ out("public "); out(className); out("(id id) {"); outln(); out("\tsuper(id);"); outln(); out("}"); outln(); outln(); /* NSObject helpers */ if (className.equals("NSObject")) { if (GENERATE_ALLOC) { out("public NSObject alloc() {"); outln(); out("\tthis.id = OS.objc_msgSend(objc_getClass(), OS.sel_alloc);"); outln(); out("\treturn this;"); outln(); out("}"); outln(); outln(); } } /* NSString helpers */ if (className.equals("NSString")) { /* Get java string */ out("public String getString() {"); outln(); out("\tchar[] buffer = new char[(int)/*64*/length()];"); outln(); out("\tgetCharacters(buffer);"); outln(); out("\treturn new String(buffer);"); outln(); out("}"); outln(); outln(); /* create NSString */ out("public NSString initWithString(String str) {"); outln(); out("\tchar[] buffer = new char[str.length()];"); outln(); out("\tstr.getChars(0, buffer.length, buffer, 0);"); outln(); out("\treturn initWithCharacters(buffer, buffer.length);"); outln(); out("}"); outln(); outln(); out("public static NSString stringWith(String str) {"); outln(); out("\tchar[] buffer = new char[str.length()];"); outln(); out("\tstr.getChars(0, buffer.length, buffer, 0);"); outln(); out("\treturn stringWithCharacters(buffer, buffer.length);"); outln(); out("}"); outln(); outln(); } } TreeMap<String, Object[]> getGeneratedClasses() { TreeMap<String, Object[]> classes = new TreeMap<String, Object[]>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("class".equals(node.getNodeName()) && getGen(node)) { ArrayList<Node> methods; String name = node.getAttributes().getNamedItem("name").getNodeValue(); Object[] clazz = classes.get(name); if (clazz == null) { methods = new ArrayList<Node>(); classes.put(name, new Object[]{node, methods}); } else { methods = (ArrayList<Node>)clazz[1]; } NodeList methodList = node.getChildNodes(); for (int j = 0; j < methodList.getLength(); j++) { Node method = methodList.item(j); if ("method".equals(method.getNodeName()) && getGen(method)) { methods.add(method); } } } } } return classes; } TreeMap<String, Object[]> getGeneratedStructs() { TreeMap<String, Object[]> structs = new TreeMap<String, Object[]>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("struct".equals(node.getNodeName()) && getGen(node)) { ArrayList<Node> fields; String name = node.getAttributes().getNamedItem("name").getNodeValue(); Object[] clazz = structs.get(name); if (clazz == null) { fields = new ArrayList<Node>(); structs.put(name, new Object[]{node, fields}); } else { fields = (ArrayList<Node>)clazz[1]; } NodeList fieldList = node.getChildNodes(); for (int j = 0; j < fieldList.getLength(); j++) { Node field = fieldList.item(j); if ("field".equals(field.getNodeName()) && getGen(field)) { fields.add(field); } } } } } return structs; } void copyClassMethodsDown(final Map<String, Object[]> classes) { ArrayList<Object[]> sortedClasses = Collections.list(Collections.enumeration(classes.values())); Collections.sort(sortedClasses, new Comparator<Object>() { int getHierarchyLevel(Node node) { String superclass = getSuperclassName(node); int level = 0; while (!superclass.equals("id") && !superclass.equals("NSObject")) { level++; superclass = getSuperclassName((Node)classes.get(superclass)[0]); } return level; } public int compare(Object arg0, Object arg1) { return getHierarchyLevel((Node)((Object[])arg0)[0]) - getHierarchyLevel((Node)((Object[])arg1)[0]); } }); for (Iterator<Object[]> iterator = sortedClasses.iterator(); iterator.hasNext();) { Object[] clazz = iterator.next(); Node node = (Node)clazz[0]; ArrayList<Node> methods = (ArrayList<Node>)clazz[1]; Object[] superclass = classes.get(getSuperclassName(node)); if (superclass != null) { for (Iterator<?> iterator2 = ((ArrayList<?>)superclass[1]).iterator(); iterator2.hasNext();) { Node method = (Node) iterator2.next(); if (isStatic(method)) { methods.add(method); } } } } } String getSuperclassName (Node node) { NamedNodeMap attributes = node.getAttributes(); Node superclass = attributes.getNamedItem("swt_superclass"); if (superclass != null) { return superclass.getNodeValue(); } else { Node name = attributes.getNamedItem("name"); if (name.getNodeValue().equals("NSObject")) { return "id"; } else { return "NSObject"; } } } void generateClasses() { MetaData metaData = new MetaData(mainClassName); TreeMap<String, Object[]> classes = getGeneratedClasses(); copyClassMethodsDown(classes); Set<String> classNames = classes.keySet(); for (Iterator<String> iterator = classNames.iterator(); iterator.hasNext();) { CharArrayWriter out = new CharArrayWriter(); this.out = new PrintWriter(out); out(fixDelimiter(metaData.getCopyright())); String className = iterator.next(); Object[] clazz = classes.get(className); Node node = (Node)clazz[0]; ArrayList<?> methods = (ArrayList<?>)clazz[1]; out("package "); String packageName = getPackageName(mainClassName); out(packageName); out(";"); outln(); outln(); out("public class "); out(className); out(" extends "); out(getSuperclassName(node)); out(" {"); outln(); outln(); generateExtraMethods(className); generateMethods(className, methods); out("}"); outln(); String fileName = outputDir + packageName.replace('.', '/') + "/" + className + ".java"; this.out.flush(); output(fileName, out.toCharArray()); this.out = null; } } void generateStructs() { MetaData metaData = new MetaData(mainClassName); TreeMap<String, Object[]> structs = getGeneratedStructs(); Set<String> structNames = structs.keySet(); for (Iterator<String> iterator = structNames.iterator(); iterator.hasNext();) { CharArrayWriter out = new CharArrayWriter(); this.out = new PrintWriter(out); out(fixDelimiter(metaData.getCopyright())); String className = iterator.next(); Object[] clazz = structs.get(className); ArrayList<?> methods = (ArrayList<?>)clazz[1]; out("package "); String packageName = getPackageName(mainClassName); out(packageName); out(";"); outln(); outln(); out("public class "); out(className); out(" {"); outln(); generateFields(className, methods); generateExtraFields(className); out("}"); outln(); String fileName = outputDir + packageName.replace('.', '/') + "/" + className + ".java"; this.out.flush(); output(fileName, out.toCharArray()); this.out = null; } } void generateExtraAttributes() { Document[] documents = getDocuments(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null || !getGen(document.getDocumentElement())) continue; saveExtraAttributes(xmls[x], document); } } void generateMainClass() { CharArrayWriter out = new CharArrayWriter(); this.out = new PrintWriter(out); String header = "", footer = ""; String fileName = outputDir + mainClassName.replace('.', '/') + ".java"; FileInputStream is = null; try { InputStreamReader input = new InputStreamReader(new BufferedInputStream(is = new FileInputStream(fileName))); StringBuffer str = new StringBuffer(); char[] buffer = new char[4096]; int read; while ((read = input.read(buffer)) != -1) { str.append(buffer, 0, read); } String section = "/** This section is auto generated */"; int start = str.indexOf(section) + section.length(); int end = str.indexOf(section, start); header = str.substring(0, start); footer = end == -1 ? "\n}" : str.substring(end); generate64Code = str.indexOf("long /*int*/") != -1; input.close(); } catch (IOException e) { } finally { try { if (is != null) is.close(); } catch (IOException e) {} } out(header); outln(); outln(); out("/** Custom callbacks */"); outln(); generateCustomCallbacks(); outln(); out("/** Classes */"); outln(); generateClassesConst(); outln(); out("/** Protocols */"); outln(); generateProtocolsConst(); outln(); out("/** Selectors */"); outln(); generateSelectorsConst(); outln(); out("/** Constants */"); outln(); generateEnums(); outln(); out("/** Globals */"); outln(); generateConstants(); outln(); out("/** Functions */"); outln(); outln(); generateFunctions(); outln(); out("/** Super Sends */"); outln(); generateSends(true); outln(); out("/** Sends */"); outln(); generateSends(false); outln(); generateStructNatives(); outln(); out(footer); this.out.flush(); output(fileName, out.toCharArray()); this.out = null; } public Document[] getDocuments() { if (documents == null) { String[] xmls = getXmls(); documents = new Document[xmls.length]; for (int i = 0; i < xmls.length; i++) { String xmlPath = xmls[i]; Document document = documents[i] = getDocument(xmlPath); if (document == null) continue; if (mainClassName != null && outputDir != null) { String packageName = getPackageName(mainClassName); String folder = extrasDir != null ? extrasDir : outputDir + packageName.replace('.', '/'); String extrasPath = folder + "/" + getFileName(xmlPath) + ".extras"; merge(document, getDocument(extrasPath)); } } } return documents; } public String[] getXmls() { if (xmls == null || xmls.length == 0) { ArrayList<String> array = new ArrayList<String>(); if (USE_SYSTEM_BRIDGE_FILES) { list(new File("/System/Library/Frameworks"), array); list(new File("/System/Library/Frameworks/CoreServices.framework/Frameworks"), array); list(new File("/System/Library/Frameworks/ApplicationServices.framework/Frameworks"), array); } else { String packageName = getPackageName(mainClassName); File folder = new File(extrasDir != null ? extrasDir : outputDir + packageName.replace('.', '/')); File[] files = folder.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith("Full.bridgesupport"); } }); for (int i = 0; i < files.length; i++) { array.add(files[i].getAbsolutePath()); } } Collections.sort(array, new Comparator<Object>() { public int compare(Object o1, Object o2) { return new File((String)o1).getName().compareTo(new File((String)o2).getName()); } }); xmls = array.toArray(new String[array.size()]); } return xmls; } void saveExtraAttributes(String xmlPath, Document document) { try { String packageName = getPackageName(mainClassName); String folder = extrasDir != null ? extrasDir : outputDir + packageName.replace('.', '/'); String fileName = folder + "/" + getFileName(xmlPath) + ".extras"; ByteArrayOutputStream out = new ByteArrayOutputStream(); DOMWriter writer = new DOMWriter(new PrintStream(out)); String[] names = getIDAttributeNames(); String[] filter = new String[names.length + 2]; filter[0] = "class_method"; filter[1] = "swt_.*"; System.arraycopy(names, 0, filter, 2, names.length); writer.setIDAttributes(names); writer.setAttributeFilter(filter); writer.setNodeFilter("swt_"); writer.print(document); if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName); } catch (Exception e) { System.out.println("Problem"); e.printStackTrace(System.out); } } public String getOutputDir() { return outputDir; } public void setOutputDir(String dir) { if (dir != null) { if (!dir.endsWith("\\") && !dir.endsWith("/") ) { dir += "/"; } } this.outputDir = dir; } public void setOutputLibDir(String dir) { if (dir != null) { if (!dir.endsWith("\\") && !dir.endsWith("/") ) { dir += "/"; } } this.outputLibDir = dir; } public void setExtrasDir(String dir) { if (dir != null) { if (!dir.endsWith("\\") && !dir.endsWith("/") ) { dir += "/"; } } this.extrasDir = dir; } public void setXmls(String[] xmls) { this.xmls = xmls; this.documents = null; } public void setMainClass(String mainClassName) { this.mainClassName = mainClassName; } Document getDocument(String xmlPath) { try { InputStream is = null; if (xmlPath.indexOf(File.separatorChar) == -1) is = getClass().getResourceAsStream(xmlPath); if (is == null) is = new BufferedInputStream(new FileInputStream(xmlPath)); if (is != null) return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(is)); } catch (Exception e) { // e.printStackTrace(); } return null; } public String[] getExtraAttributeNames(Node node) { String name = node.getNodeName(); if (name.equals("method")) { NamedNodeMap attribs = node.getAttributes(); if (attribs != null && attribs.getNamedItem("variadic") != null) { return new String[]{"swt_gen_super_msgSend", "swt_gen_custom_callback", "swt_variadic_count","swt_variadic_java_types"}; } return new String[]{"swt_gen_super_msgSend", "swt_gen_custom_callback"}; } else if (name.equals("function")) { NamedNodeMap attribs = node.getAttributes(); if (attribs != null && attribs.getNamedItem("variadic") != null) { return new String[]{"swt_variadic_count","swt_variadic_java_types"}; } } else if (name.equals("class")) { return new String[]{"swt_superclass"}; } else if (name.equals("retval")) { return new String[]{"swt_java_type", "swt_java_type64", "swt_alloc"}; } else if (name.equals("arg")) { return new String[]{"swt_java_type", "swt_java_type64", "swt_param_name", "swt_param_cast"}; } return new String[0]; } public String getFileName(String xmlPath) { File file = new File(xmlPath); return file.getName(); } int indexOfNode(Node node) { Node parent = node.getParentNode(); int count = 0; Node temp = parent.getFirstChild(); while (temp != node) { count++; temp = temp.getNextSibling(); } return count; } String getKey (Node node) { StringBuffer buffer = new StringBuffer(); while (node != null) { if (buffer.length() > 0) buffer.append("_"); String name = node.getNodeName(); StringBuffer key = new StringBuffer(name); if ("arg".equals(name)) { key.append("-"); key.append(indexOfNode(node)); } else { Node nameAttrib = getIDAttribute(node); if (nameAttrib != null) { key.append("-"); key.append(nameAttrib.getNodeValue()); } } NamedNodeMap attributes = node.getAttributes(); if (attributes != null) { boolean isStatic = attributes.getNamedItem("class_method") != null; if (isStatic) key.append("-static"); } buffer.append(key.reverse()); node = node.getParentNode(); } buffer.reverse(); return buffer.toString(); } public Node getIDAttribute(Node node) { NamedNodeMap attributes = node.getAttributes(); if (attributes == null) return null; String[] names = getIDAttributeNames(); for (int i = 0; i < names.length; i++) { Node nameAttrib = attributes.getNamedItem(names[i]); if (nameAttrib != null) return nameAttrib; } return null; } public String[] getIDAttributeNames() { return new String[]{ "name", "selector", "path", }; } void merge(Node node, HashMap<String, Node> extras, HashMap<String, Node> docLookup) { NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node childNode = list.item(i); if (childNode.getNodeType() == Node.ELEMENT_NODE) { String key = getKey(childNode); if (docLookup != null && docLookup.get(key) == null) { docLookup.put(key, childNode); } Node extra = extras.remove(key); if (extra != null) { NamedNodeMap attributes = extra.getAttributes(); for (int j = 0, length = attributes.getLength(); j < length; j++) { Node attr = attributes.item(j); String name = attr.getNodeName(); if (name.startsWith("swt_")) { ((Element)childNode).setAttribute(name, attr.getNodeValue()); } } } } merge(childNode, extras, docLookup); } } void out(String str) { PrintWriter out = this.out; out.print(str); } void outln() { PrintWriter out = this.out; out.println(); } void generateConstants() { for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("constant".equals(node.getNodeName())) { if (getGen(node)) { NamedNodeMap attributes = node.getAttributes(); String constName = attributes.getNamedItem("name").getNodeValue(); out("/** @method flags=const */"); outln(); out("public static final native "); String type = getType(node), type64 = getType64(node); out(type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } out(" "); out(constName); out("();"); outln(); if (attributes.getNamedItem("declared_type").getNodeValue().equals("NSString*")) { out("public static final NSString "); out(constName); out(" = new NSString("); out(constName); out("());"); outln(); } } } } } } void generateEnums() { for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("enum".equals(node.getNodeName())) { if (getGen(node)) { NamedNodeMap attributes = node.getAttributes(); Node valueNode = attributes.getNamedItem("value"); if (valueNode != null) { String value = valueNode.getNodeValue(); out("public static final "); boolean isLong = false; if (value.indexOf('.') != -1) { out("double "); } else { if (value.equals("4294967295")) { out("int "); value = "-1"; } else { try { Integer.parseInt(value); out("int "); } catch (NumberFormatException e) { isLong = true; out("long "); } } } out(attributes.getNamedItem("name").getNodeValue()); out(" = "); out(value); if (isLong && !value.endsWith("L")) out("L"); out(";"); outln(); } } } } } } boolean getGen(Node node) { NamedNodeMap attributes = node.getAttributes(); if (attributes == null) return false; Node gen = attributes.getNamedItem("swt_gen"); return gen != null && !gen.getNodeValue().equals("false"); } boolean getGenSuper(Node node) { NamedNodeMap attributes = node.getAttributes(); if (attributes == null) return false; Node gen = attributes.getNamedItem("swt_gen_super_msgSend"); return gen != null && !gen.getNodeValue().equals("false"); } boolean getGenCallback(Node node) { NamedNodeMap attributes = node.getAttributes(); if (attributes == null) return false; Node gen = attributes.getNamedItem("swt_gen_custom_callback"); return gen != null && !gen.getNodeValue().equals("false"); } boolean isStatic(Node node) { NamedNodeMap attributes = node.getAttributes(); Node isStatic = attributes.getNamedItem("class_method"); return isStatic != null && isStatic.getNodeValue().equals("true"); } boolean isStruct(Node node) { NamedNodeMap attributes = node.getAttributes(); Node type = attributes.getNamedItem("type"); if (type == null) return false; String code = type.getNodeValue(); return code.startsWith("{"); } boolean isFloatingPoint(Node node) { NamedNodeMap attributes = node.getAttributes(); Node type = attributes.getNamedItem("type"); if (type == null) return false; String code = type.getNodeValue(); return code.equals("f") || code.equals("d"); } boolean isObject(Node node) { NamedNodeMap attributes = node.getAttributes(); Node type = attributes.getNamedItem("type"); if (type == null) return false; String code = type.getNodeValue(); return code.equals("@"); } boolean isBoolean(Node node) { NamedNodeMap attributes = node.getAttributes(); Node type = attributes.getNamedItem("type"); if (type == null) return false; String code = type.getNodeValue(); return code.equals("B"); } void buildLookup(Node node, HashMap<String, Node> table) { NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node childNode = list.item(i); if (childNode.getNodeType() == Node.ELEMENT_NODE) { String key = getKey(childNode); if (table.get(key) == null) table.put(key, childNode); buildLookup(childNode, table); } } } boolean isUnique(Node method, ArrayList<?> methods) { String methodName = method.getAttributes().getNamedItem("selector").getNodeValue(); String signature = ""; NodeList params = method.getChildNodes(); for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { signature += getJavaType(param); } } int index = methodName.indexOf(":"); if (index != -1) methodName = methodName.substring(0, index); for (Iterator<?> iterator = methods.iterator(); iterator.hasNext();) { Node other = (Node) iterator.next(); NamedNodeMap attributes = other.getAttributes(); Node otherSel = null; if (attributes != null) otherSel = attributes.getNamedItem("selector"); if (other != method && otherSel != null) { String otherName = otherSel.getNodeValue(); index = otherName.indexOf(":"); if (index != -1) otherName = otherName.substring(0, index); if (methodName.equals(otherName)) { NodeList otherParams = other.getChildNodes(); String otherSignature = ""; for (int k = 0; k < otherParams.getLength(); k++) { Node param = otherParams.item(k); if ("arg".equals(param.getNodeName())) { otherSignature += getJavaType(param); } } if (signature.equals(otherSignature)) { return false; } } } } return true; } void generateSelectorsConst() { TreeSet<String> set = new TreeSet<String>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("class".equals(node.getNodeName()) || "informal_protocol".equals(node.getNodeName())) { if (getGen(node)) { NodeList methods = node.getChildNodes(); for (int j = 0; j < methods.getLength(); j++) { Node method = methods.item(j); if (getGen(method)) { NamedNodeMap mthAttributes = method.getAttributes(); String sel = mthAttributes.getNamedItem("selector").getNodeValue(); set.add(sel); } } } } } } if (set.size() > 0) { set.add("alloc"); set.add("dealloc"); } for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String sel = iterator.next(); String selConst = getSelConst(sel); out("public static final int /*long*/ "); out(selConst); out(" = "); out("sel_registerName(\""); out(sel); out("\");"); outln(); } } void generateStructNatives() { TreeSet<String> set = new TreeSet<String>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("struct".equals(node.getNodeName()) && getGen(node)) { set.add(getIDAttribute(node).getNodeValue()); } } } out("/** Sizeof natives */"); outln(); for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String struct = iterator.next(); out("public static final native int "); out(struct); out("_sizeof();"); outln(); } outln(); out("/** Memmove natives */"); outln(); outln(); for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String struct = iterator.next(); out("/**"); outln(); out(" * @param dest cast=(void *),flags=no_in critical"); outln(); out(" * @param src cast=(void *),flags=critical"); // out(" * @param src cast=(void *),flags=no_out critical"); outln(); out(" */"); outln(); out("public static final native void memmove("); out("int /*long*/ dest, "); out(struct); out(" src, int /*long*/ size);"); outln(); out("/**"); outln(); out(" * @param dest cast=(void *),flags=no_in critical"); outln(); out(" * @param src cast=(void *),flags=critical"); // out(" * @param src cast=(void *),flags=no_out critical"); outln(); out(" */"); outln(); out("public static final native void memmove("); out(struct); out(" dest, int /*long*/ src, int /*long*/ size);"); outln(); } } String buildSend(Node method, boolean tags, boolean only64, boolean superCall) { Node returnNode = getReturnNode(method.getChildNodes()); StringBuffer buffer = new StringBuffer(); buffer.append("public static final native "); if (returnNode != null && isStruct(returnNode)) { buffer.append("void "); buffer.append(superCall ? "objc_msgSendSuper_stret" : "objc_msgSend_stret"); buffer.append("("); buffer.append(getJavaType(returnNode)); buffer.append(" result, "); } else if (returnNode != null && isFloatingPoint(returnNode)) { String type = getType(returnNode), type64 = getType64(returnNode); if (type.equals(type64) && type.equals("float")) { buffer.append("float "); buffer.append(superCall ? "objc_msgSendSuper_floatret" : "objc_msgSend_floatret"); } else { buffer.append("double "); buffer.append(superCall ? "objc_msgSendSuper_fpret" : "objc_msgSend_fpret"); } buffer.append("("); } else if (returnNode != null && isBoolean(returnNode)) { buffer.append("boolean "); buffer.append(superCall ? "objc_msgSendSuper_bool" : "objc_msgSend_bool"); buffer.append("("); } else { if (only64) { buffer.append("long"); } else { if (tags) { buffer.append("int /*long*/"); } else { buffer.append("int"); } } buffer.append(" "); buffer.append(superCall ? "objc_msgSendSuper" : "objc_msgSend"); buffer.append("("); } if (superCall) { if (only64) { buffer.append("objc_super superId, long sel"); } else { if (tags) { buffer.append("objc_super superId, int /*long*/ sel"); } else { buffer.append("objc_super superId, int sel"); } } } else { if (only64) { buffer.append("long id, long sel"); } else { if (tags) { buffer.append("int /*long*/ id, int /*long*/ sel"); } else { buffer.append("int id, int sel"); } } } NodeList params = method.getChildNodes(); boolean first = false; int count = 0; for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { if (!first) buffer.append(", "); if (isStruct(param)) { buffer.append(getJavaType(param)); } else { String type = getType(param), type64 = getType64(param); buffer.append(only64 ? type64 : type); if (!only64 && tags && !type.equals(type64)) { buffer.append(" /*"); buffer.append(type64); buffer.append("*/"); } } first = false; buffer.append(" arg"); buffer.append(String.valueOf(count++)); } } buffer.append(");"); return buffer.toString(); } String getCType (Node node) { NamedNodeMap attributes = node.getAttributes(); return attributes.getNamedItem("declared_type").getNodeValue(); } Node findNSObjectMethod(Node method) { NamedNodeMap methodAttributes = method.getAttributes(); String selector = methodAttributes.getNamedItem("selector").getNodeValue(); NodeList list = method.getParentNode().getParentNode().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node cls = list.item(i); if ("class".equals(cls.getNodeName())) { NamedNodeMap classAttributes = cls.getAttributes(); if ("NSObject".equals(classAttributes.getNamedItem("name").getNodeValue())) { NodeList methods = cls.getChildNodes(); for (int j = 0; j < methods.getLength(); j++) { Node mth = methods.item(j); if ("method".equals(mth.getNodeName())) { NamedNodeMap mthAttributes = mth.getAttributes(); if (selector.equals(mthAttributes.getNamedItem("selector").getNodeValue())) { return mth; } } } } } } return null; } void generateCustomCallbacks() { TreeMap<String, Node> set = new TreeMap<String, Node>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if (("class".equals(node.getNodeName()) || "informal_protocol".equals(node.getNodeName())) && getGen(node)) { NodeList methods = node.getChildNodes(); for (int j = 0; j < methods.getLength(); j++) { Node method = methods.item(j); if ("method".equals(method.getNodeName()) && getGen(method) && getGenCallback(method)) { NamedNodeMap mthAttributes = method.getAttributes(); String sel = mthAttributes.getNamedItem("selector").getNodeValue(); set.put(sel, method); } } } } } for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); Node method = set.get(key); if ("informal_protocol".equals(method.getParentNode().getNodeName())) { method = findNSObjectMethod(method); if (method == null) continue; } String nativeMth = key.replaceAll(":", "_"); out("/** @method callback_types="); Node returnNode = getReturnNode(method.getChildNodes()); out(returnNode == null ? "void" : getCType(returnNode)); out(";id;SEL;"); NodeList params = method.getChildNodes(); for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { out(getCType(param)); out(";"); } } out(",callback_flags="); out(returnNode != null && isStruct(returnNode) ? "struct" : "none"); out(";none;none;"); for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { out (isStruct(param) ? "struct" : "none"); out(";"); } } out(" */"); outln(); out("public static final native int /*long*/ CALLBACK_"); out(nativeMth); out("(int /*long*/ func);"); outln(); } } void generateSends(boolean superCall) { TreeMap<String, Node> set = new TreeMap<String, Node>(); TreeMap<String, Node> set64 = new TreeMap<String, Node>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("class".equals(node.getNodeName()) && getGen(node)) { NodeList methods = node.getChildNodes(); for (int j = 0; j < methods.getLength(); j++) { Node method = methods.item(j); if ("method".equals(method.getNodeName()) && getGen(method) && (!superCall || getGenSuper(method))) { String code = buildSend(method, false, false, superCall); String code64 = buildSend(method, false, true, superCall); if (set.get(code) == null) { set.put(code, method); } if (set64.get(code64) == null) { set64.put(code64, method); } } } } } } outln(); TreeMap<String, Node> tagsSet = new TreeMap<String, Node>(); for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); Node method = set.get(key); String tagCode = buildSend(method, false, true, superCall); if (set64.get(tagCode) != null) { tagsSet.put(key, method); iterator.remove(); set64.remove(tagCode); } } TreeMap<String, Node> all = new TreeMap<String, Node>(); for (Iterator<String> iterator = tagsSet.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); Node method = tagsSet.get(key); all.put(buildSend(method, true, false, superCall), method); } for (Iterator<String> iterator = set.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); all.put(key, set.get(key)); } for (Iterator<String> iterator = set64.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); all.put(key, set64.get(key)); } for (Iterator<String> iterator = all.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); Node method = all.get(key); NodeList params = method.getChildNodes(); ArrayList<String> tags = new ArrayList<String>(); int count = 0; for (int k = 0; k < params.getLength(); k++) { Node param = params.item(k); if ("arg".equals(param.getNodeName())) { if (isStruct(param)) { tags.add(" * @param arg" + count + " flags=struct"); } count++; } } out("/**"); if (tags.size() > 0) { outln(); out(" *"); } out(" @method flags=cast"); if (tags.size() > 0) outln(); for (Iterator<String> iterator2 = tags.iterator(); iterator2.hasNext();) { String tag = iterator2.next(); out(tag); outln(); } out(" */"); outln(); out(key.toString()); outln(); } } String getSelConst(String sel) { return "sel_" + sel.replaceAll(":", "_"); } void generateClassesConst() { TreeSet<String> set = new TreeSet<String>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("class".equals(node.getNodeName())) { if (getGen(node)) { NamedNodeMap attributes = node.getAttributes(); String name = attributes.getNamedItem("name").getNodeValue(); set.add(name); } } } } for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String cls = iterator.next(); String clsConst = "class_" + cls; out("public static final int /*long*/ "); out(clsConst); out(" = "); out("objc_getClass(\""); out(cls); out("\");"); outln(); } } void generateProtocolsConst() { TreeSet<String> set = new TreeSet<String>(); for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("informal_protocol".equals(node.getNodeName())) { if (getGen(node)) { NamedNodeMap attributes = node.getAttributes(); String name = attributes.getNamedItem("name").getNodeValue(); set.add(name); } } } } for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String cls = iterator.next(); String clsConst = "protocol_" + cls; out("public static final int /*long*/ "); out(clsConst); out(" = "); out("objc_getProtocol(\""); out(cls); out("\");"); outln(); } } String getPackageName(String className) { int dot = mainClassName.lastIndexOf('.'); if (dot == -1) return ""; return mainClassName.substring(0, dot); } String getClassName(String className) { int dot = mainClassName.lastIndexOf('.'); if (dot == -1) return mainClassName; return mainClassName.substring(dot + 1); } Node getReturnNode(NodeList list) { for (int j = 0; j < list.getLength(); j++) { Node node = list.item(j); if ("retval".equals(node.getNodeName())) { return node; } } return null; } String getType(Node node) { NamedNodeMap attributes = node.getAttributes(); Node javaType = attributes.getNamedItem("swt_java_type"); if (javaType != null) return javaType.getNodeValue(); Node type = attributes.getNamedItem("type"); if (type == null) return "notype"; String code = type.getNodeValue(); return getType(code, attributes, false); } String getType64(Node node) { NamedNodeMap attributes = node.getAttributes(); Node javaType = attributes.getNamedItem("swt_java_type"); if (javaType != null) { Node javaType64 = attributes.getNamedItem("swt_java_type64"); return javaType64 != null ? javaType64.getNodeValue() : javaType.getNodeValue(); } Node attrib = attributes.getNamedItem("type"); if (attrib == null) return "notype"; String code = attrib.getNodeValue(); Node attrib64 = attributes.getNamedItem("type64"); if (attrib64 != null) code = attrib64.getNodeValue(); return getType(code, attributes, true); } String getType(String code, NamedNodeMap attributes, boolean is64) { if (code.equals("c")) return "byte"; if (code.equals("i")) return "int"; if (code.equals("s")) return "short"; if (code.equals("l")) return "int"; if (code.equals("q")) return "long"; if (code.equals("C")) return "byte"; if (code.equals("I")) return "int"; if (code.equals("S")) return "short"; if (code.equals("L")) return "int"; if (code.equals("Q")) return "long"; if (code.equals("f")) return "float"; if (code.equals("d")) return "double"; if (code.equals("B")) return "boolean"; if (code.equals("v")) return "void"; if (code.equals("*")) return is64 ? "long" : "int"; if (code.equals("@")) return is64 ? "long" : "int"; if (code.equals("#")) return is64 ? "long" : "int"; if (code.equals(":")) return is64 ? "long" : "int"; if (code.startsWith("^")) return is64 ? "long" : "int"; if (code.startsWith("{")) { return attributes.getNamedItem("declared_type").getNodeValue(); } if (code.startsWith("@?")) { return is64 ? "long" : "int"; } return "BAD " + code; } String getJNIType(Node node) { NamedNodeMap attributes = node.getAttributes(); String code = attributes.getNamedItem("type").getNodeValue(); if (code.equals("c")) return "B"; if (code.equals("i")) return "I"; if (code.equals("s")) return "S"; if (code.equals("l")) return "I"; if (code.equals("q")) return "J"; if (code.equals("C")) return "B"; if (code.equals("I")) return "I"; if (code.equals("S")) return "S"; if (code.equals("L")) return "I"; if (code.equals("Q")) return "J"; if (code.equals("f")) return "F"; if (code.equals("d")) return "D"; if (code.equals("B")) return "Z"; if (code.equals("v")) return "V"; if (code.equals("*")) return "I"; if (code.equals("@")) return "I"; if (code.equals("#")) return "I"; if (code.equals(":")) return "I"; if (code.startsWith("^")) return "I"; if (code.startsWith("@?")) return "I"; if (code.startsWith("[")) return "BAD " + code; if (code.startsWith("{")) { return "BAD " + code; } if (code.startsWith("(")) return "BAD " + code; return "BAD " + code; } String getJavaType(Node node) { NamedNodeMap attributes = node.getAttributes(); Node javaType = attributes.getNamedItem("swt_java_type"); if (javaType != null) return javaType.getNodeValue().trim(); Node type = attributes.getNamedItem("type"); if (type == null) return "notype"; String code = type.getNodeValue(); return getJavaType(code, attributes, false); } String getJavaType64(Node node) { NamedNodeMap attributes = node.getAttributes(); Node javaType = attributes.getNamedItem("swt_java_type"); if (javaType != null) { Node javaType64 = attributes.getNamedItem("swt_java_type64"); return javaType64 != null ? javaType64.getNodeValue() : javaType.getNodeValue(); } Node attrib = attributes.getNamedItem("type"); if (attrib == null) return "notype"; String code = attrib.getNodeValue(); Node attrib64 = attributes.getNamedItem("type64"); if (attrib64 != null) code = attrib64.getNodeValue(); return getJavaType(code, attributes, true); } String getJavaType(String code, NamedNodeMap attributes, boolean is64) { if (code.equals("c")) return "byte"; if (code.equals("i")) return "int"; if (code.equals("s")) return "short"; if (code.equals("l")) return "int"; if (code.equals("q")) return "long"; if (code.equals("C")) return "byte"; if (code.equals("I")) return "int"; if (code.equals("S")) return "short"; if (code.equals("L")) return "int"; if (code.equals("Q")) return "long"; if (code.equals("f")) return "float"; if (code.equals("d")) return "double"; if (code.equals("B")) return "boolean"; if (code.equals("v")) return "void"; if (code.equals("*")) return is64 ? "long" : "int"; if (code.equals("#")) return is64 ? "long" : "int"; if (code.equals(":")) return is64 ? "long" : "int"; if (code.startsWith("^")) return is64 ? "long" : "int"; if (code.equals("@")) { String type = attributes.getNamedItem("declared_type").getNodeValue(); int index = type.indexOf('*'); if (index != -1) type = type.substring(0, index); index = type.indexOf('<'); if (index != -1) type = type.substring(0, index); return type.trim(); } if (code.startsWith("{")) { return attributes.getNamedItem("declared_type").getNodeValue().trim(); } if (code.startsWith("@?")) return is64 ? "long" : "int"; return "BAD " + code; } static String[] split(String str, String separator) { StringTokenizer tk = new StringTokenizer(str, separator); ArrayList<String> result = new ArrayList<String>(); while (tk.hasMoreTokens()) { result.add(tk.nextToken()); } return result.toArray(new String[result.size()]); } void generateFunctions() { for (int x = 0; x < xmls.length; x++) { Document document = documents[x]; if (document == null) continue; NodeList list = document.getDocumentElement().getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if ("function".equals(node.getNodeName())) { if (getGen(node)) { NamedNodeMap attributes = node.getAttributes(); String name = attributes.getNamedItem("name").getNodeValue(); NodeList params = node.getChildNodes(); int count = 0; for (int j = 0; j < params.getLength(); j++) { Node param = params.item(j); if ("arg".equals(param.getNodeName())) { count++; } } if (count > 0) { out("/**"); outln(); } int argIndex = 0; for (int j = 0; j < params.getLength(); j++) { Node param = params.item(j); if ("arg".equals(param.getNodeName())) { out(" * @param "); out(getParamName(param, argIndex++)); if (isStruct(param)) { out(" flags=struct"); } else { out(" cast="); NamedNodeMap paramAttributes = param.getAttributes(); Node swtCast = paramAttributes.getNamedItem("swt_param_cast"); Node declaredType = swtCast != null ? swtCast : paramAttributes.getNamedItem("declared_type"); String cast = declaredType.getNodeValue(); if (!cast.startsWith("(")) out("("); out(cast); if (!cast.endsWith(")")) out(")"); } outln(); } } if (count > 0) { out(" */"); outln(); } out("public static final native "); Node returnNode = getReturnNode(node.getChildNodes()); if (returnNode != null) { String type = getType(returnNode), type64 = getType64(returnNode); out(type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } out(" "); } else { out("void "); } out(name); out("("); params = node.getChildNodes(); boolean first = true; argIndex = 0; for (int j = 0; j < params.getLength(); j++) { Node param = params.item(j); if ("arg".equals(param.getNodeName())) { if (!first) out(", "); first = false; String type = getType(param), type64 = getType64(param); out(type); if (!type.equals(type64)) { out(" /*"); out(type64); out("*/"); } out(" "); out(getParamName(param, argIndex++)); } } generateVariadics(node); out(");"); outln(); } } } } } void generateVariadics(Node node) { NamedNodeMap attributes = node.getAttributes(); Node variadicCount = attributes.getNamedItem("swt_variadic_count"); if (variadicCount != null) { Node variadicTypes = attributes.getNamedItem("swt_variadic_java_types"); String[] types = null; if (variadicTypes != null) { types = split(variadicTypes.getNodeValue(), ","); } int varCount = 0; try { varCount = Integer.parseInt(variadicCount.getNodeValue()); } catch (NumberFormatException e) {} for (int j = 0; j < varCount; j++) { out(", "); if (types != null && types.length > j && !types[j].equals("*")) { out(types[j]); } else if (types != null && types[types.length - 1].equals("*")) { out(types[types.length - 2]); } else { out("int /*long*/"); } out(" varArg"); out("" + j); } } } public static void main(String[] args) { try { MacGenerator gen = new MacGenerator(); gen.setXmls(args); gen.setOutputDir("../org.eclipse.swt/Eclipse SWT PI/cocoa/"); gen.setMainClass("org.eclipse.swt.internal.cocoa.OS"); gen.generate(null); } catch (Throwable e) { e.printStackTrace(); } } }