mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 1019836 - Support narrow char strings in android bridge r=snorp
This commit is contained in:
parent
ddcc616c4b
commit
6c6fe8361b
@ -12,12 +12,14 @@ public class AnnotationInfo {
|
||||
public final boolean isStatic;
|
||||
public final boolean isMultithreaded;
|
||||
public final boolean noThrow;
|
||||
public final boolean narrowChars;
|
||||
|
||||
public AnnotationInfo(String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded,
|
||||
boolean aNoThrow) {
|
||||
boolean aNoThrow, boolean aNarrowChars) {
|
||||
wrapperName = aWrapperName;
|
||||
isStatic = aIsStatic;
|
||||
isMultithreaded = aIsMultithreaded;
|
||||
noThrow = aNoThrow;
|
||||
narrowChars = aNarrowChars;
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ public class CodeGenerator {
|
||||
Class<?> returnType = theMethod.getReturnType();
|
||||
|
||||
// Get the C++ method signature for this method.
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic);
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic, aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
|
||||
// Add the header signature to the header file.
|
||||
writeSignatureToHeader(headerSignature);
|
||||
@ -113,10 +113,11 @@ public class CodeGenerator {
|
||||
writeMethodBody(implementationSignature, CMethodName, theMethod, mClassToWrap,
|
||||
aMethodTuple.mAnnotationInfo.isStatic,
|
||||
aMethodTuple.mAnnotationInfo.isMultithreaded,
|
||||
aMethodTuple.mAnnotationInfo.noThrow);
|
||||
aMethodTuple.mAnnotationInfo.noThrow,
|
||||
aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
}
|
||||
|
||||
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter) {
|
||||
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
|
||||
StringBuilder argumentContent = null;
|
||||
|
||||
if (isSetter) {
|
||||
@ -133,7 +134,7 @@ public class CodeGenerator {
|
||||
wrapperMethodBodies.append("return ");
|
||||
|
||||
if (isObjectReturningMethod) {
|
||||
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType)).append(">(");
|
||||
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType, aNarrowChars)).append(">(");
|
||||
}
|
||||
|
||||
wrapperMethodBodies.append("env->Get");
|
||||
@ -184,14 +185,14 @@ public class CodeGenerator {
|
||||
boolean shallGenerateStatic = isFieldStatic || aFieldTuple.mAnnotationInfo.isStatic;
|
||||
|
||||
String getterName = "get" + CFieldName;
|
||||
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName);
|
||||
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic);
|
||||
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
|
||||
writeSignatureToHeader(getterHeaderSignature);
|
||||
|
||||
writeFunctionStartupBoilerPlate(getterSignature, fieldType, isFieldStatic, true);
|
||||
|
||||
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false);
|
||||
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
|
||||
// If field not final, also generate a setter function.
|
||||
if (!isFieldFinal) {
|
||||
@ -199,14 +200,14 @@ public class CodeGenerator {
|
||||
|
||||
Class<?>[] setterArguments = new Class<?>[]{fieldType};
|
||||
|
||||
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName);
|
||||
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic);
|
||||
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
|
||||
writeSignatureToHeader(setterHeaderSignature);
|
||||
|
||||
writeFunctionStartupBoilerPlate(setterSignature, Void.class, isFieldStatic, true);
|
||||
|
||||
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true);
|
||||
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,8 +218,8 @@ public class CodeGenerator {
|
||||
|
||||
generateMemberCommon(theCtor, mCClassName, mClassToWrap);
|
||||
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false);
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars);
|
||||
|
||||
// Slice off the "void " from the start of the constructor declaration.
|
||||
headerSignature = headerSignature.substring(5);
|
||||
@ -426,7 +427,7 @@ public class CodeGenerator {
|
||||
*/
|
||||
private void writeMethodBody(String methodSignature, String aCMethodName, Method aMethod,
|
||||
Class<?> aClass, boolean aIsStaticBridgeMethod, boolean aIsMultithreaded,
|
||||
boolean aNoThrow) {
|
||||
boolean aNoThrow, boolean aNarrowChars) {
|
||||
Class<?>[] argumentTypes = aMethod.getParameterTypes();
|
||||
Class<?> returnType = aMethod.getReturnType();
|
||||
|
||||
@ -455,7 +456,7 @@ public class CodeGenerator {
|
||||
if (isObjectReturningMethod) {
|
||||
wrapperMethodBodies.append("jobject");
|
||||
} else {
|
||||
wrapperMethodBodies.append(Utils.getCReturnType(returnType));
|
||||
wrapperMethodBodies.append(Utils.getCReturnType(returnType, aNarrowChars));
|
||||
}
|
||||
wrapperMethodBodies.append(" temp = ");
|
||||
}
|
||||
@ -494,8 +495,8 @@ public class CodeGenerator {
|
||||
// value.
|
||||
if (isObjectReturningMethod) {
|
||||
wrapperMethodBodies.append(" ")
|
||||
.append(Utils.getCReturnType(returnType))
|
||||
.append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
|
||||
.append(Utils.getCReturnType(returnType, aNarrowChars))
|
||||
.append(" ret = static_cast<").append(Utils.getCReturnType(returnType, aNarrowChars)).append(">(env->PopLocalFrame(temp));\n" +
|
||||
" return ret;\n");
|
||||
} else if (!returnType.getCanonicalName().equals("void")) {
|
||||
// If we're a primitive-returning function, just return the directly-obtained primative
|
||||
|
@ -76,6 +76,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
boolean isStaticStub = false;
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
@ -97,6 +98,11 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
noThrowMethod.setAccessible(true);
|
||||
noThrow = (Boolean) noThrowMethod.invoke(annotation);
|
||||
|
||||
// Determine if strings should be wide or narrow
|
||||
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
@ -118,7 +124,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
}
|
||||
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
stubName, isStaticStub, isMultithreadedStub, noThrow);
|
||||
stubName, isStaticStub, isMultithreadedStub, noThrow, narrowChars);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
@ -128,7 +134,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
// thanks to the "Generate everything" annotation.
|
||||
if (mIterateEveryEntry) {
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
candidateElement.getName(), false, false, false);
|
||||
candidateElement.getName(), false, false, false, false);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ public class Utils {
|
||||
* @param type Class to determine the corresponding JNI type for.
|
||||
* @return true if the type an object type, false otherwise.
|
||||
*/
|
||||
public static String getCParameterType(Class<?> type) {
|
||||
public static String getCParameterType(Class<?> type, boolean aNarrowChars) {
|
||||
String name = type.getCanonicalName();
|
||||
if (sBasicCTypes.containsKey(name)) {
|
||||
return sBasicCTypes.get(name);
|
||||
@ -161,6 +161,9 @@ public class Utils {
|
||||
|
||||
// Check for CharSequences (Strings and things that are string-like)
|
||||
if (isCharSequence(type)) {
|
||||
if (aNarrowChars) {
|
||||
return "const nsACString&";
|
||||
}
|
||||
return "const nsAString&";
|
||||
}
|
||||
|
||||
@ -181,12 +184,12 @@ public class Utils {
|
||||
* @param type The Java return type.
|
||||
* @return A string representation of the C++ return type.
|
||||
*/
|
||||
public static String getCReturnType(Class<?> type) {
|
||||
public static String getCReturnType(Class<?> type, boolean aNarrowChars) {
|
||||
if (type.getCanonicalName().equals("java.lang.Void")) {
|
||||
return "void";
|
||||
}
|
||||
String cParameterType = getCParameterType(type);
|
||||
if (cParameterType.equals("const nsAString&")) {
|
||||
String cParameterType = getCParameterType(type, aNarrowChars);
|
||||
if (cParameterType.equals("const nsAString&") || cParameterType.equals("const nsACString&")) {
|
||||
return "jstring";
|
||||
} else {
|
||||
return cParameterType;
|
||||
@ -381,10 +384,10 @@ public class Utils {
|
||||
* @param aCClassName Name of the C++ class into which the method is declared.
|
||||
* @return The C++ method implementation signature for the method described.
|
||||
*/
|
||||
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
|
||||
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) {
|
||||
StringBuilder retBuffer = new StringBuilder();
|
||||
|
||||
retBuffer.append(getCReturnType(aReturnType));
|
||||
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
|
||||
retBuffer.append(' ');
|
||||
retBuffer.append(aCClassName);
|
||||
retBuffer.append("::");
|
||||
@ -393,7 +396,7 @@ public class Utils {
|
||||
|
||||
// Write argument types...
|
||||
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
|
||||
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
|
||||
retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
|
||||
retBuffer.append(" a");
|
||||
// We, imaginatively, call our arguments a1, a2, a3...
|
||||
// The only way to preserve the names from Java would be to parse the
|
||||
@ -420,7 +423,7 @@ public class Utils {
|
||||
* @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
|
||||
* @return The generated C++ header method signature for the method described.
|
||||
*/
|
||||
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
|
||||
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) {
|
||||
StringBuilder retBuffer = new StringBuilder();
|
||||
|
||||
// Add the static keyword, if applicable.
|
||||
@ -429,14 +432,14 @@ public class Utils {
|
||||
}
|
||||
|
||||
// Write return type..
|
||||
retBuffer.append(getCReturnType(aReturnType));
|
||||
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
|
||||
retBuffer.append(' ');
|
||||
retBuffer.append(aCMethodName);
|
||||
retBuffer.append('(');
|
||||
|
||||
// Write argument types...
|
||||
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
|
||||
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
|
||||
retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
|
||||
retBuffer.append(" a");
|
||||
// We, imaginatively, call our arguments a1, a2, a3...
|
||||
// The only way to preserve the names from Java would be to parse the
|
||||
|
@ -44,4 +44,6 @@ public @interface WrapElementForJNI {
|
||||
* Any exception must be handled or cleared by the code calling the stub.
|
||||
*/
|
||||
boolean noThrow() default false;
|
||||
|
||||
boolean narrowChars() default false;
|
||||
}
|
||||
|
@ -1011,3 +1011,30 @@ nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
|
||||
}
|
||||
jni->ReleaseStringChars(jstr, jCharPtr);
|
||||
}
|
||||
|
||||
nsJNICString::nsJNICString(jstring jstr, JNIEnv *jenv)
|
||||
{
|
||||
if (!jstr) {
|
||||
SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
JNIEnv *jni = jenv;
|
||||
if (!jni) {
|
||||
jni = AndroidBridge::GetJNIEnv();
|
||||
}
|
||||
const char* jCharPtr = jni->GetStringUTFChars(jstr, nullptr);
|
||||
|
||||
if (!jCharPtr) {
|
||||
SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
|
||||
jsize len = jni->GetStringUTFLength(jstr);
|
||||
|
||||
if (len <= 0) {
|
||||
SetIsVoid(true);
|
||||
} else {
|
||||
Assign(jCharPtr, len);
|
||||
}
|
||||
jni->ReleaseStringUTFChars(jstr, jCharPtr);
|
||||
}
|
||||
|
@ -750,6 +750,12 @@ public:
|
||||
nsJNIString(jstring jstr, JNIEnv *jenv);
|
||||
};
|
||||
|
||||
class nsJNICString : public nsCString
|
||||
{
|
||||
public:
|
||||
nsJNICString(jstring jstr, JNIEnv *jenv);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user