BPicture: Fix archive constructor.
[haiku.git] / src / kits / locale / Collator.cpp
blobcfb0f9445af166617ddff0011f8a33607adc4276
1 /*
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.
5 */
8 #include <unicode/uversion.h>
9 #include <Collator.h>
11 #include <ctype.h>
12 #include <stdlib.h>
14 #include <new>
15 #include <typeinfo>
17 #include <UnicodeChar.h>
18 #include <String.h>
19 #include <Message.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)
51 BArchivable(archive),
52 fICUCollator(NULL),
53 fDefaultStrength(B_COLLATE_PRIMARY),
54 fIgnorePunctuation(true)
56 int32 data;
57 if (archive->FindInt32("loc:strength", &data) == B_OK)
58 fDefaultStrength = (uint8)data;
59 else
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));
68 ssize_t size;
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)
84 fICUCollator(NULL)
86 *this = other;
90 BCollator::~BCollator()
92 delete fICUCollator;
96 BCollator& BCollator::operator=(const BCollator& source)
98 if (&source != this) {
99 delete fICUCollator;
101 fICUCollator = source.fICUCollator != NULL
102 ? source.fICUCollator->clone()
103 : NULL;
104 fDefaultStrength = source.fDefaultStrength;
105 fIgnorePunctuation = source.fIgnorePunctuation;
108 return *this;
112 void
113 BCollator::SetDefaultStrength(int8 strength)
115 fDefaultStrength = strength;
119 int8
120 BCollator::DefaultStrength() const
122 return fDefaultStrength;
126 void
127 BCollator::SetIgnorePunctuation(bool ignore)
129 fIgnorePunctuation = ignore;
133 bool
134 BCollator::IgnorePunctuation() const
136 return fIgnorePunctuation;
140 status_t
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"
151 if (buffer == NULL)
152 return B_NO_MEMORY;
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);
159 if (buffer == NULL)
160 return B_NO_MEMORY;
162 error = U_ZERO_ERROR;
163 fICUCollator->getSortKey(UnicodeString(string, length, NULL, error),
164 buffer, requiredSize);
167 key->SetTo((char*)buffer);
168 free(buffer);
170 if (error == U_ZERO_ERROR)
171 return B_OK;
173 return B_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);
189 status_t
190 BCollator::Archive(BMessage* archive, bool deep) const
192 status_t status = BArchivable::Archive(archive, deep);
193 if (status < B_OK)
194 return status;
196 if (status == B_OK)
197 status = archive->AddInt32("loc:strength", fDefaultStrength);
198 if (status == B_OK)
199 status = archive->AddBool("loc:punctuation", fIgnorePunctuation);
201 UErrorCode error = U_ZERO_ERROR;
202 int size = static_cast<RuleBasedCollator*>(fICUCollator)->cloneBinary(NULL,
203 0, error);
204 // This WILL fail with U_BUFFER_OVERFLOW_ERROR. But we get the needed
205 // size.
206 error = U_ZERO_ERROR;
207 uint8_t* buffer = (uint8_t*)malloc(size);
208 static_cast<RuleBasedCollator*>(fICUCollator)->cloneBinary(buffer, size,
209 error);
211 if (status == B_OK && error == U_ZERO_ERROR)
212 status = archive->AddData("loc:collator", B_RAW_TYPE, buffer, size);
213 free(buffer);
215 if (error == U_ZERO_ERROR)
216 return status;
217 return B_ERROR;
221 BArchivable*
222 BCollator::Instantiate(BMessage* archive)
224 if (validate_instantiation(archive, "BCollator"))
225 return new(std::nothrow) BCollator(archive);
227 return NULL;
231 status_t
232 BCollator::_SetStrength(int8 strength) const
234 if (strength == B_COLLATE_DEFAULT)
235 strength = fDefaultStrength;
237 Collator::ECollationStrength icuStrength;
238 switch (strength) {
239 case B_COLLATE_PRIMARY:
240 icuStrength = Collator::PRIMARY;
241 break;
242 case B_COLLATE_SECONDARY:
243 icuStrength = Collator::SECONDARY;
244 break;
245 case B_COLLATE_TERTIARY:
246 default:
247 icuStrength = Collator::TERTIARY;
248 break;
249 case B_COLLATE_QUATERNARY:
250 icuStrength = Collator::QUATERNARY;
251 break;
252 case B_COLLATE_IDENTICAL:
253 icuStrength = Collator::IDENTICAL;
254 break;
256 fICUCollator->setStrength(icuStrength);
258 return B_OK;