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 fDefaultStrength(B_COLLATE_PRIMARY
),
28 fIgnorePunctuation(true)
30 // TODO: the collator construction will have to change; the default
31 // collator should be constructed by the Locale/LocaleRoster, so we
32 // only need a constructor where you specify all details
34 UErrorCode error
= U_ZERO_ERROR
;
35 fICUCollator
= Collator::createInstance(error
);
39 BCollator::BCollator(const char* locale
, int8 strength
, bool ignorePunctuation
)
41 fDefaultStrength(strength
),
42 fIgnorePunctuation(ignorePunctuation
)
44 UErrorCode error
= U_ZERO_ERROR
;
45 fICUCollator
= Collator::createInstance(locale
, error
);
49 BCollator::BCollator(BMessage
* archive
)
53 fDefaultStrength(B_COLLATE_PRIMARY
),
54 fIgnorePunctuation(true)
57 if (archive
->FindInt32("loc:strength", &data
) == B_OK
)
58 fDefaultStrength
= (uint8
)data
;
60 fDefaultStrength
= B_COLLATE_PRIMARY
;
62 archive
->FindBool("loc:punctuation", &fIgnorePunctuation
);
64 UErrorCode error
= U_ZERO_ERROR
;
65 RuleBasedCollator
* fallbackICUCollator
66 = static_cast<RuleBasedCollator
*>(Collator::createInstance(error
));
69 const void* buffer
= NULL
;
70 if (archive
->FindData("loc:collator", B_RAW_TYPE
, &buffer
, &size
) == B_OK
) {
71 fICUCollator
= new RuleBasedCollator((const uint8_t*)buffer
, (int)size
,
72 fallbackICUCollator
, error
);
73 if (fICUCollator
== NULL
) {
74 fICUCollator
= fallbackICUCollator
;
75 // Unarchiving failed, so we revert to the fallback collator
76 // TODO: when can this happen, can it be avoided?
82 BCollator::BCollator(const BCollator
& other
)
90 BCollator::~BCollator()
96 BCollator
& BCollator::operator=(const BCollator
& source
)
98 if (&source
!= this) {
101 fICUCollator
= source
.fICUCollator
!= NULL
102 ? source
.fICUCollator
->clone()
104 fDefaultStrength
= source
.fDefaultStrength
;
105 fIgnorePunctuation
= source
.fIgnorePunctuation
;
113 BCollator::SetDefaultStrength(int8 strength
)
115 fDefaultStrength
= strength
;
120 BCollator::DefaultStrength() const
122 return fDefaultStrength
;
127 BCollator::SetIgnorePunctuation(bool ignore
)
129 fIgnorePunctuation
= ignore
;
134 BCollator::IgnorePunctuation() const
136 return fIgnorePunctuation
;
141 BCollator::GetSortKey(const char* string
, BString
* key
, int8 strength
) const
143 _SetStrength(strength
);
145 // TODO : handle fIgnorePunctuation
147 int length
= strlen(string
);
149 uint8_t* buffer
= (uint8_t*)malloc(length
* 2);
150 // According to ICU documentation this should be enough in "most cases"
154 UErrorCode error
= U_ZERO_ERROR
;
155 int requiredSize
= fICUCollator
->getSortKey(UnicodeString(string
, length
,
156 NULL
, error
), buffer
, length
* 2);
157 if (requiredSize
> length
* 2) {
158 buffer
= (uint8_t*)realloc(buffer
, requiredSize
);
162 error
= U_ZERO_ERROR
;
163 fICUCollator
->getSortKey(UnicodeString(string
, length
, NULL
, error
),
164 buffer
, requiredSize
);
167 key
->SetTo((char*)buffer
);
170 if (error
== U_ZERO_ERROR
)
178 BCollator::Compare(const char* s1
, const char* s2
, int8 strength
) const
180 _SetStrength(strength
);
182 // TODO : handle fIgnorePunctuation
184 UErrorCode error
= U_ZERO_ERROR
;
185 return fICUCollator
->compare(s1
, s2
, error
);
190 BCollator::Archive(BMessage
* archive
, bool deep
) const
192 status_t status
= BArchivable::Archive(archive
, deep
);
197 status
= archive
->AddInt32("loc:strength", fDefaultStrength
);
199 status
= archive
->AddBool("loc:punctuation", fIgnorePunctuation
);
201 UErrorCode error
= U_ZERO_ERROR
;
202 int size
= static_cast<RuleBasedCollator
*>(fICUCollator
)->cloneBinary(NULL
,
204 // This WILL fail with U_BUFFER_OVERFLOW_ERROR. But we get the needed
206 error
= U_ZERO_ERROR
;
207 uint8_t* buffer
= (uint8_t*)malloc(size
);
208 static_cast<RuleBasedCollator
*>(fICUCollator
)->cloneBinary(buffer
, size
,
211 if (status
== B_OK
&& error
== U_ZERO_ERROR
)
212 status
= archive
->AddData("loc:collator", B_RAW_TYPE
, buffer
, size
);
215 if (error
== U_ZERO_ERROR
)
222 BCollator::Instantiate(BMessage
* archive
)
224 if (validate_instantiation(archive
, "BCollator"))
225 return new(std::nothrow
) BCollator(archive
);
232 BCollator::_SetStrength(int8 strength
) const
234 if (strength
== B_COLLATE_DEFAULT
)
235 strength
= fDefaultStrength
;
237 Collator::ECollationStrength icuStrength
;
239 case B_COLLATE_PRIMARY
:
240 icuStrength
= Collator::PRIMARY
;
242 case B_COLLATE_SECONDARY
:
243 icuStrength
= Collator::SECONDARY
;
245 case B_COLLATE_TERTIARY
:
247 icuStrength
= Collator::TERTIARY
;
249 case B_COLLATE_QUATERNARY
:
250 icuStrength
= Collator::QUATERNARY
;
252 case B_COLLATE_IDENTICAL
:
253 icuStrength
= Collator::IDENTICAL
;
256 fICUCollator
->setStrength(icuStrength
);