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