Added support for Strings! (WIP, needs more testing)

This commit is contained in:
Ioannis Tsakpinis 2010-03-12 21:55:13 +00:00
parent cb925a91e9
commit 6ac8e327f2
29 changed files with 889 additions and 231 deletions

View file

@ -0,0 +1,268 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.opengl;
import org.lwjgl.BufferUtils;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
/** @author spasi */
final class StringUtils {
private static final int INITIAL_BUFFER_SIZE = 256;
private static final int INITIAL_LENGTHS_SIZE = 4;
private static final ThreadLocal arrayTL = new ThreadLocal() {
protected Object initialValue() {
return new char[INITIAL_BUFFER_SIZE];
}
};
private static final ThreadLocal bufferTL = new ThreadLocal() {
protected Object initialValue() {
return BufferUtils.createByteBuffer(INITIAL_BUFFER_SIZE);
}
};
private static final ThreadLocal lengthsTL = new ThreadLocal() {
protected Object initialValue() {
return BufferUtils.createIntBuffer(INITIAL_LENGTHS_SIZE);
}
};
private StringUtils() {
}
private static char[] getArray(final int size) {
char[] array = (char[])arrayTL.get();
if ( array.length < size ) {
int sizeNew = array.length << 1;
while ( sizeNew < size )
sizeNew <<= 1;
array = new char[size];
arrayTL.set(array);
}
return array;
}
static ByteBuffer getBuffer(final int size) {
ByteBuffer buffer = (ByteBuffer)bufferTL.get();
if ( buffer.capacity() < size ) {
int sizeNew = buffer.capacity() << 1;
while ( sizeNew < size )
sizeNew <<= 1;
buffer = BufferUtils.createByteBuffer(size);
bufferTL.set(buffer);
}
buffer.clear();
return buffer;
}
private static ByteBuffer getBufferOffset(final int size) {
ByteBuffer buffer = (ByteBuffer)bufferTL.get();
if ( buffer.capacity() < size ) {
int sizeNew = buffer.capacity() << 1;
while ( sizeNew < size )
sizeNew <<= 1;
final ByteBuffer bufferNew = BufferUtils.createByteBuffer(size);
bufferNew.put(buffer);
bufferTL.set(buffer = bufferNew);
} else {
buffer.position(buffer.limit());
buffer.limit(buffer.capacity());
}
return buffer;
}
static IntBuffer getLengths(final int size) {
IntBuffer lengths = (IntBuffer)lengthsTL.get();
if ( lengths.capacity() < size ) {
int sizeNew = lengths.capacity();
while ( sizeNew < size )
sizeNew <<= 1;
lengths = BufferUtils.createIntBuffer(size);
lengthsTL.set(lengths);
}
lengths.clear();
return lengths;
}
/*
* Reads a byte string from the specified buffer.
*
* @param buffer
*
* @return the buffer as a String.
*/
static String getString(final ByteBuffer buffer) {
final int length = buffer.remaining();
final char[] charArray = getArray(length);
for ( int i = buffer.position(); i < buffer.limit(); i++ )
charArray[i - buffer.position()] = (char)buffer.get(i);
return new String(charArray, 0, length);
}
/**
* Returns a buffer containing the specified string as bytes.
*
* @param string
*
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string) {
final ByteBuffer buffer = getBuffer(string.length());
for ( int i = 0; i < string.length(); i++ )
buffer.put((byte)string.charAt(i));
buffer.flip();
return buffer;
}
/**
* Returns a buffer containing the specified string as bytes, starting at the specified offset.
*
* @param string
*
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferOffset(final CharSequence string, final int offset) {
final ByteBuffer buffer = getBufferOffset(offset + string.length());
for ( int i = 0; i < string.length(); i++ )
buffer.put((byte)string.charAt(i));
buffer.flip();
return buffer;
}
/**
* Returns a buffer containing the specified string as bytes, including null-termination.
*
* @param string
*
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence string) {
final ByteBuffer buffer = getBuffer(string.length() + 1);
for ( int i = 0; i < string.length(); i++ )
buffer.put((byte)string.charAt(i));
buffer.put((byte)0);
buffer.flip();
return buffer;
}
/**
* Returns a buffer containing the specified strings as bytes.
*
* @param strings
*
* @return the Strings as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence[] strings) {
int length = 0;
for ( int i = 0; i < strings.length; i++ )
length += strings[i].length();
final ByteBuffer buffer = getBuffer(length);
for ( int i = 0; i < strings.length; i++ ) {
final CharSequence string = strings[i];
for ( int j = 0; j < string.length(); j++ )
buffer.put((byte)string.charAt(i));
}
buffer.flip();
return buffer;
}
/**
* Returns a buffer containing the specified strings as bytes, including null-termination.
*
* @param strings
*
* @return the Strings as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence[] strings) {
int length = 0;
for ( int i = 0; i < strings.length; i++ )
length += strings[i].length() + 1;
final ByteBuffer buffer = getBuffer(length);
for ( int i = 0; i < strings.length; i++ ) {
final CharSequence string = strings[i];
for ( int j = 0; j < string.length(); j++ )
buffer.put((byte)string.charAt(i));
buffer.put((byte)0);
}
buffer.flip();
return buffer;
}
/**
* Returns a buffer containing the lengths of the specified strings.
*
* @param strings
*
* @return the String lengths in an IntBuffer
*/
static IntBuffer getLengths(final CharSequence[] strings) {
IntBuffer buffer = getLengths(strings.length);
for ( int i = 0; i < strings.length; i++ )
buffer.put(strings[i].length());
buffer.flip();
return buffer;
}
}

