diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index e0cd5319ac..65d0b69e5a 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -44,6 +44,11 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) set(CRENGINE_SRC_FILES ${CR3_ROOT}/crengine/src/cp_stats.cpp ${CR3_ROOT}/crengine/src/lvstring.cpp + ${CR3_ROOT}/crengine/src/lvstring8collection.cpp + ${CR3_ROOT}/crengine/src/lvstring16collection.cpp + ${CR3_ROOT}/crengine/src/lvstring16hashedcollection.cpp + ${CR3_ROOT}/crengine/src/crlog.cpp + ${CR3_ROOT}/crengine/src/serialbuf.cpp ${CR3_ROOT}/crengine/src/props.cpp ${CR3_ROOT}/crengine/src/lstridmap.cpp ${CR3_ROOT}/crengine/src/rtfimp.cpp diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 99ddcdfb14..c8c57f6a79 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -40,6 +40,11 @@ LOCAL_CFLAGS += -g -O1 -fexceptions -flto CRENGINE_SRC_FILES := \ ../../crengine/src/cp_stats.cpp \ ../../crengine/src/lvstring.cpp \ + ../../crengine/src/lvstring8collection.cpp \ + ../../crengine/src/lvstring16collection.cpp \ + ../../crengine/src/lvstring16hashedcollection.cpp \ + ../../crengine/src/crlog.cpp \ + ../../crengine/src/serialbuf.cpp \ ../../crengine/src/props.cpp \ ../../crengine/src/lstridmap.cpp \ ../../crengine/src/rtfimp.cpp \ diff --git a/android/jni/cr3engine.cpp b/android/jni/cr3engine.cpp index d7ce1e4a6f..cdb6c4b636 100644 --- a/android/jni/cr3engine.cpp +++ b/android/jni/cr3engine.cpp @@ -647,7 +647,9 @@ void cr3androidFatalErrorHandler(int errorCode, const char * errorText ) /// set fatal error handler void crSetFatalErrorHandler( lv_FatalErrorHandler_t * handler ); -jboolean initInternal(JNIEnv * penv, jclass obj, jobjectArray fontArray) { +jboolean initInternal(JNIEnv * penv, jclass obj, jobjectArray fontArray, jint sdk_int) { + + CRJNIEnv::sdk_int = sdk_int; CRJNIEnv env(penv); @@ -686,13 +688,13 @@ jboolean initInternal(JNIEnv * penv, jclass obj, jobjectArray fontArray) { /* * Class: org_coolreader_crengine_Engine * Method: initInternal - * Signature: ([Ljava/lang/String;)Z + * Signature: ([Ljava/lang/String;I)Z */ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_initInternal - (JNIEnv * penv, jclass obj, jobjectArray fontArray) + (JNIEnv * penv, jclass obj, jobjectArray fontArray, jint sdk_int) { jboolean res = JNI_FALSE; - COFFEE_TRY_JNI(penv, res = initInternal(penv, obj, fontArray)); + COFFEE_TRY_JNI(penv, res = initInternal(penv, obj, fontArray, sdk_int)); return res; } @@ -817,6 +819,52 @@ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_checkFontLanguage return res; } +/* + * Class: org_coolreader_crengine_Engine + * Method: listFilesInternal + * Signature: (Ljava/io/File;)[Ljava/io/File; + */ +JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_listFilesInternal + (JNIEnv *env, jclass, jobject jdir) +{ + if (NULL == jdir) + return NULL; + jclass pjcFile = env->FindClass("java/io/File"); + if (NULL == pjcFile) + return NULL; + jmethodID pjmFile_GetAbsolutePath = env->GetMethodID(pjcFile, "getAbsolutePath", "()Ljava/lang/String;"); + if (NULL == pjmFile_GetAbsolutePath) + return NULL; + jmethodID pjmFile_Ctor = env->GetMethodID(pjcFile, "", "(Ljava/lang/String;)V"); + if (NULL == pjmFile_Ctor) + return NULL; + jstring jpathname = (jstring)env->CallObjectMethod(jdir, pjmFile_GetAbsolutePath); + jboolean iscopy; + const char * s = env->GetStringUTFChars(jpathname, &iscopy); + lString16 path = (CRJNIEnv::sdk_int >= ANDROID_SDK_M) ? Utf8ToUnicode(s) : Wtf8ToUnicode(s); + env->ReleaseStringUTFChars(jpathname, s); + jobjectArray jarray = NULL; + LVContainerRef dir = LVOpenDirectory(path); + if ( !dir.isNull() ) { + jstring emptyString = env->NewStringUTF(""); + jobject emptyFile = env->NewObject(pjcFile, pjmFile_Ctor, emptyString); + jarray = env->NewObjectArray(dir->GetObjectCount(), pjcFile, emptyFile); + if (NULL != jarray) { + for (int i = 0; i < dir->GetObjectCount(); i++) { + const LVContainerItemInfo *item = dir->GetObjectInfo(i); + lString16 fileName = path + "/" + item->GetName(); + jstring jfilename = env->NewStringUTF( + (CRJNIEnv::sdk_int >= ANDROID_SDK_M) ? UnicodeToUtf8(fileName).c_str() + : UnicodeToWtf8(fileName).c_str()); + jobject jfile = env->NewObject(pjcFile, pjmFile_Ctor, jfilename); + if (NULL != jfile) + env->SetObjectArrayElement(jarray, i, jfile); + } + } + } + return jarray; +} + /* * Class: org_coolreader_crengine_Engine * Method: isLink @@ -885,7 +933,7 @@ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_setKeyBacklightIn static JNINativeMethod sEngineMethods[] = { /* name, signature, funcPtr */ - {"initInternal", "([Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_Engine_initInternal}, + {"initInternal", "([Ljava/lang/String;I)Z", (void*)Java_org_coolreader_crengine_Engine_initInternal}, {"uninitInternal", "()V", (void*)Java_org_coolreader_crengine_Engine_uninitInternal}, {"getFontFaceListInternal", "()[Ljava/lang/String;", (void*)Java_org_coolreader_crengine_Engine_getFontFaceListInternal}, {"getFontFaceAndFileNameListInternal", "()[Ljava/lang/String;", (void*)Java_org_coolreader_crengine_Engine_getFontFaceAndFileNameListInternal}, @@ -898,6 +946,9 @@ static JNINativeMethod sEngineMethods[] = { {"setKeyBacklightInternal", "(I)Z", (void*)Java_org_coolreader_crengine_Engine_setKeyBacklightInternal}, {"scanBookCoverInternal", "(Ljava/lang/String;)[B", (void*)Java_org_coolreader_crengine_Engine_scanBookCoverInternal}, {"drawBookCoverInternal", "(Landroid/graphics/Bitmap;[BLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V", (void*)Java_org_coolreader_crengine_Engine_drawBookCoverInternal}, + {"haveFcLangCodeInternal", "(Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_Engine_haveFcLangCodeInternal}, + {"checkFontLanguageCompatibilityInternal", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_Engine_checkFontLanguageCompatibilityInternal}, + {"listFilesInternal", "(Ljava/io/File;)[Ljava/io/File;", (void*)Java_org_coolreader_crengine_Engine_listFilesInternal} }; diff --git a/android/jni/cr3java.cpp b/android/jni/cr3java.cpp index aea3e678f1..a0276b8389 100644 --- a/android/jni/cr3java.cpp +++ b/android/jni/cr3java.cpp @@ -1,21 +1,34 @@ #include "cr3java.h" +#include "../../crengine/include/crlog.h" #include +uint8_t CRJNIEnv::sdk_int = 0; + lString16 CRJNIEnv::fromJavaString( jstring str ) { if (!str) return lString16::empty_str; jboolean iscopy; const char * s = env->GetStringUTFChars(str, &iscopy); - lString16 res(s); + lString16 res; + if (CRJNIEnv::sdk_int >= ANDROID_SDK_M) + res = Utf8ToUnicode(s); + else + res = Wtf8ToUnicode(s); env->ReleaseStringUTFChars(str, s); return res; } jstring CRJNIEnv::toJavaString( const lString16 & str ) { - return env->NewStringUTF(UnicodeToUtf8(str).c_str()); + if (CRJNIEnv::sdk_int >= ANDROID_SDK_M) + return env->NewStringUTF(UnicodeToUtf8(str).c_str()); + // To support 4-byte UTF-8 sequence on Android older that 6.0 (API 23), + // we encode characters with codes >= 0x10000 to WTF-8. + // Otherwise, we have crash with following message: + // "input is not valid Modified UTF-8: illegal start byte 0xf0" + return env->NewStringUTF(UnicodeToWtf8(str).c_str()); } void CRJNIEnv::fromJavaStringArray( jobjectArray array, lString16Collection & dst ) diff --git a/android/jni/cr3java.h b/android/jni/cr3java.h index ce03add21b..b0bf89eb01 100644 --- a/android/jni/cr3java.h +++ b/android/jni/cr3java.h @@ -20,6 +20,9 @@ #include "../../crengine/include/props.h" #include "../../crengine/include/lvtinydom.h" +// M is for Marshmallow! +#define ANDROID_SDK_M 23 + //==================================================================== // libjnigraphics replacement for pre-2.2 SDKs enum AndroidBitmapFormat { @@ -58,6 +61,7 @@ class BitmapAccessorInterface { class CRJNIEnv { public: JNIEnv * env; + static uint8_t sdk_int; CRJNIEnv(JNIEnv * pEnv) : env(pEnv) { } JNIEnv * operator -> () { return env; } lString16 fromJavaString( jstring str ); diff --git a/android/jni/gen_jni_studio b/android/jni/gen_jni_studio index 6c61c78028..2d17c5c239 100644 --- a/android/jni/gen_jni_studio +++ b/android/jni/gen_jni_studio @@ -1,7 +1,7 @@ #!/bin/sh sdk="/opt/android-sdk-update-manager" -binclass_path=../app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes +binclass_path=../app/build/intermediates/javac/debug/classes export CLASSPATH="${CLASSPATH}:${sdk}/platforms/android-17/*:${binclass_path}" diff --git a/android/jni/org_coolreader_crengine_Engine.h b/android/jni/org_coolreader_crengine_Engine.h index e2fc3a0f74..5816a21565 100644 --- a/android/jni/org_coolreader_crengine_Engine.h +++ b/android/jni/org_coolreader_crengine_Engine.h @@ -22,10 +22,10 @@ extern "C" { /* * Class: org_coolreader_crengine_Engine * Method: initInternal - * Signature: ([Ljava/lang/String;)Z + * Signature: ([Ljava/lang/String;I)Z */ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_initInternal - (JNIEnv *, jclass, jobjectArray); + (JNIEnv *, jclass, jobjectArray, jint); /* * Class: org_coolreader_crengine_Engine @@ -121,7 +121,7 @@ JNIEXPORT void JNICALL Java_org_coolreader_crengine_Engine_suspendLongOperationI * Signature: (Ljava/lang/String;)Z */ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_haveFcLangCodeInternal - (JNIEnv *, jclass, jstring); + (JNIEnv *, jclass, jstring); /* * Class: org_coolreader_crengine_Engine @@ -131,6 +131,14 @@ JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_haveFcLangCodeInt JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_checkFontLanguageCompatibilityInternal (JNIEnv *, jclass, jstring, jstring); +/* + * Class: org_coolreader_crengine_Engine + * Method: listFilesInternal + * Signature: (Ljava/io/File;)[Ljava/io/File; + */ +JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_listFilesInternal + (JNIEnv *, jclass, jobject); + /* * Class: org_coolreader_crengine_Engine * Method: isLink diff --git a/android/src/org/coolreader/crengine/Engine.java b/android/src/org/coolreader/crengine/Engine.java index d0eb4e5cdc..fc055b46d5 100755 --- a/android/src/org/coolreader/crengine/Engine.java +++ b/android/src/org/coolreader/crengine/Engine.java @@ -592,7 +592,7 @@ public void initAgain() { } mFonts = findFonts(); findExternalHyphDictionaries(); - if (!initInternal(mFonts)) { + if (!initInternal(mFonts, DeviceInfo.getSDKLevel())) { log.i("Engine.initInternal failed!"); throw new RuntimeException("Cannot initialize CREngine JNI"); } @@ -601,7 +601,7 @@ public void initAgain() { } // Native functions - private native static boolean initInternal(String[] fontList); + private native static boolean initInternal(String[] fontList, int sdk_int); private native static void uninitInternal(); @@ -644,6 +644,8 @@ public void initAgain() { */ private native static boolean checkFontLanguageCompatibilityInternal(String fontFace, String langCode); + private native static File[] listFilesInternal(File dir); + public static void suspendLongOperation() { suspendLongOperationInternal(); } @@ -652,6 +654,10 @@ public synchronized static boolean checkFontLanguageCompatibility(String fontFac return checkFontLanguageCompatibilityInternal(fontFace, langCode); } + public static synchronized File[] listFiles(File dir) { + return listFilesInternal(dir); + } + /** * Finds the corresponding language code in embedded FontConfig language orthography catalog. * @@ -2136,7 +2142,7 @@ public MountPathCorrector getPathCorrector() { } mFonts = findFonts(); findExternalHyphDictionaries(); - if (!initInternal(mFonts)) { + if (!initInternal(mFonts, DeviceInfo.getSDKLevel())) { log.i("Engine.initInternal failed!"); throw new RuntimeException("Cannot initialize CREngine JNI"); } diff --git a/android/src/org/coolreader/crengine/Scanner.java b/android/src/org/coolreader/crengine/Scanner.java index 1f0c8374ec..9c01ac83d9 100755 --- a/android/src/org/coolreader/crengine/Scanner.java +++ b/android/src/org/coolreader/crengine/Scanner.java @@ -114,7 +114,15 @@ public boolean listDirectory(FileInfo baseDir) } try { File dir = new File(baseDir.pathname); - File[] items = dir.listFiles(); + //File[] items = dir.listFiles(); + // To resolve unhandled exception + // 'JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0' + // that can be produced by invalid filename (broken sdcard, etc) + // or 'JNI WARNING: input is not valid Modified UTF-8: illegal start byte 0xf0' + // that can be generated if 4-byte UTF-8 sequence found in the filename, + // we implement own directory listing method instead of File.listFiles(). + // TODO: replace other occurrences of the method File.listFiles(). + File[] items = Engine.listFiles(dir); // process normal files if ( items!=null ) { for ( File f : items ) { diff --git a/crengine/CMakeLists.txt b/crengine/CMakeLists.txt index f585ccb065..c9a3e192f8 100644 --- a/crengine/CMakeLists.txt +++ b/crengine/CMakeLists.txt @@ -3,64 +3,69 @@ option(BUILD_TOOLS "Build tools" OFF) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/fc-lang) -SET (CRENGINE_SOURCES -src/cp_stats.cpp -src/lvstring.cpp -src/props.cpp -src/lstridmap.cpp -src/rtfimp.cpp -src/cri18n.cpp -src/lvmemman.cpp -src/lvstyles.cpp -src/crtxtenc.cpp -src/lvtinydom.cpp -src/lvstream.cpp -src/lvxml.cpp -src/lvstsheet.cpp -src/txtselector.cpp -#src/xutils.cpp -src/crtest.cpp -fc-lang/fc-lang-cat.c +SET (CRENGINE_SOURCES + src/cp_stats.cpp + src/lvstring.cpp + src/lvstring8collection.cpp + src/lvstring16collection.cpp + src/lvstring16hashedcollection.cpp + src/serialbuf.cpp + src/crlog.cpp + src/props.cpp + src/lstridmap.cpp + src/rtfimp.cpp + src/cri18n.cpp + src/lvmemman.cpp + src/lvstyles.cpp + src/crtxtenc.cpp + src/lvtinydom.cpp + src/lvstream.cpp + src/lvxml.cpp + src/lvstsheet.cpp + src/txtselector.cpp + #src/xutils.cpp + src/crtest.cpp + fc-lang/fc-lang-cat.c ) if ( NOT ${GUI} STREQUAL FB2PROPS ) SET (CRENGINE_SOURCES ${CRENGINE_SOURCES} - src/lvbmpbuf.cpp - src/lvfnt.cpp - src/hyphman.cpp - src/lvembeddedfont.cpp - src/lvfont.cpp - src/lvfntman.cpp - src/crgui.cpp - src/lvimg.cpp - src/crskin.cpp - src/lvdrawbuf.cpp - src/lvdocview.cpp - src/lvpagesplitter.cpp - src/lvtextfm.cpp - src/lvrend.cpp - src/wolutil.cpp - src/hist.cpp - src/chmfmt.cpp - src/epubfmt.cpp - src/pdbfmt.cpp - src/wordfmt.cpp - src/lvopc.cpp - src/docxfmt.cpp - src/fb3fmt.cpp - src/crconcurrent.cpp - src/private/lvbasefont.cpp - src/private/lvbitmapfont.cpp - src/private/lvbitmapfontman.cpp - src/private/lvfontglyphcache.cpp - src/private/lvfontcache.cpp - src/private/lvfontboldtransform.cpp - src/private/lvfontdef.cpp - src/private/lvwin32font.cpp - src/private/lvwin32fontman.cpp - src/private/lvfreetypeface.cpp - src/private/lvfreetypefontman.cpp - #src/xutils.cpp + src/lvbmpbuf.cpp + src/lvfnt.cpp + src/hyphman.cpp + src/lvembeddedfont.cpp + src/lvfont.cpp + src/lvfntman.cpp + src/crgui.cpp + src/lvimg.cpp + src/crskin.cpp + src/lvdrawbuf.cpp + src/lvdocview.cpp + src/lvpagesplitter.cpp + src/lvtextfm.cpp + src/lvrend.cpp + src/wolutil.cpp + src/hist.cpp + src/chmfmt.cpp + src/epubfmt.cpp + src/pdbfmt.cpp + src/wordfmt.cpp + src/lvopc.cpp + src/docxfmt.cpp + src/fb3fmt.cpp + src/crconcurrent.cpp + src/private/lvbasefont.cpp + src/private/lvbitmapfont.cpp + src/private/lvbitmapfontman.cpp + src/private/lvfontglyphcache.cpp + src/private/lvfontcache.cpp + src/private/lvfontboldtransform.cpp + src/private/lvfontdef.cpp + src/private/lvwin32font.cpp + src/private/lvwin32fontman.cpp + src/private/lvfreetypeface.cpp + src/private/lvfreetypefontman.cpp + #src/xutils.cpp ) endif (NOT ${GUI} STREQUAL FB2PROPS) diff --git a/crengine/Tools/CMakeLists.txt b/crengine/Tools/CMakeLists.txt index f70201d188..cbc0694b47 100644 --- a/crengine/Tools/CMakeLists.txt +++ b/crengine/Tools/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(HyphConv) add_subdirectory(langstat) add_subdirectory(langstat2) add_subdirectory(glyphcache_bench) +add_subdirectory(wtf8-test) diff --git a/crengine/Tools/HyphConv/CMakeLists.txt b/crengine/Tools/HyphConv/CMakeLists.txt index 458c4571d1..8875b8d6d3 100644 --- a/crengine/Tools/HyphConv/CMakeLists.txt +++ b/crengine/Tools/HyphConv/CMakeLists.txt @@ -9,6 +9,8 @@ set(crengine_part_SRC_LIST ../../src/lvmemman.cpp ../../src/cp_stats.cpp ../../src/lvstream.cpp + ../../src/crlog.cpp + ../../src/serialbuf.cpp ) if(UNIX) diff --git a/crengine/Tools/langstat/CMakeLists.txt b/crengine/Tools/langstat/CMakeLists.txt index e38f18d492..d39056bc8d 100644 --- a/crengine/Tools/langstat/CMakeLists.txt +++ b/crengine/Tools/langstat/CMakeLists.txt @@ -9,6 +9,8 @@ set(crengine_part_SRC_LIST ../../src/lvmemman.cpp ../../src/lvstream.cpp ../../src/lvstring.cpp + ../../src/crlog.cpp + ../../src/serialbuf.cpp ) add_definitions(-DBUILD_LITE=1) diff --git a/crengine/Tools/langstat2/CMakeLists.txt b/crengine/Tools/langstat2/CMakeLists.txt index 4defad6ce4..ef27fb467c 100644 --- a/crengine/Tools/langstat2/CMakeLists.txt +++ b/crengine/Tools/langstat2/CMakeLists.txt @@ -9,6 +9,8 @@ set(crengine_part_SRC_LIST ../../src/lvmemman.cpp ../../src/lvstream.cpp ../../src/lvstring.cpp + ../../src/crlog.cpp + ../../src/serialbuf.cpp ) if(UNIX) diff --git a/crengine/Tools/wtf8-test/CMakeLists.txt b/crengine/Tools/wtf8-test/CMakeLists.txt new file mode 100644 index 0000000000..00d8946607 --- /dev/null +++ b/crengine/Tools/wtf8-test/CMakeLists.txt @@ -0,0 +1,28 @@ + +set(SRC_LIST + main.cpp +) + +set(crengine_part_SRC_LIST + ../../src/cp_stats.cpp + ../../src/crtxtenc.cpp + ../../src/lvmemman.cpp + ../../src/lvstream.cpp + ../../src/lvstring.cpp + ../../src/crlog.cpp + ../../src/serialbuf.cpp +) + +#add_definitions(-DBUILD_LITE=1) + +if(UNIX) + add_definitions(-DLINUX -D_LINUX) +endif(UNIX) + +if(WIN32) + add_definitions(-DWIN32 -D_CONSOLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mconsole") +endif(WIN32) + +add_executable(wtf8-test ${SRC_LIST} ${crengine_part_SRC_LIST}) +target_link_libraries(wtf8-test ${STD_LIBS}) diff --git a/crengine/Tools/wtf8-test/main.cpp b/crengine/Tools/wtf8-test/main.cpp new file mode 100644 index 0000000000..4c176a85b8 --- /dev/null +++ b/crengine/Tools/wtf8-test/main.cpp @@ -0,0 +1,42 @@ +#include "lvstring.h" + +#include + +lUInt32 uni_chars[] = { + 0x10000, // LINEAR B SYLLABLE B008 A + 0x10123, // AEGEAN NUMBER TWO THOUSAND + 0x10081, // LINEAR B IDEOGRAM B102 WOMAN + 0x1F600, // GRINNING FACE + 0x1F601, // GRINNING FACE WITH SMILING EYES + 0x1F602, // FACE WITH TEARS OF JOY + 0x1F603, // SMILING FACE WITH OPEN MOUTH + 0x1F604, // SMILING FACE WITH OPEN MOUTH AND SMILING EYES + 0x1F605, // SMILING FACE WITH OPEN MOUTH AND COLD SWEAT + 0x1F606, // SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES + 0x1F607, // SMILING FACE WITH HALO + 0x1F608, // SMILING FACE WITH HORNS + 0x1F609, // WINKING FACE + 0x1F60A, // SMILING FACE WITH SMILING EYES + 0x1F60B // FACE SAVOURING DELICIOUS FOOD +}; + +int main(int argc, char* argv[]) +{ + lString16 src; + for (size_t i = 0; i < sizeof(uni_chars)/sizeof(lUInt32); i++) + { + src.append(1, uni_chars[i]); + } + lString8 dst = UnicodeToUtf8(src); + printf("UTF8: %s\n", dst.c_str()); + lString8 dstw = UnicodeToWtf8(src); + printf("WTF8: %s\n", dstw.c_str()); + // Back to unicode + lString16 str2 = Wtf8ToUnicode(dstw); + // and compare... + if (str2.compare(src) == 0) + printf("OK, strings is equal.\n"); + else + printf("Sorry, strings is NOT equal!\n"); + return 0; +} diff --git a/crengine/include/crlog.h b/crengine/include/crlog.h new file mode 100644 index 0000000000..f80ed83cda --- /dev/null +++ b/crengine/include/crlog.h @@ -0,0 +1,68 @@ +/** \file crlog.h + \brief logging class interface + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __CR_LOG_H_INCLUDED__ +#define __CR_LOG_H_INCLUDED__ + +#include + +/// Logger +class CRLog +{ +public: + /// log levels + enum log_level { + LL_FATAL, + LL_ERROR, + LL_WARN, + LL_INFO, + LL_DEBUG, + LL_TRACE + }; + /// set current log level + static void setLogLevel( log_level level ); + /// returns current log level + static log_level getLogLevel(); + /// returns true if specified log level is enabled + static bool isLogLevelEnabled( log_level level ); + /// returns true if log level is DEBUG or lower + static bool inline isDebugEnabled() { return isLogLevelEnabled( LL_DEBUG ); } + /// returns true if log level is TRACE + static bool inline isTraceEnabled() { return isLogLevelEnabled( LL_TRACE ); } + /// returns true if log level is INFO or lower + static bool inline isInfoEnabled() { return isLogLevelEnabled( LL_INFO ); } + /// returns true if log level is WARN or lower + static bool inline isWarnEnabled() { return isLogLevelEnabled( LL_WARN ); } + static void fatal( const char * msg, ... ); + static void error( const char * msg, ... ); + static void warn( const char * msg, ... ); + static void info( const char * msg, ... ); + static void debug( const char * msg, ... ); + static void trace( const char * msg, ... ); + /// sets logger instance + static void setLogger( CRLog * logger ); + virtual ~CRLog(); + + /// write log to specified file, flush after every message if autoFlush parameter is true + static void setFileLogger( const char * fname, bool autoFlush=false ); + /// use stdout for output + static void setStdoutLogger(); + /// use stderr for output + static void setStderrLogger(); +protected: + CRLog(); + virtual void log( const char * level, const char * msg, va_list args ) = 0; + log_level curr_level; + static CRLog * CRLOG; +}; + +#endif // __CR_LOG_H_INCLUDED__ diff --git a/crengine/include/crskin.h b/crengine/include/crskin.h index fbd7c6cdc7..6fd4ffa3ea 100644 --- a/crengine/include/crskin.h +++ b/crengine/include/crskin.h @@ -24,6 +24,7 @@ #include "lvptrvec.h" #include "lvref.h" #include "lvstring.h" +#include "crlog.h" #include "lvfntman.h" #include "lvdrawbuf.h" #include "lvtinydom.h" diff --git a/crengine/include/crtest.h b/crengine/include/crtest.h index b3a7097975..f363c232cc 100644 --- a/crengine/include/crtest.h +++ b/crengine/include/crtest.h @@ -4,6 +4,7 @@ #include "lvtypes.h" #include "lvstring.h" #include "lvstream.h" +#include "crlog.h" #define MYASSERT(x,t) \ if (!(x)) { \ diff --git a/crengine/include/crtimerutil.h b/crengine/include/crtimerutil.h new file mode 100644 index 0000000000..87d25f08e3 --- /dev/null +++ b/crengine/include/crtimerutil.h @@ -0,0 +1,93 @@ +/** \file crtimerutil.h + \brief timer to interval expiration + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + See LICENSE file for details. +*/ + +#ifndef __CR_TIMERUTIL_H_INCLUDED__ +#define __CR_TIMERUTIL_H_INCLUDED__ + +#include "lvtypes.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +/// timer to interval expiration, in milliseconds +class CRTimerUtil { + lInt64 _start; + volatile lInt64 _interval; +public: + static lInt64 getSystemTimeMillis() { +#ifdef _WIN32 + FILETIME ts; + GetSystemTimeAsFileTime(&ts); + return ((lInt64)ts.dwLowDateTime)/10000 + ((lInt64)ts.dwHighDateTime)*1000; +#else + timeval ts; + gettimeofday(&ts, 0); + return ((lInt64)ts.tv_usec)/1000 + ((lInt64)ts.tv_sec)*1000; +#endif + } + + /// create timer with infinite limit + CRTimerUtil() { + _start = getSystemTimeMillis(); + _interval = -1; + } + + /// create timer with limited interval (milliseconds) + CRTimerUtil(lInt64 expirationIntervalMillis) { + _start = getSystemTimeMillis(); + _interval = expirationIntervalMillis; + } + + CRTimerUtil(const CRTimerUtil & t) { + _start = t._start; + _interval = t._interval; + } + + void restart() { + _start = getSystemTimeMillis(); + } + + void restart(lInt64 expirationIntervalMillis) { + _start = getSystemTimeMillis(); + _interval = expirationIntervalMillis; + } + + CRTimerUtil & operator = (const CRTimerUtil & t) { + _start = t._start; + _interval = t._interval; + return *this; + } + + void cancel() { + _interval = 0; + } + + /// returns true if timeout is infinite + bool infinite() { + return _interval==-1; + } + /// returns true if expirationIntervalMillis is expired + bool expired() { + if ( _interval==-1 ) + return false; + return getSystemTimeMillis() - _start >= _interval; + } + /// return milliseconds elapsed since timer start + lInt64 elapsed() { + return getSystemTimeMillis() - _start; + } + int interval() { + return (int)_interval; + } +}; + +#endif // __CR_TIMERUTIL_H_INCLUDED__ diff --git a/crengine/include/lstridmap.h b/crengine/include/lstridmap.h index 15db4afc4a..ecd95d9fcb 100644 --- a/crengine/include/lstridmap.h +++ b/crengine/include/lstridmap.h @@ -21,6 +21,7 @@ #include struct css_elem_def_props_t; +class SerialBuf; //=========================================== class LDOMNameIdMapItem diff --git a/crengine/include/lvembeddedfont.h b/crengine/include/lvembeddedfont.h index 917142dbe4..07c29925ea 100644 --- a/crengine/include/lvembeddedfont.h +++ b/crengine/include/lvembeddedfont.h @@ -19,6 +19,7 @@ #include "lvstring.h" #include "lvptrvec.h" +class SerialBuf; class LVEmbeddedFontDef { lString16 _url; diff --git a/crengine/include/lvfntman.h b/crengine/include/lvfntman.h index fcd19c9cda..4d634f1ba9 100644 --- a/crengine/include/lvfntman.h +++ b/crengine/include/lvfntman.h @@ -18,6 +18,7 @@ #include #include "crsetup.h" #include "lvstring.h" +#include "lvstring16collection.h" #include "lvfont.h" diff --git a/crengine/include/lvfont.h b/crengine/include/lvfont.h index be17282755..7a7cc726db 100644 --- a/crengine/include/lvfont.h +++ b/crengine/include/lvfont.h @@ -67,10 +67,11 @@ class LVFont : public LVRefCounter { virtual int getVisualAligmentWidth(); /** \brief get glyph info + \param code is unicode character code \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ - virtual bool getGlyphInfo(lUInt16 code, glyph_info_t *glyph, lChar16 def_char = 0) = 0; + virtual bool getGlyphInfo(lUInt32 code, glyph_info_t *glyph, lChar16 def_char = 0) = 0; /** \brief measure text \param text is text string pointer @@ -104,12 +105,12 @@ class LVFont : public LVRefCounter { // \param buf is buffer [width*height] to place glyph data // \return true if glyph was found // */ -// virtual bool getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char=0) = 0; +// virtual bool getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char=0) = 0; /** \brief get glyph item - \param code is unicode character + \param code is unicode character code \return glyph pointer if glyph was found, NULL otherwise */ - virtual LVFontGlyphCacheItem *getGlyph(lUInt16 ch, lChar16 def_char = 0) = 0; + virtual LVFontGlyphCacheItem *getGlyph(lUInt32 ch, lChar16 def_char = 0) = 0; /// returns font baseline offset virtual int getBaseline() = 0; diff --git a/crengine/include/lvpagesplitter.h b/crengine/include/lvpagesplitter.h index d25d2b5faa..3e47130960 100644 --- a/crengine/include/lvpagesplitter.h +++ b/crengine/include/lvpagesplitter.h @@ -21,6 +21,7 @@ #include "lvref.h" #include "lvstring.h" #include "lvhashtable.h" +#include "crtimerutil.h" #ifndef RENDER_PROGRESS_INTERVAL_MILLIS #define RENDER_PROGRESS_INTERVAL_MILLIS 1200 @@ -52,6 +53,8 @@ enum page_type_t { PAGE_TYPE_COVER = 1 }; +class SerialBuf; + /// footnote fragment inside page class LVPageFootNoteInfo { public: diff --git a/crengine/include/lvstream.h b/crengine/include/lvstream.h index 1c486887a5..7a881326a9 100644 --- a/crengine/include/lvstream.h +++ b/crengine/include/lvstream.h @@ -32,6 +32,7 @@ #include "lvstring.h" #include "lvarray.h" #include "lvptrvec.h" +#include "crtimerutil.h" #if LVLONG_FILE_SUPPORT == 1 typedef lUInt64 lvsize_t; ///< file size type diff --git a/crengine/include/lvstring.h b/crengine/include/lvstring.h index 106cc6e182..a9d040f5c2 100644 --- a/crengine/include/lvstring.h +++ b/crengine/include/lvstring.h @@ -744,151 +744,9 @@ const lString16 & cs16(const char * str); /// get reference to atomic constant wide string for string literal e.g. cs16(L"abc") -- fast and memory effective replacement of lString16(L"abc") const lString16 & cs16(const lChar16 * str); -/// collection of wide strings -class lString16Collection -{ -private: - lstring16_chunk_t * * chunks; - int count; - int size; -public: - lString16Collection() - : chunks(NULL), count(0), size(0) - { } - /// parse delimiter-separated string - void parse( lString16 string, lChar16 delimiter, bool flgTrim ); - /// parse delimiter-separated string - void parse( lString16 string, lString16 delimiter, bool flgTrim ); - void reserve(int space); - int add( const lString16 & str ); - int add(const lChar16 * str) { return add(lString16(str)); } - int add(const lChar8 * str) { return add(lString16(str)); } - void addAll( const lString16Collection & v ) - { - for (int i=0; i class lStringBuf16 { - lString16 & str; - lChar16 buf[BUFSIZE]; - int pos; - lStringBuf16 & operator = (const lStringBuf16 & v) - { - CR_UNUSED(v); - // not available - return *this; - } -public: - lStringBuf16( lString16 & s ) - : str(s), pos(0) - { - } - inline void append( lChar16 ch ) - { - buf[ pos++ ] = ch; - if ( pos==BUFSIZE ) - flush(); - } - inline lStringBuf16& operator << ( lChar16 ch ) - { - buf[ pos++ ] = ch; - if ( pos==BUFSIZE ) - flush(); - return *this; - } - inline void flush() - { - str.append( buf, pos ); - pos = 0; - } - ~lStringBuf16( ) - { - flush(); - } -}; - -/// fast 8-bit string character appender -template class lStringBuf8 { - lString8 & str; - lChar8 buf[BUFSIZE]; - int pos; -public: - lStringBuf8( lString8 & s ) - : str(s), pos(0) - { - } - inline void append( lChar8 ch ) - { - buf[ pos++ ] = ch; - if ( pos==BUFSIZE ) - flush(); - } - inline lStringBuf8& operator << ( lChar8 ch ) - { - buf[ pos++ ] = ch; - if ( pos==BUFSIZE ) - flush(); - return *this; - } - inline void flush() - { - str.append( buf, pos ); - pos = 0; - } - ~lStringBuf8( ) - { - flush(); - } -}; - lString8 UnicodeToTranslit( const lString16 & str ); /// converts wide unicode string to local 8-bit encoding lString8 UnicodeToLocal( const lString16 & str ); @@ -1030,6 +814,10 @@ lString8 UnicodeToLocal( const lString16 & str ); lString8 UnicodeToUtf8( const lString16 & str ); /// converts wide unicode string to utf-8 string lString8 UnicodeToUtf8(const lChar16 * s, int count); +/// converts wide unicode string to wtf-8 string +lString8 UnicodeToWtf8( const lString16 & str ); +/// converts wide unicode string to wtf-8 string +lString8 UnicodeToWtf8(const lChar16 * s, int count); /// converts unicode string to 8-bit string using specified conversion table lString8 UnicodeTo8Bit( const lString16 & str, const lChar8 * * table ); /// converts 8-bit string to unicode string using specified conversion table for upper 128 characters @@ -1044,6 +832,12 @@ lString16 Utf8ToUnicode( const char * s ); lString16 Utf8ToUnicode( const char * s, int sz ); /// converts utf-8 string fragment to wide unicode string void Utf8ToUnicode(const lUInt8 * src, int &srclen, lChar16 * dst, int &dstlen); +/// converts wtf-8 string to wide unicode string +lString16 Wtf8ToUnicode( const lString8 & str ); +/// converts utf-8 c-string to wide unicode string +lString16 Wtf8ToUnicode( const char * s ); +/// converts utf-8 string fragment to wide unicode string +lString16 Wtf8ToUnicode( const char * s, int sz ); /// decodes path like "file%20name" to "file name" lString16 DecodeHTMLUrlString( lString16 s ); /// truncates string by specified size, appends ... if truncated, prefers to wrap whole words @@ -1055,191 +849,8 @@ int TrimDoubleSpaces(lChar16 * buf, int len, bool allowStartSpace, bool allowEn #define LCSTR(x) (UnicodeToUtf8(x).c_str()) bool splitIntegerList( lString16 s, lString16 delim, int & value1, int & value2 ); -/// serialization/deserialization buffer -class SerialBuf -{ - lUInt8 * _buf; - bool _ownbuf; - bool _error; - bool _autoresize; - int _size; - int _pos; -public: - /// swap content of buffer with another buffer - void swap( SerialBuf & v ); - /// constructor of serialization buffer - SerialBuf( int sz, bool autoresize = true ); - SerialBuf( const lUInt8 * p, int sz ); - ~SerialBuf(); - - void set( lUInt8 * buf, int size ) - { - if ( _buf && _ownbuf ) - free( _buf ); - _buf = buf; - _ownbuf = true; - _error = false; - _autoresize = true; - _size = _pos = size; - } - bool copyTo( lUInt8 * buf, int maxSize ); - inline lUInt8 * buf() { return _buf; } - inline void setPos( int pos ) { _pos = pos; } - inline int space() const { return _size-_pos; } - inline int pos() const { return _pos; } - inline int size() const { return _size; } - - /// returns true if error occured during one of operations - inline bool error() const { return _error; } - - inline void seterror() { _error = true; } - /// move pointer to beginning, clear error flag - inline void reset() { _error = false; _pos = 0; } - - /// checks whether specified number of bytes is available, returns true in case of error - bool check( int reserved ); - - // write methods - /// put magic signature - void putMagic( const char * s ); - - /// add CRC32 for last N bytes - void putCRC( int N ); - - /// returns CRC32 for the whole buffer - lUInt32 getCRC(); - - /// add contents of another buffer - SerialBuf & operator << ( const SerialBuf & v ); - - SerialBuf & operator << ( lUInt8 n ); - - SerialBuf & operator << ( char n ); - - SerialBuf & operator << ( bool n ); - - SerialBuf & operator << ( lUInt16 n ); - - SerialBuf & operator << ( lInt16 n ); - - SerialBuf & operator << ( lUInt32 n ); - - SerialBuf & operator << ( lInt32 n ); - - SerialBuf & operator << ( const lString16 & s ); - - SerialBuf & operator << ( const lString8 & s8 ); - - // read methods - SerialBuf & operator >> ( lUInt8 & n ); - - SerialBuf & operator >> ( char & n ); - - SerialBuf & operator >> ( bool & n ); - - SerialBuf & operator >> ( lUInt16 & n ); - - SerialBuf & operator >> ( lInt16 & n ); - - SerialBuf & operator >> ( lUInt32 & n ); - - SerialBuf & operator >> ( lInt32 & n ); - - SerialBuf & operator >> ( lString8 & s8 ); - - SerialBuf & operator >> ( lString16 & s ); - - bool checkMagic( const char * s ); - /// read crc32 code, comapare with CRC32 for last N bytes - bool checkCRC( int N ); -}; - - -/// Logger -class CRLog -{ -public: - /// log levels - enum log_level { - LL_FATAL, - LL_ERROR, - LL_WARN, - LL_INFO, - LL_DEBUG, - LL_TRACE - }; - /// set current log level - static void setLogLevel( log_level level ); - /// returns current log level - static log_level getLogLevel(); - /// returns true if specified log level is enabled - static bool isLogLevelEnabled( log_level level ); - /// returns true if log level is DEBUG or lower - static bool inline isDebugEnabled() { return isLogLevelEnabled( LL_DEBUG ); } - /// returns true if log level is TRACE - static bool inline isTraceEnabled() { return isLogLevelEnabled( LL_TRACE ); } - /// returns true if log level is INFO or lower - static bool inline isInfoEnabled() { return isLogLevelEnabled( LL_INFO ); } - /// returns true if log level is WARN or lower - static bool inline isWarnEnabled() { return isLogLevelEnabled( LL_WARN ); } - static void fatal( const char * msg, ... ); - static void error( const char * msg, ... ); - static void warn( const char * msg, ... ); - static void info( const char * msg, ... ); - static void debug( const char * msg, ... ); - static void trace( const char * msg, ... ); - /// sets logger instance - static void setLogger( CRLog * logger ); - virtual ~CRLog(); - - /// write log to specified file, flush after every message if autoFlush parameter is true - static void setFileLogger( const char * fname, bool autoFlush=false ); - /// use stdout for output - static void setStdoutLogger(); - /// use stderr for output - static void setStderrLogger(); -protected: - CRLog(); - virtual void log( const char * level, const char * msg, va_list args ) = 0; - log_level curr_level; - static CRLog * CRLOG; -}; - - +#if LDOM_USE_OWN_MEM_MAN==1 void free_ls_storage(); - -lUInt64 GetCurrentTimeMillis(); -void CRReinitTimer(); - - - -#ifdef _DEBUG -#include -class DumpFile -{ -public: - FILE * f; - DumpFile( const char * fname ) - : f(NULL) - { - if ( fname ) - f = fopen( fname, "at" ); - if ( !f ) - f = stdout; - fprintf(f, "DumpFile log started\n"); - } - ~DumpFile() - { - if ( f!=stdout ) - fclose(f); - } - operator FILE * () { if (f) fflush(f); return f?f:stdout; } -}; -#endif - #endif - - - - +#endif // __LV_STRING_H_INCLUDED__ diff --git a/crengine/include/lvstring16collection.h b/crengine/include/lvstring16collection.h new file mode 100644 index 0000000000..2d85de4378 --- /dev/null +++ b/crengine/include/lvstring16collection.h @@ -0,0 +1,74 @@ +/** \file lvstring16collection.h + \brief collection of wide strings + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __LV_STRING16COLLECTION_H_INCLUDED__ +#define __LV_STRING16COLLECTION_H_INCLUDED__ + +#include "lvstring.h" + +/// collection of wide strings +class lString16Collection +{ +private: + lstring16_chunk_t * * chunks; + int count; + int size; +public: + lString16Collection() + : chunks(NULL), count(0), size(0) + { } + /// parse delimiter-separated string + void parse( lString16 string, lChar16 delimiter, bool flgTrim ); + /// parse delimiter-separated string + void parse( lString16 string, lString16 delimiter, bool flgTrim ); + void reserve(int space); + int add( const lString16 & str ); + int add(const lChar16 * str) { return add(lString16(str)); } + int add(const lChar8 * str) { return add(lString16(str)); } + void addAll( const lString16Collection & v ) + { + for (int i=0; i #include "crsetup.h" -#ifdef _WIN32 -#include -#else -#include -#endif - #ifdef _WIN32 typedef long lInt32; ///< signed 32 bit int typedef unsigned long lUInt32; ///< unsigned 32 bit int @@ -315,78 +309,6 @@ class lvByteOrderConv { } }; -/// timer to interval expiration, in milliseconds -class CRTimerUtil { - lInt64 _start; - volatile lInt64 _interval; -public: - static lInt64 getSystemTimeMillis() { -#ifdef _WIN32 - FILETIME ts; - GetSystemTimeAsFileTime(&ts); - return ((lInt64)ts.dwLowDateTime)/10000 + ((lInt64)ts.dwHighDateTime)*1000; -#else - timeval ts; - gettimeofday(&ts, 0); - return ((lInt64)ts.tv_usec)/1000 + ((lInt64)ts.tv_sec)*1000; -#endif - } - - /// create timer with infinite limit - CRTimerUtil() { - _start = getSystemTimeMillis(); - _interval = -1; - } - - /// create timer with limited interval (milliseconds) - CRTimerUtil(lInt64 expirationIntervalMillis) { - _start = getSystemTimeMillis(); - _interval = expirationIntervalMillis; - } - - CRTimerUtil(const CRTimerUtil & t) { - _start = t._start; - _interval = t._interval; - } - - void restart() { - _start = getSystemTimeMillis(); - } - - void restart(lInt64 expirationIntervalMillis) { - _start = getSystemTimeMillis(); - _interval = expirationIntervalMillis; - } - - CRTimerUtil & operator = (const CRTimerUtil & t) { - _start = t._start; - _interval = t._interval; - return *this; - } - - void cancel() { - _interval = 0; - } - - /// returns true if timeout is infinite - bool infinite() { - return _interval==-1; - } - /// returns true if expirationIntervalMillis is expired - bool expired() { - if ( _interval==-1 ) - return false; - return getSystemTimeMillis() - _start >= _interval; - } - /// return milliseconds elapsed since timer start - lInt64 elapsed() { - return getSystemTimeMillis() - _start; - } - int interval() { - return (int)_interval; - } -}; - // MACROS to avoid UNUSED PARAM warning #define CR_UNUSED(x) (void)x; #define CR_UNUSED2(x,x2) (void)x;(void)x2; diff --git a/crengine/include/props.h b/crengine/include/props.h index d0a1339cdd..3d0d2a9a27 100644 --- a/crengine/include/props.h +++ b/crengine/include/props.h @@ -19,6 +19,7 @@ class CRPropAccessor; typedef LVFastRef CRPropRef; +class SerialBuf; /// interface to get/set properties class CRPropAccessor : public LVRefCounter { diff --git a/crengine/include/serialbuf.h b/crengine/include/serialbuf.h new file mode 100644 index 0000000000..d723ef46c7 --- /dev/null +++ b/crengine/include/serialbuf.h @@ -0,0 +1,118 @@ +/** \file serialbuf.h + \brief serialization buffer interface + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __LV_SERIALBUF_H_INCLUDED__ +#define __LV_SERIALBUF_H_INCLUDED__ + +#include "lvtypes.h" +#include "lvstring.h" + +/// serialization/deserialization buffer +class SerialBuf +{ + lUInt8 * _buf; + bool _ownbuf; + bool _error; + bool _autoresize; + int _size; + int _pos; +public: + /// swap content of buffer with another buffer + void swap( SerialBuf & v ); + /// constructor of serialization buffer + SerialBuf( int sz, bool autoresize = true ); + SerialBuf( const lUInt8 * p, int sz ); + ~SerialBuf(); + + void set( lUInt8 * buf, int size ) + { + if ( _buf && _ownbuf ) + free( _buf ); + _buf = buf; + _ownbuf = true; + _error = false; + _autoresize = true; + _size = _pos = size; + } + bool copyTo( lUInt8 * buf, int maxSize ); + inline lUInt8 * buf() { return _buf; } + inline void setPos( int pos ) { _pos = pos; } + inline int space() const { return _size-_pos; } + inline int pos() const { return _pos; } + inline int size() const { return _size; } + + /// returns true if error occured during one of operations + inline bool error() const { return _error; } + + inline void seterror() { _error = true; } + /// move pointer to beginning, clear error flag + inline void reset() { _error = false; _pos = 0; } + + /// checks whether specified number of bytes is available, returns true in case of error + bool check( int reserved ); + + // write methods + /// put magic signature + void putMagic( const char * s ); + + /// add CRC32 for last N bytes + void putCRC( int N ); + + /// returns CRC32 for the whole buffer + lUInt32 getCRC(); + + /// add contents of another buffer + SerialBuf & operator << ( const SerialBuf & v ); + + SerialBuf & operator << ( lUInt8 n ); + + SerialBuf & operator << ( char n ); + + SerialBuf & operator << ( bool n ); + + SerialBuf & operator << ( lUInt16 n ); + + SerialBuf & operator << ( lInt16 n ); + + SerialBuf & operator << ( lUInt32 n ); + + SerialBuf & operator << ( lInt32 n ); + + SerialBuf & operator << ( const lString16 & s ); + + SerialBuf & operator << ( const lString8 & s8 ); + + // read methods + SerialBuf & operator >> ( lUInt8 & n ); + + SerialBuf & operator >> ( char & n ); + + SerialBuf & operator >> ( bool & n ); + + SerialBuf & operator >> ( lUInt16 & n ); + + SerialBuf & operator >> ( lInt16 & n ); + + SerialBuf & operator >> ( lUInt32 & n ); + + SerialBuf & operator >> ( lInt32 & n ); + + SerialBuf & operator >> ( lString8 & s8 ); + + SerialBuf & operator >> ( lString16 & s ); + + bool checkMagic( const char * s ); + /// read crc32 code, comapare with CRC32 for last N bytes + bool checkCRC( int N ); +}; + +#endif // __LV_SERIALBUF_H_INCLUDED__ diff --git a/crengine/obsolete/lvstringbuf16.h b/crengine/obsolete/lvstringbuf16.h new file mode 100644 index 0000000000..78c7855915 --- /dev/null +++ b/crengine/obsolete/lvstringbuf16.h @@ -0,0 +1,58 @@ +/** \file lvstringbuf16.h + \brief string classes interface + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __LV_STRINGBUF16_H_INCLUDED__ +#define __LV_STRINGBUF16_H_INCLUDED__ + +#include "../include/lvstring.h" + +/// fast 16-bit string character appender +template class lStringBuf16 { + lString16 & str; + lChar16 buf[BUFSIZE]; + int pos; + lStringBuf16 & operator = (const lStringBuf16 & v) + { + CR_UNUSED(v); + // not available + return *this; + } +public: + lStringBuf16( lString16 & s ) + : str(s), pos(0) + { + } + inline void append( lChar16 ch ) + { + buf[ pos++ ] = ch; + if ( pos==BUFSIZE ) + flush(); + } + inline lStringBuf16& operator << ( lChar16 ch ) + { + buf[ pos++ ] = ch; + if ( pos==BUFSIZE ) + flush(); + return *this; + } + inline void flush() + { + str.append( buf, pos ); + pos = 0; + } + ~lStringBuf16( ) + { + flush(); + } +}; + +#endif // __LV_STRINGBUF16_H_INCLUDED__ diff --git a/crengine/obsolete/lvstringbuf8.h b/crengine/obsolete/lvstringbuf8.h new file mode 100644 index 0000000000..2621fc4a30 --- /dev/null +++ b/crengine/obsolete/lvstringbuf8.h @@ -0,0 +1,52 @@ +/** \file lvstringbuf8.h + \brief string classes interface + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __LV_STRINGBUF8_H_INCLUDED__ +#define __LV_STRINGBUF8_H_INCLUDED__ + +#include "../include/lvstring.h" + +/// fast 8-bit string character appender +template class lStringBuf8 { + lString8 & str; + lChar8 buf[BUFSIZE]; + int pos; +public: + lStringBuf8( lString8 & s ) + : str(s), pos(0) + { + } + inline void append( lChar8 ch ) + { + buf[ pos++ ] = ch; + if ( pos==BUFSIZE ) + flush(); + } + inline lStringBuf8& operator << ( lChar8 ch ) + { + buf[ pos++ ] = ch; + if ( pos==BUFSIZE ) + flush(); + return *this; + } + inline void flush() + { + str.append( buf, pos ); + pos = 0; + } + ~lStringBuf8( ) + { + flush(); + } +}; + +#endif // __LV_STRINGBUF8_H_INCLUDED__ diff --git a/crengine/obsolete/readme.txt b/crengine/obsolete/readme.txt new file mode 100644 index 0000000000..4a886ca726 --- /dev/null +++ b/crengine/obsolete/readme.txt @@ -0,0 +1 @@ +This classes is unused, saved for history! diff --git a/crengine/src/chmfmt.cpp b/crengine/src/chmfmt.cpp index 9ef341165a..fde8db0235 100644 --- a/crengine/src/chmfmt.cpp +++ b/crengine/src/chmfmt.cpp @@ -3,6 +3,7 @@ //#define CHM_SUPPORT_ENABLED 1 #if CHM_SUPPORT_ENABLED==1 #include "../include/chmfmt.h" +#include "../include/crlog.h" #include #define DUMP_CHM_DOC 0 diff --git a/crengine/src/crconcurrent.cpp b/crengine/src/crconcurrent.cpp index bfbd48bf8b..7e61574d15 100644 --- a/crengine/src/crconcurrent.cpp +++ b/crengine/src/crconcurrent.cpp @@ -2,6 +2,7 @@ #include "crconcurrent.h" #include "lvptrvec.h" #include "lvstring.h" +#include "crlog.h" CRMutex * _refMutex = NULL; CRMutex * _fontMutex = NULL; diff --git a/crengine/src/cri18n.cpp b/crengine/src/cri18n.cpp index 45501c9ca4..98f72027d8 100644 --- a/crengine/src/cri18n.cpp +++ b/crengine/src/cri18n.cpp @@ -14,6 +14,8 @@ #include "../include/cri18n.h" #include "../include/lvstream.h" +#include "../include/crlog.h" +#include "../include/lvstring8collection.h" CRI18NTranslator * CRI18NTranslator::_translator = NULL; CRI18NTranslator * CRI18NTranslator::_defTranslator = NULL; diff --git a/crengine/src/crlog.cpp b/crengine/src/crlog.cpp new file mode 100644 index 0000000000..7e99918af6 --- /dev/null +++ b/crengine/src/crlog.cpp @@ -0,0 +1,257 @@ +/******************************************************* + + CoolReader Engine + + crlog.cpp: logging classes implementation + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License + See LICENSE file for details + +*******************************************************/ + +#include "../include/crlog.h" +#include "lvtypes.h" + +#include +#include +#include + +class CRFileLogger; + +CRLog * CRLog::CRLOG = NULL; +void CRLog::setLogger( CRLog * logger ) +{ + if ( CRLOG!=NULL ) { + delete CRLOG; + } + CRLOG = logger; +} + +void CRLog::setLogLevel( CRLog::log_level level ) +{ + if ( !CRLOG ) + return; + warn( "Changing log level from %d to %d", (int)CRLOG->curr_level, (int)level ); + CRLOG->curr_level = level; +} + +CRLog::log_level CRLog::getLogLevel() +{ + if ( !CRLOG ) + return LL_INFO; + return CRLOG->curr_level; +} + +bool CRLog::isLogLevelEnabled( CRLog::log_level level ) +{ + if ( !CRLOG ) + return false; + return (CRLOG->curr_level >= level); +} + +void CRLog::fatal( const char * msg, ... ) +{ + if ( !CRLOG ) + return; + va_list args; + va_start( args, msg ); + CRLOG->log( "FATAL", msg, args ); + va_end(args); +} + +void CRLog::error( const char * msg, ... ) +{ + if ( !CRLOG || CRLOG->curr_levellog( "ERROR", msg, args ); + va_end(args); +} + +void CRLog::warn( const char * msg, ... ) +{ + if ( !CRLOG || CRLOG->curr_levellog( "WARN", msg, args ); + va_end(args); +} + +void CRLog::info( const char * msg, ... ) +{ + if ( !CRLOG || CRLOG->curr_levellog( "INFO", msg, args ); + va_end(args); +} + +void CRLog::debug( const char * msg, ... ) +{ + if ( !CRLOG || CRLOG->curr_levellog( "DEBUG", msg, args ); + va_end(args); +} + +void CRLog::trace( const char * msg, ... ) +{ + if ( !CRLOG || CRLOG->curr_levellog( "TRACE", msg, args ); + va_end(args); +} + +CRLog::CRLog() + : curr_level(LL_INFO) +{ +} + +CRLog::~CRLog() +{ +} + + +// private class CRFileLogger + +#ifndef LOG_HEAP_USAGE +#define LOG_HEAP_USAGE 0 +#endif + +#ifdef _WIN32 +static bool __timerInitialized = false; +static double __timeTicksPerMillis; +static lUInt64 __timeStart; +static lUInt64 __timeAbsolute; +static lUInt64 __startTimeMillis; + +static void CRReinitTimer() { + LARGE_INTEGER tps; + QueryPerformanceFrequency(&tps); + __timeTicksPerMillis = (double)(tps.QuadPart / 1000L); + LARGE_INTEGER queryTime; + QueryPerformanceCounter(&queryTime); + __timeStart = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis); + __timerInitialized = true; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + __startTimeMillis = (ft.dwLowDateTime | (((lUInt64)ft.dwHighDateTime) << 32)) / 10000; +} +#endif + +static lUInt64 GetCurrentTimeMillis() { +#if defined(LINUX) || defined(ANDROID) || defined(_LINUX) + timeval ts; + gettimeofday(&ts, NULL); + return ts.tv_sec * (lUInt64)1000 + ts.tv_usec / 1000; +#else +#ifdef _WIN32 + if (!__timerInitialized) { + CRReinitTimer(); + return __startTimeMillis; + } else { + LARGE_INTEGER queryTime; + QueryPerformanceCounter(&queryTime); + __timeAbsolute = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis); + return __startTimeMillis + (lUInt64)(__timeAbsolute - __timeStart); + } +#else +#error * You should define GetCurrentTimeMillis() * +#endif +#endif +} + +class CRFileLogger : public CRLog +{ +protected: + FILE * f; + bool autoClose; + bool autoFlush; + virtual void log( const char * level, const char * msg, va_list args ) + { + if ( !f ) + return; +#ifdef LINUX + struct timeval tval; + gettimeofday( &tval, NULL ); + int ms = tval.tv_usec; + time_t t = tval.tv_sec; +#if LOG_HEAP_USAGE + struct mallinfo mi = mallinfo(); + int memusage = mi.arena; +#endif +#else + lUInt64 ts = GetCurrentTimeMillis(); + //time_t t = (time_t)time(0); + time_t t = ts / 1000; + int ms = (ts % 1000) * 1000; +#if LOG_HEAP_USAGE + int memusage = 0; +#endif +#endif + struct tm * bt = localtime(&t); +#if LOG_HEAP_USAGE + fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d [%d] %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, memusage, level); +#else + fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, level); +#endif + vfprintf( f, msg, args ); + fprintf(f, "\n" ); + if ( autoFlush ) + fflush( f ); + } +public: + CRFileLogger( FILE * file, bool _autoClose, bool _autoFlush ) + : f(file), autoClose(_autoClose), autoFlush( _autoFlush ) + { + info( "Started logging" ); + } + CRFileLogger( const char * fname, bool _autoFlush ) + : f(fopen( fname, "wt" )), autoClose(true), autoFlush( _autoFlush ) + { + static unsigned char utf8sign[] = {0xEF, 0xBB, 0xBF}; + static const char * log_level_names[] = { + "FATAL", + "ERROR", + "WARN", + "INFO", + "DEBUG", + "TRACE", + }; + fwrite( utf8sign, 3, 1, f); + info( "Started logging. Level=%s", log_level_names[getLogLevel()] ); + } + virtual ~CRFileLogger() { + if ( f && autoClose ) { + info( "Stopped logging" ); + fclose( f ); + } + f = NULL; + } +}; + + +// CRLog +void CRLog::setFileLogger( const char * fname, bool autoFlush ) +{ + setLogger( new CRFileLogger( fname, autoFlush ) ); +} + +void CRLog::setStdoutLogger() +{ + setLogger( new CRFileLogger( (FILE*)stdout, false, true ) ); +} + +void CRLog::setStderrLogger() +{ + setLogger( new CRFileLogger( (FILE*)stderr, false, true ) ); +} diff --git a/crengine/src/crtxtenc.cpp b/crengine/src/crtxtenc.cpp index 8cd632562e..deeee01234 100644 --- a/crengine/src/crtxtenc.cpp +++ b/crengine/src/crtxtenc.cpp @@ -14,6 +14,7 @@ #include "../include/crtxtenc.h" #include "../include/lvstring.h" #include "../include/cp_stats.h" +#include "../include/crlog.h" #include #include diff --git a/crengine/src/docxfmt.cpp b/crengine/src/docxfmt.cpp index 8bb9fa8d9b..290f094740 100644 --- a/crengine/src/docxfmt.cpp +++ b/crengine/src/docxfmt.cpp @@ -2,6 +2,7 @@ #include "../include/lvtinydom.h" #include "../include/fb2def.h" #include "../include/lvopc.h" +#include "../include/crlog.h" #define DOCX_TAG_NAME(itm) docx_el_##itm##_name #define DOCX_TAG_ID(itm) docx_el_##itm diff --git a/crengine/src/epubfmt.cpp b/crengine/src/epubfmt.cpp index a0679f5aa6..7f77c81b0f 100644 --- a/crengine/src/epubfmt.cpp +++ b/crengine/src/epubfmt.cpp @@ -1,4 +1,5 @@ #include "../include/epubfmt.h" +#include "../include/crlog.h" class EpubItem { diff --git a/crengine/src/fb3fmt.cpp b/crengine/src/fb3fmt.cpp index a1e94e6a1e..a477c0e0b4 100644 --- a/crengine/src/fb3fmt.cpp +++ b/crengine/src/fb3fmt.cpp @@ -2,6 +2,7 @@ #include "../include/lvtinydom.h" #include "../include/fb2def.h" #include "../include/lvopc.h" +#include "../include/crlog.h" static const lChar16 * const fb3_BodyContentType = L"application/fb3-body+xml"; static const lChar16 * const fb3_DescriptionContentType = L"application/fb3-description+xml"; diff --git a/crengine/src/hist.cpp b/crengine/src/hist.cpp index 58b9c0c3eb..52762a7757 100644 --- a/crengine/src/hist.cpp +++ b/crengine/src/hist.cpp @@ -11,6 +11,7 @@ #include "../include/lvtinydom.h" #include "../include/hist.h" +#include "../include/crlog.h" void CRFileHist::clear() { diff --git a/crengine/src/hyphman.cpp b/crengine/src/hyphman.cpp index 38e2442cd6..5f0d3bce14 100644 --- a/crengine/src/hyphman.cpp +++ b/crengine/src/hyphman.cpp @@ -38,6 +38,8 @@ #include "../include/hyphman.h" #include "../include/lvfnt.h" #include "../include/lvstring.h" +#include "../include/lvstring16collection.h" +#include "../include/crlog.h" #ifdef ANDROID diff --git a/crengine/src/lvdrawbuf.cpp b/crengine/src/lvdrawbuf.cpp index 53e91959b6..1aaaa13a89 100644 --- a/crengine/src/lvdrawbuf.cpp +++ b/crengine/src/lvdrawbuf.cpp @@ -16,6 +16,7 @@ #include #include #include "../include/lvdrawbuf.h" +#include "../include/crlog.h" #define GUARD_BYTE 0xa5 #define CHECK_GUARD_BYTE \ diff --git a/crengine/src/lvembeddedfont.cpp b/crengine/src/lvembeddedfont.cpp index fddd953d0c..e4ceafe061 100644 --- a/crengine/src/lvembeddedfont.cpp +++ b/crengine/src/lvembeddedfont.cpp @@ -13,6 +13,7 @@ */ #include "../include/lvembeddedfont.h" +#include "../include/serialbuf.h" #include diff --git a/crengine/src/lvfntman.cpp b/crengine/src/lvfntman.cpp index 4e54acd5c8..e082981556 100644 --- a/crengine/src/lvfntman.cpp +++ b/crengine/src/lvfntman.cpp @@ -14,6 +14,7 @@ #include "../include/lvfntman.h" #include "../include/lvstyles.h" +#include "../include/crlog.h" #include "private/lvfreetypefontman.h" #include "private/lvwin32fontman.h" #include "private/lvbitmapfontman.h" diff --git a/crengine/src/lvimg.cpp b/crengine/src/lvimg.cpp index 810b13b1f9..ebfc3073ca 100644 --- a/crengine/src/lvimg.cpp +++ b/crengine/src/lvimg.cpp @@ -20,6 +20,7 @@ #include "../include/lvimg.h" #include "../include/lvtinydom.h" +#include "../include/crlog.h" #if (USE_LIBPNG==1) #include diff --git a/crengine/src/lvmemman.cpp b/crengine/src/lvmemman.cpp index a7fba470f0..2120fc0d33 100644 --- a/crengine/src/lvmemman.cpp +++ b/crengine/src/lvmemman.cpp @@ -15,6 +15,7 @@ #include "../include/lvmemman.h" #include "../include/lvref.h" #include "../include/lvtinydom.h" +#include "../include/crlog.h" #ifdef _LINUX #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE diff --git a/crengine/src/lvopc.cpp b/crengine/src/lvopc.cpp index 5d3e68227f..64f48f75d5 100644 --- a/crengine/src/lvopc.cpp +++ b/crengine/src/lvopc.cpp @@ -1,5 +1,6 @@ #include "../include/lvopc.h" #include "../include/lvtinydom.h" +#include "../include/crlog.h" static const lChar16 * const OPC_PropertiesContentType = L"application/vnd.openxmlformats-package.core-properties+xml"; diff --git a/crengine/src/lvpagesplitter.cpp b/crengine/src/lvpagesplitter.cpp index 725ff01094..79676a80f1 100644 --- a/crengine/src/lvpagesplitter.cpp +++ b/crengine/src/lvpagesplitter.cpp @@ -12,6 +12,8 @@ #include "../include/lvpagesplitter.h" #include "../include/lvtinydom.h" +#include "../include/crlog.h" +#include "../include/serialbuf.h" #include diff --git a/crengine/src/lvrend.cpp b/crengine/src/lvrend.cpp index 21b3426b0e..025bc855b6 100644 --- a/crengine/src/lvrend.cpp +++ b/crengine/src/lvrend.cpp @@ -16,6 +16,7 @@ #include "../include/lvtinydom.h" #include "../include/fb2def.h" #include "../include/lvrend.h" +#include "../include/crlog.h" //#define DEBUG_TREE_DRAW 3 diff --git a/crengine/src/lvstream.cpp b/crengine/src/lvstream.cpp index 83c8480105..e5028f1ec6 100644 --- a/crengine/src/lvstream.cpp +++ b/crengine/src/lvstream.cpp @@ -27,6 +27,7 @@ #include "../include/lvstream.h" #include "../include/lvptrvec.h" #include "../include/crtxtenc.h" +#include "../include/crlog.h" #include #include #include @@ -2097,6 +2098,10 @@ struct ZipHd2 lUInt16 getZIPAttr() { return _Attr_and_Offset[0]; } lUInt32 getAttr() { return _Attr_and_Offset[1] | ((lUInt32)_Attr_and_Offset[2]<<16); } lUInt32 getOffset() { return _Attr_and_Offset[3] | ((lUInt32)_Attr_and_Offset[4]<<16); } + void setOffset(lUInt32 offset) { + _Attr_and_Offset[3] = (lUInt16)(offset & 0xFFFF); + _Attr_and_Offset[4] = (lUInt16)(offset >> 16); + } void byteOrderConv() { // @@ -2489,14 +2494,20 @@ class LVZipDecodeStream : public LVNamedStream class LVZipArc : public LVArcContainerBase { +protected: + // whether the alternative "truncated" method was used, or is to be used + bool m_alt_reading_method = false; public: + bool isAltReadingMethod() { return m_alt_reading_method; } + void setAltReadingMethod() { m_alt_reading_method = true; } + virtual LVStreamRef OpenStream( const wchar_t * fname, lvopen_mode_t /*mode*/ ) { if ( fname[0]=='/' ) fname++; int found_index = -1; for (int i=0; iGetName() ) ) { + if ( m_list[i]->GetName() != NULL && !lStr_cmp( fname, m_list[i]->GetName() ) ) { if ( m_list[i]->IsContainer() ) { // found directory with same name!!! return LVStreamRef(); @@ -2592,6 +2603,18 @@ class LVZipArc : public LVArcContainerBase } truncated = !found; + + // If the main reading method (using zip header at the end of the + // archive) failed, we can try using the alternative method used + // when this zip header is missing ("truncated"), which uses + // local zip headers met along while scanning the zip. + if (m_alt_reading_method) + truncated = true; // do as if truncated + else if (truncated) // archive detected as truncated + // flag that, so there's no need to try that alt method, + // as it was used on first scan + m_alt_reading_method = true; + if (truncated) NextPosition=0; @@ -2612,6 +2635,11 @@ class LVZipArc : public LVArcContainerBase if (truncated) { + // The offset (that we don't find in a local header, but + // that we will store in the ZipHeader we're building) + // happens to be the current position here. + lUInt32 offset = (lUInt32)m_stream->GetPos(); + m_stream->Read( &ZipHd1, ZipHd1_size, &ReadSize); ZipHd1.byteOrderConv(); @@ -2636,6 +2664,10 @@ class LVZipArc : public LVArcContainerBase ZipHeader.NameLen=ZipHd1.getNameLen(); ZipHeader.AddLen=ZipHd1.getAddLen(); ZipHeader.Method=ZipHd1.getMethod(); + ZipHeader.setOffset(offset); + // We may get a last invalid record with NameLen=0, which shouldn't hurt. + // If it does, use: + // if (ZipHeader.NameLen == 0) break; } else { m_stream->Read( &ZipHeader, ZipHeader_size, &ReadSize); @@ -2741,8 +2773,17 @@ class LVZipArc : public LVArcContainerBase return NULL; LVZipArc * arc = new LVZipArc( stream ); int itemCount = arc->ReadContents(); + if ( itemCount > 0 && arc->isAltReadingMethod() ) { + CRLog::warn("Zip file truncated: going on with possibly partial content."); + } + else if ( itemCount <= 0 && !arc->isAltReadingMethod() ) { + CRLog::warn("Zip file corrupted or invalid: trying alternative processing..."); + arc->setAltReadingMethod(); + itemCount = arc->ReadContents(); + } if ( itemCount <= 0 ) { + CRLog::error("Zip file corrupted or invalid: processing failure."); delete arc; return NULL; } diff --git a/crengine/src/lvstring.cpp b/crengine/src/lvstring.cpp index 3bf3a7ae09..29782b04d7 100644 --- a/crengine/src/lvstring.cpp +++ b/crengine/src/lvstring.cpp @@ -12,6 +12,7 @@ *******************************************************/ #include "../include/lvstring.h" + #include #include #include @@ -560,6 +561,12 @@ int lStr_cmp(const lChar16 * dst, const lChar8 * src) int lStr_cmp(const lChar8 * dst, const lChar16 * src) { + if (!dst && !src) + return 0; + if (!dst) + return -1; + else if (!src) + return 1; while ( (lChar16)*dst == *src) { if (! *dst ) @@ -1262,172 +1269,6 @@ lUInt32 lString16::getHash() const } - -void lString16Collection::reserve(int space) -{ - if ( count + space > size ) - { - int tmpSize = count + space + 64; - void* tmp = realloc( chunks, sizeof(lstring16_chunk_t *) * tmpSize ); - if (tmp) { - size = tmpSize; - chunks = (lstring16_chunk_t * *)tmp; - } - else { - // TODO: throw exception or change function prototype & return code - } - } -} - -static int (str16_comparator)(const void * n1, const void * n2) -{ - lstring16_chunk_t ** s1 = (lstring16_chunk_t **)n1; - lstring16_chunk_t ** s2 = (lstring16_chunk_t **)n2; - return lStr_cmp( (*s1)->data16(), (*s2)->data16() ); -} - -static int(*custom_lstr16_comparator_ptr)(lString16 & s1, lString16 & s2); -static int (str16_custom_comparator)(const void * n1, const void * n2) -{ - lString16 s1(*((lstring16_chunk_t **)n1)); - lString16 s2(*((lstring16_chunk_t **)n2)); - return custom_lstr16_comparator_ptr(s1, s2); -} - -void lString16Collection::sort(int(comparator)(lString16 & s1, lString16 & s2)) -{ - custom_lstr16_comparator_ptr = comparator; - qsort(chunks,count,sizeof(lstring16_chunk_t*), str16_custom_comparator); -} - -void lString16Collection::sort() -{ - qsort(chunks,count,sizeof(lstring16_chunk_t*), str16_comparator); -} - -int lString16Collection::add( const lString16 & str ) -{ - reserve( 1 ); - chunks[count] = str.pchunk; - str.addref(); - return count++; -} -void lString16Collection::clear() -{ - if (chunks) { - for (int i=0; i= count) - return; - int i; - for (i = offset; i < offset + cnt; i++) - { - ((lString16 *)chunks)[i].release(); - } - for (i = offset + cnt; i < count; i++) - { - chunks[i-cnt] = chunks[i]; - } - count -= cnt; - if (!count) - clear(); -} - -void lString8Collection::split( const lString8 & str, const lString8 & delimiter ) -{ - if (str.empty()) - return; - for (int startpos = 0; startpos < str.length(); ) { - int pos = str.pos(delimiter, startpos); - if (pos < 0) - pos = str.length(); - add(str.substr(startpos, pos - startpos)); - startpos = pos + delimiter.length(); - } -} - -void lString16Collection::split( const lString16 & str, const lString16 & delimiter ) -{ - if (str.empty()) - return; - for (int startpos = 0; startpos < str.length(); ) { - int pos = str.pos(delimiter, startpos); - if (pos < 0) - pos = str.length(); - add(str.substr(startpos, pos - startpos)); - startpos = pos + delimiter.length(); - } -} - -void lString8Collection::erase(int offset, int cnt) -{ - if (count <= 0) - return; - if (offset < 0 || offset + cnt > count) - return; - int i; - for (i = offset; i < offset + cnt; i++) - { - ((lString8 *)chunks)[i].release(); - } - for (i = offset + cnt; i < count; i++) - { - chunks[i-cnt] = chunks[i]; - } - count -= cnt; - if (!count) - clear(); -} - -void lString8Collection::reserve(int space) -{ - if ( count + space > size ) - { - int tmpSize = count + space + 64; - void* tmp = realloc( chunks, sizeof(lstring8_chunk_t *) * tmpSize ); - if (tmp) { - size = tmpSize; - chunks = (lstring8_chunk_t * *)tmp; - } - else { - // TODO: throw exception or change function prototype & return code - } - } -} - -int lString8Collection::add( const lString8 & str ) -{ - reserve( 1 ); - chunks[count] = str.pchunk; - str.addref(); - return count++; -} -void lString8Collection::clear() -{ - for (int i=0; i_pos ) { - *this << (lUInt32)0; - seterror(); - } - lUInt32 n = 0; - n = lStr_crc32( n, _buf + _pos-size, size ); - *this << n; -} - -/// get CRC32 for the whole buffer -lUInt32 SerialBuf::getCRC() -{ - if (error()) - return 0; - lUInt32 n = 0; - n = lStr_crc32( n, _buf, _pos ); - return n; -} - -/// read crc32 code, comapare with CRC32 for last N bytes -bool SerialBuf::checkCRC( int size ) -{ - if ( error() ) - return false; - if ( size>_pos ) { - seterror(); - return false; - } - lUInt32 n0 = 0; - n0 = lStr_crc32(n0, _buf + _pos-size, size); - lUInt32 n = 0; - *this >> n; - if ( error() ) - return false; - if ( n!=n0 ) - seterror(); - return !error(); -} - -/// deserialize from byte array (pointer will be incremented by number of bytes read) -bool lString16HashedCollection::deserialize( SerialBuf & buf ) -{ - if ( buf.error() ) - return false; - clear(); - int start = buf.pos(); - buf.putMagic( str_hash_magic ); - lInt32 count = 0; - buf >> count; - for ( int i=0; i> s; - if ( buf.error() ) - break; - add( s.c_str() ); - } - buf.checkCRC( buf.pos() - start ); - return !buf.error(); -} - -lString16HashedCollection::lString16HashedCollection( lString16HashedCollection & v ) -: lString16Collection( v ) -, hashSize( v.hashSize ) -, hash( NULL ) -{ - hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); - for ( int i=0; iindex ); - next = next->next; - } - } -} - -void lString16HashedCollection::addHashItem( int hashIndex, int storageIndex ) -{ - if ( hash[ hashIndex ].index == -1 ) { - hash[hashIndex].index = storageIndex; - } else { - HashPair * np = (HashPair *)malloc(sizeof(HashPair)); - np->index = storageIndex; - np->next = hash[hashIndex].next; - hash[hashIndex].next = np; - } -} - -void lString16HashedCollection::clearHash() -{ - if ( hash ) { - for ( int i=0; inext; - free( p ); - p = tmp; - } - } - free( hash ); - } - hash = NULL; -} - -lString16HashedCollection::lString16HashedCollection( lUInt32 hash_size ) -: hashSize(hash_size), hash(NULL) -{ - - hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); - for ( int i=0; inext ) { - const lString16 & str = at( p->index ); - if ( str==s ) - return p->index; - } - } - return -1; -} - -void lString16HashedCollection::reHash( int newSize ) -{ - if (hashSize == newSize) - return; - clearHash(); - hashSize = newSize; - if (hashSize > 0) { - hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); - for ( int i=0; inext ) { - const lString16 & str = at( p->index ); - if ( str==s ) - return p->index; - } - } - lUInt32 i = lString16Collection::add( lString16(s) ); - addHashItem( n, i ); - return i; -} const lString16 lString16::empty_str; @@ -2660,50 +2293,6 @@ void lStr_lowercase( lChar16 * str, int len ) } } -void lString16Collection::parse( lString16 string, lChar16 delimiter, bool flgTrim ) -{ - int wstart=0; - for ( int i=0; i<=string.length(); i++ ) { - if ( i==string.length() || string[i]==delimiter ) { - lString16 s( string.substr( wstart, i-wstart) ); - if ( flgTrim ) - s.trimDoubleSpaces(false, false, false); - if ( !flgTrim || !s.empty() ) - add( s ); - wstart = i+1; - } - } -} - -void lString16Collection::parse( lString16 string, lString16 delimiter, bool flgTrim ) -{ - if ( delimiter.empty() || string.pos(delimiter)<0 ) { - lString16 s( string ); - if ( flgTrim ) - s.trimDoubleSpaces(false, false, false); - add(s); - return; - } - int wstart=0; - for ( int i=0; i<=string.length(); i++ ) { - bool matched = true; - for ( int j=0; j endp) + break; + count++; + } + return count; +} + +inline int charUtf8ByteCount(lUInt32 ch) { if (!(ch & ~0x7F)) return 1; if (!(ch & ~0x7FF)) @@ -2866,6 +2526,18 @@ int Utf8ByteCount(const lChar16 * str) return count; } +inline int charWtf8ByteCount(lUInt32 ch) { + if (!(ch & ~0x7F)) + return 1; + if (!(ch & ~0x7FF)) + return 2; + if (!(ch & ~0xFFFF)) + return 3; + if (!(ch & ~0x1FFFFF)) + return 6; + return 1; +} + int Utf8ByteCount(const lChar16 * str, int len) { int count = 0; @@ -2877,6 +2549,17 @@ int Utf8ByteCount(const lChar16 * str, int len) return count; } +int Wtf8ByteCount(const lChar16 * str, int len) +{ + int count = 0; + lUInt32 ch; + while ((len--) > 0) { + ch = *str++; + count += charWtf8ByteCount(ch); + } + return count; +} + lString16 Utf8ToUnicode( const lString8 & str ) { return Utf8ToUnicode( str.c_str() ); @@ -2915,34 +2598,38 @@ static void DecodeUtf8(const char * s, lChar16 * p, int len) } } -void Utf8ToUnicode(const lUInt8 * src, int &srclen, lChar16 * dst, int &dstlen) +static void DecodeWtf8(const char * s, lChar16 * p, int len) { - const lUInt8 * s = src; - const lUInt8 * ends = s + srclen; - lChar16 * p = dst; - lChar16 * endp = p + dstlen; + lChar16 * endp = p + len; lUInt32 ch; - while (p < endp && s < ends) { + while (p < endp) { ch = *s; if ( (ch & 0x80) == 0 ) { *p++ = (char)ch; s++; } else if ( (ch & 0xE0) == 0xC0 ) { - if (s + 2 > ends) - break; *p++ = ((ch & 0x1F) << 6) | CONT_BYTE(1,0); s += 2; } else if ( (ch & 0xF0) == 0xE0 ) { - if (s + 3 > ends) - break; *p++ = ((ch & 0x0F) << 12) | CONT_BYTE(1,6) | CONT_BYTE(2,0); s += 3; + if (*(p-1) >= 0xD800 && *(p-1) <= 0xDBFF) { // what we wrote is a high surrogate, + lUInt32 next = *s; // and there's room next for a low surrogate + if ( (next & 0xF0) == 0xE0) { // is a 3-bytes sequence + next = ((next & 0x0F) << 12) | CONT_BYTE(1,6) | CONT_BYTE(2,0); + if (next >= 0xDC00 && next <= 0xDFFF) { // is a low surrogate: valid surrogates sequence + ch = 0x10000 + ((*(p-1) & 0x3FF)<<10) + (next & 0x3FF); + p--; // rewind to override what we wrote + *p++ = ch; + s += 3; + } + } + } } else if ( (ch & 0xF8) == 0xF0 ) { - if (s + 4 > ends) - break; + // Mostly unused *p++ = ((ch & 0x07) << 18) | CONT_BYTE(1,12) | CONT_BYTE(2,6) @@ -2955,6 +2642,98 @@ void Utf8ToUnicode(const lUInt8 * src, int &srclen, lChar16 * dst, int &dstlen) s++; } } +} + +// Top two bits are 10, i.e. original & 11000000(2) == 10000000(2) +#define IS_FOLLOWING(index) ((s[index] & 0xC0) == 0x80) + +void Utf8ToUnicode(const lUInt8 * src, int &srclen, lChar16 * dst, int &dstlen) +{ + const lUInt8 * s = src; + const lUInt8 * ends = s + srclen; + lChar16 * p = dst; + lChar16 * endp = p + dstlen; + lUInt32 ch; + bool matched; + while (p < endp && s < ends) { + ch = *s; + matched = false; + if ( (ch & 0x80) == 0 ) { + matched = true; + *p++ = (char)ch; + s++; + } else if ( (ch & 0xE0) == 0xC0 ) { + if (s + 2 > ends) + break; + if (IS_FOLLOWING(1)) { + matched = true; + *p++ = ((ch & 0x1F) << 6) + | CONT_BYTE(1,0); + s += 2; + } + } else if ( (ch & 0xF0) == 0xE0 ) { + if (s + 3 > ends) + break; + if (IS_FOLLOWING(1) && IS_FOLLOWING(2)) { + matched = true; + *p++ = ((ch & 0x0F) << 12) + | CONT_BYTE(1,6) + | CONT_BYTE(2,0); + s += 3; + // Supports WTF-8 : https://en.wikipedia.org/wiki/UTF-8#WTF-8 + // a superset of UTF-8, that includes UTF-16 surrogates + // in UTF-8 bytes (forbidden in well-formed UTF-8). + // We may get that from bad producers or converters. + // As these shouldn't be there in UTF-8, if we find + // these surrogates in the right sequence, we might as well + // convert the char they represent to the right Unicode + // codepoint and display it instead of a '?'. + // Surrogates are code points from two special ranges of + // Unicode values, reserved for use as the leading, and + // trailing values of paired code units in UTF-16. Leading, + // also called high, surrogates are from D800 to DBFF, and + // trailing, or low, surrogates are from DC00 to DFFF. They + // are called surrogates, since they do not represent + // characters directly, but only as a pair. + // (Note that lChar16 (wchar_t) is 4-bytes, and can store + // unicode codepoint > 0xFFFF like 0x10123) + if (*(p-1) >= 0xD800 && *(p-1) <= 0xDBFF && s+2 < ends) { // what we wrote is a high surrogate, + lUInt32 next = *s; // and there's room next for a low surrogate + if ( (next & 0xF0) == 0xE0 && IS_FOLLOWING(1) && IS_FOLLOWING(2)) { // is a valid 3-bytes sequence + next = ((next & 0x0F) << 12) | CONT_BYTE(1,6) | CONT_BYTE(2,0); + if (next >= 0xDC00 && next <= 0xDFFF) { // is a low surrogate: valid surrogates sequence + ch = 0x10000 + ((*(p-1) & 0x3FF)<<10) + (next & 0x3FF); + p--; // rewind to override what we wrote + *p++ = ch; + s += 3; + } + } + } + } + } else if ( (ch & 0xF8) == 0xF0 ) { + if (s + 4 > ends) + break; + if (IS_FOLLOWING(1) && IS_FOLLOWING(2) && IS_FOLLOWING(3)) { + matched = true; + *p++ = ((ch & 0x07) << 18) + | CONT_BYTE(1,12) + | CONT_BYTE(2,6) + | CONT_BYTE(3,0); + s += 4; + } + } else { + // Invalid first byte in UTF-8 sequence + // Pass with mask 0x7F, to resolve exception around env->NewStringUTF() + *p++ = (char) (ch & 0x7F); + s++; + matched = true; // just to avoid next if + } + // unexpected character + if (!matched) { + *p++ = '?'; + s++; + } + } srclen = (int)(s - src); dstlen = (int)(p - dst); } @@ -2985,6 +2764,36 @@ lString16 Utf8ToUnicode( const char * s, int sz ) { return dst; } +lString16 Wtf8ToUnicode( const lString8 & str ) +{ + return Wtf8ToUnicode( str.c_str() ); +} + +lString16 Wtf8ToUnicode( const char * s ) { + if (!s || !s[0]) + return lString16::empty_str; + int len = Wtf8CharCount( s ); + if (!len) + return lString16::empty_str; + lString16 dst; + dst.append(len, (lChar16)0); + lChar16 * p = dst.modify(); + DecodeWtf8(s, p, len); + return dst; +} + +lString16 Wtf8ToUnicode( const char * s, int sz ) { + if (!s || !s[0] || sz <= 0) + return lString16::empty_str; + int len = Utf8CharCount( s, sz ); + if (!len) + return lString16::empty_str; + lString16 dst; + dst.append(len, 0); + lChar16 * p = dst.modify(); + DecodeWtf8(s, p, len); + return dst; +} lString8 UnicodeToUtf8(const lChar16 * s, int count) { @@ -3029,6 +2838,60 @@ lString8 UnicodeToUtf8( const lString16 & str ) return UnicodeToUtf8(str.c_str(), str.length()); } +lString8 UnicodeToWtf8(const lChar16 * s, int count) +{ + if (count <= 0) + return lString8::empty_str; + lString8 dst; + int len = Wtf8ByteCount(s, count); + if (len <= 0) + return lString8::empty_str; + dst.append( len, ' ' ); + lChar8 * buf = dst.modify(); + { + lUInt32 ch; + while ((count--) > 0) { + ch = *s++; + if (!(ch & ~0x7F)) { + *buf++ = ( (lUInt8)ch ); + } else if (!(ch & ~0x7FF)) { + *buf++ = ( (lUInt8) ( ((ch >> 6) & 0x1F) | 0xC0 ) ); + *buf++ = ( (lUInt8) ( ((ch ) & 0x3F) | 0x80 ) ); + } else if (!(ch & ~0xFFFF)) { + *buf++ = ( (lUInt8) ( ((ch >> 12) & 0x0F) | 0xE0 ) ); + *buf++ = ( (lUInt8) ( ((ch >> 6) & 0x3F) | 0x80 ) ); + *buf++ = ( (lUInt8) ( ((ch ) & 0x3F) | 0x80 ) ); + } else if (!(ch & ~0x1FFFFF)) { + // UTF-16 Scalar Value + // 000uuuuu xxxxxxxxxxxxxxxx + // UTF-16 + // 110110wwwwxxxxxx 110111xxxxxxxxxx + // wwww = uuuuu - 1 + lUInt16 wwww = (ch >> 16) - 1; + lUInt16 low = ch & 0xFFFF; + lUInt32 hiSurr = 0xD800 | (wwww << 6) | (low >> 10); // high surrogate + lUInt32 lowSurr = 0xDC00 | (low & 0x3FF); // low surrogate + *buf++ = ( (lUInt8) ( ((hiSurr >> 12) & 0x0F) | 0xE0 ) ); + *buf++ = ( (lUInt8) ( ((hiSurr >> 6) & 0x3F) | 0x80 ) ); + *buf++ = ( (lUInt8) ( ((hiSurr ) & 0x3F) | 0x80 ) ); + *buf++ = ( (lUInt8) ( ((lowSurr >> 12) & 0x0F) | 0xE0 ) ); + *buf++ = ( (lUInt8) ( ((lowSurr >> 6) & 0x3F) | 0x80 ) ); + *buf++ = ( (lUInt8) ( ((lowSurr ) & 0x3F) | 0x80 ) ); + } else { + // invalid codepoint + // In Unicode Standard codepoint must be in range U+0000 .. U+10FFFF + *buf++ = '?'; + } + } + } + return dst; +} + +lString8 UnicodeToWtf8( const lString16 & str ) +{ + return UnicodeToWtf8(str.c_str(), str.length()); +} + lString8 UnicodeTo8Bit( const lString16 & str, const lChar8 * * table ) { lString8 buf; @@ -4234,197 +4097,6 @@ lUInt16 lGetCharProps( lChar16 ch ) } - -CRLog * CRLog::CRLOG = NULL; -void CRLog::setLogger( CRLog * logger ) -{ - if ( CRLOG!=NULL ) { - delete CRLOG; - } - CRLOG = logger; -} - -void CRLog::setLogLevel( CRLog::log_level level ) -{ - if ( !CRLOG ) - return; - warn( "Changing log level from %d to %d", (int)CRLOG->curr_level, (int)level ); - CRLOG->curr_level = level; -} - -CRLog::log_level CRLog::getLogLevel() -{ - if ( !CRLOG ) - return LL_INFO; - return CRLOG->curr_level; -} - -bool CRLog::isLogLevelEnabled( CRLog::log_level level ) -{ - if ( !CRLOG ) - return false; - return (CRLOG->curr_level >= level); -} - -void CRLog::fatal( const char * msg, ... ) -{ - if ( !CRLOG ) - return; - va_list args; - va_start( args, msg ); - CRLOG->log( "FATAL", msg, args ); - va_end(args); -} - -void CRLog::error( const char * msg, ... ) -{ - if ( !CRLOG || CRLOG->curr_levellog( "ERROR", msg, args ); - va_end(args); -} - -void CRLog::warn( const char * msg, ... ) -{ - if ( !CRLOG || CRLOG->curr_levellog( "WARN", msg, args ); - va_end(args); -} - -void CRLog::info( const char * msg, ... ) -{ - if ( !CRLOG || CRLOG->curr_levellog( "INFO", msg, args ); - va_end(args); -} - -void CRLog::debug( const char * msg, ... ) -{ - if ( !CRLOG || CRLOG->curr_levellog( "DEBUG", msg, args ); - va_end(args); -} - -void CRLog::trace( const char * msg, ... ) -{ - if ( !CRLOG || CRLOG->curr_levellog( "TRACE", msg, args ); - va_end(args); -} - -CRLog::CRLog() - : curr_level(LL_INFO) -{ -} - -CRLog::~CRLog() -{ -} - -#ifndef LOG_HEAP_USAGE -#define LOG_HEAP_USAGE 0 -#endif - -class CRFileLogger : public CRLog -{ -protected: - FILE * f; - bool autoClose; - bool autoFlush; - virtual void log( const char * level, const char * msg, va_list args ) - { - if ( !f ) - return; -#ifdef LINUX - struct timeval tval; - gettimeofday( &tval, NULL ); - int ms = tval.tv_usec; - time_t t = tval.tv_sec; -#if LOG_HEAP_USAGE - struct mallinfo mi = mallinfo(); - int memusage = mi.arena; -#endif -#else - lUInt64 ts = GetCurrentTimeMillis(); - //time_t t = (time_t)time(0); - time_t t = ts / 1000; - int ms = (ts % 1000) * 1000; -#if LOG_HEAP_USAGE - int memusage = 0; -#endif -#endif - tm * bt = localtime(&t); -#if LOG_HEAP_USAGE - fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d [%d] %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, memusage, level); -#else - fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, level); -#endif - vfprintf( f, msg, args ); - fprintf(f, "\n" ); - if ( autoFlush ) - fflush( f ); - } -public: - CRFileLogger( FILE * file, bool _autoClose, bool _autoFlush ) - : f(file), autoClose(_autoClose), autoFlush( _autoFlush ) - { - info( "Started logging" ); - } - - CRFileLogger( const char * fname, bool _autoFlush ) - : f(fopen( fname, "wt" )), autoClose(true), autoFlush( _autoFlush ) - { - static unsigned char utf8sign[] = {0xEF, 0xBB, 0xBF}; - static const char * log_level_names[] = { - "FATAL", - "ERROR", - "WARN", - "INFO", - "DEBUG", - "TRACE", - }; - fwrite( utf8sign, 3, 1, f); - info( "Started logging. Level=%s", log_level_names[getLogLevel()] ); - } - - virtual ~CRFileLogger() { - if ( f && autoClose ) { - info( "Stopped logging" ); - fclose( f ); - } - f = NULL; - } -}; - -void CRLog::setFileLogger( const char * fname, bool autoFlush ) -{ - setLogger( new CRFileLogger( fname, autoFlush ) ); -} - -void CRLog::setStdoutLogger() -{ - setLogger( new CRFileLogger( (FILE*)stdout, false, true ) ); -} - -void CRLog::setStderrLogger() -{ - setLogger( new CRFileLogger( (FILE*)stderr, false, true ) ); -} - /// returns true if string starts with specified substring, case insensitive bool lString16::startsWithNoCase ( const lString16 & substring ) const { @@ -4567,287 +4239,6 @@ bool lString16::startsWith(const lChar8 * substring) const return true; } - - -/// serialization/deserialization buffer - -/// constructor of serialization buffer -SerialBuf::SerialBuf( int sz, bool autoresize ) - : _buf( (lUInt8*)malloc(sz) ), _ownbuf(true), _error(false), _autoresize(autoresize), _size(sz), _pos(0) -{ - memset( _buf, 0, _size ); -} -/// constructor of deserialization buffer -SerialBuf::SerialBuf( const lUInt8 * p, int sz ) - : _buf( const_cast(p) ), _ownbuf(false), _error(false), _autoresize(false), _size(sz), _pos(0) -{ -} - -SerialBuf::~SerialBuf() -{ - if ( _ownbuf ) - free( _buf ); -} - -bool SerialBuf::copyTo( lUInt8 * buf, int maxSize ) -{ - if ( _pos==0 ) - return true; - if ( _pos > maxSize ) - return false; - memcpy( buf, _buf, _pos ); - return true; -} - -/// checks whether specified number of bytes is available, returns true in case of error -bool SerialBuf::check( int reserved ) -{ - if ( _error ) - return true; - if ( space()16384 ? _size*2 : 16384) + reserved; - _buf = cr_realloc(_buf, _size ); - memset( _buf+_pos, 0, _size-_pos ); - return false; - } else { - _error = true; - return true; - } - } - return false; -} - -// write methods -/// put magic signature -void SerialBuf::putMagic( const char * s ) -{ - if ( check(1) ) - return; - while ( *s ) { - _buf[ _pos++ ] = *s++; - if ( check(1) ) - return; - } -} - -#define SWAPVARS(t,a) \ -{ \ - t tmp; \ - tmp = a; a = v.a; v.a = tmp; \ -} -void SerialBuf::swap( SerialBuf & v ) -{ - SWAPVARS(lUInt8 *, _buf) - SWAPVARS(bool, _ownbuf) - SWAPVARS(bool, _error) - SWAPVARS(bool, _autoresize) - SWAPVARS(int, _size) - SWAPVARS(int, _pos) -} - - -/// add contents of another buffer -SerialBuf & SerialBuf::operator << ( const SerialBuf & v ) -{ - if ( check(v.pos()) || v.pos()==0 ) - return *this; - memcpy( _buf + _pos, v._buf, v._pos ); - _pos += v._pos; - return *this; -} - -SerialBuf & SerialBuf::operator << ( lUInt8 n ) -{ - if ( check(1) ) - return *this; - _buf[_pos++] = n; - return *this; -} -SerialBuf & SerialBuf::operator << ( char n ) -{ - if ( check(1) ) - return *this; - _buf[_pos++] = (lUInt8)n; - return *this; -} -SerialBuf & SerialBuf::operator << ( bool n ) -{ - if ( check(1) ) - return *this; - _buf[_pos++] = (lUInt8)(n ? 1 : 0); - return *this; -} -SerialBuf & SerialBuf::operator << ( lUInt16 n ) -{ - if ( check(2) ) - return *this; - _buf[_pos++] = (lUInt8)(n & 255); - _buf[_pos++] = (lUInt8)((n>>8) & 255); - return *this; -} -SerialBuf & SerialBuf::operator << ( lInt16 n ) -{ - if ( check(2) ) - return *this; - _buf[_pos++] = (lUInt8)(n & 255); - _buf[_pos++] = (lUInt8)((n>>8) & 255); - return *this; -} -SerialBuf & SerialBuf::operator << ( lUInt32 n ) -{ - if ( check(4) ) - return *this; - _buf[_pos++] = (lUInt8)(n & 255); - _buf[_pos++] = (lUInt8)((n>>8) & 255); - _buf[_pos++] = (lUInt8)((n>>16) & 255); - _buf[_pos++] = (lUInt8)((n>>24) & 255); - return *this; -} -SerialBuf & SerialBuf::operator << ( lInt32 n ) -{ - if ( check(4) ) - return *this; - _buf[_pos++] = (lUInt8)(n & 255); - _buf[_pos++] = (lUInt8)((n>>8) & 255); - _buf[_pos++] = (lUInt8)((n>>16) & 255); - _buf[_pos++] = (lUInt8)((n>>24) & 255); - return *this; -} -SerialBuf & SerialBuf::operator << ( const lString16 & s ) -{ - if ( check(2) ) - return *this; - lString8 s8 = UnicodeToUtf8(s); - lUInt16 len = (lUInt16)s8.length(); - (*this) << len; - for ( int i=0; i> ( lUInt8 & n ) -{ - if ( check(1) ) - return *this; - n = _buf[_pos++]; - return *this; -} - -SerialBuf & SerialBuf::operator >> ( char & n ) -{ - if ( check(1) ) - return *this; - n = (char)_buf[_pos++]; - return *this; -} - -SerialBuf & SerialBuf::operator >> ( bool & n ) -{ - if ( check(1) ) - return *this; - n = _buf[_pos++] ? true : false; - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lUInt16 & n ) -{ - if ( check(2) ) - return *this; - n = _buf[_pos++]; - n |= (((lUInt16)_buf[_pos++]) << 8); - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lInt16 & n ) -{ - if ( check(2) ) - return *this; - n = (lInt16)(_buf[_pos++]); - n |= (lInt16)(((lUInt16)_buf[_pos++]) << 8); - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lUInt32 & n ) -{ - if ( check(4) ) - return *this; - n = _buf[_pos++]; - n |= (((lUInt32)_buf[_pos++]) << 8); - n |= (((lUInt32)_buf[_pos++]) << 16); - n |= (((lUInt32)_buf[_pos++]) << 24); - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lInt32 & n ) -{ - if ( check(4) ) - return *this; - n = (lInt32)(_buf[_pos++]); - n |= (((lUInt32)_buf[_pos++]) << 8); - n |= (((lUInt32)_buf[_pos++]) << 16); - n |= (((lUInt32)_buf[_pos++]) << 24); - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lString8 & s8 ) -{ - if ( check(2) ) - return *this; - lUInt16 len = 0; - (*this) >> len; - s8.clear(); - s8.reserve(len); - for ( int i=0; i> c; - s8.append(1, c); - } - return *this; -} - -SerialBuf & SerialBuf::operator >> ( lString16 & s ) -{ - lString8 s8; - (*this) >> s8; - s = Utf8ToUnicode(s8); - return *this; -} - -// read methods -bool SerialBuf::checkMagic( const char * s ) -{ - if ( _error ) - return false; - while ( *s ) { - if ( check(1) ) - return false; - if ( _buf[ _pos++ ] != *s++ ) { - seterror(); - return false; - } - } - return true; -} - bool lString16::split2( const lString16 & delim, lString16 & value1, lString16 & value2 ) { if ( empty() ) @@ -5016,53 +4407,3 @@ void limitStringSize(lString16 & str, int maxSize) { str = str.substr(0, split); str += "..."; } - - -#ifdef _WIN32 -static bool __timerInitialized = false; -static double __timeTicksPerMillis; -static lUInt64 __timeStart; -static lUInt64 __timeAbsolute; -static lUInt64 __startTimeMillis; -#endif - -void CRReinitTimer() { -#ifdef _WIN32 - LARGE_INTEGER tps; - QueryPerformanceFrequency(&tps); - __timeTicksPerMillis = (double)(tps.QuadPart / 1000L); - LARGE_INTEGER queryTime; - QueryPerformanceCounter(&queryTime); - __timeStart = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis); - __timerInitialized = true; - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - __startTimeMillis = (ft.dwLowDateTime | (((lUInt64)ft.dwHighDateTime) << 32)) / 10000; -#else - // do nothing. it's for win32 only -#endif -} - - -lUInt64 GetCurrentTimeMillis() { -#if defined(LINUX) || defined(ANDROID) || defined(_LINUX) - timeval ts; - gettimeofday(&ts, NULL); - return ts.tv_sec * (lUInt64)1000 + ts.tv_usec / 1000; -#else - #ifdef _WIN32 - if (!__timerInitialized) { - CRReinitTimer(); - return __startTimeMillis; - } else { - LARGE_INTEGER queryTime; - QueryPerformanceCounter(&queryTime); - __timeAbsolute = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis); - return __startTimeMillis + (lUInt64)(__timeAbsolute - __timeStart); - } - #else - #error * You should define GetCurrentTimeMillis() * - #endif -#endif -} - diff --git a/crengine/src/lvstring16collection.cpp b/crengine/src/lvstring16collection.cpp new file mode 100644 index 0000000000..69a8c0c661 --- /dev/null +++ b/crengine/src/lvstring16collection.cpp @@ -0,0 +1,155 @@ +/******************************************************* + + CoolReader Engine + + lvstring16collection.cpp: collection of wide strings + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License + See LICENSE file for details + +*******************************************************/ + +#include "../include/lvstring16collection.h" + +void lString16Collection::reserve(int space) +{ + if ( count + space > size ) + { + int tmpSize = count + space + 64; + void* tmp = realloc( chunks, sizeof(lstring16_chunk_t *) * tmpSize ); + if (tmp) { + size = tmpSize; + chunks = (lstring16_chunk_t * *)tmp; + } + else { + // TODO: throw exception or change function prototype & return code + } + } +} + +static int (str16_comparator)(const void * n1, const void * n2) +{ + lstring16_chunk_t ** s1 = (lstring16_chunk_t **)n1; + lstring16_chunk_t ** s2 = (lstring16_chunk_t **)n2; + return lStr_cmp( (*s1)->data16(), (*s2)->data16() ); +} + +static int(*custom_lstr16_comparator_ptr)(lString16 & s1, lString16 & s2); +static int (str16_custom_comparator)(const void * n1, const void * n2) +{ + lString16 s1(*((lstring16_chunk_t **)n1)); + lString16 s2(*((lstring16_chunk_t **)n2)); + return custom_lstr16_comparator_ptr(s1, s2); +} + +void lString16Collection::sort(int(comparator)(lString16 & s1, lString16 & s2)) +{ + custom_lstr16_comparator_ptr = comparator; + qsort(chunks,count,sizeof(lstring16_chunk_t*), str16_custom_comparator); +} + +void lString16Collection::sort() +{ + qsort(chunks,count,sizeof(lstring16_chunk_t*), str16_comparator); +} + +int lString16Collection::add( const lString16 & str ) +{ + reserve( 1 ); + chunks[count] = str.pchunk; + str.addref(); + return count++; +} +void lString16Collection::clear() +{ + if (chunks) { + for (int i=0; i= count) + return; + int i; + for (i = offset; i < offset + cnt; i++) + { + ((lString16 *)chunks)[i].release(); + } + for (i = offset + cnt; i < count; i++) + { + chunks[i-cnt] = chunks[i]; + } + count -= cnt; + if (!count) + clear(); +} + +void lString16Collection::split( const lString16 & str, const lString16 & delimiter ) +{ + if (str.empty()) + return; + for (int startpos = 0; startpos < str.length(); ) { + int pos = str.pos(delimiter, startpos); + if (pos < 0) + pos = str.length(); + add(str.substr(startpos, pos - startpos)); + startpos = pos + delimiter.length(); + } +} + +void lString16Collection::parse( lString16 string, lChar16 delimiter, bool flgTrim ) +{ + int wstart=0; + for ( int i=0; i<=string.length(); i++ ) { + if ( i==string.length() || string[i]==delimiter ) { + lString16 s( string.substr( wstart, i-wstart) ); + if ( flgTrim ) + s.trimDoubleSpaces(false, false, false); + if ( !flgTrim || !s.empty() ) + add( s ); + wstart = i+1; + } + } +} + +void lString16Collection::parse( lString16 string, lString16 delimiter, bool flgTrim ) +{ + if ( delimiter.empty() || string.pos(delimiter)<0 ) { + lString16 s( string ); + if ( flgTrim ) + s.trimDoubleSpaces(false, false, false); + add(s); + return; + } + int wstart=0; + for ( int i=0; i<=string.length(); i++ ) { + bool matched = true; + for ( int j=0; j> count; + for ( int i=0; i> s; + if ( buf.error() ) + break; + add( s.c_str() ); + } + buf.checkCRC( buf.pos() - start ); + return !buf.error(); +} + +lString16HashedCollection::lString16HashedCollection( lString16HashedCollection & v ) +: lString16Collection( v ) +, hashSize( v.hashSize ) +, hash( NULL ) +{ + hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); + for ( int i=0; iindex ); + next = next->next; + } + } +} + +void lString16HashedCollection::addHashItem( int hashIndex, int storageIndex ) +{ + if ( hash[ hashIndex ].index == -1 ) { + hash[hashIndex].index = storageIndex; + } else { + HashPair * np = (HashPair *)malloc(sizeof(HashPair)); + np->index = storageIndex; + np->next = hash[hashIndex].next; + hash[hashIndex].next = np; + } +} + +void lString16HashedCollection::clearHash() +{ + if ( hash ) { + for ( int i=0; inext; + free( p ); + p = tmp; + } + } + free( hash ); + } + hash = NULL; +} + +lString16HashedCollection::lString16HashedCollection( lUInt32 hash_size ) +: hashSize(hash_size), hash(NULL) +{ + + hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); + for ( int i=0; inext ) { + const lString16 & str = at( p->index ); + if ( str==s ) + return p->index; + } + } + return -1; +} + +void lString16HashedCollection::reHash( int newSize ) +{ + if (hashSize == newSize) + return; + clearHash(); + hashSize = newSize; + if (hashSize > 0) { + hash = (HashPair *)malloc( sizeof(HashPair) * hashSize ); + for ( int i=0; inext ) { + const lString16 & str = at( p->index ); + if ( str==s ) + return p->index; + } + } + lUInt32 i = lString16Collection::add( lString16(s) ); + addHashItem( n, i ); + return i; +} diff --git a/crengine/src/lvstring8collection.cpp b/crengine/src/lvstring8collection.cpp new file mode 100644 index 0000000000..806bdb1025 --- /dev/null +++ b/crengine/src/lvstring8collection.cpp @@ -0,0 +1,83 @@ +/******************************************************* + + CoolReader Engine + + lvstring16collection.cpp: collection of strings + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License + See LICENSE file for details + +*******************************************************/ + +#include "../include/lvstring8collection.h" + +void lString8Collection::split( const lString8 & str, const lString8 & delimiter ) +{ + if (str.empty()) + return; + for (int startpos = 0; startpos < str.length(); ) { + int pos = str.pos(delimiter, startpos); + if (pos < 0) + pos = str.length(); + add(str.substr(startpos, pos - startpos)); + startpos = pos + delimiter.length(); + } +} + +void lString8Collection::erase(int offset, int cnt) +{ + if (count <= 0) + return; + if (offset < 0 || offset + cnt > count) + return; + int i; + for (i = offset; i < offset + cnt; i++) + { + ((lString8 *)chunks)[i].release(); + } + for (i = offset + cnt; i < count; i++) + { + chunks[i-cnt] = chunks[i]; + } + count -= cnt; + if (!count) + clear(); +} + +void lString8Collection::reserve(int space) +{ + if ( count + space > size ) + { + int tmpSize = count + space + 64; + void* tmp = realloc( chunks, sizeof(lstring8_chunk_t *) * tmpSize ); + if (tmp) { + size = tmpSize; + chunks = (lstring8_chunk_t * *)tmp; + } + else { + // TODO: throw exception or change function prototype & return code + } + } +} + +int lString8Collection::add( const lString8 & str ) +{ + reserve( 1 ); + chunks[count] = str.pchunk; + str.addref(); + return count++; +} +void lString8Collection::clear() +{ + for (int i=0; i #include #include diff --git a/crengine/src/pdbfmt.cpp b/crengine/src/pdbfmt.cpp index f0afb1c81a..72184822a1 100644 --- a/crengine/src/pdbfmt.cpp +++ b/crengine/src/pdbfmt.cpp @@ -1,4 +1,5 @@ #include "../include/pdbfmt.h" +#include "../include/crlog.h" #include // uncomment following line to save PDB content streams to /tmp diff --git a/crengine/src/private/dumpfile.h b/crengine/src/private/dumpfile.h new file mode 100644 index 0000000000..ef2f365191 --- /dev/null +++ b/crengine/src/private/dumpfile.h @@ -0,0 +1,40 @@ +/** \file dumpfile.h + \brief dump file interface + + CoolReader Engine + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License. + + See LICENSE file for details. +*/ + +#ifndef __DUMPFILE_H_INCLUDED__ +#define __DUMPFILE_H_INCLUDED__ + +#ifdef _DEBUG +#include +class DumpFile +{ +public: + FILE * f; + DumpFile( const char * fname ) + : f(NULL) + { + if ( fname ) + f = fopen( fname, "at" ); + if ( !f ) + f = stdout; + fprintf(f, "DumpFile log started\n"); + } + ~DumpFile() + { + if ( f!=stdout ) + fclose(f); + } + operator FILE * () { if (f) fflush(f); return f?f:stdout; } +}; +#endif + +#endif // __DUMPFILE_H_INCLUDED__ diff --git a/crengine/src/private/lvbitmapfont.cpp b/crengine/src/private/lvbitmapfont.cpp index 96c61e6880..363176231e 100644 --- a/crengine/src/private/lvbitmapfont.cpp +++ b/crengine/src/private/lvbitmapfont.cpp @@ -32,7 +32,7 @@ LVFontRef LoadFontFromFile( const char * fname ) return ref; } -bool LBitmapFont::getGlyphInfo( lUInt16 code, LVFont::glyph_info_t * glyph, lChar16 def_char ) +bool LBitmapFont::getGlyphInfo( lUInt32 code, LVFont::glyph_info_t * glyph, lChar16 def_char ) { const lvfont_glyph_t * ptr = lvfontGetGlyph( m_font, code ); if (!ptr) @@ -110,7 +110,7 @@ int LBitmapFont::getItalic() const return hdr->flgItalic; } /* -bool LBitmapFont::getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char) +bool LBitmapFont::getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char) { const lvfont_glyph_t * ptr = lvfontGetGlyph( m_font, code ); if (!ptr) @@ -122,7 +122,7 @@ bool LBitmapFont::getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char) return true; } */ -LVFontGlyphCacheItem *LBitmapFont::getGlyph(lUInt16 ch, lChar16 def_char) { +LVFontGlyphCacheItem *LBitmapFont::getGlyph(lUInt32 ch, lChar16 def_char) { // TODO: return NULL; } diff --git a/crengine/src/private/lvbitmapfont.h b/crengine/src/private/lvbitmapfont.h index 4c5c487a23..9b06f4b93e 100644 --- a/crengine/src/private/lvbitmapfont.h +++ b/crengine/src/private/lvbitmapfont.h @@ -30,7 +30,7 @@ class LBitmapFont : public LVBaseFont { public: LBitmapFont() : m_font(NULL) {} - virtual bool getGlyphInfo(lUInt16 code, LVFont::glyph_info_t *glyph, lChar16 def_char = 0); + virtual bool getGlyphInfo(lUInt32 code, LVFont::glyph_info_t *glyph, lChar16 def_char = 0); virtual lUInt16 measureText(const lChar16 *text, int len, lUInt16 *widths, lUInt8 *flags, int max_width, @@ -60,9 +60,9 @@ class LBitmapFont : public LVBaseFont { /// returns italic flag virtual int getItalic() const; - //virtual bool getGlyphImage(lUInt16 code, lUInt8 *buf, lChar16 def_char = 0); + //virtual bool getGlyphImage(lUInt32 code, lUInt8 *buf, lChar16 def_char = 0); - virtual LVFontGlyphCacheItem *getGlyph(lUInt16 ch, lChar16 def_char = 0); + virtual LVFontGlyphCacheItem *getGlyph(lUInt32 ch, lChar16 def_char = 0); /// returns char width virtual int getCharWidth(lChar16 ch, lChar16 def_char = 0) { diff --git a/crengine/src/private/lvfontboldtransform.cpp b/crengine/src/private/lvfontboldtransform.cpp index edae8dabf0..aec67cf601 100644 --- a/crengine/src/private/lvfontboldtransform.cpp +++ b/crengine/src/private/lvfontboldtransform.cpp @@ -39,7 +39,7 @@ int LVFontBoldTransform::getHyphenWidth() { } bool -LVFontBoldTransform::getGlyphInfo(lUInt16 code, LVFont::glyph_info_t *glyph, lChar16 def_char) { +LVFontBoldTransform::getGlyphInfo(lUInt32 code, LVFont::glyph_info_t *glyph, lChar16 def_char) { bool res = _baseFont->getGlyphInfo(code, glyph, def_char); if (!res) return res; @@ -91,7 +91,7 @@ lUInt32 LVFontBoldTransform::getTextWidth(const lChar16 *text, int len) { return 0; } -LVFontGlyphCacheItem *LVFontBoldTransform::getGlyph(lUInt16 ch, lChar16 def_char) { +LVFontGlyphCacheItem *LVFontBoldTransform::getGlyph(lUInt32 ch, lChar16 def_char) { LVFontGlyphCacheItem *item = _glyph_cache.get(ch); if (item) diff --git a/crengine/src/private/lvfontboldtransform.h b/crengine/src/private/lvfontboldtransform.h index 9e63163546..df3dbe16fe 100644 --- a/crengine/src/private/lvfontboldtransform.h +++ b/crengine/src/private/lvfontboldtransform.h @@ -50,7 +50,7 @@ class LVFontBoldTransform : public LVFont { \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ - virtual bool getGlyphInfo(lUInt16 code, glyph_info_t *glyph, lChar16 def_char = 0); + virtual bool getGlyphInfo(lUInt32 code, glyph_info_t *glyph, lChar16 def_char = 0); /** \brief measure text \param text is text string pointer @@ -83,7 +83,7 @@ class LVFontBoldTransform : public LVFont { \param code is unicode character \return glyph pointer if glyph was found, NULL otherwise */ - virtual LVFontGlyphCacheItem *getGlyph(lUInt16 ch, lChar16 def_char = 0); + virtual LVFontGlyphCacheItem *getGlyph(lUInt32 ch, lChar16 def_char = 0); /** \brief get glyph image in 1 byte per pixel format \param code is unicode character diff --git a/crengine/src/private/lvfontcache.cpp b/crengine/src/private/lvfontcache.cpp index 261a95a05f..b74125b13d 100644 --- a/crengine/src/private/lvfontcache.cpp +++ b/crengine/src/private/lvfontcache.cpp @@ -14,6 +14,7 @@ #include "lvfontcache.h" #include "../../include/lvstyles.h" +#include "../../include/crlog.h" LVFontCacheItem *LVFontCache::findDuplicate(const LVFontDef *def) { diff --git a/crengine/src/private/lvfontcache.h b/crengine/src/private/lvfontcache.h index 4311d4059b..2d3466759d 100644 --- a/crengine/src/private/lvfontcache.h +++ b/crengine/src/private/lvfontcache.h @@ -18,6 +18,7 @@ #include "../../include/crsetup.h" #include "../../include/lvfont.h" #include "../../include/lvptrvec.h" +#include "../../include/lvstring16collection.h" #include "lvfontdef.h" /// font cache item diff --git a/crengine/src/private/lvfreetypeface.cpp b/crengine/src/private/lvfreetypeface.cpp index 70370c2f6f..f6f9db0bd4 100644 --- a/crengine/src/private/lvfreetypeface.cpp +++ b/crengine/src/private/lvfreetypeface.cpp @@ -18,6 +18,7 @@ #include "../../include/lvfntman.h" #include "../../include/lvfnt.h" #include "../../include/lvtextfm.h" +#include "../../include/crlog.h" #include "lvfontglyphcache.h" #include "lvfontdef.h" #include "lvfontcache.h" @@ -636,7 +637,7 @@ bool LVFreeTypeFace::hbCalcCharWidth(LVCharPosInfo *posInfo, const LVCharTriplet #endif // USE_HARFBUZZ==1 -FT_UInt LVFreeTypeFace::getCharIndex(lChar16 code, lChar16 def_char) { +FT_UInt LVFreeTypeFace::getCharIndex(lUInt32 code, lChar16 def_char) { if (code == '\t') code = ' '; FT_UInt ch_glyph_index = FT_Get_Char_Index(_face, code); @@ -650,7 +651,7 @@ FT_UInt LVFreeTypeFace::getCharIndex(lChar16 code, lChar16 def_char) { return ch_glyph_index; } -bool LVFreeTypeFace::getGlyphInfo(lUInt16 code, LVFont::glyph_info_t *glyph, lChar16 def_char) { +bool LVFreeTypeFace::getGlyphInfo(lUInt32 code, LVFont::glyph_info_t *glyph, lChar16 def_char) { //FONT_GUARD int glyph_index = getCharIndex(code, 0); if (glyph_index == 0) { @@ -1022,7 +1023,7 @@ void LVFreeTypeFace::updateTransform() { // } } -LVFontGlyphCacheItem *LVFreeTypeFace::getGlyph(lUInt16 ch, lChar16 def_char) { +LVFontGlyphCacheItem *LVFreeTypeFace::getGlyph(lUInt32 ch, lChar16 def_char) { //FONT_GUARD FT_UInt ch_glyph_index = getCharIndex(ch, 0); if (ch_glyph_index == 0) { diff --git a/crengine/src/private/lvfreetypeface.h b/crengine/src/private/lvfreetypeface.h index 3ab24d4d15..639ccde201 100644 --- a/crengine/src/private/lvfreetypeface.h +++ b/crengine/src/private/lvfreetypeface.h @@ -194,13 +194,11 @@ class LVFreeTypeFace : public LVFont { #endif // USE_HARFBUZZ==1 - FT_UInt getCharIndex(lChar16 code, lChar16 def_char); - /** \brief get glyph info \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ - virtual bool getGlyphInfo(lUInt16 code, glyph_info_t *glyph, lChar16 def_char = 0); + virtual bool getGlyphInfo(lUInt32 code, glyph_info_t *glyph, lChar16 def_char = 0); /* // USE GET_CHAR_FLAGS instead inline int calcCharFlags( lChar16 ch ) @@ -258,7 +256,7 @@ class LVFreeTypeFace : public LVFont { \param code is unicode character \return glyph pointer if glyph was found, NULL otherwise */ - virtual LVFontGlyphCacheItem *getGlyph(lUInt16 ch, lChar16 def_char = 0); + virtual LVFontGlyphCacheItem *getGlyph(lUInt32 ch, lChar16 def_char = 0); #if USE_HARFBUZZ == 1 @@ -340,6 +338,8 @@ class LVFreeTypeFace : public LVFont { } virtual void Clear(); +protected: + FT_UInt getCharIndex(lUInt32 code, lChar16 def_char); }; #endif // (USE_FREETYPE==1) diff --git a/crengine/src/private/lvfreetypefontman.cpp b/crengine/src/private/lvfreetypefontman.cpp index 2da77ed2a6..106c7acc4a 100644 --- a/crengine/src/private/lvfreetypefontman.cpp +++ b/crengine/src/private/lvfreetypefontman.cpp @@ -1,4 +1,4 @@ -/** \file lvfreetypefontman.c +/** \file lvfreetypefontman.cpp \brief FreeType font manager implementation CoolReader Engine @@ -15,6 +15,7 @@ #include "lvfreetypefontman.h" #include "lvfreetypeface.h" #include "lvfontboldtransform.h" +#include "../../include/crlog.h" #if (USE_FONTCONFIG == 1) #include diff --git a/crengine/src/private/lvwin32font.cpp b/crengine/src/private/lvwin32font.cpp index d15d516684..8a7fbe1f8e 100644 --- a/crengine/src/private/lvwin32font.cpp +++ b/crengine/src/private/lvwin32font.cpp @@ -118,7 +118,7 @@ bool LVBaseWin32Font::Create(int size, int weight, bool italic, css_font_family_ \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ -bool LVWin32DrawFont::getGlyphInfo( lUInt16 code, glyph_info_t * glyph, lChar16 def_char ) +bool LVWin32DrawFont::getGlyphInfo( lUInt32 code, glyph_info_t * glyph, lChar16 def_char ) { return false; } @@ -356,7 +356,7 @@ void LVWin32DrawFont::DrawTextString( LVDrawBuf * buf, int x, int y, \param buf is buffer [width*height] to place glyph data \return true if glyph was found */ -bool LVWin32DrawFont::getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char) +bool LVWin32DrawFont::getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char) { return false; } @@ -505,7 +505,7 @@ glyph_t * LVWin32Font::GetGlyphRec( lChar16 ch ) \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ -bool LVWin32Font::getGlyphInfo( lUInt16 code, glyph_info_t * glyph, lChar16 def_char ) +bool LVWin32Font::getGlyphInfo( lUInt32 code, glyph_info_t * glyph, lChar16 def_char ) { if (_hfont==NULL) return false; @@ -618,7 +618,7 @@ lUInt16 LVWin32Font::measureText( \param buf is buffer [width*height] to place glyph data \return true if glyph was found */ -bool LVWin32Font::getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char) +bool LVWin32Font::getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char) { if (_hfont==NULL) return false; diff --git a/crengine/src/private/lvwin32font.h b/crengine/src/private/lvwin32font.h index 65c1ec6e90..5a5e6f910c 100644 --- a/crengine/src/private/lvwin32font.h +++ b/crengine/src/private/lvwin32font.h @@ -104,7 +104,7 @@ class LVBaseWin32Font : public LVBaseFont return css_ff_inherit; } - virtual LVFontGlyphCacheItem * getGlyph(lUInt16 ch, lChar16 def_char=0) { + virtual LVFontGlyphCacheItem * getGlyph(lUInt32 ch, lChar16 def_char=0) { return NULL; } @@ -127,7 +127,7 @@ class LVWin32DrawFont : public LVBaseWin32Font \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ - virtual bool getGlyphInfo( lUInt16 code, glyph_info_t * glyph, lChar16 def_char=0 ); + virtual bool getGlyphInfo( lUInt32 code, glyph_info_t * glyph, lChar16 def_char=0 ); /** \brief measure text \param glyph is pointer to glyph_info_t struct to place retrieved info @@ -164,7 +164,7 @@ class LVWin32DrawFont : public LVBaseWin32Font \param buf is buffer [width*height] to place glyph data \return true if glyph was found */ - virtual bool getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char=0); + virtual bool getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char=0); }; @@ -302,7 +302,7 @@ class LVWin32Font : public LVBaseWin32Font \param glyph is pointer to glyph_info_t struct to place retrieved info \return true if glyh was found */ - virtual bool getGlyphInfo( lUInt16 code, glyph_info_t * glyph, lChar16 def_char=0 ); + virtual bool getGlyphInfo( lUInt32 code, glyph_info_t * glyph, lChar16 def_char=0 ); /** \brief measure text \param glyph is pointer to glyph_info_t struct to place retrieved info @@ -331,7 +331,7 @@ class LVWin32Font : public LVBaseWin32Font \param buf is buffer [width*height] to place glyph data \return true if glyph was found */ - virtual bool getGlyphImage(lUInt16 code, lUInt8 * buf, lChar16 def_char=0); + virtual bool getGlyphImage(lUInt32 code, lUInt8 * buf, lChar16 def_char=0); virtual void Clear(); diff --git a/crengine/src/props.cpp b/crengine/src/props.cpp index 1ae8253020..84140a98cf 100644 --- a/crengine/src/props.cpp +++ b/crengine/src/props.cpp @@ -10,6 +10,7 @@ */ #include "../include/props.h" +#include "../include/serialbuf.h" #include diff --git a/crengine/src/serialbuf.cpp b/crengine/src/serialbuf.cpp new file mode 100644 index 0000000000..8cfd3b0ed1 --- /dev/null +++ b/crengine/src/serialbuf.cpp @@ -0,0 +1,337 @@ +/******************************************************* + + CoolReader Engine + + serialbuf.cpp: serialization buffer class implementation + + (c) Vadim Lopatin, 2000-2006 + This source code is distributed under the terms of + GNU General Public License + See LICENSE file for details + +*******************************************************/ + +#include "../include/serialbuf.h" + +/// serialization/deserialization buffer + +/// constructor of serialization buffer +SerialBuf::SerialBuf( int sz, bool autoresize ) + : _buf( (lUInt8*)malloc(sz) ), _ownbuf(true), _error(false), _autoresize(autoresize), _size(sz), _pos(0) +{ + memset( _buf, 0, _size ); +} +/// constructor of deserialization buffer +SerialBuf::SerialBuf( const lUInt8 * p, int sz ) + : _buf( const_cast(p) ), _ownbuf(false), _error(false), _autoresize(false), _size(sz), _pos(0) +{ +} + +SerialBuf::~SerialBuf() +{ + if ( _ownbuf ) + free( _buf ); +} + +bool SerialBuf::copyTo( lUInt8 * buf, int maxSize ) +{ + if ( _pos==0 ) + return true; + if ( _pos > maxSize ) + return false; + memcpy( buf, _buf, _pos ); + return true; +} + +/// checks whether specified number of bytes is available, returns true in case of error +bool SerialBuf::check( int reserved ) +{ + if ( _error ) + return true; + if ( space()16384 ? _size*2 : 16384) + reserved; + _buf = cr_realloc(_buf, _size ); + memset( _buf+_pos, 0, _size-_pos ); + return false; + } else { + _error = true; + return true; + } + } + return false; +} + +// write methods +/// put magic signature +void SerialBuf::putMagic( const char * s ) +{ + if ( check(1) ) + return; + while ( *s ) { + _buf[ _pos++ ] = *s++; + if ( check(1) ) + return; + } +} + +#define SWAPVARS(t,a) \ +{ \ + t tmp; \ + tmp = a; a = v.a; v.a = tmp; \ +} +void SerialBuf::swap( SerialBuf & v ) +{ + SWAPVARS(lUInt8 *, _buf) + SWAPVARS(bool, _ownbuf) + SWAPVARS(bool, _error) + SWAPVARS(bool, _autoresize) + SWAPVARS(int, _size) + SWAPVARS(int, _pos) +} + + +/// add contents of another buffer +SerialBuf & SerialBuf::operator << ( const SerialBuf & v ) +{ + if ( check(v.pos()) || v.pos()==0 ) + return *this; + memcpy( _buf + _pos, v._buf, v._pos ); + _pos += v._pos; + return *this; +} + +SerialBuf & SerialBuf::operator << ( lUInt8 n ) +{ + if ( check(1) ) + return *this; + _buf[_pos++] = n; + return *this; +} +SerialBuf & SerialBuf::operator << ( char n ) +{ + if ( check(1) ) + return *this; + _buf[_pos++] = (lUInt8)n; + return *this; +} +SerialBuf & SerialBuf::operator << ( bool n ) +{ + if ( check(1) ) + return *this; + _buf[_pos++] = (lUInt8)(n ? 1 : 0); + return *this; +} +SerialBuf & SerialBuf::operator << ( lUInt16 n ) +{ + if ( check(2) ) + return *this; + _buf[_pos++] = (lUInt8)(n & 255); + _buf[_pos++] = (lUInt8)((n>>8) & 255); + return *this; +} +SerialBuf & SerialBuf::operator << ( lInt16 n ) +{ + if ( check(2) ) + return *this; + _buf[_pos++] = (lUInt8)(n & 255); + _buf[_pos++] = (lUInt8)((n>>8) & 255); + return *this; +} +SerialBuf & SerialBuf::operator << ( lUInt32 n ) +{ + if ( check(4) ) + return *this; + _buf[_pos++] = (lUInt8)(n & 255); + _buf[_pos++] = (lUInt8)((n>>8) & 255); + _buf[_pos++] = (lUInt8)((n>>16) & 255); + _buf[_pos++] = (lUInt8)((n>>24) & 255); + return *this; +} +SerialBuf & SerialBuf::operator << ( lInt32 n ) +{ + if ( check(4) ) + return *this; + _buf[_pos++] = (lUInt8)(n & 255); + _buf[_pos++] = (lUInt8)((n>>8) & 255); + _buf[_pos++] = (lUInt8)((n>>16) & 255); + _buf[_pos++] = (lUInt8)((n>>24) & 255); + return *this; +} +SerialBuf & SerialBuf::operator << ( const lString16 & s ) +{ + if ( check(2) ) + return *this; + lString8 s8 = UnicodeToUtf8(s); + lUInt16 len = (lUInt16)s8.length(); + (*this) << len; + for ( int i=0; i> ( lUInt8 & n ) +{ + if ( check(1) ) + return *this; + n = _buf[_pos++]; + return *this; +} + +SerialBuf & SerialBuf::operator >> ( char & n ) +{ + if ( check(1) ) + return *this; + n = (char)_buf[_pos++]; + return *this; +} + +SerialBuf & SerialBuf::operator >> ( bool & n ) +{ + if ( check(1) ) + return *this; + n = _buf[_pos++] ? true : false; + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lUInt16 & n ) +{ + if ( check(2) ) + return *this; + n = _buf[_pos++]; + n |= (((lUInt16)_buf[_pos++]) << 8); + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lInt16 & n ) +{ + if ( check(2) ) + return *this; + n = (lInt16)(_buf[_pos++]); + n |= (lInt16)(((lUInt16)_buf[_pos++]) << 8); + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lUInt32 & n ) +{ + if ( check(4) ) + return *this; + n = _buf[_pos++]; + n |= (((lUInt32)_buf[_pos++]) << 8); + n |= (((lUInt32)_buf[_pos++]) << 16); + n |= (((lUInt32)_buf[_pos++]) << 24); + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lInt32 & n ) +{ + if ( check(4) ) + return *this; + n = (lInt32)(_buf[_pos++]); + n |= (((lUInt32)_buf[_pos++]) << 8); + n |= (((lUInt32)_buf[_pos++]) << 16); + n |= (((lUInt32)_buf[_pos++]) << 24); + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lString8 & s8 ) +{ + if ( check(2) ) + return *this; + lUInt16 len = 0; + (*this) >> len; + s8.clear(); + s8.reserve(len); + for ( int i=0; i> c; + s8.append(1, c); + } + return *this; +} + +SerialBuf & SerialBuf::operator >> ( lString16 & s ) +{ + lString8 s8; + (*this) >> s8; + s = Utf8ToUnicode(s8); + return *this; +} + +// read methods +bool SerialBuf::checkMagic( const char * s ) +{ + if ( _error ) + return false; + while ( *s ) { + if ( check(1) ) + return false; + if ( _buf[ _pos++ ] != *s++ ) { + seterror(); + return false; + } + } + return true; +} + +/// add CRC32 for last N bytes +void SerialBuf::putCRC( int size ) +{ + if ( error() ) + return; + if ( size>_pos ) { + *this << (lUInt32)0; + seterror(); + } + lUInt32 n = 0; + n = lStr_crc32( n, _buf + _pos-size, size ); + *this << n; +} + +/// get CRC32 for the whole buffer +lUInt32 SerialBuf::getCRC() +{ + if (error()) + return 0; + lUInt32 n = 0; + n = lStr_crc32( n, _buf, _pos ); + return n; +} + +/// read crc32 code, comapare with CRC32 for last N bytes +bool SerialBuf::checkCRC( int size ) +{ + if ( error() ) + return false; + if ( size>_pos ) { + seterror(); + return false; + } + lUInt32 n0 = 0; + n0 = lStr_crc32(n0, _buf + _pos-size, size); + lUInt32 n = 0; + *this >> n; + if ( error() ) + return false; + if ( n!=n0 ) + seterror(); + return !error(); +} diff --git a/crengine/src/txtselector.cpp b/crengine/src/txtselector.cpp index 8c44d6c90c..894e3ccca8 100644 --- a/crengine/src/txtselector.cpp +++ b/crengine/src/txtselector.cpp @@ -12,6 +12,7 @@ *******************************************************/ #include "../include/txtselector.h" +#include "../include/crlog.h" /// create selection tool for specified initial range (usually current page) ldomTextSelectionTool::ldomTextSelectionTool( ldomXRange & initialRange, ldomTextSelectionTool::interval_t initialInterval, ldomTextSelectionTool::origin_t initialOrigin ) diff --git a/crengine/src/wolutil.cpp b/crengine/src/wolutil.cpp index fb31f785d7..83a0a93004 100644 --- a/crengine/src/wolutil.cpp +++ b/crengine/src/wolutil.cpp @@ -10,7 +10,7 @@ #include #include "../include/wolutil.h" - +#include "private/dumpfile.h" #define N 4096 #define F 18 diff --git a/crengine/src/wordfmt.cpp b/crengine/src/wordfmt.cpp index 5a76049263..587524f7bc 100644 --- a/crengine/src/wordfmt.cpp +++ b/crengine/src/wordfmt.cpp @@ -2,6 +2,7 @@ #include "../include/lvstring.h" #include "../include/lvstream.h" #include "../include/lvtinydom.h" +#include "../include/crlog.h" //#ifndef ENABLE_ANTIWORD //#define ENABLE_ANTIWORD 1