diff --git a/headers/os/locale/Collator.h b/headers/os/locale/Collator.h index 991a08b49f..92d8c6ae8f 100644 --- a/headers/os/locale/Collator.h +++ b/headers/os/locale/Collator.h @@ -14,6 +14,7 @@ namespace icu_44 { class Collator; + class RuleBasedCollator; }; @@ -65,6 +66,7 @@ class BCollator : public BArchivable { private: icu_44::Collator* fICUCollator; + icu_44::RuleBasedCollator* fFallbackICUCollator; int8 fStrength; bool fIgnorePunctuation; }; diff --git a/src/kits/locale/Collator.cpp b/src/kits/locale/Collator.cpp index 569710fdfa..5c86622ed8 100644 --- a/src/kits/locale/Collator.cpp +++ b/src/kits/locale/Collator.cpp @@ -15,10 +15,12 @@ #include #include +#include BCollator::BCollator() : + fFallbackICUCollator(NULL), fStrength(B_COLLATE_PRIMARY), fIgnorePunctuation(true) { @@ -34,6 +36,7 @@ BCollator::BCollator() BCollator::BCollator(const char *locale, int8 strength, bool ignorePunctuation) : + fFallbackICUCollator(NULL), fStrength(strength), fIgnorePunctuation(ignorePunctuation) { @@ -45,9 +48,9 @@ BCollator::BCollator(const char *locale, int8 strength, BCollator::BCollator(BMessage *archive) : BArchivable(archive), fICUCollator(NULL), + fFallbackICUCollator(NULL), fIgnorePunctuation(true) { -#if HAIKU_TARGET_PLATFORM_HAIKU int32 data; if (archive->FindInt32("loc:strength", &data) == B_OK) fStrength = (uint8)data; @@ -57,14 +60,28 @@ BCollator::BCollator(BMessage *archive) if (archive->FindBool("loc:punctuation", &fIgnorePunctuation) != B_OK) fIgnorePunctuation = true; - // TODO : ICU collator ? or just store the locale name ? -#endif + UErrorCode error = U_ZERO_ERROR; + fFallbackICUCollator = static_cast + (Collator::createInstance(error)); + + ssize_t size; + const void* buffer = NULL; + if (archive->FindData("loc:collator", B_RAW_TYPE, &buffer, &size) == B_OK) { + fICUCollator = new RuleBasedCollator((const uint8_t*)buffer, (int)size, + fFallbackICUCollator, error); + if (fICUCollator == NULL) { + fICUCollator = fFallbackICUCollator; + // Unarchiving failed, so we revert to the fallback collator + } + } } BCollator::~BCollator() { delete fICUCollator; + fICUCollator = NULL; + delete fFallbackICUCollator; } @@ -169,17 +186,24 @@ BCollator::Archive(BMessage *archive, bool deep) const if (status == B_OK) status = archive->AddBool("loc:punctuation", fIgnorePunctuation); - /* - BMessage collatorArchive; - if (status == B_OK && deep - && typeid(*fCollator) != typeid(BCollatorAddOn) - // only archive subclasses from BCollatorAddOn - && (status = fCollator->Archive(&collatorArchive, true)) == B_OK) - status = archive->AddMessage("loc:collator", &collatorArchive); - */ - //TODO : archive fICUCollator + UErrorCode error = U_ZERO_ERROR; + int size = static_cast(fICUCollator)->cloneBinary(NULL, + 0, error); + // This WILL fail with U_BUFFER_OVERFLOW_ERROR. But we get the needed + // size. + error = U_ZERO_ERROR; + uint8_t* buffer = (uint8_t*)malloc(size); + static_cast(fICUCollator)->cloneBinary(buffer, size, + error); - return status; + if (status == B_OK && error == U_ZERO_ERROR) + status = archive->AddData("loc:collator", B_RAW_TYPE, buffer, size); + delete buffer; + + if (error == U_ZERO_ERROR) + return status; + else + return B_ERROR; } diff --git a/src/tests/kits/locale/collatorTest.cpp b/src/tests/kits/locale/collatorTest.cpp index ba8db2e6b2..5b85766c30 100644 --- a/src/tests/kits/locale/collatorTest.cpp +++ b/src/tests/kits/locale/collatorTest.cpp @@ -156,20 +156,7 @@ main(int argc, char **argv) // load the collator add-on if necessary if (addon != NULL) { - image_id image = load_add_on(addon); - if (image < B_OK) - fprintf(stderr, "could not load add-on at \"%s\": %s.\n", addon, strerror(image)); - - BCollatorAddOn *(*instantiate)(void); - if (get_image_symbol(image, "instantiate_collator", - B_SYMBOL_TYPE_TEXT, (void **)&instantiate) == B_OK) { - BCollatorAddOn *collator = instantiate(); - if (collator != NULL) - gCollator = new BCollator(collator, strength, true); - } else if (image >= B_OK) { - fprintf(stderr, "could not find instantiate_collator() function in add-on!\n"); - unload_add_on(image); - } + gCollator = new BCollator(addon, strength, true); } if (gCollator == NULL) { @@ -177,7 +164,7 @@ main(int argc, char **argv) gCollator = be_locale->Collator(); } - // test archiving/unarchiving collator + printf("test archiving/unarchiving collator\n"); BMessage archive; if (gCollator->Archive(&archive, true) != B_OK) @@ -193,7 +180,10 @@ main(int argc, char **argv) } } - // test the BCollator::Compare() and GetSortKey() methods + printf(" Archived content :"); + archive.PrintToStream(); + + printf("test the BCollator::Compare() and GetSortKey() methods\n"); const char *strengthLabels[] = {"primary: ", "secondary:", "tertiary: "}; uint32 strengths[] = {B_COLLATE_PRIMARY, B_COLLATE_SECONDARY, B_COLLATE_TERTIARY};