1 /*
2  * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package com.apple.internal.jobjc.generator.model;
26 
27 import java.io.File;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 
36 import javax.xml.xpath.XPath;
37 import javax.xml.xpath.XPathConstants;
38 import javax.xml.xpath.XPathExpressionException;
39 import javax.xml.xpath.XPathFactory;
40 
41 import org.w3c.dom.Node;
42 import org.xml.sax.InputSource;
43 
44 import com.apple.internal.jobjc.generator.ClassGenerator;
45 import com.apple.internal.jobjc.generator.Utils;
46 import com.apple.internal.jobjc.generator.classes.FrameworkClassFile;
47 import com.apple.internal.jobjc.generator.classes.OutputFile;
48 import com.apple.internal.jobjc.generator.utils.Fp;
49 import com.apple.internal.jobjc.generator.utils.Fp.Map1;
50 import com.apple.jobjc.MacOSXFramework;
51 import com.apple.jobjc.UnsafeRuntimeAccess;
52 
53 public class Framework extends Element<Element<?>> implements OutputFileGenerator {
54     public final String path;
55     public final String pkg;
56     public final List<File> binaries;
57     public MacOSXFramework nativeFramework;
58 
load()59     public MacOSXFramework load(){
60         if(nativeFramework == null){
61             String[] bins = new String[binaries.size()];
62             for(int i = 0; i < binaries.size(); ++i)
63                 bins[i] = Utils.getCanonicalPath(binaries.get(i));
64             nativeFramework = UnsafeRuntimeAccess.getFramework(bins);
65         }
66         return nativeFramework;
67     }
68 
getMainFrameworkBinary()69     public File getMainFrameworkBinary(){ return binaries.get(0); }
70 
71     final Node rootNode;
72 
73     public Set<Clazz> classes;
74     public List<Struct> structs;
75     public List<CFType> cfTypes;
76     public List<Opaque> opaques;
77     public List<Constant> constants;
78     public List<StringConstant> stringConstants;
79     public List<NativeEnum> enums;
80     public List<Function> functions;
81     public List<FunctionAlias> functionAliases;
82     public List<InformalProtocol> informalProtocols;
83     public List<Protocol> protocols;
84     public List<Category> categories;
85     public List<FrameworkDependency> dependencies;
86 
87     public static class FrameworkDependency extends Element<Framework>{
88         final String path;
89         public Framework object = null;
90 
FrameworkDependency(final Node node, final Framework parent)91         public FrameworkDependency(final Node node, final Framework parent) {
92             super(getAttr(node, "path").replaceFirst("^.*/([^/]+)\\.framework$", "$1"), parent);
93             this.path = getAttr(node, "path");
94         }
95     }
96 
97     public static final XPath XPATH = XPathFactory.newInstance().newXPath();
Framework(final String name, final File bsFile)98     public Framework(final String name, final File bsFile) {
99         super(name, null);
100         try {
101             final File pathf = bsFile.getCanonicalFile().getParentFile().getParentFile().getParentFile();
102             path = pathf.getParentFile().getParentFile().getCanonicalPath();
103         } catch (IOException x) {
104             throw new RuntimeException(x);
105         }
106         binaries = findBinaries(path, name);
107 
108         pkg = ClassGenerator.JOBJC_PACKAGE + "." + name.toLowerCase();
109         try {
110             rootNode = (Node)XPATH.evaluate("signatures", new InputSource(bsFile.getAbsolutePath()), XPathConstants.NODE);
111         } catch (final XPathExpressionException e) { throw new RuntimeException(e); }
112         protocols = new ArrayList<Protocol>();
113         categories = new ArrayList<Category>();
114     }
115 
findBinaries(final String rootPath, final String name)116     private static List<File> findBinaries(final String rootPath, final String name){
117         List<File> bins = new ArrayList<File>(2);
118 
119         File mainBin = new File(rootPath, name);
120         if(mainBin.exists()) bins.add(mainBin);
121 
122         File bsBin = new File(rootPath, "Resources/BridgeSupport/" + name + ".dylib");
123         if(bsBin.exists()) bins.add(bsBin);
124 
125         return bins;
126     }
127 
parseDependencies(final Collection<Framework> frameworks)128     public void parseDependencies(final Collection<Framework> frameworks) {
129         // Parse
130         dependencies = getNodesFor(rootNode, "depends_on", FrameworkDependency.class, this);
131         // Resolve
132         for(final FrameworkDependency dep : dependencies)
133             dep.object = Fp.find(new Map1<Framework,Boolean>(){
134                 public Boolean apply(Framework f) {
135                     return f.path.equals(dep.path);
136                 }}, frameworks);
137     }
138 
parseStructs()139     public void parseStructs() {
140         structs = getNodesFor(rootNode, "struct", Struct.class, this);
141 
142         // HACK BS bug #6100313
143         if(Utils.isSnowLeopard && name.equals("IOBluetooth"))
144             structs.remove(getStructByName("BluetoothHCIRequestNotificationInfo"));
145 
146         // GLIFunctionDispatch is frequently out of sync in BS / system
147         if(name.equals("OpenGL"))
148             structs.remove(getStructByName("GLIFunctionDispatch"));
149     }
150 
parseCFTypes()151     public void parseCFTypes() {
152         cfTypes = getNodesFor(rootNode, "cftype", CFType.class, this);
153     }
154 
parseOpaques()155     public void parseOpaques() {
156         opaques = getNodesFor(rootNode, "opaque", Opaque.class, this);
157     }
158 
parseConstants()159     public void parseConstants() {
160         constants = getNodesFor(rootNode, "constant", Constant.class, this);
161         stringConstants = getNodesFor(rootNode, "string_constant", StringConstant.class, this);
162         enums = getNodesFor(rootNode, "enum", NativeEnum.class, this);
163     }
164 
parseFunctions()165     public void parseFunctions() {
166         functions = getNodesFor(rootNode, "function", Function.class, this);
167         functionAliases = getNodesFor(rootNode, "function_alias", FunctionAlias.class, this);
168     }
169 
parseClasses()170     public void parseClasses() {
171         classes = new HashSet<Clazz>(getNodesFor(rootNode, "class", Clazz.class, this));
172         classes = Fp.filterSet(new Map1<Clazz,Boolean>(){
173             public Boolean apply(Clazz a) {
174                 if(a.doesActuallyExist())
175                     return true;
176                 else{
177                     System.out.println("Could not find class " + name + ":" + a.name + " in runtime. Discarding.");
178                     return false;
179                 }
180             }}, classes);
181         informalProtocols = getNodesFor(rootNode, "informal_protocol", InformalProtocol.class, this);
182     }
183 
resolveSuperClasses(final Map<String, Clazz> allClasses)184     public void resolveSuperClasses(final Map<String, Clazz> allClasses) throws Throwable {
185         load();
186         for (final Clazz clazz : classes)
187             clazz.resolveSuperClass(nativeFramework, allClasses);
188     }
189 
generateClasses(final List<OutputFile> generatedClassFiles)190     public void generateClasses(final List<OutputFile> generatedClassFiles) {
191         generatedClassFiles.add(new FrameworkClassFile(this));
192 
193         final List<List<OutputFileGenerator>> generatorLists =
194                   Utils.list(new ArrayList<Clazz>(classes), structs, cfTypes, opaques, categories);
195         for (final List<OutputFileGenerator> generators : generatorLists) {
196             for (final OutputFileGenerator generator : generators)
197                 generator.generateClasses(generatedClassFiles);
198         }
199     }
200 
toString()201     @Override public String toString() { return reflectOnMySelf(); }
202 
getStructByName(final String stname)203     public Struct getStructByName(final String stname) {
204         return Fp.find(new Fp.Map1<Struct,Boolean>(){
205             public Boolean apply(Struct a) {
206                 return stname.equals(a.name);
207             }}, structs);
208     }
209 }
210