/* oCpyright (c) 2009-2013 Olivier Chafik, All Rights Reserved This file is part of JNAerator (http://jnaerator.googlecode.com/). JNAerator is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JNAerator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with JNAerator. If not, see <http://www.gnu.org/licenses/>. */ package com.ochafik.lang.jnaerator; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.ochafik.lang.jnaerator.parser.TypeRef.SimpleTypeRef; import java.io.PrintWriter; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; //import org.rococoa.cocoa.foundation.FoundationLibrary; //import org.rococoa.cocoa.foundation.NSClass; //import org.rococoa.cocoa.foundation.NSInvocation; //import org.rococoa.cocoa.foundation.NSMethodSignature; import org.rococoa.cocoa.foundation.NSObject; //import org.rococoa.cocoa.foundation.NSString; import com.ochafik.lang.jnaerator.JNAerator.Feedback; import com.ochafik.lang.jnaerator.TypeConversion.JavaPrim; import com.ochafik.lang.jnaerator.parser.Define; import com.ochafik.lang.jnaerator.parser.Element; import com.ochafik.lang.jnaerator.parser.Enum; import com.ochafik.lang.jnaerator.parser.Expression; import com.ochafik.lang.jnaerator.parser.Function; import com.ochafik.lang.jnaerator.parser.Identifier; import com.ochafik.lang.jnaerator.parser.Scanner; import com.ochafik.lang.jnaerator.parser.SourceFile; import com.ochafik.lang.jnaerator.parser.Struct; import com.ochafik.lang.jnaerator.parser.TypeRef; import com.ochafik.lang.jnaerator.parser.Declarator; import com.ochafik.lang.jnaerator.parser.VariablesDeclaration; import com.ochafik.lang.jnaerator.parser.Declarator.DirectDeclarator; import com.ochafik.lang.jnaerator.parser.Enum.EnumItem; import com.ochafik.lang.jnaerator.parser.Expression.MemberRefStyle; import com.ochafik.lang.jnaerator.parser.Printer; import com.ochafik.lang.jnaerator.parser.StoredDeclarations.TypeDef; import com.ochafik.lang.jnaerator.parser.TypeRef.FunctionSignature; import com.ochafik.lang.jnaerator.parser.TypeRef.TaggedTypeRef; import com.ochafik.util.SystemUtils; import com.nativelibs4java.jalico.Pair; import com.ochafik.util.string.StringUtils; import java.util.LinkedHashMap; import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*; import com.ochafik.lang.jnaerator.parser.Namespace; import com.ochafik.lang.jnaerator.parser.TaggedTypeRefDeclaration; import java.util.Stack; public class Result extends Scanner { public final JNAeratorConfig config; public final Feedback feedback; public final ClassOutputter classOutputter; public TypeConversion typeConverter; public DeclarationsConverter declarationsConverter; public GlobalsGenerator globalsGenerator; public ObjectiveCGenerator objectiveCGenerator; public UniversalReconciliator universalReconciliator; public Reifier reifier; public BridJer bridjer; public Symbols symbols; public boolean hasCPlusPlus; public final Set<Identifier> structsFullNames = new HashSet<Identifier>(), enumsFullNames = new HashSet<Identifier>(), unionsFullNames = new HashSet<Identifier>(), callbacksFullNames = new HashSet<Identifier>(), objectiveCClassesFullNames = new HashSet<Identifier>(); /** * @param config * @param classOutputter * @param feedback */ public Result(JNAeratorConfig config, ClassOutputter classOutputter, Feedback feedback) { if (config == null) { throw new IllegalArgumentException("No config in result !"); } this.config = config; this.classOutputter = classOutputter; this.feedback = feedback; init(); } public void init() { declarationsConverter = config.runtime.createDeclarationsConverter(this); globalsGenerator = config.runtime.createGlobalsGenerator(this); typeConverter = config.runtime.createTypeConversion(this); reifier = new Reifier(this); objectiveCGenerator = new ObjectiveCGenerator(this); universalReconciliator = new UniversalReconciliator(); bridjer = new BridJer(this); } Set<Identifier> javaPackages = new TreeSet<Identifier>(); //Map<Identifier, ObjCClass> objCClasses = new LinkedHashMap<Identifier, ObjCClass>(); Map<Struct.Type, Map<Identifier, Struct>> classes = new TreeMap<Struct.Type, Map<Identifier, Struct>>(); Map<Identifier, Map<String, Struct>> objCCategoriesByTargetType = new LinkedHashMap<Identifier, Map<String, Struct>>(); Map<String, Struct> objCCategoriesByName = new LinkedHashMap<String, Struct>(); Map<String, Map<String, String>> stringConstants = new LinkedHashMap<String, Map<String, String>>(); Map<String, Map<String, Boolean>> retainedRetValFunctions = new LinkedHashMap<String, Map<String, Boolean>>(); //Set<String> //cStructNames = new HashSet<String>(), //enumNames = new HashSet<String>(); public Map<String, List<String>> missingPointersByUsingLibrary = new LinkedHashMap<String, List<String>>(); public Map<String, List<Struct>> structsByLibrary = new LinkedHashMap<String, List<Struct>>(); public Map<String, List<FunctionSignature>> callbacksByLibrary = new LinkedHashMap<String, List<FunctionSignature>>(); public Map<String, List<VariablesDeclaration>> globalsByLibrary = new LinkedHashMap<String, List<VariablesDeclaration>>(); public Map<Identifier, VariablesDeclaration> globalVariablesByName = new LinkedHashMap<Identifier, VariablesDeclaration>(); public Map<Identifier, Struct> structsByName = new LinkedHashMap<Identifier, Struct>(); public Map<Identifier, FunctionSignature> callbacksByName = new LinkedHashMap<Identifier, FunctionSignature>(); public Map<String, List<Enum>> enumsByLibrary = new LinkedHashMap<String, List<Enum>>(); public Map<Identifier, Enum> enumsByName = new LinkedHashMap<Identifier, Enum>(); public Map<String, EnumItem> enumItems = new LinkedHashMap<String, EnumItem>(); public Map<String, Define> defines = new LinkedHashMap<String, Define>(); public Map<String, List<Define>> definesByLibrary = new LinkedHashMap<String, List<Define>>(); public Map<String, Set<String>> fakePointersByLibrary = new LinkedHashMap<String, Set<String>>(); public Map<String, Set<String>> undefinedTypesByLibrary = new LinkedHashMap<String, Set<String>>(); public Map<String, List<Function>> functionsByLibrary = new LinkedHashMap<String, List<Function>>(); //Map<String, Expression> defines = new LinkedHashMap<String, Expression>(); public Map<Identifier, Signatures> signaturesByOutputClass = new LinkedHashMap<Identifier, Signatures>(); public Map<String, Pair<TypeDef, Declarator>> typeDefs = new LinkedHashMap<String, Pair<TypeDef, Declarator>>(); static <T> List<T> getList(Map<String, List<T>> m, String key) { List<T> list = m.get(key); if (list == null) { m.put(key, list = new ArrayList<T>()); } return list; } static <T, U, V> Map<U, V> getMap(Map<T, Map<U, V>> m, T key) { Map<U, V> map = m.get(key); if (map == null) { m.put(key, map = new LinkedHashMap<U, V>()); } return map; } public Identifier findFakePointer(Identifier name) { name = getFakePointerName(name); if (name == null) { return null; } String s = name.toString(); for (Map.Entry<String, Set<String>> e : fakePointersByLibrary.entrySet()) { if (e.getValue().contains(s)) { return ident(ident(e.getKey()), name); } } return null; } public Identifier findUndefinedType(Identifier name) { name = getUndefinedTypeName(name); if (name == null) { return null; } String s = name.toString(); for (Map.Entry<String, Set<String>> e : undefinedTypesByLibrary.entrySet()) { if (e.getValue().contains(s)) { return ident(ident(e.getKey()), name); } } return null; } public boolean isFakePointer(Identifier id) { return resolvedFakePointers.contains(id); } public boolean isUndefinedType(Identifier id) { return resolvedUndefinedTypes.contains(id); } public boolean isUndefinedType(TypeRef tpe) { return tpe instanceof SimpleTypeRef && isUndefinedType(((SimpleTypeRef) tpe).getName()); } Map<Identifier, List<Pair<Identifier, Function>>> functionsReifiableInFakePointers = new LinkedHashMap<Identifier, List<Pair<Identifier, Function>>>(); Set<Identifier> resolvedFakePointers = new HashSet<Identifier>(); Set<Identifier> resolvedUndefinedTypes = new HashSet<Identifier>(); public Identifier getFakePointer(Identifier libraryToUseIfNotDefinedYet, Identifier name) { Identifier lib = findFakePointer(name); if (lib != null) { return lib; } name = getFakePointerName(name); Set<String> set = fakePointersByLibrary.get(libraryToUseIfNotDefinedYet); if (set == null && libraryToUseIfNotDefinedYet != null) { fakePointersByLibrary.put(libraryToUseIfNotDefinedYet.toString(), set = new HashSet<String>()); } set.add(name.toString()); Identifier id = libraryToUseIfNotDefinedYet == null ? ident(name) : ident(libraryToUseIfNotDefinedYet, name); resolvedFakePointers.add(id); return id; } public Identifier getUndefinedType(Identifier libraryToUseIfNotDefinedYet, Identifier name) { Identifier lib = findUndefinedType(name); if (lib != null) { return lib; } name = getUndefinedTypeName(name); Set<String> set = undefinedTypesByLibrary.get(libraryToUseIfNotDefinedYet); if (set == null) { undefinedTypesByLibrary.put(libraryToUseIfNotDefinedYet.toString(), set = new HashSet<String>()); } set.add(name.toString()); Identifier id = ident(libraryToUseIfNotDefinedYet, name); resolvedUndefinedTypes.add(id); return id; } private Identifier getFakePointerName(Identifier name) { String nameStr = name == null ? null : name.toString(); String trimmed = StringUtils.trimUnderscores(nameStr); if (trimmed != null && !nameStr.equals(trimmed)) { String nicerName = trimmed; Pair<TypeDef, Declarator> pair = typeDefs.get(nicerName); if (pair != null) { TypeRef targetType = pair.getFirst().getValueType(); String target = targetType.toString(); if (target.equals(nameStr + "*") || target.equals(nameStr)) { name = ident(nameStr = nicerName); } } } return name; } private Identifier getUndefinedTypeName(Identifier name) { String nameStr = name == null ? null : name.toString(); String trimmed = StringUtils.trimUnderscores(nameStr); if (trimmed != null && !nameStr.equals(trimmed)) { String nicerName = trimmed; Pair<TypeDef, Declarator> pair = typeDefs.get(nicerName); if (pair != null) { String target = pair.getFirst().getValueType().toString(); if (target.equals(nameStr))// || target.equals(nameStr+"*")) { name = ident(nameStr = nicerName); } } } return name; } public Signatures getSignaturesForOutputClass(Identifier name) { Signatures s = signaturesByOutputClass.get(name); if (s == null) { signaturesByOutputClass.put(name, s = new Signatures()); } return s; } /* public void addDefine(String name, Expression ex) { defines.put(name, ex); String library = getLibrary(ex); if (library.equals("")) library = library.toString(); getList(definesByLibrary, getLibrary(ex)).add(new Pair<String, Expression>(name, ex)); }*/ @Override public void visitDefine(Define define) { super.visitDefine(define); defines.put(define.getName(), define); getList(definesByLibrary, getLibrary(define)).add(define); } @Override public void visitEnum(Enum e) { super.visitEnum(e); if (e.getTag() == null) { // Hack to infer the enum name from the next typedef NSUInteger NSSomethingThatLooksLikeTheEnumsIdentifiers Element nextDeclaration = e.getNextSibling(); if (nextDeclaration != null && (nextDeclaration instanceof TypeDef)) { TypeDef typeDef = (TypeDef) nextDeclaration; TypeRef type = typeDef.getValueType(); if (type instanceof TypeRef.SimpleTypeRef) { String simpleTypeStr = ((TypeRef.SimpleTypeRef) type).getName().toString(); if (simpleTypeStr.equals("NSUInteger") || simpleTypeStr.equals("NSInteger") || simpleTypeStr.equals("CFIndex")) { Declarator bestPlainStorage = null; for (Declarator st : typeDef.getDeclarators()) { if (st instanceof DirectDeclarator) { String name = st.resolveName(); boolean niceName = StringUtils.trimUnderscores(name).equals(name);; if (bestPlainStorage == null || niceName) { bestPlainStorage = st; if (niceName) { break; } } } } if (bestPlainStorage != null) { String name = bestPlainStorage.resolveName(); System.err.println("Automatic struct name matching : " + name); e.setTag(ident(name)); } } } } } Identifier name = e.getTag(); String lib = getLibrary(e); if (name == null) { getList(enumsByLibrary, lib).add(e); } else { Enum oldEnum = enumsByName.get(name); if (declarativePower(e) > declarativePower(oldEnum)) { enumsByName.put(name, e); e.setResolvedJavaIdentifier(typeConverter.computeTaggedTypeIdentifierInJava(e)); if (!currentNamespace.isEmpty()) e.setParentNamespace(currentNamespace.peek().clone()); Identifier originalName = e.getOriginalTag(); if (originalName != null) { enumsByName.put(originalName, e); } //if (e.getTag() != null) { // enumsByName.put(e.getTag(), e); //} getList(enumsByLibrary, lib).add(e); Identifier identifier = typeConverter.getTaggedTypeIdentifierInJava(e); if (identifier != null) { enumsFullNames.add(identifier); } } } } static int declarativePower(TaggedTypeRef e) { if (e == null) { return 0; } int base = e.isForwardDeclaration() ? 0 : 10; Element p = e.getParentElement(); if (p instanceof TypeDef) { return base + 4; } if (p instanceof TaggedTypeRefDeclaration) { return base + 3; } return base + 1; } @Override public void visitEnumItem(EnumItem enumItem) { super.visitEnumItem(enumItem); enumItems.put(enumItem.getName(), enumItem); String library = getLibrary(enumItem); if (library == null) { return; } Element parent = enumItem.getParentElement(); if (parent == null || !(parent instanceof Enum)) { return; } Enum e = (Enum) parent; Identifier ident = ident(getLibraryClassFullName(library), declarationsConverter.getActualTaggedTypeName(e), ident(enumItem.getName())); enumItemsFullName.add(ident); } @Override public void visitVariablesDeclaration(VariablesDeclaration v) { super.visitVariablesDeclaration(v); if (v.findParentOfTypes(Struct.class, Function.class, Enum.class) != null) { return; } for (Declarator d : v.getDeclarators()) { globalVariablesByName.put(ident(d.resolveName()), v); } getList(globalsByLibrary, getLibrary(v)).add(v); } @Override public void visitTypeDef(TypeDef typeDef) { super.visitTypeDef(typeDef); for (Declarator vs : typeDef.getDeclarators()) { typeDefs.put(vs.resolveName(), new Pair<TypeDef, Declarator>(typeDef, vs)); } } private static Pattern frameworkPathPattern = Pattern.compile(".*/(\\w+)\\.framework/(?:.*/)?Headers/(?:.*/)?([^/]+)\\.[^/.]+$"); private static Pattern bridgesupportFrameworkPattern = Pattern.compile("(?:^|/)(\\w+?)(?:Full)?\\.bridgesupport$"); String guessFramework(String file) { Matcher matcher = frameworkPathPattern.matcher(file); if (matcher.find() || (matcher = bridgesupportFrameworkPattern.matcher(file)).find()) { return matcher.group(1); } return null; } String getLibrary(Element decl) { String file = resolveFile(decl); String library = config.getLibrary(file, Element.getName(decl)); if (library == null) { SourceFile f = decl.findParentOfType(SourceFile.class); if (f != null) { //library = config.getLibrary(f.getElementFile()); //if (library == null) { library = guessFramework(file); if (library == null) { library = f.getLibrary(); } //} } } return library; } public String resolveFile(Element e) { String file = null; while (e != null && (file = e.getElementFile()) == null) { e = e.getParentElement(); } return file; } @Override public void visitFunction(Function function) { super.visitFunction(function); Element parent = function.getParentElement(); if (parent != null) { if (parent instanceof FunctionSignature) { return; } if (parent instanceof Struct) { Struct parentStruct = (Struct) parent; switch (parentStruct.getType()) { case CPPClass: // if (config.genCPlusPlus) // break; case JavaClass: case JavaInterface: case ObjCClass: case ObjCProtocol: case CStruct: return; } } } getList(functionsByLibrary, getLibrary(function)).add(function); } public Expression getLibraryInstanceReferenceExpression(String libraryName) { Identifier hub = getHubFullClassName(); Identifier classIdent; String fieldName; if (hub != null) { classIdent = hub; fieldName = libraryName; } else { classIdent = getLibraryClassFullName(libraryName); fieldName = "INSTANCE"; } return memberRef(expr(typeRef(classIdent)), MemberRefStyle.Dot, fieldName); } public Identifier getHubFullClassName() { return config.entryName == null ? null : ident(config.entryName.toLowerCase(), config.entryName); } //List<Identifier> currentNamespace = new ArrayList<Identifier>(); Stack<Identifier> currentNamespace = new Stack<Identifier>(); @Override public void visitNamespace(Namespace ns) { if (currentNamespace.isEmpty()) currentNamespace.push(ns.getName()); else currentNamespace.push(currentNamespace.peek().derive(Identifier.QualificationSeparator.Colons, ns.getName())); try { super.visitNamespace(ns); } finally { currentNamespace.pop(); } } @Override public void visitStruct(Struct struct) { Identifier name = struct.getTag(); if (name != null) { switch (struct.getType()) { case CPPClass: if (!config.runtime.equals(JNAeratorConfig.Runtime.BridJ) && !config.genCPlusPlus) { break; } case CStruct: case CUnion: if (!currentNamespace.isEmpty()) struct.setParentNamespace(currentNamespace.peek().clone()); boolean isFwd = struct.isForwardDeclaration(); if (!isFwd && struct.getDeclarations().isEmpty() && config.treatEmptyStructsAsForwardDecls) { List<SimpleTypeRef> parents = struct.getParents(); Struct p; if (parents.isEmpty() || parents.size() == 1 && ((p = structsByName.get(parents.get(0))) == null || p.isForwardDeclaration())) { isFwd = true; } } if (isFwd) { break; } if (config.skipIncludedFrameworks) { String lib = getLibrary(struct); if (lib != null) { if (!config.frameworks.contains(lib)) { break; } } } Struct oldStruct = structsByName.get(name); if (declarativePower(struct) > declarativePower(oldStruct)) { structsByName.put(name, struct); Identifier originalName = struct.getOriginalTag(); if (originalName != null) { structsByName.put(originalName, struct); } Identifier resolvedJavaIdentifier = typeConverter.computeTaggedTypeIdentifierInJava(struct); struct.setResolvedJavaIdentifier(resolvedJavaIdentifier); if (struct.findParentOfType(Struct.class) == null) { getList(structsByLibrary, getLibrary(struct)).add(struct); } Identifier identifier = typeConverter.getTaggedTypeIdentifierInJava(struct); if (identifier != null) { if (struct.getType() == Struct.Type.CUnion) { unionsFullNames.add(identifier); } structsFullNames.add(identifier); } } break; case ObjCClass: case ObjCProtocol: // if (name.equals("NSObject")) // name = name.clone(); if (struct.isForwardDeclaration()) { break; } if (struct.getCategoryName() != null) { getMap(objCCategoriesByTargetType, struct.getTag()).put(struct.getCategoryName(), struct); objCCategoriesByName.put(struct.getCategoryName(), struct); } else { getMap(classes, struct.getType()).put(struct.getTag(), struct); } Identifier fullName = objectiveCGenerator.getFullClassName(struct); objectiveCClassesFullNames.add(fullName); struct.setResolvedJavaIdentifier(fullName); break; default: struct = null; } } super.visitStruct(struct); } @Override public void visitFunctionSignature(FunctionSignature functionSignature) { super.visitFunctionSignature(functionSignature); Function function = functionSignature.getFunction(); Identifier name = typeConverter.inferCallBackName(functionSignature, false, false, null); Identifier identifier = typeConverter.computeCallbackIdentifierInJava(functionSignature); functionSignature.setResolvedJavaIdentifier(identifier); if (function != null) { if (functionSignature.findParentOfType(Struct.class) == null) { getList(callbacksByLibrary, getLibrary(functionSignature)).add(functionSignature); } if (name != null) { callbacksByName.put(name, functionSignature); if (identifier != null) { callbacksFullNames.add(identifier); } } } } static String camelCase(String name) { StringBuilder out = new StringBuilder(); for (String s : name.split("[^\\w]+")) { String t = s.trim(); if (t.length() > 0) { out.append(StringUtils.capitalize(t)); } } return out.toString(); } public Identifier getLibraryClassSimpleName(String library) { return ident(camelCase(library) + "Library"); } public Identifier getLibraryClassFullName(String library) { return ident(getLibraryPackage(library), getLibraryClassSimpleName(library)); } public Identifier getLibraryDeclarationsClassSimpleName(String library) { if (config.runtime != JNAeratorConfig.Runtime.BridJ) return null; String name = config.extractedLibraries.get(library); if (name == null) return null; return ident(name); } public Identifier getLibraryDeclarationsClassFullName(String library) { Identifier name = getLibraryDeclarationsClassSimpleName(library); return name == null ? null : ident(getLibraryPackage(library), name); } public String getLibraryFileExpression(String library) { Class<?> platformClass = config.runtime.hasJNA ? com.sun.jna.Platform.class : SystemUtils.class; if (library.equals("c")) { return "(" + platformClass.getName() + ".isWindows() ? \"msvcrt\" : \"c\")"; } return "\"" + library + "\""; } Set<String> libraries = new HashSet<String>(); Map<String, Identifier> javaPackageByLibrary = new LinkedHashMap<String, Identifier>(); public Set<Identifier> enumItemsFullName = new HashSet<Identifier>(); public Identifier getLibraryPackage(String library) { if (library == null) { return null; } return config.packageName == null ? ident(ident(config.rootPackageName), library.toLowerCase().replaceAll("[^\\w.]", "")) : ident(config.packageName.replaceAll("[^\\w.]", "")); } public void chooseLibraryClasses(String packageName, String rootPackageName) { libraries.clear(); javaPackages.clear(); javaPackageByLibrary.clear(); libraries.addAll(structsByLibrary.keySet()); libraries.addAll(callbacksByLibrary.keySet()); libraries.addAll(functionsByLibrary.keySet()); libraries.addAll(enumsByLibrary.keySet()); libraries.addAll(globalsByLibrary.keySet()); libraries.addAll(definesByLibrary.keySet()); libraries.addAll(stringConstants.keySet()); for (String library : libraries) { Identifier javaPackage = getLibraryPackage(library); if (javaPackage != null) { javaPackageByLibrary.put(library, javaPackage); } } javaPackages.addAll(javaPackageByLibrary.values()); } public Struct resolveObjCClass(Identifier name) { if (name == null) { return null; } Struct s = getMap(classes, Struct.Type.ObjCClass).get(name); if (s == null) { s = getMap(classes, Struct.Type.ObjCProtocol).get(name); } if (s == null) { s = objCCategoriesByName.get(name.toString()); } return s; } Class<?>[] overwrittenClassesThatNeedToKeepAllTheirMethods = new Class[]{ NSObject.class, //NSClass.class, //NSMethodSignature.class, //NSInvocation.class, //FoundationLibrary.class }; public void addFunctionReifiableInFakePointer(Identifier resolvedFakePointer, Identifier libraryClassName, Function f) { List<Pair<Identifier, Function>> list = functionsReifiableInFakePointers.get(resolvedFakePointer); if (list == null) { functionsReifiableInFakePointers.put(resolvedFakePointer, list = new ArrayList<Pair<Identifier, Function>>()); } list.add(new Pair<Identifier, Function>(libraryClassName, f)); } public List<Pair<Identifier, Function>> getFunctionsReifiableInFakePointer(Identifier resolvedFakePointer) { return functionsReifiableInFakePointers.get(resolvedFakePointer); } public JavaPrim resolvePrimitive(String name) { return name == null ? null : javaPrims.get(name); } private boolean isPrimitive(TypeRef tr) { // TODO un-hack me return tr != null && javaPrims.containsKey(tr.toString()); } public TaggedTypeRef resolveFullTaggedTypeRef(TaggedTypeRef s) { Identifier tag = s.getTag(); if (tag != null && s.getResolvedJavaIdentifier() == null) { TaggedTypeRef rep = null; if (s instanceof Struct) { rep = structsByName.get(tag); } else if (s instanceof Enum) { rep = enumsByName.get(tag); } if (rep != null && rep != s) { s = rep; } } return s; } public interface ClassWritingNotifiable { Struct writingClass(Identifier fullClassName, Struct interf, Signatures signatures, String currentLibrary); } public Struct notifyBeforeWritingClass(Identifier fullClassName, Struct interf, Signatures signatures, String currentLibrary) { for (Class<?> c : overwrittenClassesThatNeedToKeepAllTheirMethods) { if (fullClassName.equals(c.getName())) { declarationsConverter.addMissingMethods(c, signatures, interf); break; } } if (fullClassName.resolveLastSimpleIdentifier().equals("char")) { return null; } String runtimeSpecificHelp = config.runtime == JNAeratorConfig.Runtime.BridJ ? "or <a href=\"http://bridj.googlecode.com/\">BridJ</a> " : ", <a href=\"http://rococoa.dev.java.net/\">Rococoa</a>, " + "or <a href=\"http://jna.dev.java.net/\">JNA</a>"; interf.addToCommentBefore( "This file was autogenerated by <a href=\"http://jnaerator.googlecode.com/\">JNAerator</a>, ", "a tool written by <a href=\"http://ochafik.com/\">Olivier Chafik</a> that <a href=\"http://code.google.com/p/jnaerator/wiki/CreditsAndLicense\">uses a few opensource projects.</a>.", "For help, please visit <a href=\"http://nativelibs4java.googlecode.com/\">NativeLibs4Java</a> " + runtimeSpecificHelp + "."); for (ClassWritingNotifiable n : classWritingNotifiables) { interf = n.writingClass(fullClassName, interf, signatures, currentLibrary); if (interf == null) { return null; } } return interf; } public List<ClassWritingNotifiable> classWritingNotifiables = new ArrayList<ClassWritingNotifiable>(); public void printJavaClass(Identifier javaPackage, Struct javaClass, PrintWriter out) { if (javaPackage != null) { out.println("package " + javaPackage + ";"); } if (config.noAutoImports) { out.println(javaClass); } else { Printer.printJava(javaPackage, ident(javaPackage == null ? null : javaPackage.clone(), javaClass.getTag().clone()), javaClass, out); } // out.println("@SuppressWarnings(\"unused\")"); } public boolean hasObjectiveC() { if (!objCCategoriesByName.isEmpty()) { return true; } Map<Identifier, Struct> m; if ((m = classes.get(Struct.Type.ObjCClass)) != null && !m.isEmpty()) { return true; } if ((m = classes.get(Struct.Type.ObjCProtocol)) != null && !m.isEmpty()) { return true; } return false; } public final Map<String, TypeRef> weakTypeDefs = new LinkedHashMap<String, TypeRef>(); public void addWeakTypeDef(TypeRef clone, String sn) { weakTypeDefs.put(sn, clone); } public void rehabilitateWeakTypeDefs() { for (Map.Entry<String, TypeRef> e : weakTypeDefs.entrySet()) { if (typeDefs.get(e.getKey()) == null) { DirectDeclarator dd = new DirectDeclarator(e.getKey()); TypeDef td = new TypeDef(e.getValue(), dd); typeDefs.put(e.getKey(), new Pair<TypeDef, Declarator>(td, dd)); } } } Map<String, TypeRef> manualTypeDefs = new LinkedHashMap<String, TypeRef>(); public TypeRef getTypeDef(Identifier nameId) { if (nameId == null) { return null; } String name = nameId.toString(); Pair<TypeDef, Declarator> p = typeDefs.get(name); if (p == null) { return manualTypeDefs.get(name); } Declarator value = p.getValue(); String rname = value == null ? null : value.resolveName(); if (rname != null) { if (name.equals("id")) { return null; } if (name.equals("SEL")) { return null; } if (name.equals("IMP")) { return null; } if (name.equals("Class")) { return null; } if (name.equals("BOOL")) { if (rname.equals("byte")) { return null; } } } Declarator.MutableByDeclarator mt = p.getValue().mutateType(p.getFirst().getValueType()); return mt instanceof TypeRef ? (TypeRef) mt : null; } public void addManualTypeDef(String name, TypeRef tr) { manualTypeDefs.put(name, tr); } public TypeRef resolveType(TypeRef tr, boolean keepUnresolvedIdentifiers) { return resolveType(tr, keepUnresolvedIdentifiers, new HashSet<Identifier>()); } protected TypeRef resolveType(TypeRef tr, boolean keepUnresolvedIdentifiers, Set<Identifier> resolvedTypeDefs) { if (tr instanceof TypeRef.TaggedTypeRef) { TypeRef.TaggedTypeRef ttr = (TypeRef.TaggedTypeRef) tr; if (ttr.isForwardDeclaration() && ttr.getTag() != null) { TypeRef resolved = null; if (ttr instanceof Enum) { resolved = resolveEnum(ttr.getTag()); } else if (ttr instanceof Struct) { resolved = resolveStruct(ttr.getTag()); } return resolved != null ? resolved : tr; } } if (tr instanceof TypeRef.TargettedTypeRef) { TypeRef.TargettedTypeRef ttr = (TypeRef.TargettedTypeRef) tr; TypeRef originalTarget = ttr.getTarget(); TypeRef resolvedTarget = resolveType(originalTarget, keepUnresolvedIdentifiers, resolvedTypeDefs); if (resolvedTarget == null) { return null; } ttr.setTarget(null); TypeRef.TargettedTypeRef clone = (TypeRef.TargettedTypeRef) ttr.clone(); ttr.setTarget(originalTarget); clone.setTarget(resolvedTarget.clone()); clone.setParentElement(ttr.findParentOfType(Struct.class)); return clone; } if (isPrimitive(tr)) { return tr; } if (tr instanceof SimpleTypeRef) { TypeRef resolved = resolveType(((SimpleTypeRef) tr).getName(), keepUnresolvedIdentifiers, resolvedTypeDefs); if (resolved != null || !keepUnresolvedIdentifiers) { return resolved; } } return tr; } protected TypeRef resolveType(Identifier name, boolean keepUnresolvedIdentifiers, Set<Identifier> resolvedTypeDefs) { TypeRef res; res = resolveStruct(name); if (res != null) { return res; } res = resolveEnum(name); if (res != null) { return res; } res = resolveCallback(name); if (res != null) { return res; } res = resolveObjCClass(name); if (res != null) { return res; } if (resolvedTypeDefs.add(name)) { res = getTypeDef(name); if (res != null) { return resolveType(res, keepUnresolvedIdentifiers, resolvedTypeDefs); } } return null; } public FunctionSignature resolveCallback(Identifier name) { return callbacksByName.get(name); } public Enum resolveEnum(Identifier name) { return enumsByName.get(name); } public Struct resolveStruct(Identifier name) { return structsByName.get(name); } Map<String, TypeConversion.JavaPrim> javaPrims = new TreeMap<String, TypeConversion.JavaPrim>(); public boolean isObjCppPrimitive(String s) { return javaPrims.containsKey(s); } protected void prim(String from, TypeConversion.JavaPrim to) { javaPrims.put(from, to); } }