View file

@ -42,6 +42,10 @@ import java.lang.annotation.Target;
*/
@Target({ ElementType.METHOD })
public @interface Alternate {
/** This must match an existing GL method name. */
String value();
/** If true, an alternate Java->native call will be created. Useful when the alternate implementation uses different types. */
boolean nativeAlt() default false;
}

View file

@ -210,8 +210,18 @@ public class ContextCapabilitiesGenerator {
writer.println(") {");
writer.println("\t\treturn ");
boolean first = true;
while ( methods.hasNext() ) {
MethodDeclaration method = methods.next();
if ( method.getAnnotation(Alternate.class) != null )
continue;
if ( !first )
writer.println(" &&");
else
first = false;
optional = method.getAnnotation(Optional.class) != null;
deprecated = method.getAnnotation(DeprecatedGL.class) != null;
dependent = method.getAnnotation(Dependent.class);
@ -261,8 +271,6 @@ public class ContextCapabilitiesGenerator {
writer.print(')');
if ( optional )
writer.print(" || true)");
if ( methods.hasNext() )
writer.println(" &&");
}
writer.println(";");
writer.println("\t}");
@ -271,7 +279,8 @@ public class ContextCapabilitiesGenerator {
public static void generateSymbolAddresses(PrintWriter writer, InterfaceDeclaration d) {
for ( MethodDeclaration method : d.getMethods() ) {
writer.println("\tlong " + Utils.getFunctionAddressName(d, method) + ";");
if ( method.getAnnotation(Alternate.class) == null )
writer.println("\tlong " + Utils.getFunctionAddressName(d, method) + ";");
}
}

View file

@ -220,7 +220,7 @@ public class GLTypeMap implements TypeMap {
else if ( type.equals(boolean.class) )
return new Class[] { GLboolean.class };
else if ( type.equals(void.class) )
return new Class[] { GLvoid.class };
return new Class[] { GLvoid.class, GLstring.class };
else
return new Class[] { };
}
@ -243,6 +243,8 @@ public class GLTypeMap implements TypeMap {
valid_types = new Class[] { GLubyte.class };
else if ( PointerWrapper.class.isAssignableFrom(type) )
valid_types = new Class[] { GLpointer.class };
else if (void.class.equals(type) )
valid_types = new Class[] { GLstring.class };
else
valid_types = new Class[] { };
return valid_types;

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.util.generator;
/**
* Methods annotated with @GLstring will return a String instead of void.
*
* @author spasi
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@NativeType
@Target({ ElementType.METHOD })
public @interface GLstring {
/** The ByteBuffer argument that will be used to retrieve the String bytes. */
String string();
/** The argument that specifies the maximum number of bytes that may be read. */
String maxLength();
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.util.generator;
/**
* This annotation must be used when there are more than one CharSequence arguments in a method.
* TODO: Add support for CharSequence[] if/when we need it.
*
* @author spasi
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER })
public @interface GLstringOffset {
/** An expression that will specify the offset from which this String will be written to the ByteBuffer. */
String value();
}

View file

@ -125,7 +125,8 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
private void validateParameters(MethodDeclaration method) {
for (ParameterDeclaration param : method.getParameters()) {
validateTypes(method, param.getAnnotationMirrors(), param.getType());
if (Utils.getNIOBufferType(param.getType()) != null) {
Class<?> param_type = Utils.getJavaType(param.getType());
if (Utils.getNIOBufferType(param.getType()) != null && param_type != CharSequence.class && param_type != CharSequence[].class) {
Check parameter_check_annotation = param.getAnnotation(Check.class);
NullTerminated null_terminated_annotation = param.getAnnotation(NullTerminated.class);
if (parameter_check_annotation == null && null_terminated_annotation == null) {
@ -138,7 +139,11 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
break;
}
}
if (!found_auto_size_param && param.getAnnotation(Result.class) == null && param.getAnnotation(Constant.class) == null)
if (!found_auto_size_param
&& param.getAnnotation(Result.class) == null
&& param.getAnnotation(Constant.class) == null
&& !Utils.isReturnString(method, param)
)
throw new RuntimeException(param + " has no Check, Result nor Constant annotation and no other parameters has" +
" an @AutoSize annotation on it in method " + method);
}
@ -158,8 +163,10 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
}
private static void generateMethodsNativePointers(PrintWriter writer, Collection<? extends MethodDeclaration> methods) {
for (MethodDeclaration method : methods)
generateMethodNativePointers(writer, method);
for (MethodDeclaration method : methods) {
if ( method.getAnnotation(Alternate.class) == null )
generateMethodNativePointers(writer, method);
}
}
private static void generateMethodNativePointers(PrintWriter writer, MethodDeclaration method) {

View file

@ -56,7 +56,10 @@ public class JNITypeTranslator implements TypeVisitor {
}
public void visitArrayType(ArrayType t) {
throw new RuntimeException(t + " is not allowed");
if ( "java.lang.CharSequence".equals(t.getComponentType().toString()) )
signature.append("jobject");
else
throw new RuntimeException(t + " is not allowed");
}
public void visitClassType(ClassType t) {

View file

@ -71,7 +71,8 @@ public class JavaMethodsGenerator {
if ( method.getAnnotation(CachedResult.class) != null && !method.getAnnotation(CachedResult.class).isRange() ) {
printMethodWithMultiType(env, type_map, writer, interface_decl, method, TypeInfo.getDefaultTypeInfoMap(method), Mode.CACHEDRESULT, generate_error_checks, context_specific);
}
if ( method.getAnnotation(Alternate.class) == null ) {
Alternate alt_annotation = method.getAnnotation(Alternate.class);
if ( alt_annotation == null || alt_annotation.nativeAlt() ) {
printJavaNativeStub(writer, method, Mode.NORMAL, generate_error_checks, context_specific);
if (Utils.hasMethodBufferObjectParameter(method)) {
printMethodWithMultiType(env, type_map, writer, interface_decl, method, TypeInfo.getDefaultTypeInfoMap(method), Mode.BUFFEROBJECT, generate_error_checks, context_specific);
@ -119,8 +120,12 @@ public class JavaMethodsGenerator {
writer.print("boolean " + TypeInfo.UNSIGNED_PARAMETER_NAME);
}
}
} else if (param.getAnnotation(Result.class) == null && (native_stub || param.getAnnotation(Constant.class) == null) &&
(getAutoTypeParameter(method, param) == null || mode != Mode.AUTOS)) {
} else if (
param.getAnnotation(Result.class) == null
&& (native_stub || (param.getAnnotation(Constant.class) == null && !Utils.isReturnString(method, param)))
&& (getAutoTypeParameter(method, param) == null || mode != Mode.AUTOS)
)
{
TypeInfo type_info = typeinfos_instance.get(param);
first_parameter = generateParameterJava(writer, param, type_info, native_stub, first_parameter, mode);
}
@ -161,10 +166,15 @@ public class JavaMethodsGenerator {
} else {
if ( native_stub && param.getAnnotation(GLpointer.class) != null )
writer.print("long");
else
writer.print(type_info.getType().getSimpleName());
else {
Class type = type_info.getType();
if ( native_stub && (type == CharSequence.class || type == CharSequence[].class) )
writer.print("ByteBuffer");
else
writer.print(type_info.getType().getSimpleName());
}
writer.print(" " + param.getSimpleName());
if (buffer_type != null && native_stub)
if ( native_stub && buffer_type != null )
writer.print(", int " + param.getSimpleName() + NativeMethodStubsGenerator.BUFFER_POSITION_POSTFIX);
}
return false;
@ -208,7 +218,7 @@ public class JavaMethodsGenerator {
if (context_specific) {
writer.println("\t\tContextCapabilities caps = GLContext.getCapabilities();");
writer.print("\t\tlong " + Utils.FUNCTION_POINTER_VAR_NAME + " = caps.");
writer.println(Utils.getFunctionAddressName(interface_decl, method) + ";");
writer.println(Utils.getFunctionAddressName(interface_decl, method, true) + ";");
writer.print("\t\tBufferChecks.checkFunctionAddress(");
writer.println(Utils.FUNCTION_POINTER_VAR_NAME + ");");
}
@ -227,6 +237,13 @@ public class JavaMethodsGenerator {
if ( method.getAnnotation(GLpointer.class) != null )
writer.print("new " + method.getReturnType() + "(");
}
GLstring string_annotation = method.getAnnotation(GLstring.class);
if ( string_annotation != null ) {
has_result = true;
writer.println("IntBuffer " + string_annotation.string() + "_length = StringUtils.getLengths(1);");
writer.println("\t\tByteBuffer " + string_annotation.string() + " = StringUtils.getBuffer(" + string_annotation.maxLength() + ");");
writer.print("\t\t");
}
writer.print(Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific));
if (mode == Mode.BUFFEROBJECT)
writer.print(Utils.BUFFER_OBJECT_METHOD_POSTFIX);
@ -244,8 +261,14 @@ public class JavaMethodsGenerator {
writer.println("\t\t" + type_map.getErrorCheckMethodName() + ";");
// DISABLED: indirect buffer support
//printNondirectParameterCopies(writer, method, mode);
if (has_result)
writer.println("\t\treturn " + Utils.RESULT_VAR_NAME + ";");
if (has_result) {
if ( string_annotation == null )
writer.println("\t\treturn " + Utils.RESULT_VAR_NAME + ";");
else {
writer.println("\t\t" + string_annotation.string() + ".limit(" + string_annotation.string() + "_length.get(0));");
writer.println("\t\treturn StringUtils.getString(" + string_annotation.string() + ");");
}
}
writer.println("\t}");
}
@ -383,8 +406,24 @@ public class JavaMethodsGenerator {
boolean hide_buffer = mode == Mode.AUTOS && getAutoTypeParameter(method, param) != null;
if (hide_buffer)
writer.print("null");
else
writer.print(param.getSimpleName());
else {
Class type = typeinfos_instance.get(param).getType();
if ( type == CharSequence.class || type == CharSequence[].class ) {
GLstringOffset offset_annotation = param.getAnnotation(GLstringOffset.class);
writer.print("StringUtils.getBuffer");
if ( offset_annotation != null )
writer.print("Offset");
if ( param.getAnnotation(NullTerminated.class) != null )
writer.print("NT");
writer.print("(" + param.getSimpleName());
if ( offset_annotation != null )
writer.print(", " + offset_annotation.value());
writer.print(")");
hide_buffer = true;
} else
writer.print(param.getSimpleName());
}
Class buffer_type = Utils.getNIOBufferType(param.getType());
if (buffer_type != null) {
writer.print(", ");
@ -404,7 +443,9 @@ public class JavaMethodsGenerator {
writer.print(" << " + shifting);
if (check_annotation != null && check_annotation.canBeNull())
writer.print(" : 0");
} else
} else if ( param.getAnnotation(GLstringOffset.class) != null )
writer.print(param.getAnnotation(GLstringOffset.class).value());
else
writer.print("0");
} else if ( param.getAnnotation(GLpointer.class) != null ) {
writer.print(".getPointer()");
@ -489,7 +530,8 @@ public class JavaMethodsGenerator {
if (Utils.isAddressableType(java_type) &&
(mode != Mode.BUFFEROBJECT || param.getAnnotation(BufferObject.class) == null) &&
(mode != Mode.AUTOS || getAutoTypeParameter(method, param) == null) &&
param.getAnnotation(Result.class) == null) {
param.getAnnotation(Result.class) == null &&
!Utils.isReturnString(method, param) ) {
String check_value = null;
boolean can_be_null = false;
Check check_annotation = param.getAnnotation(Check.class);
@ -547,6 +589,8 @@ public class JavaMethodsGenerator {
private static void printResultType(PrintWriter writer, MethodDeclaration method, boolean native_stub) {
if ( native_stub && method.getAnnotation(GLpointer.class) != null )
writer.print("long");
else if ( !native_stub && method.getAnnotation(GLstring.class) != null )
writer.print("String");
else
writer.print(Utils.getMethodReturnType(method).toString());
}

View file

@ -56,7 +56,10 @@ public class JavaTypeTranslator implements TypeVisitor {
}
public void visitArrayType(ArrayType t) {
throw new RuntimeException(t + " is not allowed");
if ( "java.lang.CharSequence".equals(t.getComponentType().toString()) )
type = CharSequence[].class;
else
throw new RuntimeException(t + " is not allowed");
}
public void visitPrimitiveType(PrimitiveType t) {

View file

@ -56,6 +56,9 @@ public class NativeMethodStubsGenerator {
public static void generateNativeMethodStubs(AnnotationProcessorEnvironment env, TypeMap type_map, PrintWriter writer, InterfaceDeclaration d, boolean generate_error_checks, boolean context_specific) {
for (MethodDeclaration method : d.getMethods()) {
Alternate alt_annotation = method.getAnnotation(Alternate.class);
if ( alt_annotation != null && !alt_annotation.nativeAlt() )
continue;
generateMethodStub(env, type_map, writer, Utils.getQualifiedClassName(d), method, Mode.NORMAL, generate_error_checks, context_specific);
if (Utils.hasMethodBufferObjectParameter(method))
generateMethodStub(env, type_map, writer, Utils.getQualifiedClassName(d), method, Mode.BUFFEROBJECT, generate_error_checks, context_specific);
@ -117,9 +120,10 @@ public class NativeMethodStubsGenerator {
}
writer.println(") {");
generateBufferParameterAddresses(type_map, writer, method, mode);
Alternate alt_annotation = method.getAnnotation(Alternate.class);
if (context_specific) {
String typedef_name = Utils.getTypedefName(method);
writer.print("\t" + typedef_name + " " + method.getSimpleName());
writer.print("\t" + typedef_name + " " + (alt_annotation == null ? method.getSimpleName() : alt_annotation.value()));
writer.print(" = (" + typedef_name + ")((intptr_t)");
writer.println(Utils.FUNCTION_POINTER_VAR_NAME + ");");
}
@ -141,7 +145,7 @@ public class NativeMethodStubsGenerator {
} else
writer.print(" = ");
}
writer.print(method.getSimpleName() + "(");
writer.print((alt_annotation == null ? method.getSimpleName() : alt_annotation.value()) + "(");
generateCallParameters(writer, type_map, method.getParameters());
writer.print(")");
writer.println(";");
@ -222,13 +226,13 @@ public class NativeMethodStubsGenerator {
}
private static void generateBufferParameterAddresses(TypeMap type_map, PrintWriter writer, MethodDeclaration method, Mode mode) {
boolean loopDeclared = false;
for (ParameterDeclaration param : method.getParameters())
if (Utils.isAddressableType(param.getType()) &&
param.getAnnotation(Result.class) == null)
generateBufferParameterAddress(type_map, writer, method, param, mode);
if (Utils.isAddressableType(param.getType()) && param.getAnnotation(Result.class) == null)
loopDeclared = generateBufferParameterAddress(type_map, writer, method, param, mode, loopDeclared);
}
private static void generateBufferParameterAddress(TypeMap type_map, PrintWriter writer, MethodDeclaration method, ParameterDeclaration param, Mode mode) {
private static boolean generateBufferParameterAddress(TypeMap type_map, PrintWriter writer, MethodDeclaration method, ParameterDeclaration param, Mode mode, boolean loopDeclared) {
NativeTypeTranslator translator = new NativeTypeTranslator(type_map, param);
param.getType().accept(translator);
writer.print("\t" + translator.getSignature() + param.getSimpleName());
@ -240,7 +244,7 @@ public class NativeMethodStubsGenerator {
writer.print("offsetToPointer(" + param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX + "))");
} else {
Class java_type = Utils.getJavaType(param.getType());
if (Buffer.class.isAssignableFrom(java_type)) {
if (Buffer.class.isAssignableFrom(java_type) || java_type.equals(CharSequence.class) || java_type.equals(CharSequence[].class)) {
boolean explicitly_byte_sized = java_type.equals(Buffer.class) ||
translator.getAnnotationType().equals(type_map.getVoidType());
if (explicitly_byte_sized)
@ -262,30 +266,47 @@ public class NativeMethodStubsGenerator {
writer.println(";");
if ( param.getAnnotation(StringList.class) != null ) {
if ( param.getAnnotation(GLchar.class) == null ||
param.getAnnotation(NullTerminated.class) == null ||
param.getAnnotation(NullTerminated.class).value().length() == 0
if ( Utils.getJavaType(param.getType()) != CharSequence[].class && (
param.getAnnotation(GLchar.class) == null ||
param.getAnnotation(NullTerminated.class) == null ||
param.getAnnotation(NullTerminated.class).value().length() == 0
)
)
throw new RuntimeException("StringList annotation can only be applied on null-terminated GLchar buffers.");
// Declare string array and loop counters
writer.print("\tGLchar **" + param.getSimpleName() + STRING_LIST_POSTFIX + "; ");
writer.println("\tunsigned int " + param.getSimpleName() + "_i = 0;");
writer.println("\tGLchar *" + param.getSimpleName() + "_next = (GLchar *)" + param.getSimpleName() + BUFFER_ADDRESS_POSTFIX + ";");
if ( "_str".equals(param.getSimpleName()) )
throw new RuntimeException("The name '_str' is not valid for arguments annotated with StringList");
// Declare loop counters and allocate string array
if ( !loopDeclared ) {
writer.println("\tunsigned int _str_i;");
writer.println("\tGLchar *_str_address;");
loopDeclared = true;
}
writer.println("\tGLchar **" + param.getSimpleName() + STRING_LIST_POSTFIX + " = (GLchar **) malloc(" + param.getAnnotation(StringList.class).value() + "*sizeof(GLchar*));");
}
return loopDeclared;
}
private static void generateStringListInits(PrintWriter writer, Collection<ParameterDeclaration> params) {
for ( ParameterDeclaration param : params ) {
StringList stringList_annotation = param.getAnnotation(StringList.class);
if ( stringList_annotation != null ) {
// Allocate the string array
writer.println("\t" + param.getSimpleName() + STRING_LIST_POSTFIX + " = (GLchar **) malloc(" + stringList_annotation.value() + "*sizeof(GLchar*));");
String lengths = stringList_annotation.lengths();
// Init vars
writer.println("\t_str_i = 0;");
writer.println("\t_str_address = (GLchar *)" + param.getSimpleName() + BUFFER_ADDRESS_POSTFIX + ";");
// Fill string array with the string pointers
writer.println("\tdo {");
writer.println("\t\t" + param.getSimpleName() + STRING_LIST_POSTFIX + "[" + param.getSimpleName() + "_i++] = " + param.getSimpleName() + "_next;");
writer.println("\t\t" + param.getSimpleName() + "_next += strlen(" + param.getSimpleName() + "_next) + 1;");
writer.println("\t} while ( " + param.getSimpleName() + "_i < " + stringList_annotation.value() + " );");
writer.println("\twhile ( _str_i < " + stringList_annotation.value() + " ) {");
if ( lengths.length() == 0 ) {
writer.println("\t\t" + param.getSimpleName() + STRING_LIST_POSTFIX + "[_str_i++] = _str_address;");
writer.println("\t\t_str_address += strlen(_str_address_next) + 1;");
} else {
writer.println("\t\t" + param.getSimpleName() + STRING_LIST_POSTFIX + "[_str_i] = _str_address;");
writer.println("\t\t_str_address += " + lengths + BUFFER_ADDRESS_POSTFIX + "[_str_i++];");
}
writer.println("\t}");
}
}
}

View file

@ -104,7 +104,12 @@ public class NativeTypeTranslator implements TypeVisitor {
}
public void visitArrayType(ArrayType t) {
throw new RuntimeException(t + " is not allowed");
if ( "java.lang.CharSequence".equals(t.getComponentType().toString()) ) {
is_indirect = true;
native_types = new ArrayList<Class>();
native_types.add(GLchar.class);
} else
throw new RuntimeException(t + " is not allowed");
}
public static PrimitiveType.Kind getPrimitiveKindFromBufferClass(Class c) {

View file

@ -41,5 +41,8 @@ import java.lang.annotation.Target;
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface StringList {
/** Number of values in the string list (name of native-side parameter) */
String value();
/** List of string lengths (name of native-side parameter) */
String lengths() default "";
}

View file

@ -82,8 +82,10 @@ public class TypedefsGenerator {
}
public static void generateNativeTypedefs(TypeMap type_map, PrintWriter writer, Collection<? extends MethodDeclaration> methods) {
for (MethodDeclaration method : methods)
generateNativeTypedefs(type_map, writer, method);
for (MethodDeclaration method : methods) {
if ( method.getAnnotation(Alternate.class) == null )
generateNativeTypedefs(type_map, writer, method);
}
}
}

View file

@ -43,9 +43,16 @@ package org.lwjgl.util.generator;
import com.sun.mirror.type.*;
import java.nio.Buffer;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.*;
import javax.lang.model.util.SimpleTypeVisitor6;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.PrimitiveType.Kind;
import com.sun.mirror.util.SimpleTypeVisitor;
import com.sun.mirror.util.TypeVisitor;
import com.sun.mirror.util.Types;
public class Utils {
public static final String TYPEDEF_POSTFIX = "PROC";
@ -63,11 +70,20 @@ public class Utils {
private static final String OVERLOADED_METHOD_PREFIX = "n";
public static String getTypedefName(MethodDeclaration method) {
return method.getSimpleName() + TYPEDEF_POSTFIX;
Alternate alt_annotation = method.getAnnotation(Alternate.class);
return (alt_annotation == null ? method.getSimpleName() : alt_annotation.value()) + TYPEDEF_POSTFIX;
}
public static String getFunctionAddressName(InterfaceDeclaration interface_decl, MethodDeclaration method) {
return interface_decl.getSimpleName() + "_" + method.getSimpleName() + FUNCTION_POINTER_POSTFIX;
return getFunctionAddressName(interface_decl, method, false);
}
public static String getFunctionAddressName(InterfaceDeclaration interface_decl, MethodDeclaration method, boolean forceAlt) {
Alternate alt_annotation = method.getAnnotation(Alternate.class);
if ( alt_annotation == null || (alt_annotation.nativeAlt() && !forceAlt) )
return interface_decl.getSimpleName() + "_" + method.getSimpleName() + FUNCTION_POINTER_POSTFIX;
else
return interface_decl.getSimpleName() + "_" + alt_annotation.value() + FUNCTION_POINTER_POSTFIX;
}
public static boolean isFinal(InterfaceDeclaration d) {
@ -103,7 +119,7 @@ public class Utils {
}
public static boolean isAddressableType(Class type) {
return Buffer.class.isAssignableFrom(type) || String.class.equals(type);
return Buffer.class.isAssignableFrom(type) || String.class.equals(type) || CharSequence.class.equals(type) || CharSequence[].class.equals(type);
}
public static Class getJavaType(TypeMirror type_mirror) {
@ -248,6 +264,8 @@ public class Utils {
Class<?> param_type = getJavaType(t);
if (Buffer.class.isAssignableFrom(param_type))
return param_type;
else if ( param_type == CharSequence.class || param_type == CharSequence[].class )
return ByteBuffer.class;
else
return null;
}
@ -255,10 +273,15 @@ public class Utils {
public static String getSimpleNativeMethodName(MethodDeclaration method, boolean generate_error_checks, boolean context_specific) {
String method_name;
Alternate alt_annotation = method.getAnnotation(Alternate.class);
method_name = alt_annotation == null ? method.getSimpleName() : alt_annotation.value();
method_name = alt_annotation == null || alt_annotation.nativeAlt() ? method.getSimpleName() : alt_annotation.value();
if (isMethodIndirect(generate_error_checks, context_specific, method))
method_name = OVERLOADED_METHOD_PREFIX + method_name;
return method_name;
}
static boolean isReturnString(MethodDeclaration method, ParameterDeclaration param) {
GLstring string_annotation = method.getAnnotation(GLstring.class);
return string_annotation != null && string_annotation.string().equals(param.getSimpleName());
}
}