1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-03 09:49:19 +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, "()");
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, "()");

View file

@ -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() {

View file

@ -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

View file

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

View file

@ -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();
}
}