aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/basetypes
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/basetypes')
-rw-r--r--src/core/basetypes/MCArray.cc23
-rw-r--r--src/core/basetypes/MCArray.h1
-rw-r--r--src/core/basetypes/MCData.cc3
-rw-r--r--src/core/basetypes/MCHTMLCleaner.cc3
-rw-r--r--src/core/basetypes/MCIndexSet.cc6
-rw-r--r--src/core/basetypes/MCIterator.h55
-rw-r--r--src/core/basetypes/MCLibetpan.cc202
-rw-r--r--src/core/basetypes/MCLibetpan.h12
-rw-r--r--src/core/basetypes/MCObject.cc4
-rw-r--r--src/core/basetypes/MCOperation.cc11
-rw-r--r--src/core/basetypes/MCOperationQueue.cc35
-rw-r--r--src/core/basetypes/MCOperationQueue.h2
-rw-r--r--src/core/basetypes/MCSet.cc2
-rw-r--r--src/core/basetypes/MCString.cc54
-rw-r--r--src/core/basetypes/MCString.h2
-rw-r--r--src/core/basetypes/MCUtils.h2
16 files changed, 392 insertions, 25 deletions
diff --git a/src/core/basetypes/MCArray.cc b/src/core/basetypes/MCArray.cc
index 804f796c..43ee6bd4 100644
--- a/src/core/basetypes/MCArray.cc
+++ b/src/core/basetypes/MCArray.cc
@@ -212,21 +212,26 @@ static int sortCompare(Object ** pa, Object ** pb, struct sortData * data)
Array * Array::sortedArray(int (* compare)(void * a, void * b, void * context), void * context)
{
- struct sortData data;
Array * result = (Array *) this->copy()->autorelease();
+ result->sortArray(compare, context);
+ return result;
+}
+
+void Array::sortArray(int (* compare)(void * a, void * b, void * context), void * context)
+{
+ struct sortData data;
data.compare = compare;
data.context = context;
#ifdef __MACH__
- qsort_r(carray_data(result->mArray), carray_count(result->mArray),
- sizeof(* carray_data(result->mArray)), &data,
- (int (*)(void *, const void *, const void *)) sortCompare);
+ qsort_r(carray_data(mArray), carray_count(mArray),
+ sizeof(* carray_data(mArray)), &data,
+ (int (*)(void *, const void *, const void *)) sortCompare);
#else
- qsort_r(carray_data(result->mArray), carray_count(result->mArray),
- sizeof(* carray_data(result->mArray)),
- (int (*)(const void *, const void *, void *)) sortCompare,
- &data);
+ qsort_r(carray_data(mArray), carray_count(mArray),
+ sizeof(* carray_data(mArray)),
+ (int (*)(const void *, const void *, void *)) sortCompare,
+ &data);
#endif
- return result;
}
String * Array::componentsJoinedByString(String * delimiter)
diff --git a/src/core/basetypes/MCArray.h b/src/core/basetypes/MCArray.h
index 6ee64792..82e9760a 100644
--- a/src/core/basetypes/MCArray.h
+++ b/src/core/basetypes/MCArray.h
@@ -36,6 +36,7 @@ namespace mailcore {
virtual bool containsObject(Object * obj);
virtual Array * sortedArray(int (* compare)(void * a, void * b, void * context), void * context);
+ virtual void sortArray(int (* compare)(void * a, void * b, void * context), void * context);
virtual String * componentsJoinedByString(String * delimiter);
public: // subclass behavior
diff --git a/src/core/basetypes/MCData.cc b/src/core/basetypes/MCData.cc
index 0a03316c..60b8ff8f 100644
--- a/src/core/basetypes/MCData.cc
+++ b/src/core/basetypes/MCData.cc
@@ -283,6 +283,9 @@ String * Data::stringWithDetectedCharset(String * hintCharset, bool isHTML)
if (result == NULL) {
result = data->stringWithCharset("iso-2022-jp");
}
+ if (result == NULL) {
+ result = MCSTR("");
+ }
return result;
}
diff --git a/src/core/basetypes/MCHTMLCleaner.cc b/src/core/basetypes/MCHTMLCleaner.cc
index 78d2461a..81145c9e 100644
--- a/src/core/basetypes/MCHTMLCleaner.cc
+++ b/src/core/basetypes/MCHTMLCleaner.cc
@@ -43,6 +43,9 @@ String * HTMLCleaner::cleanHTML(String * input)
tidyOptSetBool(tdoc, TidyDropEmptyElems, no);
#endif
tidyOptSetBool(tdoc, TidyXhtmlOut, yes);
+ tidyOptSetInt(tdoc, TidyDoctypeMode, TidyDoctypeUser);
+
+ tidyOptSetBool(tdoc, TidyMark, no);
tidySetCharEncoding(tdoc, "utf8");
tidyOptSetBool(tdoc, TidyForceOutput, yes);
//tidyOptSetValue(tdoc, TidyErrFile, "/dev/null");
diff --git a/src/core/basetypes/MCIndexSet.cc b/src/core/basetypes/MCIndexSet.cc
index 07d78d5d..768cd601 100644
--- a/src/core/basetypes/MCIndexSet.cc
+++ b/src/core/basetypes/MCIndexSet.cc
@@ -148,7 +148,7 @@ int IndexSet::leftRangeIndexForIndexWithBounds(uint64_t idx, unsigned int left,
Range middleRange = mRanges[middle];
if (left == right) {
- if (idx <= middleRange.location) {
+ if (idx <= RangeRightBound(middleRange)) {
return left;
}
else {
@@ -156,7 +156,7 @@ int IndexSet::leftRangeIndexForIndexWithBounds(uint64_t idx, unsigned int left,
}
}
- if (idx <= middleRange.location) {
+ if (idx <= RangeRightBound(middleRange)) {
return leftRangeIndexForIndexWithBounds(idx, left, middle);
}
else {
@@ -372,7 +372,7 @@ void IndexSet::intersectsRange(Range range)
}
else {
removeRange(RangeMake(0, range.location - 1));
- removeRange(RangeMake(right, UINT64_MAX));
+ removeRange(RangeMake(right + 1, UINT64_MAX));
}
}
diff --git a/src/core/basetypes/MCIterator.h b/src/core/basetypes/MCIterator.h
index 08a3b256..c8b23fab 100644
--- a/src/core/basetypes/MCIterator.h
+++ b/src/core/basetypes/MCIterator.h
@@ -12,6 +12,7 @@
#include <MailCore/MCArray.h>
#include <MailCore/MCHashMap.h>
+#include <MailCore/MCIndexSet.h>
#include <MailCore/MCAutoreleasePool.h>
#include <string.h>
@@ -25,7 +26,7 @@ for (; NULL != (__variable = (type *) mailcore::ArrayIteratorNext(&__variable##_
#define mc_foreacharrayIndex(__index, type, __variable, __array) \
type * __variable; \
mailcore::ArrayIterator __variable##__iterator = mailcore::ArrayIteratorInit(__array); \
-for (unsigned int __index = 0; NULL != (__variable = mailcore::ArrayIteratorNext(&__variable##__iterator)); __index++)
+for (unsigned int __index = 0; NULL != (__variable = (type *) mailcore::ArrayIteratorNext(&__variable##__iterator)); __index++)
#define mc_foreachhashmapKey(keyType, __key, __hashmap) \
keyType * __key; \
@@ -46,8 +47,60 @@ HashMapIterator __key##__value##__iterator = HashMapIteratorInit(__hashmap, true
while (HashMapIteratorRun(&__key##__value##__iterator)) \
while (HashMapIteratorNext(&__key##__value##__iterator, (Object **) &__key, (Object **) &__value))
+#define mc_foreachindexset(__variable, __indexset) \
+int64_t __variable; \
+mailcore::IndexSetIterator __variable##__iterator = mailcore::IndexSetIteratorInit(__indexset); \
+for (; (__variable = IndexSetIteratorValue(&__variable##__iterator)), IndexSetIteratorIsValid(&__variable##__iterator) ; mailcore::IndexSetIteratorNext(&__variable##__iterator))
+
namespace mailcore {
+ struct IndexSetIterator {
+ unsigned int rangeIndex;
+ unsigned int index;
+ Range * currentRange;
+ IndexSet * indexSet;
+ };
+
+ static inline IndexSetIterator IndexSetIteratorInit(IndexSet * indexSet)
+ {
+ IndexSetIterator iterator = { 0, 0, NULL, indexSet };
+ if (indexSet->rangesCount() >= 1) {
+ iterator.currentRange = &indexSet->allRanges()[0];
+ }
+ return iterator;
+ }
+
+ static inline bool IndexSetIteratorIsValid(IndexSetIterator * iterator)
+ {
+ return iterator->currentRange != NULL;
+ }
+
+ static inline int64_t IndexSetIteratorValue(IndexSetIterator * iterator)
+ {
+ return iterator->currentRange == NULL ? -1 : iterator->currentRange->location + iterator->index;
+ }
+
+ static inline bool IndexSetIteratorNext(IndexSetIterator * iterator)
+ {
+ iterator->index ++;
+ if (iterator->index > iterator->currentRange->length) {
+ // switch to an other range
+ iterator->index = 0;
+ iterator->rangeIndex ++;
+ if (iterator->rangeIndex >= iterator->indexSet->rangesCount()) {
+ iterator->currentRange = NULL;
+ return false;
+ }
+ else {
+ iterator->currentRange = &iterator->indexSet->allRanges()[iterator->rangeIndex];
+ return true;
+ }
+ }
+ else {
+ return true;
+ }
+ }
+
struct ArrayIterator {
unsigned index;
unsigned count;
diff --git a/src/core/basetypes/MCLibetpan.cc b/src/core/basetypes/MCLibetpan.cc
index fcc1b772..1779d605 100644
--- a/src/core/basetypes/MCLibetpan.cc
+++ b/src/core/basetypes/MCLibetpan.cc
@@ -10,9 +10,211 @@
#include <libetpan/libetpan.h>
+using namespace mailcore;
+
+static time_t mkgmtime(struct tm * tmp);
+static int tmcomp(struct tm * atmp, struct tm * btmp);
+
__attribute__((constructor))
static void initialize()
{
// It will enable CFStream on platforms that supports it.
mailstream_cfstream_enabled = 1;
}
+
+time_t mailcore::timestampFromDate(struct mailimf_date_time * date_time)
+{
+ struct tm tmval;
+ time_t timeval;
+ int zone_min;
+ int zone_hour;
+
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_min = date_time->dt_min;
+ tmval.tm_hour = date_time->dt_hour;
+ tmval.tm_mday = date_time->dt_day;
+ tmval.tm_mon = date_time->dt_month - 1;
+ if (date_time->dt_year < 1000) {
+ // workaround when century is not given in year
+ tmval.tm_year = date_time->dt_year + 2000 - 1900;
+ }
+ else {
+ tmval.tm_year = date_time->dt_year - 1900;
+ }
+
+ timeval = mkgmtime(&tmval);
+
+ if (date_time->dt_zone >= 0) {
+ zone_hour = date_time->dt_zone / 100;
+ zone_min = date_time->dt_zone % 100;
+ }
+ else {
+ zone_hour = -((- date_time->dt_zone) / 100);
+ zone_min = -((- date_time->dt_zone) % 100);
+ }
+ timeval -= zone_hour * 3600 + zone_min * 60;
+
+ return timeval;
+}
+
+struct mailimf_date_time * mailcore::dateFromTimestamp(time_t timeval)
+{
+ struct tm gmt;
+ struct tm lt;
+ int off;
+ struct mailimf_date_time * date_time;
+ int sign;
+ int hour;
+ int min;
+
+ gmtime_r(&timeval, &gmt);
+ localtime_r(&timeval, &lt);
+
+ off = (int) ((mkgmtime(&lt) - mkgmtime(&gmt)) / 60);
+ if (off < 0) {
+ sign = -1;
+ }
+ else {
+ sign = 1;
+ }
+ off = off * sign;
+ min = off % 60;
+ hour = off / 60;
+ off = hour * 100 + min;
+ off = off * sign;
+
+ date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1,
+ lt.tm_year + 1900,
+ lt.tm_hour, lt.tm_min, lt.tm_sec,
+ off);
+
+ return date_time;
+}
+
+struct mailimap_date_time * mailcore::imapDateFromTimestamp(time_t timeval)
+{
+ struct tm gmt;
+ struct tm lt;
+ int off;
+ struct mailimap_date_time * date_time;
+ int sign;
+ int hour;
+ int min;
+
+ gmtime_r(&timeval, &gmt);
+ localtime_r(&timeval, &lt);
+
+ off = (int) ((mkgmtime(&lt) - mkgmtime(&gmt)) / 60);
+ if (off < 0) {
+ sign = -1;
+ }
+ else {
+ sign = 1;
+ }
+ off = off * sign;
+ min = off % 60;
+ hour = off / 60;
+ off = hour * 100 + min;
+ off = off * sign;
+
+ date_time = mailimap_date_time_new(lt.tm_mday, lt.tm_mon + 1,
+ lt.tm_year + 1900,
+ lt.tm_hour, lt.tm_min, lt.tm_sec,
+ off);
+
+ return date_time;
+}
+
+time_t mailcore::timestampFromIMAPDate(struct mailimap_date_time * date_time)
+{
+ struct tm tmval;
+ time_t timeval;
+ int zone_min;
+ int zone_hour;
+
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_min = date_time->dt_min;
+ tmval.tm_hour = date_time->dt_hour;
+ tmval.tm_mday = date_time->dt_day;
+ tmval.tm_mon = date_time->dt_month - 1;
+ if (date_time->dt_year < 1000) {
+ // workaround when century is not given in year
+ tmval.tm_year = date_time->dt_year + 2000 - 1900;
+ }
+ else {
+ tmval.tm_year = date_time->dt_year - 1900;
+ }
+
+ timeval = mkgmtime(&tmval);
+
+ if (date_time->dt_zone >= 0) {
+ zone_hour = date_time->dt_zone / 100;
+ zone_min = date_time->dt_zone % 100;
+ }
+ else {
+ zone_hour = -((- date_time->dt_zone) / 100);
+ zone_min = -((- date_time->dt_zone) % 100);
+ }
+ timeval -= zone_hour * 3600 + zone_min * 60;
+
+ return timeval;
+}
+
+#define INVALID_TIMESTAMP (-1)
+
+static int tmcomp(struct tm * atmp, struct tm * btmp)
+{
+ int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t mkgmtime(struct tm * tmp)
+{
+ int dir;
+ int bits;
+ int saved_seconds;
+ time_t t;
+ struct tm yourtm, mytm;
+
+ yourtm = *tmp;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ /*
+ ** Calculate the number of magnitude bits in a time_t
+ ** (this works regardless of whether time_t is
+ ** signed or unsigned, though lint complains if unsigned).
+ */
+ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
+ ;
+ /*
+ ** If time_t is signed, then 0 is the median value,
+ ** if time_t is unsigned, then 1 << bits is median.
+ */
+ if(bits > 40) bits = 40;
+ t = (t < 0) ? 0 : ((time_t) 1 << bits);
+ for ( ; ; ) {
+ gmtime_r(&t, &mytm);
+ dir = tmcomp(&mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0) {
+ return INVALID_TIMESTAMP;
+ }
+ if (bits < 0)
+ --t;
+ else if (dir > 0)
+ t -= (time_t) 1 << bits;
+ else t += (time_t) 1 << bits;
+ continue;
+ }
+ break;
+ }
+ t += saved_seconds;
+ return t;
+}
diff --git a/src/core/basetypes/MCLibetpan.h b/src/core/basetypes/MCLibetpan.h
index 9670a47b..41024137 100644
--- a/src/core/basetypes/MCLibetpan.h
+++ b/src/core/basetypes/MCLibetpan.h
@@ -10,6 +10,16 @@
#define MAILCORE_MCLIBETPAN_H
-// No API in this file.
+#include <time.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ time_t timestampFromDate(struct mailimf_date_time * date_time);
+ time_t timestampFromIMAPDate(struct mailimap_date_time * date_time);
+ struct mailimf_date_time * dateFromTimestamp(time_t timeval);
+ struct mailimap_date_time * imapDateFromTimestamp(time_t timeval);
+
+}
#endif
diff --git a/src/core/basetypes/MCObject.cc b/src/core/basetypes/MCObject.cc
index 26b59e67..0e8d9639 100644
--- a/src/core/basetypes/MCObject.cc
+++ b/src/core/basetypes/MCObject.cc
@@ -5,7 +5,9 @@
#include <cxxabi.h>
#include <libetpan/libetpan.h>
#include <string.h>
+#if __APPLE__
#include <Block.h>
+#endif
#include "MCAutoreleasePool.h"
#include "MCString.h"
@@ -367,7 +369,7 @@ void Object::cancelDelayedPerformMethod(Method method, void * context)
#else
initDelayedPerform();
- struct mainThreadCallData * data = getFromPerformHash(this, method, context, NULL);
+ struct mainThreadCallData * data = (struct mainThreadCallData *) getFromPerformHash(this, method, context, NULL);
if (data == NULL)
return;
diff --git a/src/core/basetypes/MCOperation.cc b/src/core/basetypes/MCOperation.cc
index 71b3c52f..51497cba 100644
--- a/src/core/basetypes/MCOperation.cc
+++ b/src/core/basetypes/MCOperation.cc
@@ -15,6 +15,11 @@ Operation::Operation()
Operation::~Operation()
{
+#if __APPLE__
+ if (mCallbackDispatchQueue != NULL) {
+ dispatch_release(mCallbackDispatchQueue);
+ }
+#endif
pthread_mutex_destroy(&mLock);
}
@@ -73,7 +78,13 @@ void Operation::start()
#if __APPLE__
void Operation::setCallbackDispatchQueue(dispatch_queue_t callbackDispatchQueue)
{
+ if (mCallbackDispatchQueue != NULL) {
+ dispatch_release(mCallbackDispatchQueue);
+ }
mCallbackDispatchQueue = callbackDispatchQueue;
+ if (mCallbackDispatchQueue != NULL) {
+ dispatch_retain(mCallbackDispatchQueue);
+ }
}
dispatch_queue_t Operation::callbackDispatchQueue()
diff --git a/src/core/basetypes/MCOperationQueue.cc b/src/core/basetypes/MCOperationQueue.cc
index 73b62f19..e45f04ee 100644
--- a/src/core/basetypes/MCOperationQueue.cc
+++ b/src/core/basetypes/MCOperationQueue.cc
@@ -28,10 +28,16 @@ OperationQueue::OperationQueue()
#if __APPLE__
mDispatchQueue = dispatch_get_main_queue();
#endif
+ _pendingCheckRunning = false;
}
OperationQueue::~OperationQueue()
{
+#if __APPLE__
+ if (mDispatchQueue != NULL) {
+ dispatch_release(mDispatchQueue);
+ }
+#endif
MC_SAFE_RELEASE(mOperations);
pthread_mutex_destroy(&mLock);
mailsem_free(mOperationSem);
@@ -49,6 +55,16 @@ void OperationQueue::addOperation(Operation * op)
startThread();
}
+void OperationQueue::cancelAllOperations()
+{
+ pthread_mutex_lock(&mLock);
+ for (unsigned int i = 0 ; i < mOperations->count() ; i ++) {
+ Operation * op = (Operation *) mOperations->objectAtIndex(i);
+ op->cancel();
+ }
+ pthread_mutex_unlock(&mLock);
+}
+
void OperationQueue::runOperationsOnThread(OperationQueue * queue)
{
queue->runOperations();
@@ -115,7 +131,7 @@ void OperationQueue::runOperations()
if (needsCheckRunning) {
retain(); // (1)
- MCLog("check running %p", this);
+ //MCLog("check running %p", this);
#if __APPLE__
performMethodOnDispatchQueue((Object::Method) &OperationQueue::checkRunningOnMainThread, this, mDispatchQueue);
#else
@@ -160,12 +176,19 @@ void OperationQueue::callbackOnMainThread(Operation * op)
void OperationQueue::checkRunningOnMainThread(void * context)
{
- cancelDelayedPerformMethod((Object::Method) &OperationQueue::checkRunningAfterDelay, NULL);
+ retain(); // (4)
+ if (_pendingCheckRunning) {
+ cancelDelayedPerformMethod((Object::Method) &OperationQueue::checkRunningAfterDelay, NULL);
+ release(); // (4)
+ }
+ _pendingCheckRunning = true;
performMethodAfterDelay((Object::Method) &OperationQueue::checkRunningAfterDelay, NULL, 1);
+ release(); // (1)
}
void OperationQueue::checkRunningAfterDelay(void * context)
{
+ _pendingCheckRunning = false;
pthread_mutex_lock(&mLock);
if (!mQuitting) {
if (mOperations->count() == 0) {
@@ -179,7 +202,7 @@ void OperationQueue::checkRunningAfterDelay(void * context)
// Number of operations can't be changed because it runs on main thread.
// And addOperation() should also be called from main thread.
- release(); // (1)
+ release(); // (4)
}
void OperationQueue::stoppedOnMainThread(void * context)
@@ -256,7 +279,13 @@ void OperationQueue::waitUntilAllOperationsAreFinished()
#if __APPLE__
void OperationQueue::setDispatchQueue(dispatch_queue_t dispatchQueue)
{
+ if (mDispatchQueue != NULL) {
+ dispatch_release(mDispatchQueue);
+ }
mDispatchQueue = dispatchQueue;
+ if (mDispatchQueue != NULL) {
+ dispatch_retain(mDispatchQueue);
+ }
}
dispatch_queue_t OperationQueue::dispatchQueue()
diff --git a/src/core/basetypes/MCOperationQueue.h b/src/core/basetypes/MCOperationQueue.h
index 202dec40..119befcc 100644
--- a/src/core/basetypes/MCOperationQueue.h
+++ b/src/core/basetypes/MCOperationQueue.h
@@ -21,6 +21,7 @@ namespace mailcore {
virtual ~OperationQueue();
virtual void addOperation(Operation * op);
+ virtual void cancelAllOperations();
virtual unsigned int count();
@@ -47,6 +48,7 @@ namespace mailcore {
#if __APPLE__
dispatch_queue_t mDispatchQueue;
#endif
+ bool _pendingCheckRunning;
void startThread();
static void runOperationsOnThread(OperationQueue * queue);
diff --git a/src/core/basetypes/MCSet.cc b/src/core/basetypes/MCSet.cc
index ad615388..ceccbdcc 100644
--- a/src/core/basetypes/MCSet.cc
+++ b/src/core/basetypes/MCSet.cc
@@ -45,7 +45,7 @@ Set * Set::setWithArray(Array * objects)
String * Set::description()
{
String * result = String::string();
- result->appendUTF8Format("<%s:%p ", className(), this);
+ result->appendUTF8Format("<%s:%p ", MCUTF8(className()), this);
result->appendString(mHash->allKeys()->description());
result->appendUTF8Characters(">");
return result;
diff --git a/src/core/basetypes/MCString.cc b/src/core/basetypes/MCString.cc
index 054cbb80..5c2da323 100644
--- a/src/core/basetypes/MCString.cc
+++ b/src/core/basetypes/MCString.cc
@@ -761,6 +761,9 @@ String * String::string()
String * String::stringWithData(Data * data, const char * charset)
{
+ if (data == NULL) {
+ return String::string();
+ }
String * result = NULL;
result = new String(data->bytes(), data->length(), charset);
result->autorelease();
@@ -807,6 +810,9 @@ String * String::stringWithCharacters(const UChar * characters, unsigned int len
void String::appendCharactersLength(const UChar * unicodeCharacters, unsigned int length)
{
+ if (unicodeCharacters == NULL) {
+ return;
+ }
allocate(mLength + length);
u_strncpy(&mUnicodeChars[mLength], unicodeCharacters, length);
mLength += length;
@@ -815,6 +821,9 @@ void String::appendCharactersLength(const UChar * unicodeCharacters, unsigned in
void String::appendString(String * otherString)
{
+ if (otherString == NULL) {
+ return;
+ }
appendCharactersLength(otherString->unicodeCharacters(), otherString->length());
}
@@ -831,8 +840,9 @@ void String::appendUTF8Format(const char * format, ...)
void String::appendUTF8CharactersLength(const char * UTF8Characters, unsigned int length)
{
- if (UTF8Characters == NULL)
+ if (UTF8Characters == NULL) {
return;
+ }
UChar * dest;
int32_t destLength;
@@ -1124,6 +1134,10 @@ String * String::uppercaseString()
void String::appendBytes(const char * bytes, unsigned int length, const char * charset)
{
+ if (bytes == NULL) {
+ return;
+ }
+
#if __APPLE__
CFStringEncoding encoding;
if (strcasecmp(charset, "mutf-7") == 0) {
@@ -1138,7 +1152,16 @@ void String::appendBytes(const char * bytes, unsigned int length, const char * c
if (cfStr != NULL) {
CFDataRef data = CFStringCreateExternalRepresentation(NULL, cfStr, kCFStringEncodingUTF16LE, '_');
if (data != NULL) {
- appendCharactersLength((const UChar *) CFDataGetBytePtr(data), (unsigned int) CFDataGetLength(data) / 2);
+ UChar * fixedData = (UChar *) malloc(CFDataGetLength(data));
+ memcpy(fixedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ unsigned int length = (unsigned int) CFDataGetLength(data) / 2;
+ for(int32_t i = 0 ; i < length ; i ++) {
+ if (fixedData[i] == 0) {
+ fixedData[i] = ' ';
+ }
+ }
+ appendCharactersLength(fixedData, length);
+ free(fixedData);
CFRelease(data);
}
CFRelease(cfStr);
@@ -1269,7 +1292,10 @@ void String::deleteCharactersInRange(Range range)
if (range.location > mLength)
return;
- if (range.location + range.length > mLength) {
+ if (range.length > mLength) {
+ range.length = mLength - range.location;
+ }
+ else if (range.location + range.length > mLength) {
range.length = mLength - range.location;
}
@@ -1795,6 +1821,24 @@ String * String::flattenHTML()
return flattenHTMLAndShowBlockquote(true);
}
+String * String::stripWhitespace()
+{
+ String *str = (String *)copy();
+
+ str->replaceOccurrencesOfString(MCSTR("\t"), MCSTR(" "));
+ str->replaceOccurrencesOfString(MCSTR("\n"), MCSTR(" "));
+ str->replaceOccurrencesOfString(MCSTR("\v"), MCSTR(" "));
+ str->replaceOccurrencesOfString(MCSTR("\f"), MCSTR(" "));
+ str->replaceOccurrencesOfString(MCSTR("\r"), MCSTR(" "));
+
+ while (str->replaceOccurrencesOfString(MCSTR(" "), MCSTR(" ")) > 0) {
+ /* do nothing */
+ }
+
+ return str;
+}
+
+
bool String::hasSuffix(String * suffix)
{
if (mLength >= suffix->mLength) {
@@ -2187,9 +2231,9 @@ String * String::htmlMessageContent()
}
}
- if (quoted != nil) {
+ if (quoted != NULL) {
localString->appendString(MCSTR("<blockquote type=\"cite\">"));
- localString->appendString(quoted);
+ localString->appendString(quoted->htmlMessageContent());
localString->appendString(MCSTR("</blockquote>"));
MC_SAFE_RELEASE(quoted);
}
diff --git a/src/core/basetypes/MCString.h b/src/core/basetypes/MCString.h
index 7fd07570..25439cf2 100644
--- a/src/core/basetypes/MCString.h
+++ b/src/core/basetypes/MCString.h
@@ -86,6 +86,8 @@ namespace mailcore {
virtual String * flattenHTMLAndShowBlockquote(bool showBlockquote);
virtual String * flattenHTMLAndShowBlockquoteAndLink(bool showBlockquote, bool showLink);
+ virtual String * stripWhitespace();
+
virtual String * lastPathComponent();
virtual String * pathExtension();
virtual Data * dataUsingEncoding(const char * charset = NULL);
diff --git a/src/core/basetypes/MCUtils.h b/src/core/basetypes/MCUtils.h
index e1bef841..ad9c4db5 100644
--- a/src/core/basetypes/MCUtils.h
+++ b/src/core/basetypes/MCUtils.h
@@ -29,7 +29,7 @@
#define MCSTR(str) mailcore::String::uniquedStringWithUTF8Characters("" str "")
-#define MCUTF8(str) ((str) != NULL ? (str)->UTF8Characters() : NULL )
+#define MCUTF8(str) MCUTF8DESC(str)
#define MCUTF8DESC(obj) ((obj) != NULL ? (obj)->description()->UTF8Characters() : NULL )
#define MCLOCALIZEDSTRING(key) key