1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.io.PrintStream;
18import java.util.ArrayList;
19import java.util.HashSet;
20import java.util.Iterator;
21import java.util.List;
22
23public class JniCodeEmitter {
24
25    static final boolean mUseCPlusPlus = true;
26    protected boolean mUseContextPointer = true;
27    protected boolean mUseStaticMethods = false;
28    protected boolean mUseSimpleMethodNames = false;
29    protected boolean mUseHideCommentForAPI = false;
30    protected String mClassPathName;
31    protected ParameterChecker mChecker;
32    protected List<String> nativeRegistrations = new ArrayList<String>();
33    boolean needsExit;
34    protected static String indent = "    ";
35    HashSet<String> mFunctionsEmitted = new HashSet<String>();
36
37    public static String getJniName(JType jType) {
38        String jniName = "";
39        if (jType.isEGLHandle()) {
40            return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";";
41        } else if (jType.isClass()) {
42            return "L" + jType.getBaseType() + ";";
43        } else if (jType.isArray()) {
44            jniName = "[";
45        }
46
47        String baseType = jType.getBaseType();
48        if (baseType.equals("int")) {
49            jniName += "I";
50        } else if (baseType.equals("float")) {
51            jniName += "F";
52        } else if (baseType.equals("boolean")) {
53            jniName += "Z";
54        } else if (baseType.equals("short")) {
55            jniName += "S";
56        } else if (baseType.equals("long")) {
57            jniName += "J";
58        } else if (baseType.equals("byte")) {
59            jniName += "B";
60        } else if (baseType.equals("String")) {
61            jniName += "Ljava/lang/String;";
62        } else if (baseType.equals("void")) {
63            // nothing.
64        } else {
65            throw new RuntimeException("Unknown primitive basetype " + baseType);
66        }
67        return jniName;
68    }
69
70    public void emitCode(CFunc cfunc, String original,
71            PrintStream javaInterfaceStream,
72            PrintStream javaImplStream,
73            PrintStream cStream) {
74        JFunc jfunc;
75        String signature;
76        boolean duplicate;
77
78        if (cfunc.hasTypedPointerArg()) {
79            jfunc = JFunc.convert(cfunc, true);
80
81            // Don't emit duplicate functions
82            // These may appear because they are defined in multiple
83            // Java interfaces (e.g., GL11/GL11ExtensionPack)
84            signature = jfunc.toString();
85            duplicate = false;
86            if (mFunctionsEmitted.contains(signature)) {
87                duplicate = true;
88            } else {
89                mFunctionsEmitted.add(signature);
90            }
91
92            if (!duplicate) {
93                emitNativeDeclaration(jfunc, javaImplStream);
94                emitJavaCode(jfunc, javaImplStream);
95            }
96            if (javaInterfaceStream != null) {
97                emitJavaInterfaceCode(jfunc, javaInterfaceStream);
98            }
99            if (!duplicate) {
100                emitJniCode(jfunc, cStream);
101            }
102            // Don't create IOBuffer versions of the EGL functions
103            if (cfunc.hasEGLHandleArg()) {
104                return;
105            }
106        }
107
108        jfunc = JFunc.convert(cfunc, false);
109
110        signature = jfunc.toString();
111        duplicate = false;
112        if (mFunctionsEmitted.contains(signature)) {
113            duplicate = true;
114        } else {
115            mFunctionsEmitted.add(signature);
116        }
117
118        if (!duplicate) {
119            emitNativeDeclaration(jfunc, javaImplStream);
120        }
121        if (javaInterfaceStream != null) {
122            emitJavaInterfaceCode(jfunc, javaInterfaceStream);
123        }
124        if (!duplicate) {
125            emitJavaCode(jfunc, javaImplStream);
126            emitJniCode(jfunc, cStream);
127        }
128    }
129
130    public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
131        if (mUseHideCommentForAPI) {
132            out.println("    /* @hide C function " + jfunc.getCFunc().getOriginal() + " */");
133            out.println();
134        } else {
135            out.println("    // C function " + jfunc.getCFunc().getOriginal());
136            out.println();
137        }
138
139        emitFunction(jfunc, out, true, false);
140    }
141
142    public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
143        emitFunction(jfunc, out, false, true);
144    }
145
146    public void emitJavaCode(JFunc jfunc, PrintStream out) {
147        emitFunction(jfunc, out, false, false);
148    }
149
150    boolean isPointerFunc(JFunc jfunc) {
151        String name = jfunc.getName();
152        return (name.endsWith("Pointer") || name.endsWith("PointerOES"))
153            && jfunc.getCFunc().hasPointerArg();
154    }
155
156    void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
157        boolean isVoid = jfunc.getType().isVoid();
158        boolean isPointerFunc = isPointerFunc(jfunc);
159
160        if (!isVoid) {
161            out.println(iii +
162                        jfunc.getType() + " _returnValue;");
163        }
164        out.println(iii +
165                    (isVoid ? "" : "_returnValue = ") +
166                    jfunc.getName() +
167                    (isPointerFunc ? "Bounds" : "" ) +
168                    "(");
169
170        int numArgs = jfunc.getNumArgs();
171        for (int i = 0; i < numArgs; i++) {
172            String argName = jfunc.getArgName(i);
173            JType argType = jfunc.getArgType(i);
174
175            if (grabArray && argType.isTypedBuffer()) {
176                String typeName = argType.getBaseType();
177                typeName = typeName.substring(9, typeName.length() - 6);
178                out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
179                out.print(iii + indent + "getOffset(" + argName + ")");
180            } else {
181                out.print(iii + indent + argName);
182            }
183            if (i == numArgs - 1) {
184                if (isPointerFunc) {
185                    out.println(",");
186                    out.println(iii + indent + argName + ".remaining()");
187                } else {
188                    out.println();
189                }
190            } else {
191                out.println(",");
192            }
193        }
194
195        out.println(iii + ");");
196    }
197
198    void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
199            String iii) {
200        printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
201                "offset", "_remaining", iii);
202    }
203
204    void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
205            String offset, String remaining, String iii) {
206        out.println(iii + "    default:");
207        out.println(iii + "        _needed = 1;");
208        out.println(iii + "        break;");
209        out.println(iii + "}");
210
211        out.println(iii + "if (" + remaining + " < _needed) {");
212        out.println(iii + indent + "_exception = 1;");
213        out.println(iii + indent +
214                "_exceptionType = \"java/lang/IllegalArgumentException\";");
215        out.println(iii + indent +
216                "_exceptionMessage = \"" +
217                (isBuffer ? "remaining()" : "length - " + offset) +
218                " < needed\";");
219        out.println(iii + indent + "goto exit;");
220        out.println(iii + "}");
221
222        needsExit = true;
223    }
224
225    boolean isNullAllowed(CFunc cfunc, String cname) {
226        String[] checks = mChecker.getChecks(cfunc.getName());
227        int index = 1;
228        if (checks != null) {
229            while (index < checks.length) {
230                if (checks[index].equals("nullAllowed") &&
231                    checks[index + 1].equals(cname)) {
232                    return true;
233                } else {
234                    index = skipOneCheck(checks, index);
235                }
236            }
237        }
238        return false;
239    }
240
241    boolean hasCheckTest(CFunc cfunc) {
242        String[] checks = mChecker.getChecks(cfunc.getName());
243        int index = 1;
244        if (checks != null) {
245            while (index < checks.length) {
246                if (checks[index].startsWith("check")) {
247                    return true;
248                } else {
249                    index = skipOneCheck(checks, index);
250                }
251            }
252        }
253        return false;
254    }
255
256    boolean hasCheckTest(CFunc cfunc, String cname) {
257        String[] checks = mChecker.getChecks(cfunc.getName());
258        int index = 1;
259        if (checks != null) {
260            while (index < checks.length) {
261                if (checks[index].startsWith("check") &&
262                    cname != null && cname.equals(checks[index + 1])) {
263                    return true;
264                } else {
265                    index = skipOneCheck(checks, index);
266                }
267            }
268        }
269        return false;
270    }
271
272    boolean hasIfTest(CFunc cfunc) {
273        String[] checks = mChecker.getChecks(cfunc.getName());
274        int index = 1;
275        if (checks != null) {
276            while (index < checks.length) {
277                if (checks[index].startsWith("ifcheck")) {
278                    return true;
279                } else {
280                    index = skipOneCheck(checks, index);
281                }
282            }
283        }
284        return false;
285    }
286
287    int skipOneCheck(String[] checks, int index) {
288        if (checks[index].equals("return")) {
289            index += 2;
290        } else if (checks[index].startsWith("check")) {
291            index += 3;
292        } else if (checks[index].startsWith("sentinel")) {
293            index += 3;
294        } else if (checks[index].equals("ifcheck")) {
295            index += 5;
296        } else if (checks[index].equals("unsupported")) {
297            index += 1;
298        } else if (checks[index].equals("requires")) {
299            index += 2;
300        } else if (checks[index].equals("nullAllowed")) {
301            index += 2;
302        } else {
303            System.out.println("Error: unknown keyword \"" +
304                               checks[index] + "\"");
305            System.exit(0);
306        }
307
308        return index;
309    }
310
311    String getErrorReturnValue(CFunc cfunc) {
312        CType returnType = cfunc.getType();
313        boolean isVoid = returnType.isVoid();
314        if (isVoid) {
315            return null;
316        }
317
318        if (returnType.getBaseType().startsWith("EGL")) {
319            return "(" + returnType.getDeclaration() + ") 0";
320        }
321
322        String[] checks = mChecker.getChecks(cfunc.getName());
323
324        int index = 1;
325        if (checks != null) {
326            while (index < checks.length) {
327                if (checks[index].equals("return")) {
328                    return checks[index + 1];
329                } else {
330                    index = skipOneCheck(checks, index);
331                }
332            }
333        }
334
335        return null;
336    }
337
338    boolean isUnsupportedFunc(CFunc cfunc) {
339        String[] checks = mChecker.getChecks(cfunc.getName());
340        int index = 1;
341        if (checks != null) {
342            while (index < checks.length) {
343                if (checks[index].equals("unsupported")) {
344                    return true;
345                } else {
346                    index = skipOneCheck(checks, index);
347                }
348            }
349        }
350        return false;
351    }
352
353    String isRequiresFunc(CFunc cfunc) {
354        String[] checks = mChecker.getChecks(cfunc.getName());
355        int index = 1;
356        if (checks != null) {
357            while (index < checks.length) {
358                if (checks[index].equals("requires")) {
359                    return checks[index+1];
360                } else {
361                    index = skipOneCheck(checks, index);
362                }
363            }
364        }
365        return null;
366    }
367
368    void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
369            boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
370
371        String[] checks = mChecker.getChecks(cfunc.getName());
372
373        boolean lastWasIfcheck = false;
374
375        int index = 1;
376        if (checks != null) {
377            while (index < checks.length) {
378                if (checks[index].startsWith("check")) {
379                    if (lastWasIfcheck) {
380                        printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
381                                offset, remaining, iii);
382                    }
383                    lastWasIfcheck = false;
384                    if (cname != null && !cname.equals(checks[index + 1])) {
385                        index += 3;
386                        continue;
387                    }
388                    out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {");
389                    out.println(iii + indent + "_exception = 1;");
390                    String exceptionClassName = "java/lang/IllegalArgumentException";
391                    // If the "check" keyword was of the form
392                    // "check_<class name>", use the class name in the
393                    // exception to be thrown
394                    int underscore = checks[index].indexOf('_');
395                    if (underscore >= 0) {
396                        String abbr = checks[index].substring(underscore + 1);
397                        if (abbr.equals("AIOOBE")) {
398                            exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";
399                        } else {
400                            throw new RuntimeException("unknown exception abbreviation: " + abbr);
401                        }
402                    }
403                    out.println(iii + indent +
404                                "_exceptionType = \""+exceptionClassName+"\";");
405                    out.println(iii + indent +
406                               "_exceptionMessage = \"" +
407                               (isBuffer ? "remaining()" : "length - " +
408                               offset) + " < " + checks[index + 2] +
409                               " < needed\";");
410
411                    out.println(iii + indent + "goto exit;");
412                    out.println(iii + "}");
413
414                    needsExit = true;
415
416                    index += 3;
417                } else if (checks[index].equals("ifcheck")) {
418                    String[] matches = checks[index + 4].split(",");
419
420                    if (!lastWasIfcheck) {
421                        out.println(iii + "int _needed;");
422                        out.println(iii + "switch (" + checks[index + 3] + ") {");
423                    }
424
425                    for (int i = 0; i < matches.length; i++) {
426                        out.println("#if defined(" + matches[i] + ")");
427                        out.println(iii + "    case " + matches[i] + ":");
428                        out.println("#endif // defined(" + matches[i] + ")");
429                    }
430                    out.println(iii + "        _needed = " + checks[index + 2] + ";");
431                    out.println(iii + "        break;");
432
433                    lastWasIfcheck = true;
434                    index += 5;
435                } else {
436                    index = skipOneCheck(checks, index);
437                }
438            }
439        }
440
441        if (lastWasIfcheck) {
442            printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
443        }
444    }
445
446    void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out,
447            boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
448
449        String[] checks = mChecker.getChecks(cfunc.getName());
450
451        int index = 1;
452        if (checks != null) {
453            while (index < checks.length) {
454                if (checks[index].startsWith("sentinel")) {
455                    if (cname != null && !cname.equals(checks[index + 1])) {
456                        index += 3;
457                        continue;
458                    }
459
460                    out.println(iii + cname + "_sentinel = false;");
461                    out.println(iii + "for (int i = " + remaining +
462                                " - 1; i >= 0; i--)  {");
463                    out.println(iii + indent + "if (" + cname +
464                                "[i] == " + checks[index + 2] + "){");
465                    out.println(iii + indent + indent +
466                                cname + "_sentinel = true;");
467                    out.println(iii + indent + indent + "break;");
468                    out.println(iii + indent + "}");
469                    out.println(iii + "}");
470                    out.println(iii +
471                                "if (" + cname + "_sentinel == false) {");
472                    out.println(iii + indent + "_exception = 1;");
473                    out.println(iii + indent +
474                                "_exceptionType = \"java/lang/IllegalArgumentException\";");
475                    out.println(iii + indent + "_exceptionMessage = \"" + cname +
476                                " must contain " + checks[index + 2] + "!\";");
477                    out.println(iii + indent + "goto exit;");
478                    out.println(iii + "}");
479
480                    needsExit = true;
481                    index += 3;
482                } else {
483                    index = skipOneCheck(checks, index);
484                }
485            }
486        }
487    }
488
489    void emitStringCheck(CFunc cfunc, String cname, PrintStream out, String iii) {
490
491        String[] checks = mChecker.getChecks(cfunc.getName());
492
493        int index = 1;
494        if (checks != null) {
495            while (index < checks.length) {
496                if (checks[index].startsWith("check")) {
497                    if (cname != null && !cname.equals(checks[index + 1])) {
498                    index += 3;
499                    continue;
500                }
501                    out.println(iii + "_stringlen = _env->GetStringUTFLength(" + cname + ");");
502                    out.println(iii + "if (" + checks[index + 2] + " > _stringlen) {");
503                    out.println(iii + indent + "_exception = 1;");
504                    out.println(iii + indent +
505                            "_exceptionType = \"java/lang/ArrayIndexOutOfBoundsException\";");
506                    out.println(iii + indent +
507                            "_exceptionMessage = \"length of " + cname + " is shorter than " +
508                            checks[index + 2] + " argument\";");
509                    out.println(iii + indent + "goto exit;");
510                    out.println(iii + "}");
511                    index += 3;
512                    needsExit = true;
513                } else {
514                    index = skipOneCheck(checks, index);
515                }
516            }
517        }
518    }
519
520    void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) {
521
522        String[] checks = mChecker.getChecks(cfunc.getName());
523
524        int index = 1;
525        if (checks != null) {
526            while (index < checks.length) {
527                if (checks[index].startsWith("sentinel")) {
528                    String cname = checks[index + 1];
529                    out.println(indent + "bool " + cname + "_sentinel = false;");
530
531                    index += 3;
532
533                } else {
534                    index = skipOneCheck(checks, index);
535                }
536            }
537        }
538    }
539
540    boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
541        if (nonPrimitiveArgs.size() > 0) {
542            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
543                int idx = nonPrimitiveArgs.get(i).intValue();
544                int cIndex = jfunc.getArgCIndex(idx);
545                if (jfunc.getArgType(idx).isArray()) {
546                    if (!cfunc.getArgType(cIndex).isConst()) {
547                        return true;
548                    }
549                } else if (jfunc.getArgType(idx).isBuffer()) {
550                    if (!cfunc.getArgType(cIndex).isConst()) {
551                        return true;
552                    }
553                }
554            }
555        }
556
557        return false;
558    }
559
560    /**
561     * Emit a function in several variants:
562     *
563     * if nativeDecl: public native <returntype> func(args);
564     *
565     * if !nativeDecl:
566     *   if interfaceDecl:  public <returntype> func(args);
567     *   if !interfaceDecl: public <returntype> func(args) { body }
568     */
569    void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
570        boolean isPointerFunc = isPointerFunc(jfunc);
571
572        if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
573            // If it's not a pointer function, we've already emitted it
574            // with nativeDecl == true
575            return;
576        }
577
578        String maybeStatic = mUseStaticMethods ? "static " : "";
579
580        if (isPointerFunc) {
581            out.println(indent +
582                        (nativeDecl ? "private " + maybeStatic +"native " :
583                         (interfaceDecl ? "" : "public ") + maybeStatic) +
584                        jfunc.getType() + " " +
585                        jfunc.getName() +
586                        (nativeDecl ? "Bounds" : "") +
587                        "(");
588        } else {
589            out.println(indent +
590                        (nativeDecl ? "public " + maybeStatic +"native " :
591                         (interfaceDecl ? "" : "public ") + maybeStatic) +
592                        jfunc.getType() + " " +
593                        jfunc.getName() +
594                        "(");
595        }
596
597        int numArgs = jfunc.getNumArgs();
598        for (int i = 0; i < numArgs; i++) {
599            String argName = jfunc.getArgName(i);
600            JType argType = jfunc.getArgType(i);
601
602            out.print(indent + indent + argType + " " + argName);
603            if (i == numArgs - 1) {
604                if (isPointerFunc && nativeDecl) {
605                    out.println(",");
606                    out.println(indent + indent + "int remaining");
607                } else {
608                    out.println();
609                }
610            } else {
611                out.println(",");
612            }
613        }
614
615        if (nativeDecl || interfaceDecl) {
616            out.println(indent + ");");
617        } else {
618            out.println(indent + ") {");
619
620            String iii = indent + indent;
621
622            // emitBoundsChecks(jfunc, out, iii);
623            emitFunctionCall(jfunc, out, iii, false);
624
625            // Set the pointer after we call the native code, so that if
626            // the native code throws an exception we don't modify the
627            // pointer. We assume that the native code is written so that
628            // if an exception is thrown, then the underlying glXXXPointer
629            // function will not have been called.
630
631            String fname = jfunc.getName();
632            if (isPointerFunc) {
633                // TODO - deal with VBO variants
634                if (fname.equals("glColorPointer")) {
635                    out.println(iii + "if ((size == 4) &&");
636                    out.println(iii + "    ((type == GL_FLOAT) ||");
637                    out.println(iii + "     (type == GL_UNSIGNED_BYTE) ||");
638                    out.println(iii + "     (type == GL_FIXED)) &&");
639                    out.println(iii + "    (stride >= 0)) {");
640                    out.println(iii + indent + "_colorPointer = pointer;");
641                    out.println(iii + "}");
642                } else if (fname.equals("glNormalPointer")) {
643                    out.println(iii + "if (((type == GL_FLOAT) ||");
644                    out.println(iii + "     (type == GL_BYTE) ||");
645                    out.println(iii + "     (type == GL_SHORT) ||");
646                    out.println(iii + "     (type == GL_FIXED)) &&");
647                    out.println(iii + "    (stride >= 0)) {");
648                    out.println(iii + indent + "_normalPointer = pointer;");
649                    out.println(iii + "}");
650                } else if (fname.equals("glTexCoordPointer")) {
651                    out.println(iii + "if (((size == 2) ||");
652                    out.println(iii + "     (size == 3) ||");
653                    out.println(iii + "     (size == 4)) &&");
654                    out.println(iii + "    ((type == GL_FLOAT) ||");
655                    out.println(iii + "     (type == GL_BYTE) ||");
656                    out.println(iii + "     (type == GL_SHORT) ||");
657                    out.println(iii + "     (type == GL_FIXED)) &&");
658                    out.println(iii + "    (stride >= 0)) {");
659                    out.println(iii + indent + "_texCoordPointer = pointer;");
660                    out.println(iii + "}");
661                } else if (fname.equals("glVertexPointer")) {
662                    out.println(iii + "if (((size == 2) ||");
663                    out.println(iii + "     (size == 3) ||");
664                    out.println(iii + "     (size == 4)) &&");
665                    out.println(iii + "    ((type == GL_FLOAT) ||");
666                    out.println(iii + "     (type == GL_BYTE) ||");
667                    out.println(iii + "     (type == GL_SHORT) ||");
668                    out.println(iii + "     (type == GL_FIXED)) &&");
669                    out.println(iii + "    (stride >= 0)) {");
670                    out.println(iii + indent + "_vertexPointer = pointer;");
671                    out.println(iii + "}");
672                } else if (fname.equals("glPointSizePointerOES")) {
673                    out.println(iii + "if (((type == GL_FLOAT) ||");
674                    out.println(iii + "     (type == GL_FIXED)) &&");
675                    out.println(iii + "    (stride >= 0)) {");
676                    out.println(iii + indent + "_pointSizePointerOES = pointer;");
677                    out.println(iii + "}");
678                } else if (fname.equals("glMatrixIndexPointerOES")) {
679                    out.println(iii + "if (((size == 2) ||");
680                    out.println(iii + "     (size == 3) ||");
681                    out.println(iii + "     (size == 4)) &&");
682                    out.println(iii + "    ((type == GL_FLOAT) ||");
683                    out.println(iii + "     (type == GL_BYTE) ||");
684                    out.println(iii + "     (type == GL_SHORT) ||");
685                    out.println(iii + "     (type == GL_FIXED)) &&");
686                    out.println(iii + "    (stride >= 0)) {");
687                    out.println(iii + indent + "_matrixIndexPointerOES = pointer;");
688                    out.println(iii + "}");
689                } else if (fname.equals("glWeightPointer")) {
690                    out.println(iii + "if (((size == 2) ||");
691                    out.println(iii + "     (size == 3) ||");
692                    out.println(iii + "     (size == 4)) &&");
693                    out.println(iii + "    ((type == GL_FLOAT) ||");
694                    out.println(iii + "     (type == GL_BYTE) ||");
695                    out.println(iii + "     (type == GL_SHORT) ||");
696                    out.println(iii + "     (type == GL_FIXED)) &&");
697                    out.println(iii + "    (stride >= 0)) {");
698                    out.println(iii + indent + "_weightPointerOES = pointer;");
699                    out.println(iii + "}");
700                }
701            }
702
703            boolean isVoid = jfunc.getType().isVoid();
704
705            if (!isVoid) {
706                out.println(indent + indent + "return _returnValue;");
707            }
708            out.println(indent + "}");
709        }
710        out.println();
711    }
712
713    public void addNativeRegistration(String s) {
714        nativeRegistrations.add(s);
715    }
716
717    public void emitNativeRegistration(String registrationFunctionName,
718            PrintStream cStream) {
719        cStream.println("static const char *classPathName = \"" +
720                        mClassPathName +
721                        "\";");
722        cStream.println();
723
724        cStream.println("static const JNINativeMethod methods[] = {");
725
726        cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
727
728        Iterator<String> i = nativeRegistrations.iterator();
729        while (i.hasNext()) {
730            cStream.println(i.next());
731        }
732
733        cStream.println("};");
734        cStream.println();
735
736
737        cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
738        cStream.println("{");
739        cStream.println(indent +
740                        "int err;");
741
742        cStream.println(indent +
743                        "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
744
745        cStream.println(indent + "return err;");
746        cStream.println("}");
747    }
748
749    public JniCodeEmitter() {
750        super();
751    }
752
753    String getJniType(JType jType) {
754        if (jType.isVoid()) {
755            return "void";
756        }
757
758        String baseType = jType.getBaseType();
759        if (jType.isPrimitive()) {
760            if (baseType.equals("String")) {
761                return "jstring";
762            } else {
763                return "j" + baseType;
764            }
765        } else if (jType.isArray()) {
766            return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array";
767        } else {
768            return "jobject";
769        }
770    }
771
772    String getJniMangledName(String name) {
773        name = name.replaceAll("_", "_1");
774        name = name.replaceAll(";", "_2");
775        name = name.replaceAll("\\[", "_3");
776        return name;
777    }
778
779    public void emitJniCode(JFunc jfunc, PrintStream out) {
780        CFunc cfunc = jfunc.getCFunc();
781
782        // Emit comment identifying original C function
783        //
784        // Example:
785        //
786        // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
787        //
788        out.println("/* " + cfunc.getOriginal() + " */");
789
790        // Emit JNI signature (name)
791        //
792        // Example:
793        //
794        // void
795        // android_glClipPlanef__I_3FI
796        //
797
798        String outName = "android_" + jfunc.getName();
799        boolean isPointerFunc = isPointerFunc(jfunc);
800        boolean isPointerOffsetFunc =
801            (outName.endsWith("Pointer") || outName.endsWith("PointerOES") ||
802             outName.endsWith("glDrawElements") ||
803             outName.endsWith("glDrawRangeElements") ||
804             outName.endsWith("glTexImage2D") ||
805             outName.endsWith("glTexSubImage2D") ||
806             outName.endsWith("glCompressedTexImage2D") ||
807             outName.endsWith("glCompressedTexSubImage2D") ||
808             outName.endsWith("glTexImage3D") ||
809             outName.endsWith("glTexSubImage3D") ||
810             outName.endsWith("glCompressedTexImage3D") ||
811             outName.endsWith("glCompressedTexSubImage3D") ||
812             outName.endsWith("glReadPixels"))
813            && !jfunc.getCFunc().hasPointerArg();
814        if (isPointerFunc) {
815            outName += "Bounds";
816        }
817
818        out.print("static ");
819        out.println(getJniType(jfunc.getType()));
820        out.print(outName);
821
822        String rsignature = getJniName(jfunc.getType());
823
824        String signature = "";
825        int numArgs = jfunc.getNumArgs();
826        for (int i = 0; i < numArgs; i++) {
827            JType argType = jfunc.getArgType(i);
828            signature += getJniName(argType);
829        }
830        if (isPointerFunc) {
831            signature += "I";
832        }
833
834        // Append signature to function name
835        String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
836        if (!mUseSimpleMethodNames) {
837            out.print("__" + sig);
838            outName += "__" + sig;
839        }
840
841        signature = signature.replace('.', '/');
842        rsignature = rsignature.replace('.', '/');
843
844        out.println();
845        if (rsignature.length() == 0) {
846            rsignature = "V";
847        }
848
849        String s = "{\"" +
850            jfunc.getName() +
851            (isPointerFunc ? "Bounds" : "") +
852            "\", \"(" + signature +")" +
853            rsignature +
854            "\", (void *) " +
855            outName +
856            " },";
857        nativeRegistrations.add(s);
858
859        List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
860        List<Integer> stringArgs = new ArrayList<Integer>();
861        int numBufferArgs = 0;
862        List<String> bufferArgNames = new ArrayList<String>();
863        List<JType> bufferArgTypes = new ArrayList<JType>();
864
865        // Emit JNI signature (arguments)
866        //
867        // Example:
868        //
869        // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
870        //
871        out.print("  (JNIEnv *_env, jobject _this");
872        for (int i = 0; i < numArgs; i++) {
873            out.print(", ");
874            JType argType = jfunc.getArgType(i);
875            String suffix = "";
876            if (!argType.isPrimitive()) {
877                if (argType.isArray()) {
878                    suffix = "_ref";
879                } else if (argType.isBuffer()) {
880                    suffix = "_buf";
881                }
882                nonPrimitiveArgs.add(new Integer(i));
883                if (jfunc.getArgType(i).isBuffer()) {
884                    int cIndex = jfunc.getArgCIndex(i);
885                    String cname = cfunc.getArgName(cIndex);
886                    bufferArgNames.add(cname);
887                    bufferArgTypes.add(jfunc.getArgType(i));
888                    numBufferArgs++;
889                }
890            }
891
892            if (argType.isString()) {
893                stringArgs.add(new Integer(i));
894            }
895
896            out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
897        }
898        if (isPointerFunc) {
899            out.print(", jint remaining");
900        }
901        out.println(") {");
902
903        int numArrays = 0;
904        int numBuffers = 0;
905        int numStrings = 0;
906        for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
907            int idx = nonPrimitiveArgs.get(i).intValue();
908            JType argType = jfunc.getArgType(idx);
909            if (argType.isArray()) {
910                ++numArrays;
911            }
912            if (argType.isBuffer()) {
913                ++numBuffers;
914            }
915            if (argType.isString()) {
916                ++numStrings;
917            }
918        }
919
920        // Emit method body
921
922        // Emit local variable declarations for _exception and _returnValue
923        //
924        // Example:
925        //
926        // android::gl::ogles_context_t *ctx;
927        //
928        // jint _exception;
929        // GLenum _returnValue;
930        //
931        CType returnType = cfunc.getType();
932        boolean isVoid = returnType.isVoid();
933
934        boolean isUnsupported = isUnsupportedFunc(cfunc);
935        if (isUnsupported) {
936            out.println(indent +
937                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
938            out.println(indent +
939                        "    \"" + cfunc.getName() + "\");");
940            if (!isVoid) {
941                String retval = getErrorReturnValue(cfunc);
942                if (cfunc.getType().isEGLHandle()) {
943                    String baseType = cfunc.getType().getBaseType().toLowerCase();
944                    out.println(indent +
945                                "return toEGLHandle(_env, " + baseType + "Class, " +
946                                baseType + "Constructor, " + retval + ");");
947                } else {
948                    out.println(indent + "return " + retval + ";");
949                }
950            }
951            out.println("}");
952            out.println();
953            return;
954        }
955
956        String requiresExtension = isRequiresFunc(cfunc);
957        if (requiresExtension != null) {
958            out.println(indent +
959                        "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");
960            out.println(indent + indent +
961                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
962            out.println(indent + indent +
963                        "    \"" + cfunc.getName() + "\");");
964            if (isVoid) {
965                out.println(indent + indent + "    return;");
966            } else {
967                String retval = getErrorReturnValue(cfunc);
968                if (cfunc.getType().isEGLHandle()) {
969                    String baseType = cfunc.getType().getBaseType().toLowerCase();
970                    out.println(indent +
971                                "return toEGLHandle(_env, " + baseType + "Class, " +
972                                baseType + "Constructor, " + retval + ");");
973                } else {
974                    out.println(indent + "return " + retval + ";");
975                }
976            }
977            out.println(indent + "}");
978        }
979        if (mUseContextPointer) {
980            out.println(indent +
981                "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
982        }
983
984        boolean initializeReturnValue = stringArgs.size() > 0;
985        boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0)
986                                             && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs)
987                                                 || (cfunc.hasPointerArg() && numArrays > 0))
988                                         || (numBufferArgs > 0)
989                                         || hasCheckTest(cfunc)
990                                         || hasIfTest(cfunc))
991                                         || (stringArgs.size() > 0);
992        // mChecker.getChecks(cfunc.getName()) != null
993        // Emit an _exeption variable if there will be error checks
994        if (emitExceptionCheck) {
995            out.println(indent + "jint _exception = 0;");
996            out.println(indent + "const char * _exceptionType = NULL;");
997            out.println(indent + "const char * _exceptionMessage = NULL;");
998        }
999
1000        // Emit a single _array or multiple _XXXArray variables
1001        if (numBufferArgs == 1) {
1002            JType bufferType = bufferArgTypes.get(0);
1003            if (bufferType.isTypedBuffer()) {
1004                String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
1005                out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;");
1006            } else {
1007                out.println(indent + "jarray _array = (jarray) 0;");
1008            }
1009            out.println(indent + "jint _bufferOffset = (jint) 0;");
1010        } else {
1011            for (int i = 0; i < numBufferArgs; i++) {
1012                JType bufferType = bufferArgTypes.get(0);
1013                if (bufferType.isTypedBuffer()) {
1014                    String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
1015                    out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) +
1016                                "Array = (" + typedArrayType + ") 0;");
1017                } else {
1018                    out.println(indent + "jarray _" + bufferArgNames.get(i) +
1019                                "Array = (jarray) 0;");
1020                }
1021                out.println(indent + "jint _" + bufferArgNames.get(i) +
1022                            "BufferOffset = (jint) 0;");
1023            }
1024        }
1025        if (!isVoid) {
1026            String retval = getErrorReturnValue(cfunc);
1027            if (retval != null) {
1028                out.println(indent + returnType.getDeclaration() +
1029                            " _returnValue = " + retval + ";");
1030            } else if (initializeReturnValue) {
1031                out.println(indent + returnType.getDeclaration() +
1032                            " _returnValue = 0;");
1033            } else {
1034                out.println(indent + returnType.getDeclaration() +
1035                            " _returnValue;");
1036            }
1037        }
1038
1039        // Emit local variable declarations for EGL Handles
1040        //
1041        // Example:
1042        //
1043        // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface);
1044        //
1045        if (nonPrimitiveArgs.size() > 0) {
1046            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1047                int idx = nonPrimitiveArgs.get(i).intValue();
1048                int cIndex = jfunc.getArgCIndex(idx);
1049                String cname = cfunc.getArgName(cIndex);
1050
1051                if (jfunc.getArgType(idx).isBuffer()
1052                   || jfunc.getArgType(idx).isArray()
1053                   || !jfunc.getArgType(idx).isEGLHandle())
1054                    continue;
1055
1056                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
1057                String decl = type.getDeclaration();
1058                out.println(indent +
1059                            decl + " " + cname + "_native = (" +
1060                            decl + ") fromEGLHandle(_env, " +
1061                            type.getBaseType().toLowerCase() +
1062                            "GetHandleID, " + jfunc.getArgName(idx) +
1063                            ");");
1064            }
1065        }
1066
1067        // Emit local variable declarations for element/sentinel checks
1068        //
1069        // Example:
1070        //
1071        // bool attrib_list_sentinel_found = false;
1072        //
1073        emitLocalVariablesForSentinel(cfunc, out);
1074
1075        // Emit local variable declarations for pointer arguments
1076        //
1077        // Example:
1078        //
1079        // GLfixed *eqn_base;
1080        // GLfixed *eqn;
1081        //
1082        String offset = "offset";
1083        String remaining = "_remaining";
1084        if (nonPrimitiveArgs.size() > 0) {
1085            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1086                int idx = nonPrimitiveArgs.get(i).intValue();
1087                int cIndex = jfunc.getArgCIndex(idx);
1088                String cname = cfunc.getArgName(cIndex);
1089
1090                if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray())
1091                    continue;
1092
1093                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
1094                String decl = type.getDeclaration();
1095                if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
1096                    out.println(indent +
1097                                decl +
1098                                (decl.endsWith("*") ? "" : " ") +
1099                                jfunc.getArgName(idx) +
1100                                "_base = (" + decl + ") 0;");
1101                }
1102                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1103                    "_" + cname + "Remaining";
1104                out.println(indent +
1105                            "jint " + remaining + ";");
1106                out.println(indent +
1107                                decl +
1108                                (decl.endsWith("*") ? "" : " ") +
1109                                jfunc.getArgName(idx) +
1110                                " = (" + decl + ") 0;");
1111            }
1112
1113            out.println();
1114        }
1115
1116        // Emit local variable declaration for strings
1117        if (stringArgs.size() > 0) {
1118            boolean requiresStringLengthCheck = false;
1119            for (int i = 0; i < stringArgs.size(); i++) {
1120                int idx = stringArgs.get(i).intValue();
1121                int cIndex = jfunc.getArgCIndex(idx);
1122                String cname = cfunc.getArgName(cIndex);
1123
1124                out.println(indent + "const char* _native" + cname + " = 0;");
1125                if (hasCheckTest(cfunc, cname)) {
1126                    requiresStringLengthCheck = true;
1127                }
1128            }
1129
1130            if (requiresStringLengthCheck) {
1131                out.println(indent + "jsize _stringlen = 0;");
1132            }
1133
1134            out.println();
1135        }
1136
1137        // Null pointer checks and GetStringUTFChars
1138        if (stringArgs.size() > 0) {
1139            for (int i = 0; i < stringArgs.size(); i++) {
1140                int idx = stringArgs.get(i).intValue();
1141                int cIndex = jfunc.getArgCIndex(idx);
1142                String cname = cfunc.getArgName(cIndex);
1143
1144                boolean nullAllowed = isNullAllowed(cfunc, cname);
1145                String nullAllowedIndent = nullAllowed ? indent : "";
1146
1147                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
1148                String decl = type.getDeclaration();
1149
1150                if (nullAllowed) {
1151                    out.println(indent + "if (" + cname + ") {");
1152                } else {
1153                    needsExit = true;
1154                    out.println(indent + "if (!" + cname + ") {");
1155                    out.println(indent + indent + "_exception = 1;");
1156                    out.println(indent + indent +
1157                            "_exceptionType = \"java/lang/IllegalArgumentException\";");
1158                    out.println(indent + indent +
1159                            "_exceptionMessage = \"" + cname + " == null\";");
1160                    out.println(indent + indent + "goto exit;");
1161                    out.println(indent + "}");
1162                }
1163
1164                out.println(nullAllowedIndent + indent + "_native" + cname +
1165                        " = _env->GetStringUTFChars(" + cname + ", 0);");
1166
1167                emitStringCheck(cfunc, cname, out, nullAllowedIndent + indent);
1168
1169                if (nullAllowed) {
1170                    out.println(indent + "}");
1171                }
1172            }
1173
1174            out.println();
1175        }
1176
1177        // Emit 'GetPrimitiveArrayCritical' for non-object arrays
1178        // Emit 'GetPointer' calls for Buffer pointers
1179        if (nonPrimitiveArgs.size() > 0) {
1180            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1181                int idx = nonPrimitiveArgs.get(i).intValue();
1182                int cIndex = jfunc.getArgCIndex(idx);
1183
1184                String cname = cfunc.getArgName(cIndex);
1185                offset = numArrays <= 1 ? "offset" :
1186                    cname + "Offset";
1187                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1188                    "_" + cname + "Remaining";
1189
1190                boolean nullAllowed = isNullAllowed(cfunc, cname);
1191                String nullAllowedIndent = nullAllowed ? indent : "";
1192
1193                if (jfunc.getArgType(idx).isArray()
1194                       && !jfunc.getArgType(idx).isEGLHandle()) {
1195                    needsExit = true;
1196
1197                    if (nullAllowed) {
1198                        out.println(indent + "if (" + cname + "_ref) {");
1199                    }
1200                    else
1201                    {
1202                        out.println(indent + "if (!" + cname + "_ref) {");
1203                        out.println(indent + indent + "_exception = 1;");
1204                        out.println(indent + indent +
1205                                "_exceptionType = " +
1206                                "\"java/lang/IllegalArgumentException\";");
1207                        out.println(indent + indent +
1208                                "_exceptionMessage = \"" + cname +
1209                                " == null\";");
1210                        out.println(indent + indent + "goto exit;");
1211                        out.println(indent + "}");
1212                    }
1213
1214                    out.println(nullAllowedIndent + indent + "if (" + offset +
1215                            " < 0) {");
1216                    out.println(nullAllowedIndent + indent + indent +
1217                            "_exception = 1;");
1218                    out.println(nullAllowedIndent + indent + indent +
1219                            "_exceptionType = " +
1220                            "\"java/lang/IllegalArgumentException\";");
1221                    out.println(nullAllowedIndent + indent + indent +
1222                            "_exceptionMessage = \"" + offset +" < 0\";");
1223                    out.println(nullAllowedIndent + indent + indent +
1224                            "goto exit;");
1225                    out.println(nullAllowedIndent + indent + "}");
1226
1227                    out.println(nullAllowedIndent + indent + remaining + " = " +
1228                            (mUseCPlusPlus ? "_env" : "(*_env)") +
1229                            "->GetArrayLength(" +
1230                            (mUseCPlusPlus ? "" : "_env, ") +
1231                            cname + "_ref) - " + offset + ";");
1232
1233                    emitNativeBoundsChecks(cfunc, cname, out, false,
1234                            emitExceptionCheck, offset, remaining,
1235                            nullAllowedIndent + indent);
1236
1237                    out.println(nullAllowedIndent + indent +
1238                                cname +
1239                                "_base = (" +
1240                                cfunc.getArgType(cIndex).getDeclaration() +
1241                                ")");
1242                    String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray();
1243                    out.println(nullAllowedIndent + indent + "    " +
1244                                (mUseCPlusPlus ? "_env" : "(*_env)") +
1245                                "->" + arrayGetter + "(" +
1246                                (mUseCPlusPlus ? "" : "_env, ") +
1247                                jfunc.getArgName(idx) +
1248                                "_ref, (jboolean *)0);");
1249                    out.println(nullAllowedIndent + indent +
1250                                cname + " = " + cname + "_base + " + offset + ";");
1251
1252                    emitSentinelCheck(cfunc, cname, out, false,
1253                            emitExceptionCheck, offset, remaining,
1254                            nullAllowedIndent + indent);
1255
1256                    if (nullAllowed) {
1257                        out.println(indent + "}");
1258                    }
1259
1260                    out.println();
1261                } else if (jfunc.getArgType(idx).isArray()
1262                              && jfunc.getArgType(idx).isEGLHandle()) {
1263                    needsExit = true;
1264
1265                    if (nullAllowed) {
1266                        out.println(indent + "if (" + cname + "_ref) {");
1267                    }
1268                    else
1269                    {
1270                        out.println(indent + "if (!" + cname + "_ref) {");
1271                        out.println(indent + indent + "_exception = 1;");
1272                        out.println(indent + indent + "_exceptionType = " +
1273                                "\"java/lang/IllegalArgumentException\";");
1274                        out.println(indent + indent + "_exceptionMessage = \"" +
1275                                cname +" == null\";");
1276                        out.println(indent + indent + "goto exit;");
1277                        out.println(indent + "}");
1278                    }
1279
1280                    out.println(nullAllowedIndent + indent + "if (" + offset +
1281                            " < 0) {");
1282                    out.println(nullAllowedIndent + indent + indent +
1283                            "_exception = 1;");
1284                    out.println(nullAllowedIndent + indent + indent +
1285                            "_exceptionType = " +
1286                            "\"java/lang/IllegalArgumentException\";");
1287                    out.println(nullAllowedIndent + indent + indent +
1288                            "_exceptionMessage = \"" + offset +" < 0\";");
1289                    out.println(nullAllowedIndent + indent + indent +
1290                            "goto exit;");
1291                    out.println(nullAllowedIndent + indent + "}");
1292
1293                    out.println(nullAllowedIndent + indent + remaining + " = " +
1294                                    (mUseCPlusPlus ? "_env" : "(*_env)") +
1295                                    "->GetArrayLength(" +
1296                                    (mUseCPlusPlus ? "" : "_env, ") +
1297                                    cname + "_ref) - " + offset + ";");
1298                    emitNativeBoundsChecks(cfunc, cname, out, false,
1299                            emitExceptionCheck, offset, remaining,
1300                            nullAllowedIndent + indent);
1301                    out.println(nullAllowedIndent + indent +
1302                                jfunc.getArgName(idx) + " = new " +
1303                                cfunc.getArgType(cIndex).getBaseType() +
1304                               "["+ remaining + "];");
1305
1306                    if (nullAllowed) {
1307                        out.println(indent + "}");
1308                    }
1309
1310                    out.println();
1311                } else if (jfunc.getArgType(idx).isBuffer()) {
1312                    needsExit = needsExit || (!nullAllowed && !isPointerFunc);
1313
1314                    String array = numBufferArgs <= 1 ? "_array" :
1315                        "_" + cfunc.getArgName(cIndex) + "Array";
1316                    String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1317                        "_" + cfunc.getArgName(cIndex) + "BufferOffset";
1318
1319                    nullAllowed = nullAllowed || isPointerFunc;
1320                    if (nullAllowed) {
1321                        out.println(indent + "if (" + cname + "_buf) {");
1322                        out.print(indent);
1323                    }
1324                    else
1325                    {
1326                        out.println(indent + "if (!" + cname + "_buf) {");
1327                        out.println(indent + indent + "_exception = 1;");
1328                        out.println(indent + indent + "_exceptionType = " +
1329                                "\"java/lang/IllegalArgumentException\";");
1330                        out.println(indent + indent + "_exceptionMessage = \"" +
1331                                cname +" == null\";");
1332                        out.println(indent + indent + "goto exit;");
1333                        out.println(indent + "}");
1334                    }
1335
1336                    if (isPointerFunc) {
1337                        out.println(indent +
1338                                cname +
1339                                " = (" +
1340                                cfunc.getArgType(cIndex).getDeclaration() +
1341                                ") getDirectBufferPointer(_env, " +
1342                                cname + "_buf);");
1343                        String iii = "    ";
1344                        out.println(iii + indent + "if ( ! " + cname + " ) {");
1345                        out.println(iii + indent + indent + "return;");
1346                        out.println(iii + indent + "}");
1347                    } else {
1348                        out.println(indent +
1349                                    cname +
1350                                    " = (" +
1351                                    cfunc.getArgType(cIndex).getDeclaration() +
1352                                    ")getPointer(_env, " +
1353                                    cname +
1354                                    "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset +
1355                                    ");");
1356                    }
1357
1358                    emitNativeBoundsChecks(cfunc, cname, out, true,
1359                                           emitExceptionCheck,
1360                                           offset, remaining, nullAllowed ? "        " : "    ");
1361
1362                    if (nullAllowed) {
1363                        out.println(indent + "}");
1364                    }
1365                }
1366            }
1367        }
1368
1369        // Emit 'GetPrimitiveArrayCritical' for pointers if needed
1370        if (nonPrimitiveArgs.size() > 0) {
1371            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1372                int idx = nonPrimitiveArgs.get(i).intValue();
1373                int cIndex = jfunc.getArgCIndex(idx);
1374
1375                if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue;
1376
1377                String cname = cfunc.getArgName(cIndex);
1378                String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1379                            "_" + cname + "BufferOffset";
1380                String array = numBufferArgs <= 1 ? "_array" :
1381                            "_" + cfunc.getArgName(cIndex) + "Array";
1382
1383                boolean nullAllowed = isNullAllowed(cfunc, cname) ||
1384                        isPointerFunc;
1385                if (nullAllowed) {
1386                    out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {");
1387                } else {
1388                    out.println(indent + "if (" + cname +" == NULL) {");
1389                }
1390                JType argType = jfunc.getArgType(idx);
1391                if (argType.isTypedBuffer()) {
1392                    String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray();
1393                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);");
1394                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
1395                    out.println(indent + "}");
1396                } else {
1397                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
1398                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
1399                    out.println(indent + "}");
1400                }
1401             }
1402        }
1403
1404
1405        if (!isVoid) {
1406            out.print(indent + "_returnValue = ");
1407        } else {
1408            out.print(indent);
1409        }
1410        String name = cfunc.getName();
1411
1412        if (mUseContextPointer) {
1413            name = name.substring(2, name.length()); // Strip off 'gl' prefix
1414            name = name.substring(0, 1).toLowerCase() +
1415                name.substring(1, name.length());
1416            out.print("ctx->procs.");
1417        }
1418
1419        out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
1420
1421        numArgs = cfunc.getNumArgs();
1422        if (numArgs == 0) {
1423            if (mUseContextPointer) {
1424                out.println("ctx);");
1425            } else {
1426                out.println(");");
1427            }
1428        } else {
1429            if (mUseContextPointer) {
1430                out.println("ctx,");
1431            } else {
1432                out.println();
1433            }
1434            for (int i = 0; i < numArgs; i++) {
1435                String typecast;
1436                if (i == numArgs - 1 && isPointerOffsetFunc) {
1437                    typecast = "reinterpret_cast<GLvoid *>";
1438                } else {
1439                    typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")";
1440                }
1441                out.print(indent + indent +
1442                          typecast);
1443
1444                if (cfunc.getArgType(i).isConstCharPointer()) {
1445                    out.print("_native");
1446                }
1447
1448                if (cfunc.getArgType(i).isEGLHandle() &&
1449                    !cfunc.getArgType(i).isPointer()){
1450                    out.print(cfunc.getArgName(i)+"_native");
1451                } else if (i == numArgs - 1 && isPointerOffsetFunc){
1452                    out.print("("+cfunc.getArgName(i)+")");
1453                } else {
1454                    out.print(cfunc.getArgName(i));
1455                }
1456
1457                if (i == numArgs - 1) {
1458                    if (isPointerFunc) {
1459                        out.println(",");
1460                        out.println(indent + indent + "(GLsizei)remaining");
1461                    } else {
1462                        out.println();
1463                    }
1464                } else {
1465                    out.println(",");
1466                }
1467            }
1468            out.println(indent + ");");
1469        }
1470
1471        if (needsExit) {
1472            out.println();
1473            out.println("exit:");
1474            needsExit = false;
1475        }
1476
1477
1478        if (nonPrimitiveArgs.size() > 0) {
1479            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1480                int idx = nonPrimitiveArgs.get(i).intValue();
1481
1482                int cIndex = jfunc.getArgCIndex(idx);
1483                if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
1484
1485                    // If the argument is 'const', GL will not write to it.
1486                    // In this case, we can use the 'JNI_ABORT' flag to avoid
1487                    // the need to write back to the Java array
1488                    out.println(indent +
1489                                "if (" + jfunc.getArgName(idx) + "_base) {");
1490                    String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray();
1491                    out.println(indent + indent +
1492                                (mUseCPlusPlus ? "_env" : "(*_env)") +
1493                                "->" + arrayReleaser + "(" +
1494                                (mUseCPlusPlus ? "" : "_env, ") +
1495                                jfunc.getArgName(idx) + "_ref, " +
1496                                "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) +
1497                                "_base,");
1498                    out.println(indent + indent + indent +
1499                                (cfunc.getArgType(cIndex).isConst() ?
1500                                 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) +
1501                                ");");
1502                    out.println(indent + "}");
1503                } else if (jfunc.getArgType(idx).isBuffer()) {
1504                    if (! isPointerFunc) {
1505                        JType argType = jfunc.getArgType(idx);
1506                        String array = numBufferArgs <= 1 ? "_array" :
1507                            "_" + cfunc.getArgName(cIndex) + "Array";
1508                        out.println(indent + "if (" + array + ") {");
1509                        if (argType.isTypedBuffer()) {
1510                            String arrayReleaser =
1511                                argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray();
1512                            out.println(indent + indent +
1513                                "_env->" + arrayReleaser + "(" + array + ", " +
1514                                "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" +
1515                                cfunc.getArgName(cIndex) +
1516                                ", " +
1517                                (cfunc.getArgType(cIndex).isConst() ?
1518                                    "JNI_ABORT" : (emitExceptionCheck ?
1519                                        "_exception ? JNI_ABORT : 0" : "0")) +
1520                                ");");
1521                        } else {
1522                            out.println(indent + indent +
1523                                "releasePointer(_env, " + array + ", " +
1524                                cfunc.getArgName(cIndex) +
1525                                ", " +
1526                                (cfunc.getArgType(cIndex).isConst() ?
1527                                    "JNI_FALSE" : (emitExceptionCheck ?
1528                                        "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
1529                                ");");
1530                        }
1531                        out.println(indent + "}");
1532                    }
1533                }
1534            }
1535        }
1536
1537        // Emit local variable declaration for strings
1538        if (stringArgs.size() > 0) {
1539            for (int i = 0; i < stringArgs.size(); i++) {
1540                int idx = stringArgs.get(i).intValue();
1541                int cIndex = jfunc.getArgCIndex(idx);
1542                String cname = cfunc.getArgName(cIndex);
1543
1544                out.println(indent + "if (_native" + cname + ") {");
1545                out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
1546                out.println(indent + "}");
1547            }
1548
1549            out.println();
1550        }
1551
1552        // Copy results back to java arrays
1553       if (nonPrimitiveArgs.size() > 0) {
1554            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1555                int idx = nonPrimitiveArgs.get(i).intValue();
1556                int cIndex = jfunc.getArgCIndex(idx);
1557                String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase();
1558                if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) {
1559                    remaining  = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1560                                     "_" + cfunc.getArgName(cIndex) + "Remaining";
1561                    offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset";
1562                    out.println(indent +
1563                                "if (" + jfunc.getArgName(idx) + ") {");
1564                    out.println(indent + indent +
1565                                "for (int i = 0; i < " + remaining + "; i++) {");
1566                    out.println(indent + indent + indent +
1567                                "jobject " + cfunc.getArgName(cIndex) +
1568                                "_new = toEGLHandle(_env, " + baseType +
1569                                "Class, " + baseType + "Constructor, " +
1570                                cfunc.getArgName(cIndex) + "[i]);");
1571                    out.println(indent + indent + indent +
1572                                (mUseCPlusPlus ? "_env" : "(*_env)") +
1573                                "->SetObjectArrayElement(" +
1574                                (mUseCPlusPlus ? "" : "_env, ") +
1575                                cfunc.getArgName(cIndex) +
1576                                "_ref, i + " + offset + ", " +
1577                                cfunc.getArgName(cIndex) + "_new);");
1578                    out.println(indent + indent + "}");
1579                    out.println(indent + indent +
1580                                "delete[] " + jfunc.getArgName(idx) + ";");
1581                    out.println(indent + "}");
1582                }
1583            }
1584        }
1585
1586
1587        // Throw exception if there is one
1588        if (emitExceptionCheck) {
1589            out.println(indent + "if (_exception) {");
1590            out.println(indent + indent +
1591                        "jniThrowException(_env, _exceptionType, _exceptionMessage);");
1592            out.println(indent + "}");
1593
1594        }
1595
1596
1597        if (!isVoid) {
1598            if (cfunc.getType().isEGLHandle()) {
1599                String baseType = cfunc.getType().getBaseType().toLowerCase();
1600                out.println(indent +
1601                            "return toEGLHandle(_env, " + baseType + "Class, " +
1602                            baseType + "Constructor, _returnValue);");
1603            } else {
1604                out.println(indent + "return (" +
1605                            getJniType(jfunc.getType()) + ")_returnValue;");
1606            }
1607        }
1608
1609        out.println("}");
1610        out.println();
1611    }
1612
1613}
1614