diff --git a/jni/NativeFormats/util/AndroidUtil.cpp b/jni/NativeFormats/util/AndroidUtil.cpp index 82c1474dd..49115ed34 100644 --- a/jni/NativeFormats/util/AndroidUtil.cpp +++ b/jni/NativeFormats/util/AndroidUtil.cpp @@ -149,7 +149,7 @@ bool AndroidUtil::init(JavaVM* jvm) { Method_Encoding_createConverter = new ObjectMethod(Class_Encoding, "createConverter", Class_EncodingConverter, "()"); Field_EncodingConverter_Name = new ObjectField(Class_EncodingConverter, "Name", Class_java_lang_String); - Method_EncodingConverter_convert = new IntMethod(Class_EncodingConverter, "convert", "([BII[BI)"); + Method_EncodingConverter_convert = new IntMethod(Class_EncodingConverter, "convert", "([BII[C)"); Method_EncodingConverter_reset = new VoidMethod(Class_EncodingConverter, "reset", "()"); StaticMethod_JavaEncodingCollection_Instance = new StaticObjectMethod(Class_JavaEncodingCollection, "Instance", Class_JavaEncodingCollection, "()"); diff --git a/jni/NativeFormats/zlibrary/core/src/encoding/JavaEncodingConverter.cpp b/jni/NativeFormats/zlibrary/core/src/encoding/JavaEncodingConverter.cpp index 5961459fa..692ab4da1 100644 --- a/jni/NativeFormats/zlibrary/core/src/encoding/JavaEncodingConverter.cpp +++ b/jni/NativeFormats/zlibrary/core/src/encoding/JavaEncodingConverter.cpp @@ -39,7 +39,8 @@ private: jobject myJavaConverter; int myBufferLength; jbyteArray myInBuffer; - jbyteArray myOutBuffer; + jcharArray myOutBuffer; + jchar *myCppOutBuffer; friend class JavaEncodingConverterProvider; }; @@ -73,11 +74,13 @@ JavaEncodingConverter::JavaEncodingConverter(const std::string &encoding) { myBufferLength = 32768; myInBuffer = env->NewByteArray(myBufferLength); - myOutBuffer = env->NewByteArray(2 * myBufferLength); + myOutBuffer = env->NewCharArray(myBufferLength); + myCppOutBuffer = new jchar[myBufferLength]; } JavaEncodingConverter::~JavaEncodingConverter() { JNIEnv *env = AndroidUtil::getEnv(); + delete[] myCppOutBuffer; env->DeleteLocalRef(myOutBuffer); env->DeleteLocalRef(myInBuffer); env->DeleteLocalRef(myJavaConverter); @@ -95,18 +98,26 @@ void JavaEncodingConverter::convert(std::string &dst, const char *srcStart, cons JNIEnv *env = AndroidUtil::getEnv(); const int srcLen = srcEnd - srcStart; if (srcLen > myBufferLength) { + delete[] myCppOutBuffer; env->DeleteLocalRef(myOutBuffer); env->DeleteLocalRef(myInBuffer); myBufferLength = srcLen; myInBuffer = env->NewByteArray(myBufferLength); - myOutBuffer = env->NewByteArray(2 * myBufferLength); + myOutBuffer = env->NewCharArray(myBufferLength); + myCppOutBuffer = new jchar[myBufferLength]; } env->SetByteArrayRegion(myInBuffer, 0, srcLen, (jbyte*)srcStart); - const jint dstLen = AndroidUtil::Method_EncodingConverter_convert->call(myJavaConverter, myInBuffer, 0, srcLen, myOutBuffer, 0); - const int origLen = dst.size(); - dst.append(dstLen, '\0'); - env->GetByteArrayRegion(myOutBuffer, 0, dstLen, (jbyte*)dst.data() + origLen); + const jint decodedCount = AndroidUtil::Method_EncodingConverter_convert->call( + myJavaConverter, myInBuffer, 0, srcLen, myOutBuffer + ); + dst.reserve(dst.length() + decodedCount * 3); + env->GetCharArrayRegion(myOutBuffer, 0, decodedCount, myCppOutBuffer); + const jchar *end = myCppOutBuffer + decodedCount; + char buffer[3]; + for (const jchar *ptr = myCppOutBuffer; ptr < end; ++ptr) { + dst.append(buffer, ZLUnicodeUtil::ucs2ToUtf8(buffer, *ptr)); + } } void JavaEncodingConverter::reset() { diff --git a/proguard.cfg b/proguard.cfg index 9bed67752..0b9eb5be9 100755 --- a/proguard.cfg +++ b/proguard.cfg @@ -51,7 +51,7 @@ -keep class org.geometerplus.zlibrary.core.encodings.EncodingConverter -keepclassmembers class org.geometerplus.zlibrary.core.encodings.EncodingConverter { public ** Name; - public int convert(byte[],int,int,byte[],int); + public int convert(byte[],int,int,char[]); public void reset(); } -keep class org.geometerplus.zlibrary.core.encodings.JavaEncodingCollection diff --git a/project.properties b/project.properties index c4a39de92..3aa40afdc 100644 --- a/project.properties +++ b/project.properties @@ -8,6 +8,6 @@ # project structure. java.encoding=utf-8 -#proguard.config=proguard.cfg +proguard.config=proguard.cfg # Project target. target=android-8 diff --git a/src/org/geometerplus/zlibrary/core/encodings/EncodingConverter.java b/src/org/geometerplus/zlibrary/core/encodings/EncodingConverter.java index c45d473bb..fd5611ca0 100644 --- a/src/org/geometerplus/zlibrary/core/encodings/EncodingConverter.java +++ b/src/org/geometerplus/zlibrary/core/encodings/EncodingConverter.java @@ -25,32 +25,24 @@ import java.nio.charset.*; public class EncodingConverter { public final String Name; private CharsetDecoder myDecoder; - private CharsetEncoder myEncoder; EncodingConverter(String encoding) { Name = encoding; myDecoder = Charset.forName(encoding).newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); - myEncoder = Charset.forName("utf-8").newEncoder(); } // we assume out is large enough for this conversion - // returns number of filled bytes in out buffer - public int convert(byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + // returns number of filled chars in out buffer + public int convert(byte[] in, int inOffset, int inLength, char[] out) { final ByteBuffer inBuffer = ByteBuffer.wrap(in, inOffset, inLength); - final ByteBuffer outBuffer = ByteBuffer.wrap(out, outOffset, out.length - outOffset); - try { - final CharBuffer charBuffer = myDecoder.decode(inBuffer); - myEncoder.encode(charBuffer, outBuffer, true); - } catch (CharacterCodingException e) { - e.printStackTrace(); - } + final CharBuffer outBuffer = CharBuffer.wrap(out, 0, out.length); + myDecoder.decode(inBuffer, outBuffer, false); return outBuffer.position(); } public void reset() { myDecoder.reset(); - myEncoder.reset(); } }