1 /*******************************************************************************
2 * Copyright (c) 2004, 2020 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.tools.internal;
15
16 import java.io.*;
17 import java.lang.reflect.*;
18 import java.util.*;
19
20 public abstract class JNIGenerator implements Flags {
21
22 JNIClass mainClass;
23 JNIClass[] classes;
24 MetaData metaData;
25 String delimiter;
26 PrintStream output;
27 ProgressMonitor progress;
28
29 static final String JNI64 = "JNI64";
30
JNIGenerator()31 public JNIGenerator() {
32 delimiter = System.lineSeparator();
33 output = System.out;
34 metaData = new MetaData(new Properties());
35 }
36
skipCopyrights(InputStream is)37 public static String skipCopyrights(InputStream is) throws IOException {
38 int state = 0;
39 StringBuilder copyrights = new StringBuilder();
40 while (state != 5) {
41 int c = is.read();
42 if (c == -1) return null;
43 switch (state) {
44 case 0:
45 if (!Character.isWhitespace((char)c)) state = 1;
46 case 1:
47 if (c == '/') state = 2;
48 else return null;
49 break;
50 case 2:
51 if (c == '*') state = 3;
52 else return null;
53 break;
54 case 3:
55 if (c == '*') state = 4;
56 break;
57 case 4:
58 if (c == '/') state = 5;
59 else state = 3;
60 break;
61 }
62 if (state > 0) copyrights.append((char)c);
63 }
64 return copyrights.toString();
65 }
66
compare(InputStream is1, InputStream is2)67 public static boolean compare(InputStream is1, InputStream is2) throws IOException {
68 skipCopyrights(is1);
69 skipCopyrights(is2);
70 while (true) {
71 int c1 = is1.read();
72 int c2 = is2.read();
73 if (c1 != c2) return false;
74 if (c1 == -1) break;
75 }
76 return true;
77 }
78
output(byte[] bytes, String fileName)79 public static void output(byte[] bytes, String fileName) throws IOException {
80 try (FileInputStream is = new FileInputStream(fileName)){
81 if (compare(new ByteArrayInputStream(bytes), new BufferedInputStream(is))) return;
82 } catch (FileNotFoundException e) {
83 }
84 try (FileOutputStream out = new FileOutputStream(fileName)) {
85 out.write(bytes);
86 }
87 }
88
getDelimiter(String fileName)89 public static String getDelimiter(String fileName) {
90
91 try (InputStream is = new BufferedInputStream(new FileInputStream(fileName))){
92 int c;
93 while ((c = is.read()) != -1) {
94 if (c == '\n') return "\n";
95 if (c == '\r') {
96 int c1 = is.read();
97 if (c1 == '\n') {
98 return "\r\n";
99 }
100 return "\r";
101 }
102 }
103 } catch (IOException e) {
104 }
105 return System.lineSeparator();
106 }
107
fixDelimiter(String str)108 String fixDelimiter(String str) {
109 if (delimiter.equals("\n")) return str;
110 int index = 0, length = str.length();
111 StringBuilder buffer = new StringBuilder();
112 while (index != -1) {
113 int start = index;
114 index = str.indexOf('\n', start);
115 if (index == -1) {
116 buffer.append(str.substring(start, length));
117 } else {
118 buffer.append(str.substring(start, index));
119 buffer.append(delimiter);
120 index++;
121 }
122 }
123 return buffer.toString();
124 }
125
getFunctionName(JNIMethod method)126 static String getFunctionName(JNIMethod method) {
127 return getFunctionName(method, method.getParameterTypes());
128 }
129
getFunctionName(JNIMethod method, JNIType[] paramTypes)130 static String getFunctionName(JNIMethod method, JNIType[] paramTypes) {
131 if ((method.getModifiers() & Modifier.NATIVE) == 0) return method.getName();
132 String function = toC(method.getName());
133 if (!method.isNativeUnique()) {
134 StringBuilder buffer = new StringBuilder();
135 buffer.append(function);
136 buffer.append("__");
137 for (JNIType paramType : paramTypes) {
138 buffer.append(toC(paramType.getTypeSignature(false)));
139 }
140 return buffer.toString();
141 }
142 return function;
143 }
144
loadFile(String file)145 static String loadFile (String file) {
146 try (FileReader fr = new FileReader(file);
147 BufferedReader br = new BufferedReader(fr)){
148 StringBuilder str = new StringBuilder();
149 char[] buffer = new char[1024];
150 int read;
151 while ((read = br.read(buffer)) != -1) {
152 str.append(buffer, 0, read);
153 }
154 fr.close();
155 return str.toString();
156 } catch (IOException e) {
157 throw new RuntimeException("File not found:" + file, e);
158 }
159 }
160
sort(JNIMethod[] methods)161 static void sort(JNIMethod[] methods) {
162 Arrays.sort(methods, (mth1, mth2) -> {
163 int result = mth1.getName().compareTo(mth2.getName());
164 return result != 0 ? result : getFunctionName(mth1).compareTo(getFunctionName(mth2));
165 });
166 }
167
sort(JNIField[] fields)168 static void sort(JNIField[] fields) {
169 Arrays.sort(fields, (a, b) -> a.getName().compareTo(b.getName()));
170 }
171
sort(JNIClass[] classes)172 static void sort(JNIClass[] classes) {
173 Arrays.sort(classes, (a, b) -> a.getName().compareTo(b.getName()));
174 }
175
split(String str, String separator)176 static String[] split(String str, String separator) {
177 StringTokenizer tk = new StringTokenizer(str, separator);
178 List<String> result = new ArrayList<>();
179 while (tk.hasMoreTokens()) {
180 result.add(tk.nextToken());
181 }
182 return result.toArray(new String[result.size()]);
183 }
184
toC(String str)185 static String toC(String str) {
186 int length = str.length();
187 StringBuilder buffer = new StringBuilder(length * 2);
188 for (int i = 0; i < length; i++) {
189 char c = str.charAt(i);
190 switch (c) {
191 case '_': buffer.append("_1"); break;
192 case ';': buffer.append("_2"); break;
193 case '[': buffer.append("_3"); break;
194 case '.': buffer.append("_"); break;
195 case '/': buffer.append("_"); break;
196 default: buffer.append(c);
197 }
198 }
199 return buffer.toString();
200 }
201
generate(JNIClass clazz)202 public abstract void generate(JNIClass clazz);
203
generateCopyright()204 public void generateCopyright() {
205 }
206
generateAutoGenNote()207 public void generateAutoGenNote() {
208 outputln("/* Note: This file was auto-generated by " + JNIGenerator.class.getName() + " */");
209 outputln("/* DO NOT EDIT - your changes will be lost. */");
210 outputln();
211 }
212
generateIncludes()213 public void generateIncludes() {
214 }
215
generate()216 public void generate() {
217 if (classes == null) return;
218 generateCopyright();
219 generateAutoGenNote();
220 generateIncludes();
221 sort(classes);
222 for (JNIClass clazz : classes) {
223 if (getGenerate(clazz)) generate(clazz);
224 if (progress != null) progress.step();
225 }
226 output.flush();
227 }
228
generateMetaData(String key)229 public void generateMetaData(String key) {
230 MetaData mt = getMetaData();
231 String data = mt.getMetaData(key, null);
232 if (data == null) return;
233 if (data.length() == 0) return;
234 outputln(fixDelimiter(data));
235 }
236
getClasses()237 public JNIClass[] getClasses() {
238 return classes;
239 }
240
getCPP()241 public boolean getCPP() {
242 for (JNIClass clazz : classes) {
243 if (clazz.getFlag(FLAG_CPP)) {
244 return true;
245 }
246 }
247 return false;
248 }
249
getDelimiter()250 public String getDelimiter() {
251 return delimiter;
252 }
253
getExtension()254 public String getExtension() {
255 return getCPP() ? ".cpp" : getM() ? ".m" : ".c";
256 }
257
getFileName()258 public String getFileName() {
259 return getOutputName() + getSuffix() + getExtension();
260 }
261
getGenerate(JNIItem item)262 protected boolean getGenerate(JNIItem item) {
263 return item.getGenerate();
264 }
265
getOutput()266 public PrintStream getOutput() {
267 return output;
268 }
269
getOutputName()270 public String getOutputName() {
271 return getMainClass().getSimpleName().toLowerCase();
272 }
273
getM()274 public boolean getM() {
275 for (JNIClass clazz : classes) {
276 if (clazz.getFlag(FLAG_M)) {
277 return true;
278 }
279 }
280 return false;
281 }
282
getMainClass()283 public JNIClass getMainClass() {
284 return mainClass;
285 }
286
getMetaData()287 public MetaData getMetaData() {
288 return metaData;
289 }
290
getProgressMonitor()291 public ProgressMonitor getProgressMonitor() {
292 return progress;
293 }
294
getSuffix()295 public String getSuffix() {
296 return "";
297 }
298
output(String str)299 public void output(String str) {
300 output.print(str);
301 }
302
outputln()303 public void outputln() {
304 output(getDelimiter());
305 }
306
outputln(String str)307 public void outputln(String str) {
308 output(str);
309 output(getDelimiter());
310 }
311
setClasses(JNIClass[] classes)312 public void setClasses(JNIClass[] classes) {
313 this.classes = classes;
314 }
315
setDelimiter(String delimiter)316 public void setDelimiter(String delimiter) {
317 this.delimiter = delimiter;
318 }
319
setMainClass(JNIClass mainClass)320 public void setMainClass(JNIClass mainClass) {
321 this.mainClass = mainClass;
322 }
323
setMetaData(MetaData data)324 public void setMetaData(MetaData data) {
325 metaData = data;
326 }
327
setOutput(PrintStream output)328 public void setOutput(PrintStream output) {
329 this.output = output;
330 }
331
setProgressMonitor(ProgressMonitor progress)332 public void setProgressMonitor(ProgressMonitor progress) {
333 this.progress = progress;
334 }
335
336 }
337