001/*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
003 * Copyright (c) 2004, 2006 IBM Corporation and others.
004 *
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 *******************************************************************************/
011package org.fusesource.hawtjni.generator;
012
013import java.io.BufferedReader;
014import java.io.FileReader;
015import java.io.IOException;
016import java.io.PrintStream;
017import java.lang.reflect.Modifier;
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.Comparator;
021import java.util.List;
022
023import org.fusesource.hawtjni.generator.model.JNIClass;
024import org.fusesource.hawtjni.generator.model.JNIField;
025import org.fusesource.hawtjni.generator.model.JNIMethod;
026import org.fusesource.hawtjni.generator.model.JNIType;
027import org.fusesource.hawtjni.runtime.ClassFlag;
028
029/**
030 * 
031 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
032 */
033public abstract class JNIGenerator {
034    
035    static final String delimiter = System.getProperty("line.separator");
036    static final String JNI64 = "JNI64";
037
038    ArrayList<JNIClass> classes;
039    String copyright = "";
040    boolean isCPP;
041    PrintStream output = System.out;
042    ProgressMonitor progress;
043    private String outputName;
044    
045    static String fixDelimiter(String str) {
046        if (delimiter.equals("\n")) {
047            return str;
048        }
049        return str.replaceAll("\n", delimiter);
050    }
051
052    static String getFunctionName(JNIMethod method) {
053        return getFunctionName(method, method.getParameterTypes());
054    }
055
056    static String getFunctionName(JNIMethod method, List<JNIType> paramTypes) {
057        if ((method.getModifiers() & Modifier.NATIVE) == 0)
058            return method.getName();
059        String function = toC(method.getName());
060        if (!method.isNativeUnique()) {
061            StringBuffer buffer = new StringBuffer();
062            buffer.append(function);
063            buffer.append("__");
064            for (JNIType paramType : paramTypes) {
065                buffer.append(toC(paramType.getTypeSignature(false)));
066            }
067            return buffer.toString();
068        }
069        return function;
070    }
071
072    static String loadFile(String file) {
073        try {
074            FileReader fr = new FileReader(file);
075            BufferedReader br = new BufferedReader(fr);
076            StringBuffer str = new StringBuffer();
077            char[] buffer = new char[1024];
078            int read;
079            while ((read = br.read(buffer)) != -1) {
080                str.append(buffer, 0, read);
081            }
082            fr.close();
083            return str.toString();
084        } catch (IOException e) {
085            throw new RuntimeException("File not found:" + file, e);
086        }
087    }
088
089    public static void sortMethods(List<JNIMethod> methods) {
090        Collections.sort(methods, new Comparator<JNIMethod>() {
091            public int compare(JNIMethod mth1, JNIMethod mth2) {
092                int result = mth1.getName().compareTo(mth2.getName());
093                return result != 0 ? result : getFunctionName(mth1).compareTo(getFunctionName(mth2));
094            }
095        });
096    }
097
098    static void sortFields(List<JNIField> fields) {
099        Collections.sort(fields, new Comparator<JNIField>() {
100            public int compare(JNIField a, JNIField b) {
101                return a.getName().compareTo(b.getName());
102            }
103        });
104    }
105
106    static void sortClasses(ArrayList<JNIClass> classes) {
107        Collections.sort(classes, new Comparator<JNIClass>() {
108            public int compare(JNIClass a, JNIClass b) {
109                return a.getName().compareTo(b.getName());
110            }
111        });
112    }
113
114    static String toC(String str) {
115        int length = str.length();
116        StringBuffer buffer = new StringBuffer(length * 2);
117        for (int i = 0; i < length; i++) {
118            char c = str.charAt(i);
119            switch (c) {
120            case '_':
121                buffer.append("_1");
122                break;
123            case ';':
124                buffer.append("_2");
125                break;
126            case '[':
127                buffer.append("_3");
128                break;
129            case '.':
130                buffer.append("_");
131                break;
132            case '/':
133                buffer.append("_");
134                break;
135            default:
136                if( 
137                   ('a' <= c && c <= 'z')
138                   || ('A' <= c && c <= 'Z')                        
139                   || ('0' <= c && c <= '9')                        
140                ) { 
141                    buffer.append(c);
142                } else {
143                    buffer.append(String.format("_0%04x",(int)c));
144                }
145            }
146        }
147        return buffer.toString();
148    }
149
150    public abstract void generate(JNIClass clazz);
151
152    public void generateCopyright() {
153    }
154
155    public void generateIncludes() {
156    }
157
158    public void generate() {
159        if (classes == null)
160            return;
161        generateCopyright();
162        generateIncludes();
163        sortClasses(classes);
164        for (JNIClass clazz : classes) {
165            if (clazz.getFlag(ClassFlag.CPP)) {
166                isCPP = true;
167                break;
168            }
169        }
170        generate(classes);
171        output.flush();
172    }
173
174    protected void generate(ArrayList<JNIClass> classes) {
175        for (JNIClass clazz : classes) {
176            if (clazz.getGenerate())
177                generate(clazz);
178            if (progress != null)
179                progress.step();
180        }
181    }
182
183    public boolean getCPP() {
184        return isCPP;
185    }
186
187    public String getDelimiter() {
188        return delimiter;
189    }
190
191    public PrintStream getOutput() {
192        return output;
193    }
194
195    public String getOutputName() {
196        return outputName;
197    }
198
199    public void setOutputName(String outputName) {
200        this.outputName = outputName;
201    }
202
203    public ProgressMonitor getProgressMonitor() {
204        return progress;
205    }
206
207    public void output(String str) {
208        output.print(str);
209    }
210
211    public void outputln() {
212        output(getDelimiter());
213    }
214
215    public void outputln(String str) {
216        output(str);
217        output(getDelimiter());
218    }
219
220    public void setClasses(ArrayList<JNIClass> classes) {
221        this.classes = classes;
222    }
223
224    public void setOutput(PrintStream output) {
225        this.output = output;
226    }
227
228    public void setProgressMonitor(ProgressMonitor progress) {
229        this.progress = progress;
230    }
231    public String getCopyright() {
232        return copyright;
233    }
234
235    public void setCopyright(String copyright) {
236        this.copyright = copyright;
237    }
238
239}