2 * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Copyright 2010, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
4 * Distributed under the terms of the MIT License.
8 #include <unicode/uversion.h>
17 #include <UnicodeChar.h>
21 #include <unicode/coll.h>
22 #include <unicode/tblcoll.h>
25 BCollator::BCollator()
27 fIgnorePunctuation(true)
29 // TODO: the collator construction will have to change; the default
30 // collator should be constructed by the Locale/LocaleRoster, so we
31 // only need a constructor where you specify all details
33 UErrorCode error
= U_ZERO_ERROR
;
34 fICUCollator
= Collator::createInstance(error
);
35 SetStrength(B_COLLATE_TERTIARY
);
39 BCollator::BCollator(const char* locale
, int8 strength
, bool ignorePunctuation
)
41 fIgnorePunctuation(ignorePunctuation
)
43 UErrorCode error
= U_ZERO_ERROR
;
44 fICUCollator
= Collator::createInstance(locale
, error
);
45 SetStrength(strength
);
49 BCollator::BCollator(BMessage
* archive
)
53 fIgnorePunctuation(true)
55 archive
->FindBool("loc:punctuation", &fIgnorePunctuation
);
57 UErrorCode error
= U_ZERO_ERROR
;
58 RuleBasedCollator
* fallbackICUCollator
59 = static_cast<RuleBasedCollator
*>(Collator::createInstance(error
));
62 const void* buffer
= NULL
;
63 if (archive
->FindData("loc:collator", B_RAW_TYPE
, &buffer
, &size
) == B_OK
) {
64 fICUCollator
= new RuleBasedCollator((const uint8_t*)buffer
, (int)size
,
65 fallbackICUCollator
, error
);
66 if (fICUCollator
== NULL
) {
67 fICUCollator
= fallbackICUCollator
;
68 // Unarchiving failed, so we revert to the fallback collator
69 // TODO: when can this happen, can it be avoided?
75 BCollator::BCollator(const BCollator
& other
)
83 BCollator::~BCollator()
89 BCollator
& BCollator::operator=(const BCollator
& source
)
91 if (&source
!= this) {
94 fICUCollator
= source
.fICUCollator
!= NULL
95 ? source
.fICUCollator
->clone()
97 fIgnorePunctuation
= source
.fIgnorePunctuation
;
105 BCollator::SetIgnorePunctuation(bool ignore
)
107 fIgnorePunctuation
= ignore
;
112 BCollator::IgnorePunctuation() const
114 return fIgnorePunctuation
;
119 BCollator::SetNumericSorting(bool enable
)
121 UErrorCode error
= U_ZERO_ERROR
;
122 fICUCollator
->setAttribute(UCOL_NUMERIC_COLLATION
,
123 enable
? UCOL_ON
: UCOL_OFF
, error
);
125 return error
== U_ZERO_ERROR
? B_OK
: B_ERROR
;
130 BCollator::GetSortKey(const char* string
, BString
* key
) const
132 // TODO : handle fIgnorePunctuation
134 int length
= strlen(string
);
136 uint8_t* buffer
= (uint8_t*)malloc(length
* 2);
137 // According to ICU documentation this should be enough in "most cases"
141 UErrorCode error
= U_ZERO_ERROR
;
142 int requiredSize
= fICUCollator
->getSortKey(UnicodeString(string
, length
,
143 NULL
, error
), buffer
, length
* 2);
144 if (requiredSize
> length
* 2) {
145 buffer
= (uint8_t*)realloc(buffer
, requiredSize
);
149 error
= U_ZERO_ERROR
;
150 fICUCollator
->getSortKey(UnicodeString(string
, length
, NULL
, error
),
151 buffer
, requiredSize
);
154 key
->SetTo((char*)buffer
);
157 if (error
== U_ZERO_ERROR
)
165 BCollator::Compare(const char* s1
, const char* s2
) const
167 // TODO : handle fIgnorePunctuation
169 UErrorCode error
= U_ZERO_ERROR
;
170 return fICUCollator
->compare(s1
, s2
, error
);
175 BCollator::Archive(BMessage
* archive
, bool deep
) const
177 status_t status
= BArchivable::Archive(archive
, deep
);
182 status
= archive
->AddBool("loc:punctuation", fIgnorePunctuation
);
184 UErrorCode error
= U_ZERO_ERROR
;
185 int size
= static_cast<RuleBasedCollator
*>(fICUCollator
)->cloneBinary(NULL
,
187 // This WILL fail with U_BUFFER_OVERFLOW_ERROR. But we get the needed
189 error
= U_ZERO_ERROR
;
190 uint8_t* buffer
= (uint8_t*)malloc(size
);
191 static_cast<RuleBasedCollator
*>(fICUCollator
)->cloneBinary(buffer
, size
,
194 if (status
== B_OK
&& error
== U_ZERO_ERROR
)
195 status
= archive
->AddData("loc:collator", B_RAW_TYPE
, buffer
, size
);
198 if (error
== U_ZERO_ERROR
)
205 BCollator::Instantiate(BMessage
* archive
)
207 if (validate_instantiation(archive
, "BCollator"))
208 return new(std::nothrow
) BCollator(archive
);
215 BCollator::SetStrength(int8 strength
) const
217 if (strength
== B_COLLATE_DEFAULT
)
218 strength
= B_COLLATE_TERTIARY
;
220 Collator::ECollationStrength icuStrength
;
222 case B_COLLATE_PRIMARY
:
223 icuStrength
= Collator::PRIMARY
;
225 case B_COLLATE_SECONDARY
:
226 icuStrength
= Collator::SECONDARY
;
228 case B_COLLATE_TERTIARY
:
230 icuStrength
= Collator::TERTIARY
;
232 case B_COLLATE_QUATERNARY
:
233 icuStrength
= Collator::QUATERNARY
;
235 case B_COLLATE_IDENTICAL
:
236 icuStrength
= Collator::IDENTICAL
;
239 fICUCollator
->setStrength(icuStrength
);