1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-03 17:59:33 +02:00

fixed encoding conversion for non-1-byte encodings

This commit is contained in:
Nikolay Pultsin 2012-05-05 00:13:25 +01:00
parent 1523188dd4
commit 482ecca302
5 changed files with 25 additions and 22 deletions

View file

@ -149,7 +149,7 @@ bool AndroidUtil::init(JavaVM* jvm) {
Method_Encoding_createConverter = new ObjectMethod(Class_Encoding, "createConverter", Class_EncodingConverter, "()"); Method_Encoding_createConverter = new ObjectMethod(Class_Encoding, "createConverter", Class_EncodingConverter, "()");
Field_EncodingConverter_Name = new ObjectField(Class_EncodingConverter, "Name", Class_java_lang_String); 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", "()"); Method_EncodingConverter_reset = new VoidMethod(Class_EncodingConverter, "reset", "()");
StaticMethod_JavaEncodingCollection_Instance = new StaticObjectMethod(Class_JavaEncodingCollection, "Instance", Class_JavaEncodingCollection, "()"); StaticMethod_JavaEncodingCollection_Instance = new StaticObjectMethod(Class_JavaEncodingCollection, "Instance", Class_JavaEncodingCollection, "()");

View file

@ -39,7 +39,8 @@ private:
jobject myJavaConverter; jobject myJavaConverter;
int myBufferLength; int myBufferLength;
jbyteArray myInBuffer; jbyteArray myInBuffer;
jbyteArray myOutBuffer; jcharArray myOutBuffer;
jchar *myCppOutBuffer;
friend class JavaEncodingConverterProvider; friend class JavaEncodingConverterProvider;
}; };
@ -73,11 +74,13 @@ JavaEncodingConverter::JavaEncodingConverter(const std::string &encoding) {
myBufferLength = 32768; myBufferLength = 32768;
myInBuffer = env->NewByteArray(myBufferLength); myInBuffer = env->NewByteArray(myBufferLength);
myOutBuffer = env->NewByteArray(2 * myBufferLength); myOutBuffer = env->NewCharArray(myBufferLength);
myCppOutBuffer = new jchar[myBufferLength];
} }
JavaEncodingConverter::~JavaEncodingConverter() { JavaEncodingConverter::~JavaEncodingConverter() {
JNIEnv *env = AndroidUtil::getEnv(); JNIEnv *env = AndroidUtil::getEnv();
delete[] myCppOutBuffer;
env->DeleteLocalRef(myOutBuffer); env->DeleteLocalRef(myOutBuffer);
env->DeleteLocalRef(myInBuffer); env->DeleteLocalRef(myInBuffer);
env->DeleteLocalRef(myJavaConverter); env->DeleteLocalRef(myJavaConverter);
@ -95,18 +98,26 @@ void JavaEncodingConverter::convert(std::string &dst, const char *srcStart, cons
JNIEnv *env = AndroidUtil::getEnv(); JNIEnv *env = AndroidUtil::getEnv();
const int srcLen = srcEnd - srcStart; const int srcLen = srcEnd - srcStart;
if (srcLen > myBufferLength) { if (srcLen > myBufferLength) {
delete[] myCppOutBuffer;
env->DeleteLocalRef(myOutBuffer); env->DeleteLocalRef(myOutBuffer);
env->DeleteLocalRef(myInBuffer); env->DeleteLocalRef(myInBuffer);
myBufferLength = srcLen; myBufferLength = srcLen;
myInBuffer = env->NewByteArray(myBufferLength); myInBuffer = env->NewByteArray(myBufferLength);
myOutBuffer = env->NewByteArray(2 * myBufferLength); myOutBuffer = env->NewCharArray(myBufferLength);
myCppOutBuffer = new jchar[myBufferLength];
} }
env->SetByteArrayRegion(myInBuffer, 0, srcLen, (jbyte*)srcStart); env->SetByteArrayRegion(myInBuffer, 0, srcLen, (jbyte*)srcStart);
const jint dstLen = AndroidUtil::Method_EncodingConverter_convert->call(myJavaConverter, myInBuffer, 0, srcLen, myOutBuffer, 0); const jint decodedCount = AndroidUtil::Method_EncodingConverter_convert->call(
const int origLen = dst.size(); myJavaConverter, myInBuffer, 0, srcLen, myOutBuffer
dst.append(dstLen, '\0'); );
env->GetByteArrayRegion(myOutBuffer, 0, dstLen, (jbyte*)dst.data() + origLen); 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() { void JavaEncodingConverter::reset() {

View file

@ -51,7 +51,7 @@
-keep class org.geometerplus.zlibrary.core.encodings.EncodingConverter -keep class org.geometerplus.zlibrary.core.encodings.EncodingConverter
-keepclassmembers class org.geometerplus.zlibrary.core.encodings.EncodingConverter { -keepclassmembers class org.geometerplus.zlibrary.core.encodings.EncodingConverter {
public ** Name; public ** Name;
public int convert(byte[],int,int,byte[],int); public int convert(byte[],int,int,char[]);
public void reset(); public void reset();
} }
-keep class org.geometerplus.zlibrary.core.encodings.JavaEncodingCollection -keep class org.geometerplus.zlibrary.core.encodings.JavaEncodingCollection

View file

@ -8,6 +8,6 @@
# project structure. # project structure.
java.encoding=utf-8 java.encoding=utf-8
#proguard.config=proguard.cfg proguard.config=proguard.cfg
# Project target. # Project target.
target=android-8 target=android-8

View file

@ -25,32 +25,24 @@ import java.nio.charset.*;
public class EncodingConverter { public class EncodingConverter {
public final String Name; public final String Name;
private CharsetDecoder myDecoder; private CharsetDecoder myDecoder;
private CharsetEncoder myEncoder;
EncodingConverter(String encoding) { EncodingConverter(String encoding) {
Name = encoding; Name = encoding;
myDecoder = Charset.forName(encoding).newDecoder() myDecoder = Charset.forName(encoding).newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE) .onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE); .onUnmappableCharacter(CodingErrorAction.REPLACE);
myEncoder = Charset.forName("utf-8").newEncoder();
} }
// we assume out is large enough for this conversion // we assume out is large enough for this conversion
// returns number of filled bytes in out buffer // returns number of filled chars in out buffer
public int convert(byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { public int convert(byte[] in, int inOffset, int inLength, char[] out) {
final ByteBuffer inBuffer = ByteBuffer.wrap(in, inOffset, inLength); final ByteBuffer inBuffer = ByteBuffer.wrap(in, inOffset, inLength);
final ByteBuffer outBuffer = ByteBuffer.wrap(out, outOffset, out.length - outOffset); final CharBuffer outBuffer = CharBuffer.wrap(out, 0, out.length);
try { myDecoder.decode(inBuffer, outBuffer, false);
final CharBuffer charBuffer = myDecoder.decode(inBuffer);
myEncoder.encode(charBuffer, outBuffer, true);
} catch (CharacterCodingException e) {
e.printStackTrace();
}
return outBuffer.position(); return outBuffer.position();
} }
public void reset() { public void reset() {
myDecoder.reset(); myDecoder.reset();
myEncoder.reset();
} }
} }