diff --git a/Makefile b/Makefile index 8b761ddd..6808f843 100644 --- a/Makefile +++ b/Makefile @@ -6,38 +6,39 @@ init: git submodule update --init android update project -p . -all: clean build-external build-jni build-java copy-libs +all: build-external build-jni build-java copy-libs build-external: cd external/ && \ make -f Android.mk build-local-hack && \ - ndk-build clean && \ ndk-build && \ - make -f Android.mk copy-libs-hack + make -f Android.mk copy-libs-hack build-jni: cd jni/ && \ - ndk-build clean && \ ndk-build build-java: - ant clean && \ ant release && \ cd bin/classes && \ jar -cvf sqlcipher.jar . clean: - -rm ${LIBRARY_ROOT}/armeabi/libsqlcipher_android.so && \ - rm ${LIBRARY_ROOT}/armeabi/libdatabase_sqlcipher.so && \ - rm ${LIBRARY_ROOT}/sqlcipher.jar + ant clean + cd external/ && ndk-build clean + cd jni/ && ndk-build clean + -rm ${LIBRARY_ROOT}/armeabi/libsqlcipher_android.so + -rm ${LIBRARY_ROOT}/armeabi/libdatabase_sqlcipher.so + -rm ${LIBRARY_ROOT}/sqlcipher.jar copy-libs: + mkdir -p ${LIBRARY_ROOT}/armeabi cp external/libs/armeabi/libsqlcipher_android.so \ ${LIBRARY_ROOT}/armeabi && \ - cp jni/libs/armeabi/libdatabase_sqlcipher.so \ - ${LIBRARY_ROOT}/armeabi && \ - cp bin/classes/sqlcipher.jar ${LIBRARY_ROOT} && \ - cp ${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so \ + cp jni/libs/armeabi/libdatabase_sqlcipher.so \ + ${LIBRARY_ROOT}/armeabi && \ + cp bin/classes/sqlcipher.jar ${LIBRARY_ROOT} && \ + cp ${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so \ ${LIBRARY_ROOT}/armeabi copy-libs-dist: diff --git a/assets/icudt44l.zip b/assets/icudt44l.zip deleted file mode 100644 index 3b6372e5..00000000 Binary files a/assets/icudt44l.zip and /dev/null differ diff --git a/assets/icudt46l.zip b/assets/icudt46l.zip new file mode 100644 index 00000000..91dc7f71 Binary files /dev/null and b/assets/icudt46l.zip differ diff --git a/default.properties b/default.properties deleted file mode 100644 index b00c8c5c..00000000 --- a/default.properties +++ /dev/null @@ -1 +0,0 @@ -target=android-7 diff --git a/external/Android.mk b/external/Android.mk index 75933b14..d7d25724 100644 --- a/external/Android.mk +++ b/external/Android.mk @@ -46,7 +46,7 @@ sqlcipher_cflags := -DSQLITE_HAS_CODEC -DHAVE_FDATASYNC=0 -Dfdatasync=fsync include $(CLEAR_VARS) LOCAL_CFLAGS += $(android_sqlite_cflags) $(sqlcipher_cflags) -LOCAL_C_INCLUDES := openssl/include sqlcipher +LOCAL_C_INCLUDES := includes openssl/include sqlcipher LOCAL_LDFLAGS += $(project_ldflags) LOCAL_LDLIBS += -lcrypto LOCAL_MODULE := libsqlcipher @@ -64,7 +64,8 @@ libsqlite3_android_local_src_files := \ android-sqlite/android/PhoneNumberUtils.cpp \ android-sqlite/android/OldPhoneNumberUtils.cpp \ android-sqlite/android/PhoneticStringUtils.cpp \ - platform-frameworks-base/libs/utils/String8.cpp + String16.cpp \ + String8.cpp # android-sqlite/android/PhoneNumberUtilsTest.cpp \ # android-sqlite/android/PhoneticStringUtilsTest.cpp \ @@ -81,8 +82,8 @@ LOCAL_STATIC_LIBRARIES := libsqlcipher libicui18n libicuuc LOCAL_CFLAGS += $(android_sqlite_cflags) $(sqlite_cflags) -DOS_PATH_SEPARATOR="'/'" LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/includes \ $(LOCAL_PATH)/sqlcipher \ - $(LOCAL_PATH)/include \ $(LOCAL_PATH)/icu4c/i18n \ $(LOCAL_PATH)/icu4c/common \ $(LOCAL_PATH)/platform-system-core/include \ @@ -109,6 +110,8 @@ include $(BUILD_SHARED_LIBRARY) ICU_COMMON_PATH := icu4c/common +# new icu common build begin + icu_src_files := \ $(ICU_COMMON_PATH)/cmemory.c $(ICU_COMMON_PATH)/cstring.c \ $(ICU_COMMON_PATH)/cwchar.c $(ICU_COMMON_PATH)/locmap.c \ @@ -130,7 +133,7 @@ icu_src_files := \ $(ICU_COMMON_PATH)/ucnv_set.c $(ICU_COMMON_PATH)/ucnv_u16.c \ $(ICU_COMMON_PATH)/ucnv_u32.c $(ICU_COMMON_PATH)/ucnv_u7.c \ $(ICU_COMMON_PATH)/ucnv_u8.c \ - $(ICU_COMMON_PATH)/udata.c $(ICU_COMMON_PATH)/udatamem.c \ + $(ICU_COMMON_PATH)/udatamem.c \ $(ICU_COMMON_PATH)/udataswp.c $(ICU_COMMON_PATH)/uenum.c \ $(ICU_COMMON_PATH)/uhash.c $(ICU_COMMON_PATH)/uinit.c \ $(ICU_COMMON_PATH)/uinvchar.c $(ICU_COMMON_PATH)/uloc.c \ @@ -188,13 +191,16 @@ icu_src_files += \ $(ICU_COMMON_PATH)/loclikely.cpp $(ICU_COMMON_PATH)/locresdata.cpp \ $(ICU_COMMON_PATH)/normalizer2impl.cpp $(ICU_COMMON_PATH)/normalizer2.cpp \ $(ICU_COMMON_PATH)/filterednormalizer2.cpp $(ICU_COMMON_PATH)/ucol_swp.cpp \ - $(ICU_COMMON_PATH)/uprops.cpp $(ICU_COMMON_PATH)/utrie2.cpp - + $(ICU_COMMON_PATH)/uprops.cpp $(ICU_COMMON_PATH)/utrie2.cpp \ + $(ICU_COMMON_PATH)/charstr.cpp $(ICU_COMMON_PATH)/uts46.cpp \ + $(ICU_COMMON_PATH)/udata.cpp # This is the empty compiled-in icu data structure # that we need to satisfy the linker. icu_src_files += $(ICU_COMMON_PATH)/../stubdata/stubdata.c +# new icu common build end + icu_c_includes := \ $(ICU_COMMON_PATH)/ \ $(ICU_COMMON_PATH)//../i18n @@ -203,10 +209,10 @@ icu_c_includes := \ # device and sim builds can use the same codepath, and it's hard to break one # without noticing because the other still works. -icu_local_cflags += -D_REENTRANT -DU_COMMON_IMPLEMENTATION -O3 -DHAVE_ANDROID_OS=1 +icu_local_cflags += -D_REENTRANT -DU_COMMON_IMPLEMENTATION -O3 -DHAVE_ANDROID_OS=1 -fvisibility=hidden icu_local_cflags += '-DICU_DATA_DIR_PREFIX_ENV_VAR="SQLCIPHER_ICU_PREFIX"' icu_local_cflags += '-DICU_DATA_DIR="/icu"' -icu_local_ldlibs := -lc +icu_local_ldlibs := -lc -lpthread -lm # # Build for the target (device). @@ -216,6 +222,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(icu_src_files) LOCAL_C_INCLUDES := $(icu_c_includes) LOCAL_CFLAGS := $(icu_local_cflags) -DPIC -fPIC +LOCAL_RTTI_FLAG := -frtti +LOCAL_SHARED_LIBRARIES += libgabi++ LOCAL_LDLIBS += $(icu_local_ldlibs) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libicuuc @@ -233,15 +241,17 @@ LOCAL_PATH := $(PROJECT_ROOT_PATH) #ICU_I18N_PATH := $(LOCAL_PATH)/icu4c/i18n ICU_I18N_PATH := icu4c/i18n +# start new icu18n + src_files := \ $(ICU_I18N_PATH)/bocsu.c $(ICU_I18N_PATH)/ucln_in.c $(ICU_I18N_PATH)/decContext.c \ $(ICU_I18N_PATH)/ulocdata.c $(ICU_I18N_PATH)/utmscale.c $(ICU_I18N_PATH)/decNumber.c src_files += \ - $(ICU_I18N_PATH)/indiancal.cpp $(ICU_I18N_PATH)/dtptngen.cpp $(ICU_I18N_PATH)/dtrule.cpp \ - $(ICU_I18N_PATH)/persncal.cpp $(ICU_I18N_PATH)/rbtz.cpp $(ICU_I18N_PATH)/reldtfmt.cpp \ - $(ICU_I18N_PATH)/taiwncal.cpp $(ICU_I18N_PATH)/tzrule.cpp $(ICU_I18N_PATH)/tztrans.cpp \ - $(ICU_I18N_PATH)/udatpg.cpp $(ICU_I18N_PATH)/vtzone.cpp \ + $(ICU_I18N_PATH)/indiancal.cpp $(ICU_I18N_PATH)/dtptngen.cpp $(ICU_I18N_PATH)/dtrule.cpp \ + $(ICU_I18N_PATH)/persncal.cpp $(ICU_I18N_PATH)/rbtz.cpp $(ICU_I18N_PATH)/reldtfmt.cpp \ + $(ICU_I18N_PATH)/taiwncal.cpp $(ICU_I18N_PATH)/tzrule.cpp $(ICU_I18N_PATH)/tztrans.cpp \ + $(ICU_I18N_PATH)/udatpg.cpp $(ICU_I18N_PATH)/vtzone.cpp \ $(ICU_I18N_PATH)/anytrans.cpp $(ICU_I18N_PATH)/astro.cpp $(ICU_I18N_PATH)/buddhcal.cpp \ $(ICU_I18N_PATH)/basictz.cpp $(ICU_I18N_PATH)/calendar.cpp $(ICU_I18N_PATH)/casetrn.cpp \ $(ICU_I18N_PATH)/choicfmt.cpp $(ICU_I18N_PATH)/coleitr.cpp $(ICU_I18N_PATH)/coll.cpp \ @@ -281,18 +291,19 @@ src_files += \ $(ICU_I18N_PATH)/plurfmt.cpp $(ICU_I18N_PATH)/dtitvfmt.cpp $(ICU_I18N_PATH)/dtitvinf.cpp \ $(ICU_I18N_PATH)/tmunit.cpp $(ICU_I18N_PATH)/tmutamt.cpp $(ICU_I18N_PATH)/tmutfmt.cpp \ $(ICU_I18N_PATH)/colldata.cpp $(ICU_I18N_PATH)/bmsearch.cpp $(ICU_I18N_PATH)/bms.cpp \ - $(ICU_I18N_PATH)/currpinf.cpp $(ICU_I18N_PATH)/uspoof.cpp $(ICU_I18N_PATH)/uspoof_impl.cpp \ - $(ICU_I18N_PATH)/uspoof_build.cpp \ - $(ICU_I18N_PATH)/regextxt.cpp $(ICU_I18N_PATH)/selfmt.cpp $(ICU_I18N_PATH)/uspoof_conf.cpp \ - $(ICU_I18N_PATH)/uspoof_wsconf.cpp $(ICU_I18N_PATH)/ztrans.cpp $(ICU_I18N_PATH)/zrule.cpp \ - $(ICU_I18N_PATH)/vzone.cpp $(ICU_I18N_PATH)/fphdlimp.cpp $(ICU_I18N_PATH)/fpositer.cpp\ - $(ICU_I18N_PATH)/locdspnm.cpp $(ICU_I18N_PATH)/decnumstr.cpp $(ICU_I18N_PATH)/ucol_wgt.cpp + $(ICU_I18N_PATH)/currpinf.cpp $(ICU_I18N_PATH)/uspoof.cpp $(ICU_I18N_PATH)/uspoof_impl.cpp \ + $(ICU_I18N_PATH)/uspoof_build.cpp \ + $(ICU_I18N_PATH)/regextxt.cpp $(ICU_I18N_PATH)/selfmt.cpp $(ICU_I18N_PATH)/uspoof_conf.cpp \ + $(ICU_I18N_PATH)/uspoof_wsconf.cpp $(ICU_I18N_PATH)/ztrans.cpp $(ICU_I18N_PATH)/zrule.cpp \ + $(ICU_I18N_PATH)/vzone.cpp $(ICU_I18N_PATH)/fphdlimp.cpp $(ICU_I18N_PATH)/fpositer.cpp\ + $(ICU_I18N_PATH)/locdspnm.cpp $(ICU_I18N_PATH)/decnumstr.cpp $(ICU_I18N_PATH)/ucol_wgt.cpp + +# end new icu18n c_includes = \ $(ICU_I18N_PATH)/ \ $(ICU_I18N_PATH)/../common - # # Build for the target (device). # @@ -300,13 +311,14 @@ c_includes = \ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(src_files) -LOCAL_C_INCLUDES := $(c_includes) - -LOCAL_CFLAGS += -D_REENTRANT -DPIC -DU_I18N_IMPLEMENTATION -fPIC +LOCAL_C_INCLUDES := $(c_includes) \ + abi/cpp/include +LOCAL_CFLAGS += -D_REENTRANT -DPIC -DU_I18N_IMPLEMENTATION -fPIC -fvisibility=hidden LOCAL_CFLAGS += -O3 - +LOCAL_RTTI_FLAG := -frtti +LOCAL_SHARED_LIBRARIES += libgabi++ LOCAL_STATIC_LIBRARIES += libicuuc -LOCAL_LDLIBS += -lc +LOCAL_LDLIBS += -lc -lpthread -lm LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libicui18n diff --git a/external/String16.cpp b/external/String16.cpp new file mode 100644 index 00000000..38baf531 --- /dev/null +++ b/external/String16.cpp @@ -0,0 +1,634 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_WINSOCK +# undef nhtol +# undef htonl +# undef nhtos +# undef htons + +# ifdef HAVE_LITTLE_ENDIAN +# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) +# define htonl(x) ntohl(x) +# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) +# define htons(x) ntohs(x) +# else +# define ntohl(x) (x) +# define htonl(x) (x) +# define ntohs(x) (x) +# define htons(x) (x) +# endif +#else +//# include +# include +#endif + +#include +#include +#include + +// --------------------------------------------------------------------------- + +int strcmp16(const char16_t *s1, const char16_t *s2) +{ + char16_t ch; + int d = 0; + + while ( 1 ) { + d = (int)(ch = *s1++) - (int)*s2++; + if ( d || !ch ) + break; + } + + return d; +} + +int strncmp16(const char16_t *s1, const char16_t *s2, size_t n) +{ + char16_t ch; + int d = 0; + + while ( n-- ) { + d = (int)(ch = *s1++) - (int)*s2++; + if ( d || !ch ) + break; + } + + return d; +} + +char16_t *strcpy16(char16_t *dst, const char16_t *src) +{ + char16_t *q = dst; + const char16_t *p = src; + char16_t ch; + + do { + *q++ = ch = *p++; + } while ( ch ); + + return dst; +} + +size_t strlen16(const char16_t *s) +{ + const char16_t *ss = s; + while ( *ss ) + ss++; + return ss-s; +} + + +char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n) +{ + char16_t *q = dst; + const char16_t *p = src; + char ch; + + while (n) { + n--; + *q++ = ch = *p++; + if ( !ch ) + break; + } + + *q = 0; + + return dst; +} + +size_t strnlen16(const char16_t *s, size_t maxlen) +{ + const char16_t *ss = s; + + /* Important: the maxlen test must precede the reference through ss; + since the byte beyond the maximum may segfault */ + while ((maxlen > 0) && *ss) { + ss++; + maxlen--; + } + return ss-s; +} + +int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) +{ + const char16_t* e1 = s1+n1; + const char16_t* e2 = s2+n2; + + while (s1 < e1 && s2 < e2) { + const int d = (int)*s1++ - (int)*s2++; + if (d) { + return d; + } + } + + return n1 < n2 + ? (0 - (int)*s2) + : (n1 > n2 + ? ((int)*s1 - 0) + : 0); +} + +int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2) +{ + const char16_t* e1 = s1H+n1; + const char16_t* e2 = s2N+n2; + + while (s1H < e1 && s2N < e2) { + const char16_t c2 = ntohs(*s2N); + const int d = (int)*s1H++ - (int)c2; + s2N++; + if (d) { + return d; + } + } + + return n1 < n2 + ? (0 - (int)ntohs(*s2N)) + : (n1 > n2 + ? ((int)*s1H - 0) + : 0); +} + +static inline size_t +utf8_char_len(uint8_t ch) +{ + return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; +} + +#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte)); + +static inline uint32_t +utf8_to_utf32(const uint8_t *src, size_t length) +{ + uint32_t unicode; + + switch (length) + { + case 1: + return src[0]; + case 2: + unicode = src[0] & 0x1f; + UTF8_SHIFT_AND_MASK(unicode, src[1]) + return unicode; + case 3: + unicode = src[0] & 0x0f; + UTF8_SHIFT_AND_MASK(unicode, src[1]) + UTF8_SHIFT_AND_MASK(unicode, src[2]) + return unicode; + case 4: + unicode = src[0] & 0x07; + UTF8_SHIFT_AND_MASK(unicode, src[1]) + UTF8_SHIFT_AND_MASK(unicode, src[2]) + UTF8_SHIFT_AND_MASK(unicode, src[3]) + return unicode; + default: + return 0xffff; + } + + //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); +} + +void +utf8_to_utf16(const uint8_t *src, size_t srcLen, + char16_t* dst, const size_t dstLen) +{ + const uint8_t* const end = src + srcLen; + const char16_t* const dstEnd = dst + dstLen; + while (src < end && dst < dstEnd) { + size_t len = utf8_char_len(*src); + uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len); + + // Convert the UTF32 codepoint to one or more UTF16 codepoints + if (codepoint <= 0xFFFF) { + // Single UTF16 character + *dst++ = (char16_t) codepoint; + } else { + // Multiple UTF16 characters with surrogates + codepoint = codepoint - 0x10000; + *dst++ = (char16_t) ((codepoint >> 10) + 0xD800); + *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); + } + + src += len; + } + if (dst < dstEnd) { + *dst = 0; + } +} + +// --------------------------------------------------------------------------- + +namespace android { + +static SharedBuffer* gEmptyStringBuf = NULL; +static char16_t* gEmptyString = NULL; + +static inline char16_t* getEmptyString() +{ + gEmptyStringBuf->acquire(); + return gEmptyString; +} + +void initialize_string16() +{ + SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)); + char16_t* str = (char16_t*)buf->data(); + *str = 0; + gEmptyStringBuf = buf; + gEmptyString = str; +} + +void terminate_string16() +{ + SharedBuffer::bufferFromData(gEmptyString)->release(); + gEmptyStringBuf = NULL; + gEmptyString = NULL; +} + +// --------------------------------------------------------------------------- + +static char16_t* allocFromUTF8(const char* in, size_t len) +{ + if (len == 0) return getEmptyString(); + + size_t chars = 0; + const char* end = in+len; + const char* p = in; + + while (p < end) { + chars++; + int utf8len = utf8_char_len(*p); + uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len); + if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16 + p += utf8len; + } + + size_t bufSize = (chars+1)*sizeof(char16_t); + SharedBuffer* buf = SharedBuffer::alloc(bufSize); + if (buf) { + p = in; + char16_t* str = (char16_t*)buf->data(); + + utf8_to_utf16((const uint8_t*)p, len, str, bufSize); + + //printf("Created UTF-16 string from UTF-8 \"%s\":", in); + //printHexData(1, str, buf->size(), 16, 1); + //printf("\n"); + + return str; + } + + return getEmptyString(); +} + +// --------------------------------------------------------------------------- + +String16::String16() + : mString(getEmptyString()) +{ +} + +String16::String16(const String16& o) + : mString(o.mString) +{ + SharedBuffer::bufferFromData(mString)->acquire(); +} + +String16::String16(const String16& o, size_t len, size_t begin) + : mString(getEmptyString()) +{ + setTo(o, len, begin); +} + +String16::String16(const char16_t* o) +{ + size_t len = strlen16(o); + SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + strcpy16(str, o); + mString = str; + return; + } + + mString = getEmptyString(); +} + +String16::String16(const char16_t* o, size_t len) +{ + SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + memcpy(str, o, len*sizeof(char16_t)); + str[len] = 0; + mString = str; + return; + } + + mString = getEmptyString(); +} + +String16::String16(const String8& o) + : mString(allocFromUTF8(o.string(), o.size())) +{ +} + +String16::String16(const char* o) + : mString(allocFromUTF8(o, strlen(o))) +{ +} + +String16::String16(const char* o, size_t len) + : mString(allocFromUTF8(o, len)) +{ +} + +String16::~String16() +{ + SharedBuffer::bufferFromData(mString)->release(); +} + +void String16::setTo(const String16& other) +{ + SharedBuffer::bufferFromData(other.mString)->acquire(); + SharedBuffer::bufferFromData(mString)->release(); + mString = other.mString; +} + +status_t String16::setTo(const String16& other, size_t len, size_t begin) +{ + const size_t N = other.size(); + if (begin >= N) { + SharedBuffer::bufferFromData(mString)->release(); + mString = getEmptyString(); + return NO_ERROR; + } + if ((begin+len) > N) len = N-begin; + if (begin == 0 && len == N) { + setTo(other); + return NO_ERROR; + } + + if (&other == this) { + LOG_ALWAYS_FATAL("Not implemented"); + } + + return setTo(other.string()+begin, len); +} + +status_t String16::setTo(const char16_t* other) +{ + return setTo(other, strlen16(other)); +} + +status_t String16::setTo(const char16_t* other, size_t len) +{ + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((len+1)*sizeof(char16_t)); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + memmove(str, other, len*sizeof(char16_t)); + str[len] = 0; + mString = str; + return NO_ERROR; + } + return NO_MEMORY; +} + +status_t String16::append(const String16& other) +{ + const size_t myLen = size(); + const size_t otherLen = other.size(); + if (myLen == 0) { + setTo(other); + return NO_ERROR; + } else if (otherLen == 0) { + return NO_ERROR; + } + + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((myLen+otherLen+1)*sizeof(char16_t)); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t)); + mString = str; + return NO_ERROR; + } + return NO_MEMORY; +} + +status_t String16::append(const char16_t* chrs, size_t otherLen) +{ + const size_t myLen = size(); + if (myLen == 0) { + setTo(chrs, otherLen); + return NO_ERROR; + } else if (otherLen == 0) { + return NO_ERROR; + } + + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((myLen+otherLen+1)*sizeof(char16_t)); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + memcpy(str+myLen, chrs, otherLen*sizeof(char16_t)); + str[myLen+otherLen] = 0; + mString = str; + return NO_ERROR; + } + return NO_MEMORY; +} + +status_t String16::insert(size_t pos, const char16_t* chrs) +{ + return insert(pos, chrs, strlen16(chrs)); +} + +status_t String16::insert(size_t pos, const char16_t* chrs, size_t len) +{ + const size_t myLen = size(); + if (myLen == 0) { + return setTo(chrs, len); + return NO_ERROR; + } else if (len == 0) { + return NO_ERROR; + } + + if (pos > myLen) pos = myLen; + + #if 0 + printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n", + String8(*this).string(), pos, + len, myLen, String8(chrs, len).string()); + #endif + + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((myLen+len+1)*sizeof(char16_t)); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + if (pos < myLen) { + memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t)); + } + memcpy(str+pos, chrs, len*sizeof(char16_t)); + str[myLen+len] = 0; + mString = str; + #if 0 + printf("Result (%d chrs): %s\n", size(), String8(*this).string()); + #endif + return NO_ERROR; + } + return NO_MEMORY; +} + +ssize_t String16::findFirst(char16_t c) const +{ + const char16_t* str = string(); + const char16_t* p = str; + const char16_t* e = p + size(); + while (p < e) { + if (*p == c) { + return p-str; + } + p++; + } + return -1; +} + +ssize_t String16::findLast(char16_t c) const +{ + const char16_t* str = string(); + const char16_t* p = str; + const char16_t* e = p + size(); + while (p < e) { + e--; + if (*e == c) { + return e-str; + } + } + return -1; +} + +bool String16::startsWith(const String16& prefix) const +{ + const size_t ps = prefix.size(); + if (ps > size()) return false; + return strzcmp16(mString, ps, prefix.string(), ps) == 0; +} + +bool String16::startsWith(const char16_t* prefix) const +{ + const size_t ps = strlen16(prefix); + if (ps > size()) return false; + return strncmp16(mString, prefix, ps) == 0; +} + +status_t String16::makeLower() +{ + const size_t N = size(); + const char16_t* str = string(); + char16_t* edit = NULL; + for (size_t i=0; i= 'A' && v <= 'Z') { + if (!edit) { + SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit(); + if (!buf) { + return NO_MEMORY; + } + edit = (char16_t*)buf->data(); + mString = str = edit; + } + edit[i] = tolower((char)v); + } + } + return NO_ERROR; +} + +status_t String16::replaceAll(char16_t replaceThis, char16_t withThis) +{ + const size_t N = size(); + const char16_t* str = string(); + char16_t* edit = NULL; + for (size_t i=0; iedit(); + if (!buf) { + return NO_MEMORY; + } + edit = (char16_t*)buf->data(); + mString = str = edit; + } + edit[i] = withThis; + } + } + return NO_ERROR; +} + +status_t String16::remove(size_t len, size_t begin) +{ + const size_t N = size(); + if (begin >= N) { + SharedBuffer::bufferFromData(mString)->release(); + mString = getEmptyString(); + return NO_ERROR; + } + if ((begin+len) > N) len = N-begin; + if (begin == 0 && len == N) { + return NO_ERROR; + } + + if (begin > 0) { + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((N+1)*sizeof(char16_t)); + if (!buf) { + return NO_MEMORY; + } + char16_t* str = (char16_t*)buf->data(); + memmove(str, str+begin, (N-begin+1)*sizeof(char16_t)); + mString = str; + } + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize((len+1)*sizeof(char16_t)); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + str[len] = 0; + mString = str; + return NO_ERROR; + } + return NO_MEMORY; +} + +TextOutput& operator<<(TextOutput& to, const String16& val) +{ + to << String8(val).string(); + return to; +} + +}; // namespace android diff --git a/external/String8.cpp b/external/String8.cpp new file mode 100644 index 00000000..1c4f80c1 --- /dev/null +++ b/external/String8.cpp @@ -0,0 +1,940 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include + +#include + +/* + * Functions outside android is below the namespace android, since they use + * functions and constants in android namespace. + */ + +// --------------------------------------------------------------------------- + +namespace android { + +static const char32_t kByteMask = 0x000000BF; +static const char32_t kByteMark = 0x00000080; + +// Surrogates aren't valid for UTF-32 characters, so define some +// constants that will let us screen them out. +static const char32_t kUnicodeSurrogateHighStart = 0x0000D800; +static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; +static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00; +static const char32_t kUnicodeSurrogateLowEnd = 0x0000DFFF; +static const char32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart; +static const char32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd; +static const char32_t kUnicodeMaxCodepoint = 0x0010FFFF; + +// Mask used to set appropriate bits in first byte of UTF-8 sequence, +// indexed by number of bytes in the sequence. +// 0xxxxxxx +// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000 +// 110yyyyx 10xxxxxx +// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0 +// 1110yyyy 10yxxxxx 10xxxxxx +// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0 +// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx +// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0 +static const char32_t kFirstByteMark[] = { + 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0 +}; + +// Separator used by resource paths. This is not platform dependent contrary +// to OS_PATH_SEPARATOR. +#define RES_PATH_SEPARATOR '/' + +// Return number of utf8 bytes required for the character. +static size_t utf32_to_utf8_bytes(char32_t srcChar) +{ + size_t bytesToWrite; + + // Figure out how many bytes the result will require. + if (srcChar < 0x00000080) + { + bytesToWrite = 1; + } + else if (srcChar < 0x00000800) + { + bytesToWrite = 2; + } + else if (srcChar < 0x00010000) + { + if ((srcChar < kUnicodeSurrogateStart) + || (srcChar > kUnicodeSurrogateEnd)) + { + bytesToWrite = 3; + } + else + { + // Surrogates are invalid UTF-32 characters. + return 0; + } + } + // Max code point for Unicode is 0x0010FFFF. + else if (srcChar <= kUnicodeMaxCodepoint) + { + bytesToWrite = 4; + } + else + { + // Invalid UTF-32 character. + return 0; + } + + return bytesToWrite; +} + +// Write out the source character to . + +static void utf32_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes) +{ + dstP += bytes; + switch (bytes) + { /* note: everything falls through. */ + case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]); + } +} + +// --------------------------------------------------------------------------- + +static SharedBuffer* gEmptyStringBuf = NULL; +static char* gEmptyString = NULL; + +extern int gDarwinCantLoadAllObjects; +int gDarwinIsReallyAnnoying; + +static inline char* getEmptyString() +{ + gEmptyStringBuf->acquire(); + return gEmptyString; +} + +void initialize_string8() +{ + // HACK: This dummy dependency forces linking libutils Static.cpp, + // which is needed to initialize String8/String16 classes. + // These variables are named for Darwin, but are needed elsewhere too, + // including static linking on any platform. + gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects; + + SharedBuffer* buf = SharedBuffer::alloc(1); + char* str = (char*)buf->data(); + *str = 0; + gEmptyStringBuf = buf; + gEmptyString = str; +} + +void terminate_string8() +{ + SharedBuffer::bufferFromData(gEmptyString)->release(); + gEmptyStringBuf = NULL; + gEmptyString = NULL; +} + +// --------------------------------------------------------------------------- + +static char* allocFromUTF8(const char* in, size_t len) +{ + if (len > 0) { + SharedBuffer* buf = SharedBuffer::alloc(len+1); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char* str = (char*)buf->data(); + memcpy(str, in, len); + str[len] = 0; + return str; + } + return NULL; + } + + return getEmptyString(); +} + +template +static char* allocFromUTF16OrUTF32(const T* in, L len) +{ + if (len == 0) return getEmptyString(); + + size_t bytes = 0; + const T* end = in+len; + const T* p = in; + + while (p < end) { + bytes += utf32_to_utf8_bytes(*p); + p++; + } + + SharedBuffer* buf = SharedBuffer::alloc(bytes+1); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + p = in; + char* str = (char*)buf->data(); + char* d = str; + while (p < end) { + const T c = *p++; + size_t len = utf32_to_utf8_bytes(c); + utf32_to_utf8((uint8_t*)d, c, len); + d += len; + } + *d = 0; + + return str; + } + + return getEmptyString(); +} + +static char* allocFromUTF16(const char16_t* in, size_t len) +{ + if (len == 0) return getEmptyString(); + + const size_t bytes = utf8_length_from_utf16(in, len); + + SharedBuffer* buf = SharedBuffer::alloc(bytes+1); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char* str = (char*)buf->data(); + + utf16_to_utf8(in, len, str, bytes+1); + + return str; + } + + return getEmptyString(); +} + +static char* allocFromUTF32(const char32_t* in, size_t len) +{ + return allocFromUTF16OrUTF32(in, len); +} + +// --------------------------------------------------------------------------- + +String8::String8() + : mString(getEmptyString()) +{ +} + +String8::String8(const String8& o) + : mString(o.mString) +{ + SharedBuffer::bufferFromData(mString)->acquire(); +} + +String8::String8(const char* o) + : mString(allocFromUTF8(o, strlen(o))) +{ + if (mString == NULL) { + mString = getEmptyString(); + } +} + +String8::String8(const char* o, size_t len) + : mString(allocFromUTF8(o, len)) +{ + if (mString == NULL) { + mString = getEmptyString(); + } +} + +String8::String8(const String16& o) + : mString(allocFromUTF16(o.string(), o.size())) +{ +} + +String8::String8(const char16_t* o) + : mString(allocFromUTF16(o, strlen16(o))) +{ +} + +String8::String8(const char16_t* o, size_t len) + : mString(allocFromUTF16(o, len)) +{ +} + +String8::String8(const char32_t* o) + : mString(allocFromUTF32(o, strlen32(o))) +{ +} + +String8::String8(const char32_t* o, size_t len) + : mString(allocFromUTF32(o, len)) +{ +} + +String8::~String8() +{ + SharedBuffer::bufferFromData(mString)->release(); +} + +void String8::setTo(const String8& other) +{ + SharedBuffer::bufferFromData(other.mString)->acquire(); + SharedBuffer::bufferFromData(mString)->release(); + mString = other.mString; +} + +status_t String8::setTo(const char* other) +{ + const char *newString = allocFromUTF8(other, strlen(other)); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char* other, size_t len) +{ + const char *newString = allocFromUTF8(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char16_t* other, size_t len) +{ + const char *newString = allocFromUTF16(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char32_t* other, size_t len) +{ + const char *newString = allocFromUTF32(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::append(const String8& other) +{ + const size_t otherLen = other.bytes(); + if (bytes() == 0) { + setTo(other); + return NO_ERROR; + } else if (otherLen == 0) { + return NO_ERROR; + } + + return real_append(other.string(), otherLen); +} + +status_t String8::append(const char* other) +{ + return append(other, strlen(other)); +} + +status_t String8::append(const char* other, size_t otherLen) +{ + if (bytes() == 0) { + return setTo(other, otherLen); + } else if (otherLen == 0) { + return NO_ERROR; + } + + return real_append(other, otherLen); +} + +status_t String8::appendFormat(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + int result = NO_ERROR; + int n = vsnprintf(NULL, 0, fmt, ap); + if (n != 0) { + size_t oldLength = length(); + char* buf = lockBuffer(oldLength + n); + if (buf) { + vsnprintf(buf + oldLength, n + 1, fmt, ap); + } else { + result = NO_MEMORY; + } + } + + va_end(ap); + return result; +} + +status_t String8::real_append(const char* other, size_t otherLen) +{ + const size_t myLen = bytes(); + + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(myLen+otherLen+1); + if (buf) { + char* str = (char*)buf->data(); + mString = str; + str += myLen; + memcpy(str, other, otherLen); + str[otherLen] = '\0'; + return NO_ERROR; + } + return NO_MEMORY; +} + +char* String8::lockBuffer(size_t size) +{ + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(size+1); + if (buf) { + char* str = (char*)buf->data(); + mString = str; + return str; + } + return NULL; +} + +void String8::unlockBuffer() +{ + unlockBuffer(strlen(mString)); +} + +status_t String8::unlockBuffer(size_t size) +{ + if (size != this->size()) { + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(size+1); + if (! buf) { + return NO_MEMORY; + } + + char* str = (char*)buf->data(); + str[size] = 0; + mString = str; + } + + return NO_ERROR; +} + +ssize_t String8::find(const char* other, size_t start) const +{ + size_t len = size(); + if (start >= len) { + return -1; + } + const char* s = mString+start; + const char* p = strstr(s, other); + return p ? p-mString : -1; +} + +void String8::toLower() +{ + toLower(0, size()); +} + +void String8::toLower(size_t start, size_t length) +{ + const size_t len = size(); + if (start >= len) { + return; + } + if (start+length > len) { + length = len-start; + } + char* buf = lockBuffer(len); + buf += start; + while (length > 0) { + *buf = tolower(*buf); + buf++; + length--; + } + unlockBuffer(len); +} + +void String8::toUpper() +{ + toUpper(0, size()); +} + +void String8::toUpper(size_t start, size_t length) +{ + const size_t len = size(); + if (start >= len) { + return; + } + if (start+length > len) { + length = len-start; + } + char* buf = lockBuffer(len); + buf += start; + while (length > 0) { + *buf = toupper(*buf); + buf++; + length--; + } + unlockBuffer(len); +} + +size_t String8::getUtf32Length() const +{ + return utf32_length(mString, length()); +} + +int32_t String8::getUtf32At(size_t index, size_t *next_index) const +{ + return utf32_at(mString, length(), index, next_index); +} + +size_t String8::getUtf32(char32_t* dst, size_t dst_len) const +{ + return utf8_to_utf32(mString, length(), dst, dst_len); +} + +TextOutput& operator<<(TextOutput& to, const String8& val) +{ + to << val.string(); + return to; +} + +// --------------------------------------------------------------------------- +// Path functions + +void String8::setPathName(const char* name) +{ + setPathName(name, strlen(name)); +} + +void String8::setPathName(const char* name, size_t len) +{ + char* buf = lockBuffer(len); + + memcpy(buf, name, len); + + // remove trailing path separator, if present + if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) + len--; + + buf[len] = '\0'; + + unlockBuffer(len); +} + +String8 String8::getPathLeaf(void) const +{ + const char* cp; + const char*const buf = mString; + + cp = strrchr(buf, OS_PATH_SEPARATOR); + if (cp == NULL) + return String8(*this); + else + return String8(cp+1); +} + +String8 String8::getPathDir(void) const +{ + const char* cp; + const char*const str = mString; + + cp = strrchr(str, OS_PATH_SEPARATOR); + if (cp == NULL) + return String8(""); + else + return String8(str, cp - str); +} + +String8 String8::walkPath(String8* outRemains) const +{ + const char* cp; + const char*const str = mString; + const char* buf = str; + + cp = strchr(buf, OS_PATH_SEPARATOR); + if (cp == buf) { + // don't include a leading '/'. + buf = buf+1; + cp = strchr(buf, OS_PATH_SEPARATOR); + } + + if (cp == NULL) { + String8 res = buf != str ? String8(buf) : *this; + if (outRemains) *outRemains = String8(""); + return res; + } + + String8 res(buf, cp-buf); + if (outRemains) *outRemains = String8(cp+1); + return res; +} + +/* + * Helper function for finding the start of an extension in a pathname. + * + * Returns a pointer inside mString, or NULL if no extension was found. + */ +char* String8::find_extension(void) const +{ + const char* lastSlash; + const char* lastDot; + int extLen; + const char* const str = mString; + + // only look at the filename + lastSlash = strrchr(str, OS_PATH_SEPARATOR); + if (lastSlash == NULL) + lastSlash = str; + else + lastSlash++; + + // find the last dot + lastDot = strrchr(lastSlash, '.'); + if (lastDot == NULL) + return NULL; + + // looks good, ship it + return const_cast(lastDot); +} + +String8 String8::getPathExtension(void) const +{ + char* ext; + + ext = find_extension(); + if (ext != NULL) + return String8(ext); + else + return String8(""); +} + +String8 String8::getBasePath(void) const +{ + char* ext; + const char* const str = mString; + + ext = find_extension(); + if (ext == NULL) + return String8(*this); + else + return String8(str, ext - str); +} + +String8& String8::appendPath(const char* name) +{ + // TODO: The test below will fail for Win32 paths. Fix later or ignore. + if (name[0] != OS_PATH_SEPARATOR) { + if (*name == '\0') { + // nothing to do + return *this; + } + + size_t len = length(); + if (len == 0) { + // no existing filename, just use the new one + setPathName(name); + return *this; + } + + // make room for oldPath + '/' + newPath + int newlen = strlen(name); + + char* buf = lockBuffer(len+1+newlen); + + // insert a '/' if needed + if (buf[len-1] != OS_PATH_SEPARATOR) + buf[len++] = OS_PATH_SEPARATOR; + + memcpy(buf+len, name, newlen+1); + len += newlen; + + unlockBuffer(len); + + return *this; + } else { + setPathName(name); + return *this; + } +} + +String8& String8::convertToResPath() +{ +#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR + size_t len = length(); + if (len > 0) { + char * buf = lockBuffer(len); + for (char * end = buf + len; buf < end; ++buf) { + if (*buf == OS_PATH_SEPARATOR) + *buf = RES_PATH_SEPARATOR; + } + unlockBuffer(len); + } +#endif + return *this; +} + +}; // namespace android + +// --------------------------------------------------------------------------- + +size_t strlen32(const char32_t *s) +{ + const char32_t *ss = s; + while ( *ss ) + ss++; + return ss-s; +} + +size_t strnlen32(const char32_t *s, size_t maxlen) +{ + const char32_t *ss = s; + while ((maxlen > 0) && *ss) { + ss++; + maxlen--; + } + return ss-s; +} + +size_t utf8_length(const char *src) +{ + const char *cur = src; + size_t ret = 0; + while (*cur != '\0') { + const char first_char = *cur++; + if ((first_char & 0x80) == 0) { // ASCII + ret += 1; + continue; + } + // (UTF-8's character must not be like 10xxxxxx, + // but 110xxxxx, 1110xxxx, ... or 1111110x) + if ((first_char & 0x40) == 0) { + return 0; + } + + int32_t mask, to_ignore_mask; + size_t num_to_read = 0; + char32_t utf32 = 0; + for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80; + num_to_read < 5 && (first_char & mask); + num_to_read++, to_ignore_mask |= mask, mask >>= 1) { + if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx + return 0; + } + // 0x3F == 00111111 + utf32 = (utf32 << 6) + (*cur++ & 0x3F); + } + // "first_char" must be (110xxxxx - 11110xxx) + if (num_to_read == 5) { + return 0; + } + to_ignore_mask |= mask; + utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1)); + if (utf32 > android::kUnicodeMaxCodepoint) { + return 0; + } + + ret += num_to_read; + } + return ret; +} + +size_t utf32_length(const char *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return 0; + } + size_t ret = 0; + const char* cur; + const char* end; + size_t num_to_skip; + for (cur = src, end = src + src_len, num_to_skip = 1; + cur < end; + cur += num_to_skip, ret++) { + const char first_char = *cur; + num_to_skip = 1; + if ((first_char & 0x80) == 0) { // ASCII + continue; + } + int32_t mask; + + for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) { + } + } + return ret; +} + +size_t utf8_length_from_utf32(const char32_t *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return 0; + } + size_t ret = 0; + const char32_t *end = src + src_len; + while (src < end) { + ret += android::utf32_to_utf8_bytes(*src++); + } + return ret; +} + +size_t utf8_length_from_utf16(const char16_t *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return 0; + } + size_t ret = 0; + const char16_t* const end = src + src_len; + while (src < end) { + if ((*src & 0xFC00) == 0xD800 && (src + 1) < end + && (*++src & 0xFC00) == 0xDC00) { + // surrogate pairs are always 4 bytes. + ret += 4; + src++; + } else { + ret += android::utf32_to_utf8_bytes((char32_t) *src++); + } + } + return ret; +} + +static int32_t utf32_at_internal(const char* cur, size_t *num_read) +{ + const char first_char = *cur; + if ((first_char & 0x80) == 0) { // ASCII + *num_read = 1; + return *cur; + } + cur++; + char32_t mask, to_ignore_mask; + size_t num_to_read = 0; + char32_t utf32 = first_char; + for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80; + (first_char & mask); + num_to_read++, to_ignore_mask |= mask, mask >>= 1) { + // 0x3F == 00111111 + utf32 = (utf32 << 6) + (*cur++ & 0x3F); + } + to_ignore_mask |= mask; + utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1))); + + *num_read = num_to_read; + return static_cast(utf32); +} + +int32_t utf32_at(const char *src, size_t src_len, + size_t index, size_t *next_index) +{ + if (index >= src_len) { + return -1; + } + size_t dummy_index; + if (next_index == NULL) { + next_index = &dummy_index; + } + size_t num_read; + int32_t ret = utf32_at_internal(src + index, &num_read); + if (ret >= 0) { + *next_index = index + num_read; + } + + return ret; +} + +size_t utf8_to_utf32(const char* src, size_t src_len, + char32_t* dst, size_t dst_len) +{ + if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) { + return 0; + } + + const char* cur = src; + const char* end = src + src_len; + char32_t* cur_utf32 = dst; + const char32_t* end_utf32 = dst + dst_len; + while (cur_utf32 < end_utf32 && cur < end) { + size_t num_read; + *cur_utf32++ = + static_cast(utf32_at_internal(cur, &num_read)); + cur += num_read; + } + if (cur_utf32 < end_utf32) { + *cur_utf32 = 0; + } + return static_cast(cur_utf32 - dst); +} + +size_t utf32_to_utf8(const char32_t* src, size_t src_len, + char* dst, size_t dst_len) +{ + if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) { + return 0; + } + const char32_t *cur_utf32 = src; + const char32_t *end_utf32 = src + src_len; + char *cur = dst; + const char *end = dst + dst_len; + while (cur_utf32 < end_utf32 && cur < end) { + size_t len = android::utf32_to_utf8_bytes(*cur_utf32); + android::utf32_to_utf8((uint8_t *)cur, *cur_utf32++, len); + cur += len; + } + if (cur < end) { + *cur = '\0'; + } + return cur - dst; +} + +size_t utf16_to_utf8(const char16_t* src, size_t src_len, + char* dst, size_t dst_len) +{ + if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) { + return 0; + } + const char16_t* cur_utf16 = src; + const char16_t* const end_utf16 = src + src_len; + char *cur = dst; + const char* const end = dst + dst_len; + while (cur_utf16 < end_utf16 && cur < end) { + char32_t utf32; + // surrogate pairs + if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) { + utf32 = (*cur_utf16++ - 0xD800) << 10; + utf32 |= *cur_utf16++ - 0xDC00; + utf32 += 0x10000; + } else { + utf32 = (char32_t) *cur_utf16++; + } + size_t len = android::utf32_to_utf8_bytes(utf32); + android::utf32_to_utf8((uint8_t*)cur, utf32, len); + cur += len; + } + if (cur < end) { + *cur = '\0'; + } + return cur - dst; +} diff --git a/external/android-libs/libicudata.so b/external/android-libs/libicudata.so deleted file mode 100644 index 17b94034..00000000 Binary files a/external/android-libs/libicudata.so and /dev/null differ diff --git a/external/android-libs/libicui18n.so b/external/android-libs/libicui18n.so deleted file mode 100644 index fab86384..00000000 Binary files a/external/android-libs/libicui18n.so and /dev/null differ diff --git a/external/android-libs/libicuuc.so b/external/android-libs/libicuuc.so deleted file mode 100644 index 71251412..00000000 Binary files a/external/android-libs/libicuuc.so and /dev/null differ diff --git a/external/android-libs/libssl.so b/external/android-libs/libssl.so deleted file mode 100644 index ad627d68..00000000 Binary files a/external/android-libs/libssl.so and /dev/null differ diff --git a/external/icu4c b/external/icu4c index fa7b84a2..0fa67b93 160000 --- a/external/icu4c +++ b/external/icu4c @@ -1 +1 @@ -Subproject commit fa7b84a26dd6c44cb0d219ef7b2f7e258219b616 +Subproject commit 0fa67b93b831c6636ca18b152a1b1b14cc99b034 diff --git a/jni/include/utils/String16.h b/external/includes/utils/String16.h similarity index 100% rename from jni/include/utils/String16.h rename to external/includes/utils/String16.h diff --git a/external/includes/utils/String8.h b/external/includes/utils/String8.h new file mode 100644 index 00000000..ef0b51a4 --- /dev/null +++ b/external/includes/utils/String8.h @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_STRING8_H +#define ANDROID_STRING8_H + +#include + +// Need this for the char16_t type; String8.h should not +// be depedent on the String16 class. +#include + +#include +#include +#include + +// --------------------------------------------------------------------------- + +extern "C" { + +typedef uint32_t char32_t; + +size_t strlen32(const char32_t *); +size_t strnlen32(const char32_t *, size_t); + +/* + * Returns the length of "src" when "src" is valid UTF-8 string. + * Returns 0 if src is NULL, 0-length string or non UTF-8 string. + * This function should be used to determine whether "src" is valid UTF-8 + * characters with valid unicode codepoints. "src" must be null-terminated. + * + * If you are going to use other GetUtf... functions defined in this header + * with string which may not be valid UTF-8 with valid codepoint (form 0 to + * 0x10FFFF), you should use this function before calling others, since the + * other functions do not check whether the string is valid UTF-8 or not. + * + * If you do not care whether "src" is valid UTF-8 or not, you should use + * strlen() as usual, which should be much faster. + */ +size_t utf8_length(const char *src); + +/* + * Returns the UTF-32 length of "src". + */ +size_t utf32_length(const char *src, size_t src_len); + +/* + * Returns the UTF-8 length of "src". + */ +size_t utf8_length_from_utf16(const char16_t *src, size_t src_len); + +/* + * Returns the UTF-8 length of "src". + */ +size_t utf8_length_from_utf32(const char32_t *src, size_t src_len); + +/* + * Returns the unicode value at "index". + * Returns -1 when the index is invalid (equals to or more than "src_len"). + * If returned value is positive, it is able to be converted to char32_t, which + * is unsigned. Then, if "next_index" is not NULL, the next index to be used is + * stored in "next_index". "next_index" can be NULL. + */ +int32_t utf32_at(const char *src, size_t src_len, + size_t index, size_t *next_index); + +/* + * Stores a UTF-32 string converted from "src" in "dst", if "dst_length" is not + * large enough to store the string, the part of the "src" string is stored + * into "dst". + * Returns the size actually used for storing the string. + * "dst" is not null-terminated when dst_len is fully used (like strncpy). + */ +size_t utf8_to_utf32(const char* src, size_t src_len, + char32_t* dst, size_t dst_len); + +/* + * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not + * large enough to store the string, the part of the "src" string is stored + * into "dst" as much as possible. See the examples for more detail. + * Returns the size actually used for storing the string. + * dst" is not null-terminated when dst_len is fully used (like strncpy). + * + * Example 1 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" >= 7 + * -> + * Returned value == 6 + * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0 + * (note that "dst" is null-terminated) + * + * Example 2 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" == 5 + * -> + * Returned value == 3 + * "dst" becomes \xE3\x81\x82\0 + * (note that "dst" is null-terminated, but \u3044 is not stored in "dst" + * since "dst" does not have enough size to store the character) + * + * Example 3 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" == 6 + * -> + * Returned value == 6 + * "dst" becomes \xE3\x81\x82\xE3\x81\x84 + * (note that "dst" is NOT null-terminated, like strncpy) + */ +size_t utf32_to_utf8(const char32_t* src, size_t src_len, + char* dst, size_t dst_len); + +size_t utf16_to_utf8(const char16_t* src, size_t src_len, + char* dst, size_t dst_len); + +} + +// --------------------------------------------------------------------------- + +namespace android { + +class TextOutput; + +//! This is a string holding UTF-8 characters. Does not allow the value more +// than 0x10FFFF, which is not valid unicode codepoint. +class String8 +{ +public: + String8(); + String8(const String8& o); + explicit String8(const char* o); + explicit String8(const char* o, size_t numChars); + + explicit String8(const String16& o); + explicit String8(const char16_t* o); + explicit String8(const char16_t* o, size_t numChars); + explicit String8(const char32_t* o); + explicit String8(const char32_t* o, size_t numChars); + ~String8(); + + inline const char* string() const; + inline size_t size() const; + inline size_t length() const; + inline size_t bytes() const; + + inline const SharedBuffer* sharedBuffer() const; + + void setTo(const String8& other); + status_t setTo(const char* other); + status_t setTo(const char* other, size_t numChars); + status_t setTo(const char16_t* other, size_t numChars); + status_t setTo(const char32_t* other, + size_t length); + + status_t append(const String8& other); + status_t append(const char* other); + status_t append(const char* other, size_t numChars); + + status_t appendFormat(const char* fmt, ...) + __attribute__((format (printf, 2, 3))); + + // Note that this function takes O(N) time to calculate the value. + // No cache value is stored. + size_t getUtf32Length() const; + int32_t getUtf32At(size_t index, + size_t *next_index) const; + size_t getUtf32(char32_t* dst, size_t dst_len) const; + + inline String8& operator=(const String8& other); + inline String8& operator=(const char* other); + + inline String8& operator+=(const String8& other); + inline String8 operator+(const String8& other) const; + + inline String8& operator+=(const char* other); + inline String8 operator+(const char* other) const; + + inline int compare(const String8& other) const; + + inline bool operator<(const String8& other) const; + inline bool operator<=(const String8& other) const; + inline bool operator==(const String8& other) const; + inline bool operator!=(const String8& other) const; + inline bool operator>=(const String8& other) const; + inline bool operator>(const String8& other) const; + + inline bool operator<(const char* other) const; + inline bool operator<=(const char* other) const; + inline bool operator==(const char* other) const; + inline bool operator!=(const char* other) const; + inline bool operator>=(const char* other) const; + inline bool operator>(const char* other) const; + + inline operator const char*() const; + + char* lockBuffer(size_t size); + void unlockBuffer(); + status_t unlockBuffer(size_t size); + + // return the index of the first byte of other in this at or after + // start, or -1 if not found + ssize_t find(const char* other, size_t start = 0) const; + + void toLower(); + void toLower(size_t start, size_t numChars); + void toUpper(); + void toUpper(size_t start, size_t numChars); + + /* + * These methods operate on the string as if it were a path name. + */ + + /* + * Set the filename field to a specific value. + * + * Normalizes the filename, removing a trailing '/' if present. + */ + void setPathName(const char* name); + void setPathName(const char* name, size_t numChars); + + /* + * Get just the filename component. + * + * "/tmp/foo/bar.c" --> "bar.c" + */ + String8 getPathLeaf(void) const; + + /* + * Remove the last (file name) component, leaving just the directory + * name. + * + * "/tmp/foo/bar.c" --> "/tmp/foo" + * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX + * "bar.c" --> "" + */ + String8 getPathDir(void) const; + + /* + * Retrieve the front (root dir) component. Optionally also return the + * remaining components. + * + * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") + * "/tmp" --> "tmp" (remain = "") + * "bar.c" --> "bar.c" (remain = "") + */ + String8 walkPath(String8* outRemains = NULL) const; + + /* + * Return the filename extension. This is the last '.' and up to + * four characters that follow it. The '.' is included in case we + * decide to expand our definition of what constitutes an extension. + * + * "/tmp/foo/bar.c" --> ".c" + * "/tmp" --> "" + * "/tmp/foo.bar/baz" --> "" + * "foo.jpeg" --> ".jpeg" + * "foo." --> "" + */ + String8 getPathExtension(void) const; + + /* + * Return the path without the extension. Rules for what constitutes + * an extension are described in the comment for getPathExtension(). + * + * "/tmp/foo/bar.c" --> "/tmp/foo/bar" + */ + String8 getBasePath(void) const; + + /* + * Add a component to the pathname. We guarantee that there is + * exactly one path separator between the old path and the new. + * If there is no existing name, we just copy the new name in. + * + * If leaf is a fully qualified path (i.e. starts with '/', it + * replaces whatever was there before. + */ + String8& appendPath(const char* leaf); + String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); } + + /* + * Like appendPath(), but does not affect this string. Returns a new one instead. + */ + String8 appendPathCopy(const char* leaf) const + { String8 p(*this); p.appendPath(leaf); return p; } + String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); } + + /* + * Converts all separators in this string to /, the default path separator. + * + * If the default OS separator is backslash, this converts all + * backslashes to slashes, in-place. Otherwise it does nothing. + * Returns self. + */ + String8& convertToResPath(); + +private: + status_t real_append(const char* other, size_t numChars); + char* find_extension(void) const; + + const char* mString; +}; + +TextOutput& operator<<(TextOutput& to, const String16& val); + +// --------------------------------------------------------------------------- +// No user servicable parts below. + +inline int compare_type(const String8& lhs, const String8& rhs) +{ + return lhs.compare(rhs); +} + +inline int strictly_order_type(const String8& lhs, const String8& rhs) +{ + return compare_type(lhs, rhs) < 0; +} + +inline const char* String8::string() const +{ + return mString; +} + +inline size_t String8::length() const +{ + return SharedBuffer::sizeFromData(mString)-1; +} + +inline size_t String8::size() const +{ + return length(); +} + +inline size_t String8::bytes() const +{ + return SharedBuffer::sizeFromData(mString)-1; +} + +inline const SharedBuffer* String8::sharedBuffer() const +{ + return SharedBuffer::bufferFromData(mString); +} + +inline String8& String8::operator=(const String8& other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator=(const char* other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator+=(const String8& other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const String8& other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline String8& String8::operator+=(const char* other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const char* other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline int String8::compare(const String8& other) const +{ + return strcmp(mString, other.mString); +} + +inline bool String8::operator<(const String8& other) const +{ + return strcmp(mString, other.mString) < 0; +} + +inline bool String8::operator<=(const String8& other) const +{ + return strcmp(mString, other.mString) <= 0; +} + +inline bool String8::operator==(const String8& other) const +{ + return strcmp(mString, other.mString) == 0; +} + +inline bool String8::operator!=(const String8& other) const +{ + return strcmp(mString, other.mString) != 0; +} + +inline bool String8::operator>=(const String8& other) const +{ + return strcmp(mString, other.mString) >= 0; +} + +inline bool String8::operator>(const String8& other) const +{ + return strcmp(mString, other.mString) > 0; +} + +inline bool String8::operator<(const char* other) const +{ + return strcmp(mString, other) < 0; +} + +inline bool String8::operator<=(const char* other) const +{ + return strcmp(mString, other) <= 0; +} + +inline bool String8::operator==(const char* other) const +{ + return strcmp(mString, other) == 0; +} + +inline bool String8::operator!=(const char* other) const +{ + return strcmp(mString, other) != 0; +} + +inline bool String8::operator>=(const char* other) const +{ + return strcmp(mString, other) >= 0; +} + +inline bool String8::operator>(const char* other) const +{ + return strcmp(mString, other) > 0; +} + +inline String8::operator const char*() const +{ + return mString; +} + +} // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_STRING8_H diff --git a/external/platform-frameworks-base b/external/platform-frameworks-base index 93552de8..94180377 160000 --- a/external/platform-frameworks-base +++ b/external/platform-frameworks-base @@ -1 +1 @@ -Subproject commit 93552de8e305027fb003401e347b9493c64c981f +Subproject commit 94180377e709ed0faff6ea94c75af0f0a1183b36 diff --git a/external/platform-system-core b/external/platform-system-core index 034117e4..31b2f441 160000 --- a/external/platform-system-core +++ b/external/platform-system-core @@ -1 +1 @@ -Subproject commit 034117e47f2601d46563461a0bfe3cc22f89a0f0 +Subproject commit 31b2f4414b291d87adddf13ad62d317d3ba382fa diff --git a/jni/info_guardianproject_database_CursorWindow.cpp b/jni/info_guardianproject_database_CursorWindow.cpp index c87c896c..779d3959 100644 --- a/jni/info_guardianproject_database_CursorWindow.cpp +++ b/jni/info_guardianproject_database_CursorWindow.cpp @@ -22,8 +22,6 @@ #include #include -#include -#include #include #include diff --git a/jni/info_guardianproject_database_sqlcipher_SQLiteDatabase.cpp b/jni/info_guardianproject_database_sqlcipher_SQLiteDatabase.cpp index 3f6bcd8d..4f849eed 100644 --- a/jni/info_guardianproject_database_sqlcipher_SQLiteDatabase.cpp +++ b/jni/info_guardianproject_database_sqlcipher_SQLiteDatabase.cpp @@ -18,8 +18,6 @@ #define LOG_TAG "Database" #include -#include -#include #include #include diff --git a/project.properties b/project.properties new file mode 100644 index 00000000..5a709453 --- /dev/null +++ b/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/src/info/guardianproject/database/sqlcipher/SQLiteDatabase.java b/src/info/guardianproject/database/sqlcipher/SQLiteDatabase.java index 946fc1a9..98ddc2ef 100644 --- a/src/info/guardianproject/database/sqlcipher/SQLiteDatabase.java +++ b/src/info/guardianproject/database/sqlcipher/SQLiteDatabase.java @@ -78,9 +78,9 @@ private static void loadICUData(Context context) { File applicationFilesDirectory = context.getFilesDir(); File icuDir = new File(applicationFilesDirectory, "icu"); if(!icuDir.exists()) icuDir.mkdirs(); - File icuDataFile = new File(icuDir, "icudt44l.dat"); + File icuDataFile = new File(icuDir, "icudt46l.dat"); if(!icuDataFile.exists()) { - ZipInputStream in = new ZipInputStream(context.getAssets().open("icudt44l.zip")); + ZipInputStream in = new ZipInputStream(context.getAssets().open("icudt46l.zip")); in.getNextEntry(); OutputStream out = new FileOutputStream(icuDataFile); @@ -104,12 +104,13 @@ public static void loadLibs (Context context) System.loadLibrary("stlport_shared"); System.loadLibrary("sqlcipher_android"); System.loadLibrary("database_sqlcipher"); - + + boolean systemICUFileExists = new File("/system/usr/icu/icudt46l.dat").exists(); File applicationFilesDirectory = context.getFilesDir(); - String icuRootPath = android.os.Build.VERSION.SDK_INT < 9 ? applicationFilesDirectory.getAbsolutePath() - : "/system/usr"; + String icuRootPath = systemICUFileExists ? "/system/usr" : applicationFilesDirectory.getAbsolutePath(); setICURoot(icuRootPath); - if(android.os.Build.VERSION.SDK_INT < 9){ + + if(!systemICUFileExists){ loadICUData(context); } } @@ -917,6 +918,7 @@ public static SQLiteDatabase create(CursorFactory factory, String password) { * Close the database. */ public void close() { + if (!isOpen()) { return; // already closed }