diff options
-rwxr-xr-x | build-mac/mailcore2.xcodeproj/project.pbxproj | 34 | ||||
-rw-r--r-- | src/core/basetypes/MCData.cc | 80 | ||||
-rw-r--r-- | src/core/basetypes/MCString.cc | 152 | ||||
-rw-r--r-- | unittest/unittest.mm | 9 |
4 files changed, 240 insertions, 35 deletions
diff --git a/build-mac/mailcore2.xcodeproj/project.pbxproj b/build-mac/mailcore2.xcodeproj/project.pbxproj index f3a2e701..8005804b 100755 --- a/build-mac/mailcore2.xcodeproj/project.pbxproj +++ b/build-mac/mailcore2.xcodeproj/project.pbxproj @@ -4558,15 +4558,11 @@ OTHER_LDFLAGS = ( "-lctemplate-ios", "-letpan-ios", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lsasl2", "-liconv", "-ltidy", "-lz", - "-licucore", "-ObjC", ); PRODUCT_NAME = "MailCore-ios"; @@ -4588,15 +4584,11 @@ OTHER_LDFLAGS = ( "-lctemplate-ios", "-letpan-ios", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lsasl2", "-liconv", "-ltidy", "-lz", - "-licucore", "-ObjC", ); PRODUCT_NAME = "MailCore-ios"; @@ -4652,8 +4644,8 @@ "LIBRARY_SEARCH_PATHS[sdk=macosx*]" = "$(OSX_LIBRARY_SEARCH_PATHS)"; MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; - OSX_HEADERS_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/include\" \"$(SRCROOT)/../Externals/icu4c/include\" \"$(SRCROOT)/../Externals/ctemplate/include\" /usr/include/tidy /usr/include/libxml2"; - OSX_LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/lib\" \"$(SRCROOT)/../Externals/icu4c/lib\" \"$(SRCROOT)/../Externals/ctemplate/lib\""; + OSX_HEADERS_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/include\" \"$(SRCROOT)/../Externals/icu4c/include\" \"$(SRCROOT)/../Externals/ctemplate/include\" \"$(SRCROOT)/../Externals/uchardet/include\" /usr/include/tidy /usr/include/libxml2"; + OSX_LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/lib\" \"$(SRCROOT)/../Externals/icu4c/lib\" \"$(SRCROOT)/../Externals/uchardet/lib\" \"$(SRCROOT)/../Externals/ctemplate/lib\""; }; name = Debug; }; @@ -4699,8 +4691,8 @@ "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(IOS_LIBRARY_SEARCH_PATHS)"; "LIBRARY_SEARCH_PATHS[sdk=macosx*]" = "$(OSX_LIBRARY_SEARCH_PATHS)"; MACOSX_DEPLOYMENT_TARGET = 10.8; - OSX_HEADERS_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/include\" \"$(SRCROOT)/../Externals/icu4c/include\" \"$(SRCROOT)/../Externals/ctemplate/include\" /usr/include/tidy /usr/include/libxml2"; - OSX_LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/lib\" \"$(SRCROOT)/../Externals/icu4c/lib\" \"$(SRCROOT)/../Externals/ctemplate/lib\""; + OSX_HEADERS_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/include\" \"$(SRCROOT)/../Externals/icu4c/include\" \"$(SRCROOT)/../Externals/ctemplate/include\" \"$(SRCROOT)/../Externals/uchardet/include\" /usr/include/tidy /usr/include/libxml2"; + OSX_LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../Externals/libetpan/lib\" \"$(SRCROOT)/../Externals/icu4c/lib\" \"$(SRCROOT)/../Externals/uchardet/lib\" \"$(SRCROOT)/../Externals/ctemplate/lib\""; }; name = Release; }; @@ -4756,16 +4748,12 @@ OTHER_LDFLAGS = ( "-lctemplate-ios", "-letpan-ios", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lsasl2", "-liconv", "-all_load", "-ltidy", "-lz", - "-licucore", ); PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -4791,16 +4779,12 @@ OTHER_LDFLAGS = ( "-lctemplate-ios", "-letpan-ios", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lsasl2", "-liconv", "-all_load", "-ltidy", "-lz", - "-licucore", ); PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -4913,9 +4897,6 @@ OTHER_LDFLAGS = ( "-lctemplate", "-letpan", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lssl", "-lcrypto", @@ -4924,7 +4905,7 @@ "-all_load", "-ltidy", "-lz", - "-licucore", + "-luchardet", ); PRODUCT_NAME = MailCore; SDKROOT = macosx; @@ -4944,9 +4925,6 @@ OTHER_LDFLAGS = ( "-lctemplate", "-letpan", - "-licudata", - "-licui18n", - "-licuuc", "-lxml2", "-lssl", "-lcrypto", @@ -4955,7 +4933,7 @@ "-all_load", "-ltidy", "-lz", - "-licucore", + "-luchardet", ); PRODUCT_NAME = MailCore; SDKROOT = macosx; diff --git a/src/core/basetypes/MCData.cc b/src/core/basetypes/MCData.cc index d7d4e7a6..9845d77a 100644 --- a/src/core/basetypes/MCData.cc +++ b/src/core/basetypes/MCData.cc @@ -1,9 +1,15 @@ #include "MCData.h" +#define USE_UCHARDET 1 + #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#if USE_UCHARDET +#include <uchardet/uchardet.h> +#else #include <unicode/ucsdet.h> +#endif #include <libetpan/libetpan.h> #include <iconv.h> #if __APPLE__ @@ -202,6 +208,7 @@ static bool isHintCharsetValid(String * hintCharset) if (knownCharset == NULL) { knownCharset = new Set(); +#if !USE_UCHARDET UCharsetDetector * detector; UEnumeration * iterator; UErrorCode err = U_ZERO_ERROR; @@ -218,6 +225,41 @@ static bool isHintCharsetValid(String * hintCharset) } uenum_close(iterator); ucsdet_close(detector); +#else + const char * charset_list[] = { + "Big5", + "EUC-JP", + "EUC-KR", + "x-euc-tw", + "gb18030", + "ISO-8859-8", + "windows-1255", + "windows-1252", + "Shift_JIS", + "UTF-8", + "UTF-16", + "HZ-GB-2312", + "ISO-2022-CN", + "ISO-2022-JP", + "ISO-2022-KR", + "ISO-8859-5" + "windows-1251" + "KOI8-R" + "x-mac-cyrillic" + "IBM866" + "IBM855" + "ISO-8859-7" + "windows-1253" + "ISO-8859-2" + "windows-1250" + "TIS-620" + }; + for(unsigned int i = 0 ; i < sizeof(charset_list) / sizeof(charset_list[0]) ; i ++) { + String * str = String::stringWithUTF8Characters(charset_list[i]); + str = str->lowercaseString(); + knownCharset->addObject(str); + } +#endif } pthread_mutex_unlock(&lock); @@ -322,6 +364,7 @@ String * Data::stringWithDetectedCharset(String * hintCharset, bool isHTML) String * Data::charsetWithFilteredHTMLWithoutHint(bool filterHTML) { +#if !USE_UCHARDET UCharsetDetector * detector; const UCharsetMatch * match; UErrorCode err = U_ZERO_ERROR; @@ -343,6 +386,21 @@ String * Data::charsetWithFilteredHTMLWithoutHint(bool filterHTML) ucsdet_close(detector); return result; +#else + String * result = NULL; + uchardet_t ud = uchardet_new(); + int r = uchardet_handle_data(ud, bytes(), length()); + if (r == 0) { + uchardet_data_end(ud); + const char * charset = uchardet_get_charset(ud); + if (charset[0] != 0) { + result = String::stringWithUTF8Characters(charset); + } + } + uchardet_delete(ud); + + return result; +#endif } String * Data::charsetWithFilteredHTML(bool filterHTML, String * hintCharset) @@ -350,6 +408,7 @@ String * Data::charsetWithFilteredHTML(bool filterHTML, String * hintCharset) if (hintCharset == NULL) return charsetWithFilteredHTMLWithoutHint(filterHTML); +#if !USE_UCHARDET const UCharsetMatch ** matches; int32_t matchesCount; UCharsetDetector * detector; @@ -413,6 +472,27 @@ String * Data::charsetWithFilteredHTML(bool filterHTML, String * hintCharset) result = hintCharset; return result; +#else + String * result; + uchardet_t ud = uchardet_new(); + int r = uchardet_handle_data(ud, bytes(), length()); + if (r == 0) { + uchardet_data_end(ud); + const char * charset = uchardet_get_charset(ud); + if (charset[0] == 0) { + result = hintCharset; + } + else { + result = String::stringWithUTF8Characters(charset); + } + } + else { + result = hintCharset; + } + uchardet_delete(ud); + + return result; +#endif } void Data::takeBytesOwnership(char * bytes, unsigned int length) diff --git a/src/core/basetypes/MCString.cc b/src/core/basetypes/MCString.cc index dbf43943..88c61a99 100644 --- a/src/core/basetypes/MCString.cc +++ b/src/core/basetypes/MCString.cc @@ -1,10 +1,14 @@ #include "MCString.h" +#define DISABLE_ICU 1 + #include <string.h> #include <stdlib.h> +#if !DISABLE_ICU #include <unicode/ustring.h> #include <unicode/ucnv.h> #include <unicode/utypes.h> +#endif #include <uuid/uuid.h> #include <pthread.h> #include <libetpan/libetpan.h> @@ -30,9 +34,68 @@ using namespace mailcore; +#if DISABLE_ICU +static int32_t u_strlen(const UChar *s) { + if (s == NULL) { + return 0; + } + const UChar * p = s; + while (* p != 0) { + p ++; + } + return (int32_t) (p - s); +} + +static UChar * u_memcpy(UChar * dest, const UChar * src, int32_t count) { + memcpy(dest, src, count * sizeof(* src)); + return dest; +} + +static UChar * u_strstr(const UChar * s, const UChar * substring) +{ + if (s == NULL) { + return NULL; + } + CFStringRef cfS = CFStringCreateWithCharactersNoCopy(NULL, (const UniChar *) s, u_strlen(s), kCFAllocatorNull); + CFStringRef cfSubstring = CFStringCreateWithCharactersNoCopy(NULL, (const UniChar *) substring, u_strlen(substring), kCFAllocatorNull); + + CFRange range = CFStringFind(cfS, cfSubstring, 0); + CFRelease(cfSubstring); + CFRelease(cfS); + if (range.length == 0) { + return NULL; + } + return (UChar *) (s + range.location); +} + +static UChar * u_strrstr(const UChar * s, const UChar * substring) +{ + if (s == NULL) { + return NULL; + } + CFStringRef cfS = CFStringCreateWithCharactersNoCopy(NULL, (const UniChar *) s, u_strlen(s), kCFAllocatorNull); + CFStringRef cfSubstring = CFStringCreateWithCharactersNoCopy(NULL, (const UniChar *) substring, u_strlen(substring), kCFAllocatorNull); + + CFRange range = CFStringFind(cfS, cfSubstring, kCFCompareBackwards); + CFRelease(cfSubstring); + CFRelease(cfS); + if (range.length == 0) { + return NULL; + } + return (UChar *) (s + range.location); +} + +static int32_t u_memcmp(const UChar * buf1, const UChar * buf2, int32_t count) +{ + return memcmp(buf1, buf2, count * sizeof(* buf1)); +} +#endif + void mailcore::setICUDataDirectory(String * directory) { +#if !DISABLE_ICU u_setDataDirectory(directory->fileSystemRepresentation()); +#endif } #pragma mark quote headers string @@ -833,7 +896,11 @@ void String::appendCharactersLength(const UChar * unicodeCharacters, unsigned in return; } allocate(mLength + length); +#if DISABLE_ICU + memcpy(&mUnicodeChars[mLength], unicodeCharacters, length * sizeof(* mUnicodeChars)); +#else u_strncpy(&mUnicodeChars[mLength], unicodeCharacters, length); +#endif mLength += length; mUnicodeChars[mLength] = 0; } @@ -862,7 +929,16 @@ void String::appendUTF8CharactersLength(const char * UTF8Characters, unsigned in if (UTF8Characters == NULL) { return; } - + +#if DISABLE_ICU + CFStringRef cfStr = CFStringCreateWithBytes(NULL, (const UInt8 *) UTF8Characters, length, + kCFStringEncodingUTF8, false); + UniChar * characters = (UniChar *) malloc(sizeof(* characters) * CFStringGetLength(cfStr)); + CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), characters); + appendCharactersLength(characters, (unsigned int) CFStringGetLength(cfStr)); + free(characters); + CFRelease(cfStr); +#else UChar * dest; int32_t destLength; int32_t destCapacity; @@ -885,6 +961,7 @@ void String::appendUTF8CharactersLength(const char * UTF8Characters, unsigned in appendCharactersLength(dest, destLength); free(dest); +#endif } void String::appendUTF8Characters(const char * UTF8Characters) @@ -907,6 +984,17 @@ const UChar * String::unicodeCharacters() const char * String::UTF8Characters() { +#if DISABLE_ICU + CFStringRef cfStr = CFStringCreateWithCharactersNoCopy(NULL, mUnicodeChars, mLength, kCFAllocatorNull); + char * buffer = (char *) malloc(mLength * 6 + 1); + CFIndex usedBufLen; + CFStringGetBytes(cfStr, CFRangeMake(0, mLength), kCFStringEncodingUTF8, '?', false, (UInt8 *) buffer, mLength * 6, &usedBufLen); + buffer[usedBufLen] = 0; + Data * data = Data::dataWithBytes(buffer, (unsigned int) usedBufLen + 1); + free(buffer); + + return data->bytes(); +#else char * dest; int32_t destLength; int32_t destCapacity; @@ -924,6 +1012,7 @@ const char * String::UTF8Characters() free(dest); return data->bytes(); +#endif } unsigned int String::length() @@ -1111,12 +1200,21 @@ int String::compareWithCaseSensitive(String * otherString, bool caseSensitive) return -1; } +#if DISABLE_ICU + CFStringRef cfThis = CFStringCreateWithCharactersNoCopy(NULL, mUnicodeChars, mLength, kCFAllocatorNull); + CFStringRef cfOther = CFStringCreateWithCharactersNoCopy(NULL, otherString->mUnicodeChars, otherString->mLength, kCFAllocatorNull); + CFComparisonResult result = CFStringCompare(cfThis, cfOther, caseSensitive ? 0 : kCFCompareCaseInsensitive); + CFRelease(cfThis); + CFRelease(cfOther); + return result; +#else if (caseSensitive) { return u_strcmp(unicodeCharacters(), otherString->unicodeCharacters()); } else { return u_strcasecmp(unicodeCharacters(), otherString->unicodeCharacters(), 0); } +#endif } int String::compare(String * otherString) @@ -1129,8 +1227,20 @@ int String::caseInsensitiveCompare(String * otherString) return compareWithCaseSensitive(otherString, false); } +//Any-Lower, Any-Upper String * String::lowercaseString() { +#if DISABLE_ICU + CFMutableStringRef cfStr = CFStringCreateMutable(NULL, 0); + CFStringAppendCharacters(cfStr, (const UniChar *) mUnicodeChars, mLength); + CFStringLowercase(cfStr, NULL); + UniChar * characters = (UniChar *) malloc(sizeof(* characters) * mLength); + CFStringGetCharacters(cfStr, CFRangeMake(0, mLength), characters); + String * result = String::stringWithCharacters(characters, mLength); + free(characters); + CFRelease(cfStr); + return result; +#else UErrorCode err; String * result = (String *) copy()->autorelease(); err = U_ZERO_ERROR; @@ -1138,10 +1248,22 @@ String * String::lowercaseString() result->mUnicodeChars, result->mLength, NULL, &err); return result; +#endif } String * String::uppercaseString() { +#if DISABLE_ICU + CFMutableStringRef cfStr = CFStringCreateMutable(NULL, 0); + CFStringAppendCharacters(cfStr, (const UniChar *) mUnicodeChars, mLength); + CFStringUppercase(cfStr, NULL); + UniChar * characters = (UniChar *) malloc(sizeof(* characters) * mLength); + CFStringGetCharacters(cfStr, CFRangeMake(0, mLength), characters); + String * result = String::stringWithCharacters(characters, mLength); + free(characters); + CFRelease(cfStr); + return result; +#else UErrorCode err; String * result = (String *) copy()->autorelease(); err = U_ZERO_ERROR; @@ -1149,6 +1271,7 @@ String * String::uppercaseString() result->mUnicodeChars, result->mLength, NULL, &err); return result; +#endif } void String::appendBytes(const char * bytes, unsigned int length, const char * charset) @@ -1291,7 +1414,14 @@ unsigned int String::replaceOccurrencesOfString(String * occurrence, String * re } // copy remaining if(p) { - u_strcpy(dest_p, p); +#if DISABLE_ICU + unsigned int remainingLength = mLength - (unsigned int) (p - mUnicodeChars); + memcpy(dest_p, p, remainingLength * sizeof(* p)); + dest_p += remainingLength; + * dest_p = 0; +#else + u_strcpy(dest_p, p); +#endif } free(mUnicodeChars); @@ -1319,7 +1449,11 @@ void String::deleteCharactersInRange(Range range) } int32_t count = mLength - (int32_t) (range.location + range.length); +#if DISABLE_ICU + memmove(&mUnicodeChars[range.location], &mUnicodeChars[range.location + range.length], count * sizeof(* mUnicodeChars)); +#else u_memmove(&mUnicodeChars[range.location], &mUnicodeChars[range.location + range.length], count); +#endif mLength -= range.length; mUnicodeChars[mLength] = 0; } @@ -1882,7 +2016,14 @@ String * String::lastPathComponent() // TODO: Improve Windows compatibility. if (mUnicodeChars == NULL) return MCSTR(""); +#if DISABLE_ICU + UChar slash[2]; + slash[0] = '/'; + slash[1] = 0; + UChar * component = u_strrstr(mUnicodeChars, slash); +#else UChar * component = u_strrchr(mUnicodeChars, '/'); +#endif if (component == NULL) return (String *) this->copy()->autorelease(); return String::stringWithCharacters(component + 1); @@ -1890,7 +2031,14 @@ String * String::lastPathComponent() String * String::pathExtension() { +#if DISABLE_ICU + UChar point[2]; + point[0] = '.'; + point[1] = 0; + UChar * component = u_strrstr(mUnicodeChars, point); +#else UChar * component = u_strrchr(mUnicodeChars, '.'); +#endif if (component == NULL) return MCSTR(""); return String::stringWithCharacters(component + 1); diff --git a/unittest/unittest.mm b/unittest/unittest.mm index 44e367d1..ee543766 100644 --- a/unittest/unittest.mm +++ b/unittest/unittest.mm @@ -104,8 +104,6 @@ } - (void)testMessageBuilder1 { - // This is an example of a functional test case. - //XCTAssert(YES, @"Pass"); MCOMessageBuilder * builder = [[MCOMessageBuilder alloc] init]; [[builder header] setFrom:[MCOAddress addressWithRFC822String:@"HoĆ <dinh.viet.hoa@gmail.com>"]]; [[builder header] setTo:@[[MCOAddress addressWithRFC822String:@"Foo Bar <dinh.viet.hoa@gmail.com>"]]]; @@ -117,7 +115,8 @@ NSData * expectedData = [NSData dataWithContentsOfFile:path]; [builder _setBoundaries:@[@"1", @"2", @"3", @"4", @"5"]]; //[[builder data] writeToFile:@"/Users/hoa/builder1-now.eml" atomically:YES]; - XCTAssertEqualObjects([builder data], expectedData, @"Pass"); + XCTAssertEqualObjects([[NSString alloc] initWithData:[builder data] encoding:NSUTF8StringEncoding], [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding], @"Pass"); + //XCTAssertEqualObjects([builder data], expectedData, @"Pass"); } - (void)testMessageBuilder2 { @@ -137,7 +136,7 @@ path = [_builderOutputPath stringByAppendingPathComponent:@"builder2.eml"]; NSData * expectedData = [NSData dataWithContentsOfFile:path]; //[[builder data] writeToFile:@"/Users/hoa/builder2-now.eml" atomically:YES]; - XCTAssertEqualObjects([builder data], expectedData, @"Pass"); + XCTAssertEqualObjects([[NSString alloc] initWithData:[builder data] encoding:NSUTF8StringEncoding], [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding], @"Pass"); } - (void)testMessageBuilder3 { @@ -159,7 +158,7 @@ path = [_builderOutputPath stringByAppendingPathComponent:@"builder3.eml"]; NSData * expectedData = [NSData dataWithContentsOfFile:path]; //[[builder data] writeToFile:@"/Users/hoa/builder3-now.eml" atomically:YES]; - XCTAssertEqualObjects([builder data], expectedData, @"Pass"); + XCTAssertEqualObjects([[NSString alloc] initWithData:[builder data] encoding:NSUTF8StringEncoding], [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding], @"Pass"); } - (void)testMessageParser { |