/*
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);
}
}