/* * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.apple.internal.jobjc.generator.model; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Node; import org.xml.sax.InputSource; import com.apple.internal.jobjc.generator.ClassGenerator; import com.apple.internal.jobjc.generator.Utils; import com.apple.internal.jobjc.generator.classes.FrameworkClassFile; import com.apple.internal.jobjc.generator.classes.OutputFile; import com.apple.internal.jobjc.generator.utils.Fp; import com.apple.internal.jobjc.generator.utils.Fp.Map1; import com.apple.jobjc.MacOSXFramework; import com.apple.jobjc.UnsafeRuntimeAccess; public class Framework extends Element<Element<?>> implements OutputFileGenerator { public final String path; public final String pkg; public final List<File> binaries; public MacOSXFramework nativeFramework; public MacOSXFramework load(){ if(nativeFramework == null){ String[] bins = new String[binaries.size()]; for(int i = 0; i < binaries.size(); ++i) bins[i] = Utils.getCanonicalPath(binaries.get(i)); nativeFramework = UnsafeRuntimeAccess.getFramework(bins); } return nativeFramework; } public File getMainFrameworkBinary(){ return binaries.get(0); } final Node rootNode; public Set<Clazz> classes; public List<Struct> structs; public List<CFType> cfTypes; public List<Opaque> opaques; public List<Constant> constants; public List<StringConstant> stringConstants; public List<NativeEnum> enums; public List<Function> functions; public List<FunctionAlias> functionAliases; public List<InformalProtocol> informalProtocols; public List<Protocol> protocols; public List<Category> categories; public List<FrameworkDependency> dependencies; public static class FrameworkDependency extends Element<Framework>{ final String path; public Framework object = null; public FrameworkDependency(final Node node, final Framework parent) { super(getAttr(node, "path").replaceFirst("^.*/([^/]+)\\.framework$", "$1"), parent); this.path = getAttr(node, "path"); } } public static final XPath XPATH = XPathFactory.newInstance().newXPath(); public Framework(final String name, final File bsFile) { super(name, null); try { final File pathf = bsFile.getCanonicalFile().getParentFile().getParentFile().getParentFile(); path = pathf.getParentFile().getParentFile().getCanonicalPath(); } catch (IOException x) { throw new RuntimeException(x); } binaries = findBinaries(path, name); pkg = ClassGenerator.JOBJC_PACKAGE + "." + name.toLowerCase(); try { rootNode = (Node)XPATH.evaluate("signatures", new InputSource(bsFile.getAbsolutePath()), XPathConstants.NODE); } catch (final XPathExpressionException e) { throw new RuntimeException(e); } protocols = new ArrayList<Protocol>(); categories = new ArrayList<Category>(); } private static List<File> findBinaries(final String rootPath, final String name){ List<File> bins = new ArrayList<File>(2); File mainBin = new File(rootPath, name); if(mainBin.exists()) bins.add(mainBin); File bsBin = new File(rootPath, "Resources/BridgeSupport/" + name + ".dylib"); if(bsBin.exists()) bins.add(bsBin); return bins; } public void parseDependencies(final Collection<Framework> frameworks) { // Parse dependencies = getNodesFor(rootNode, "depends_on", FrameworkDependency.class, this); // Resolve for(final FrameworkDependency dep : dependencies) dep.object = Fp.find(new Map1<Framework,Boolean>(){ public Boolean apply(Framework f) { return f.path.equals(dep.path); }}, frameworks); } public void parseStructs() { structs = getNodesFor(rootNode, "struct", Struct.class, this); // HACK BS bug #6100313 if(Utils.isSnowLeopard && name.equals("IOBluetooth")) structs.remove(getStructByName("BluetoothHCIRequestNotificationInfo")); // GLIFunctionDispatch is frequently out of sync in BS / system if(name.equals("OpenGL")) structs.remove(getStructByName("GLIFunctionDispatch")); } public void parseCFTypes() { cfTypes = getNodesFor(rootNode, "cftype", CFType.class, this); } public void parseOpaques() { opaques = getNodesFor(rootNode, "opaque", Opaque.class, this); } public void parseConstants() { constants = getNodesFor(rootNode, "constant", Constant.class, this); stringConstants = getNodesFor(rootNode, "string_constant", StringConstant.class, this); enums = getNodesFor(rootNode, "enum", NativeEnum.class, this); } public void parseFunctions() { functions = getNodesFor(rootNode, "function", Function.class, this); functionAliases = getNodesFor(rootNode, "function_alias", FunctionAlias.class, this); } public void parseClasses() { classes = new HashSet<Clazz>(getNodesFor(rootNode, "class", Clazz.class, this)); classes = Fp.filterSet(new Map1<Clazz,Boolean>(){ public Boolean apply(Clazz a) { if(a.doesActuallyExist()) return true; else{ System.out.println("Could not find class " + name + ":" + a.name + " in runtime. Discarding."); return false; } }}, classes); informalProtocols = getNodesFor(rootNode, "informal_protocol", InformalProtocol.class, this); } public void resolveSuperClasses(final Map<String, Clazz> allClasses) throws Throwable { load(); for (final Clazz clazz : classes) clazz.resolveSuperClass(nativeFramework, allClasses); } public void generateClasses(final List<OutputFile> generatedClassFiles) { generatedClassFiles.add(new FrameworkClassFile(this)); final List<List<OutputFileGenerator>> generatorLists = Utils.list(new ArrayList<Clazz>(classes), structs, cfTypes, opaques, categories); for (final List<OutputFileGenerator> generators : generatorLists) { for (final OutputFileGenerator generator : generators) generator.generateClasses(generatedClassFiles); } } @Override public String toString() { return reflectOnMySelf(); } public Struct getStructByName(final String stname) { return Fp.find(new Fp.Map1<Struct,Boolean>(){ public Boolean apply(Struct a) { return stname.equals(a.name); }}, structs); } }