1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 2009-2012, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 */
11
12 #ifndef COLL_FE_DEBUG
13 #define COLL_FE_DEBUG 0
14 #endif
15
16 #include <icuglue/icuglue.h>
17 #include <unicode/coll.h>
18 //#include <unicode/tblcoll.h>
19 #include <unicode/ucol.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include "unicode/ustring.h"
23
24 #if COLL_FE_DEBUG
25 #define debugfprintf(x) fprintf x
26 #else
27 #define debugfprintf(x)
28 #endif
29
30 /*
31 * Before ICU 50.0.2 (50m2) - there was a different collator signature.
32 * see: ticket:9460 ticket:9346
33 */
34 #if (U_ICU_VERSION_MAJOR_NUM < 50) || ((U_ICU_VERSION_MAJOR_NUM==50)&&(U_ICU_VERSION_MINOR_NUM==0)&&(U_ICU_VERSION_PATCHLEVEL_NUM<2))
35 #define PRE_50_0_2_COLLATOR
36 #define CONST_BEFORE_50_0_2 const
37 #define CONST_AFTER_50_0_2
38 #define REF_AFTER_50_0_2
39 #else
40 /* "current" API */
41 #define CONST_BEFORE_50_0_2
42 #define CONST_AFTER_50_0_2 const
43 #define REF_AFTER_50_0_2 &
44 #endif
45
46 /**
47 * Macro to define the Collator_glue_4_2 class
48 */
49 #define GLUE_VER(x) class GLUE_SYM_V( Collator, x ) : public Collator { \
50 \
51 public: static Collator *create(const Locale &loc, const char *ver); \
52 private: UCollator *_this; GLUE_SYM_V( Collator, x ) ( UCollator* tn ) : _this(tn){} \
53 virtual ~ GLUE_SYM_V ( Collator, x) (); \
54 public: \
55 virtual void* getDynamicClassID() const; \
56 static void* getStaticClassID() ; \
57 virtual Collator* clone() const; \
58 virtual UCollationResult compare(const UnicodeString&, const UnicodeString&, UErrorCode&) const; \
59 virtual UCollationResult compare(const UnicodeString&, const UnicodeString&, int32_t, UErrorCode&) const; \
60 virtual UCollationResult compare(const UChar*, int32_t, const UChar*, int32_t, UErrorCode&) const; \
61 virtual CollationKey& getCollationKey(const UnicodeString&, CollationKey&, UErrorCode&) const; \
62 virtual CollationKey& getCollationKey(const UChar*, int32_t, CollationKey&, UErrorCode&) const; \
63 virtual int32_t hashCode() const; \
64 virtual CONST_BEFORE_50_0_2 Locale getLocale(ULocDataLocaleType, UErrorCode&) const; \
65 virtual ECollationStrength getStrength() const; \
66 virtual void setStrength(ECollationStrength); \
67 virtual void getVersion(uint8_t*) const; \
68 virtual void setAttribute(UColAttribute, UColAttributeValue, UErrorCode&) ; \
69 virtual UColAttributeValue getAttribute(UColAttribute, UErrorCode&) CONST_AFTER_50_0_2; \
70 virtual uint32_t setVariableTop(const UChar*, int32_t, UErrorCode&); \
71 virtual uint32_t setVariableTop(const UnicodeString REF_AFTER_50_0_2, UErrorCode&); \
72 virtual void setVariableTop(uint32_t, UErrorCode&); \
73 virtual uint32_t getVariableTop(UErrorCode&) const; \
74 virtual Collator* safeClone() CONST_AFTER_50_0_2 ; \
75 virtual int32_t getSortKey(const UnicodeString&, uint8_t*, int32_t) const; \
76 virtual int32_t getSortKey(const UChar*, int32_t, uint8_t*, int32_t) const; \
77 public: static int32_t countAvailable(); \
78 public: static int32_t appendAvailable(UnicodeString* strs, int32_t i, int32_t count); \
79 public: virtual int32_t internalGetShortDefinitionString(const char *locale, char *buffer, int32_t capacity, UErrorCode &status) const; \
80 };
81
82 /** ==================================== The following code runs inside the 'target' version (i.e. old ICU) ========== **/
83 #if defined ( ICUGLUE_VER )
84
85
86 // these from tblcoll.h
_getECollationStrength(const UCollationStrength & strength)87 static Collator::ECollationStrength _getECollationStrength(
88 const UCollationStrength &strength)
89 {
90 switch (strength)
91 {
92 case UCOL_PRIMARY :
93 return Collator::PRIMARY;
94 case UCOL_SECONDARY :
95 return Collator::SECONDARY;
96 case UCOL_TERTIARY :
97 return Collator::TERTIARY;
98 case UCOL_QUATERNARY :
99 return Collator::QUATERNARY;
100 default :
101 return Collator::IDENTICAL;
102 }
103 }
104
_getUCollationStrength(const Collator::ECollationStrength & strength)105 static UCollationStrength _getUCollationStrength(
106 const Collator::ECollationStrength &strength)
107 {
108 switch (strength)
109 {
110 case Collator::PRIMARY :
111 return UCOL_PRIMARY;
112 case Collator::SECONDARY :
113 return UCOL_SECONDARY;
114 case Collator::TERTIARY :
115 return UCOL_TERTIARY;
116 case Collator::QUATERNARY :
117 return UCOL_QUATERNARY;
118 default :
119 return UCOL_IDENTICAL;
120 }
121 }
122
123
124
125 /* code for some version */
126 #include <icuglue/gluren.h>
127
128 #include "oicu.h"
129
130 /* Expand GLUE_VER to define the class */
131 #ifdef GLUE_VER
132 GLUE_VER( ICUGLUE_VER )
133 #endif
134
GLUE_SYM(Collator)135 GLUE_SYM ( Collator ) :: ~ GLUE_SYM(Collator) () {
136 #if COLL_FE_DEBUG
137 fprintf(stderr, "VCF " ICUGLUE_VER_STR " ucol_close");
138 #endif
139 OICU_ucol_close(_this);
140 }
141
142 #if 0
143 U_CFUNC int32_t U_CALLCONV
144 GLUE_SYM ( glue_calcSortKey) (const UCollator *coll,
145 const UChar *source,
146 int32_t sourceLength,
147 uint8_t **result,
148 uint32_t resultLength,
149 UBool allocateSKBuffer,
150 UErrorCode *status);
151
152 #endif
153
154 Collator *
GLUE_SYM(Collator)155 GLUE_SYM ( Collator ) :: create (const Locale &loc, const char */*ver*/) {
156 // TODO: save 'ver' off.
157 UErrorCode status = U_ZERO_ERROR;
158 char locBuf[200];
159 char kwvBuf[200];
160 int32_t len = loc.getKeywordValue("collation", kwvBuf, 200, status);
161 strcpy(locBuf,loc.getBaseName());
162 if(len>0) {
163 strcat(locBuf,"@collator=");
164 strcat(locBuf,kwvBuf);
165 }
166 UCollator * uc = OICU_ucol_open( locBuf, status);
167 if(U_FAILURE(status)) return NULL; // TODO: ERR?
168 Collator *c = new GLUE_SYM( Collator ) ( uc );
169 #if COLL_FE_DEBUG
170 fprintf(stderr, "VCF " ICUGLUE_VER_STR " ucol_open=%s ->> %p\n", locBuf, c);
171 #endif
172 return c;
173 }
174
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GLUE_SYM (Collator))175 UOBJECT_DEFINE_RTTI_IMPLEMENTATION( GLUE_SYM( Collator ) )
176
177 Collator* GLUE_SYM ( Collator ) :: clone() const {
178 UErrorCode status = U_ZERO_ERROR;
179 #if COLL_FE_DEBUG
180 fprintf(stderr, "VCF " ICUGLUE_VER_STR " clone %p -> " , this);
181 #endif
182 UCollator *clc = OICU_ucol_safeClone( _this, NULL, 0, &status);
183 #if COLL_FE_DEBUG
184 fprintf(stderr, "VCF " ICUGLUE_VER_STR " .. safeclone %s _this %p-> %p " , u_errorName(status), _this, clc);
185 #endif
186 if(U_FAILURE(status)||clc==NULL) return NULL;
187 Collator *c = new GLUE_SYM( Collator ) ( clc );
188 #if COLL_FE_DEBUG
189 fprintf(stderr, "VCF " ICUGLUE_VER_STR " .. wrap(%p) -> %p\n", clc, c);
190 #endif
191
192 return c;
193 }
194
195
GLUE_SYM(Collator)196 UCollationResult GLUE_SYM ( Collator ) :: compare(const UnicodeString&, const UnicodeString&, UErrorCode&) const {
197 return (UCollationResult)0;
198 }
199
200
GLUE_SYM(Collator)201 UCollationResult GLUE_SYM ( Collator ) :: compare(const UnicodeString&, const UnicodeString&, int32_t, UErrorCode&) const {
202 return (UCollationResult)0;
203 }
204
205
GLUE_SYM(Collator)206 UCollationResult GLUE_SYM ( Collator ) :: compare(const UChar* s, int32_t sl, const UChar* d , int32_t dl, UErrorCode&/*e*/ ) const {
207 return OICU_ucol_strcoll(_this, s, sl, d, dl);
208 }
209
210 #include "unicode/sortkey.h"
211
212 static CollationKey kk;
213
GLUE_SYM(Collator)214 CollationKey& GLUE_SYM ( Collator ) :: getCollationKey(const UnicodeString&, CollationKey&, UErrorCode&) const {
215 //#if COLL_FE_DEBUG
216 fprintf(stderr, "VCF " ICUGLUE_VER_STR " GCK - notimp");
217 //#endif
218 return kk;
219 }
220
221
GLUE_SYM(Collator)222 CollationKey& GLUE_SYM ( Collator ) :: getCollationKey(const UChar*, int32_t, CollationKey&, UErrorCode&) const {
223 fprintf(stderr, "VCF " ICUGLUE_VER_STR " GKK2 - notimp");
224 return kk;
225 }
226
227
GLUE_SYM(Collator)228 int32_t GLUE_SYM ( Collator ) :: hashCode() const {
229 return 0;
230 }
231
232
GLUE_SYM(Collator)233 CONST_BEFORE_50_0_2 Locale GLUE_SYM ( Collator ) :: getLocale(ULocDataLocaleType, UErrorCode&) const {
234 return Locale();
235 }
236
237
238 Collator::ECollationStrength
GLUE_SYM(Collator)239 GLUE_SYM ( Collator ) :: getStrength() const {
240 return _getECollationStrength(OICU_ucol_getStrength(_this));
241 }
242
243
GLUE_SYM(Collator)244 void GLUE_SYM ( Collator ) :: setStrength(ECollationStrength s) {
245 OICU_ucol_setStrength(_this, _getUCollationStrength(s));
246 }
247
248
GLUE_SYM(Collator)249 void GLUE_SYM ( Collator ) :: getVersion(uint8_t*) const {
250 }
251
252
GLUE_SYM(Collator)253 void GLUE_SYM ( Collator ) :: setAttribute(UColAttribute, UColAttributeValue, UErrorCode&) {
254 }
255
256
GLUE_SYM(Collator)257 UColAttributeValue GLUE_SYM ( Collator ) :: getAttribute(UColAttribute, UErrorCode&) CONST_AFTER_50_0_2 {
258 return (UColAttributeValue)0;
259 }
260
261
GLUE_SYM(Collator)262 uint32_t GLUE_SYM ( Collator ) :: setVariableTop(const UChar*, int32_t, UErrorCode&) {
263 return 0;
264 }
265
266
GLUE_SYM(Collator)267 uint32_t GLUE_SYM ( Collator ) :: setVariableTop(const UnicodeString REF_AFTER_50_0_2, UErrorCode&) {
268 return 0;
269 }
270
271
GLUE_SYM(Collator)272 void GLUE_SYM ( Collator ) :: setVariableTop(uint32_t, UErrorCode&) {
273 }
274
275
GLUE_SYM(Collator)276 uint32_t GLUE_SYM ( Collator ) :: getVariableTop(UErrorCode&) const {
277 return 0;
278 }
279
280
GLUE_SYM(Collator)281 Collator* GLUE_SYM ( Collator ) :: safeClone() CONST_AFTER_50_0_2 {
282 return clone();
283 }
284
285
GLUE_SYM(Collator)286 int32_t GLUE_SYM ( Collator ) :: getSortKey(const UnicodeString& s, uint8_t*buf, int32_t len) const {
287 #if COLL_FE_DEBUG
288 fprintf(stderr, "VCF " ICUGLUE_VER_STR " GSK");
289 #endif
290 return getSortKey(s.getBuffer(),s.length(), buf, len);
291 }
292
293
294
295
GLUE_SYM(Collator)296 int32_t GLUE_SYM ( Collator ) :: getSortKey(const UChar*s, int32_t l, uint8_t*d, int32_t b) const {
297 #if COLL_FE_DEBUG
298 fprintf(stderr, "VCF " ICUGLUE_VER_STR " GKS");
299 #endif
300 return OICU_ucol_getSortKey(_this, s,l,d,b);
301 }
302
GLUE_SYM(Collator)303 int32_t GLUE_SYM (Collator ) :: internalGetShortDefinitionString(const char *locale, char *buffer, int32_t capacity, UErrorCode &status) const {
304 if(U_FAILURE(status)) return 0;
305 int32_t intRes = OICU_ucol_getShortDefinitionString(_this, locale, buffer, capacity, &status);
306 int32_t newRes = (intRes += 7); /* _PICU38 */
307 int32_t remainCap = capacity - newRes;
308
309 if(remainCap < 0 && U_SUCCESS(status)) {
310 status = U_BUFFER_OVERFLOW_ERROR; /* ran out of space on our watch */
311 }
312 if(U_SUCCESS(status)) {
313 char *p = buffer+strlen(buffer);
314 strncat(p,"_PICU",5);
315 p +=5 ;
316 CPY_VERSTR(p, ICUGLUE_VER_STR);
317 p +=2;
318 if(remainCap>0) {
319 *(p++)=0;
320 }
321 }
322 return newRes;
323 }
324
325
326
GLUE_SYM(Collator)327 int32_t GLUE_SYM ( Collator ) :: countAvailable() {
328 int32_t count = OICU_ucol_countAvailable();
329 return count;
330 }
331
332
GLUE_SYM(Collator)333 int32_t GLUE_SYM ( Collator ) :: appendAvailable(UnicodeString* strs, int32_t i, int32_t /*count*/) {
334 int avail = OICU_ucol_countAvailable();
335 UErrorCode status = U_ZERO_ERROR;
336 OICU_u_init(&status);
337 #if COLL_FE_DEBUG
338 fprintf(stderr, "VCF " ICUGLUE_VER_STR " avail %d - init %s\n", avail, u_errorName(status));
339 #endif
340 for(int j=0;j<avail;j++) {
341 strs[i+j].append(OICU_ucol_getAvailable(j));
342 strs[i+j].append("@sp=icu");
343
344 if(IS_OLD_VERSTR(ICUGLUE_VER_STR)) {
345 strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MAJ] ); // X_y
346 strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MIN] ); // x_Y
347 } else {
348 strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MAJ] ); // Xy_
349 strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MIN] ); // xY_
350 }
351
352 #if COLL_FE_DEBUG
353 {
354 char foo[999];
355 const UChar *ss = strs[i+j].getTerminatedBuffer();
356 u_austrcpy(foo, ss);
357 debugfprintf((stderr, "VCF " ICUGLUE_VER_STR " appending [%d+%d=%d] <<%s>>\n", i, j, i+j, foo));
358 }
359 #endif
360 }
361 return OICU_ucol_countAvailable();
362 }
363
364
365
366 #else
367 /** ==================================== The following code runs inside the 'provider' version (i.e. current ICU) ========== **/
368
369 // define Collator_XX
370 #include "icuglue/glver.h"
371
372 // generate list of versions
373 static
374 #include <icuglue/fe_verlist.h>
375
376 class VersionCollatorFactory : public CollatorFactory {
377 public:
378 virtual Collator *createCollator(const Locale &loc);
379 virtual const UnicodeString *getSupportedIDs(int32_t &count, UErrorCode &status);
380 virtual void* getDynamicClassID() const;
381 static void* getStaticClassID() ;
382 };
383
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(VersionCollatorFactory)384 UOBJECT_DEFINE_RTTI_IMPLEMENTATION( VersionCollatorFactory )
385
386 Collator *VersionCollatorFactory::createCollator(const Locale &loc) {
387 // pull off provider #
388 char provider[200];
389 UErrorCode status = U_ZERO_ERROR;
390 #if COLL_FE_DEBUG
391 fprintf(stderr, "VCF:CC %s\n", loc.getName());
392 #endif
393 int32_t len = loc.getKeywordValue("sp", provider, 200, status);
394 if(U_FAILURE(status)||len==0) return NULL;
395 #if COLL_FE_DEBUG
396 fprintf(stderr, "VCF:KWV> %s/%d\n", u_errorName(status), len);
397 #endif
398 provider[len]=0;
399 #if COLL_FE_DEBUG
400 fprintf(stderr, "VCF:KWV %s\n", provider);
401 #endif
402 if(strncmp(provider,"icu",3)) return NULL;
403 const char *icuver=provider+3;
404 #if COLL_FE_DEBUG
405 fprintf(stderr, "VCF:ICUV %s\n", icuver);
406 #endif
407
408 #if defined(GLUE_VER)
409 #undef GLUE_VER
410 #endif
411
412 #define GLUE_VER(x) \
413 debugfprintf((stderr,"%c/%c|%c/%c\n", icuver[0],(#x)[0],icuver[1],(#x)[2])); \
414 if(CMP_VERSTR(icuver, (#x))) { \
415 Collator *c = glue ## Collator ## x :: create(loc, icuver); \
416 debugfprintf((stderr, "VCF::CC %s -> %p\n", loc.getName(), c)); \
417 return c; \
418 }
419
420 #include "icuglue/glver.h"
421 #if COLL_FE_DEBUG
422 fprintf(stderr, "VCF:CC %s failed\n", loc.getName());
423 #endif
424
425 return NULL;
426 }
427
428
429 static const UnicodeString *gLocales = NULL;
430 static int32_t gLocCount = 0;
431
432 const UnicodeString
getSupportedIDs(int32_t & count,UErrorCode &)433 *VersionCollatorFactory::getSupportedIDs(int32_t &count, UErrorCode &/*status*/) {
434 if(gLocales==NULL) {
435 count = 0;
436
437
438 /* gather counts */
439 #if defined(GLUE_VER)
440 #undef GLUE_VER
441 #endif
442 #define GLUE_VER(x) count += glue ## Collator ## x :: countAvailable();
443 #include "icuglue/glver.h"
444
445 #if COLL_FE_DEBUG
446 printf("VCF: count=%d\n", count);
447 #endif
448 UnicodeString *strs = new UnicodeString[count];
449 int32_t i = 0;
450
451 #if defined(GLUE_VER)
452 #undef GLUE_VER
453 #endif
454 #define GLUE_VER(x) i += glue ## Collator ## x :: appendAvailable(strs, i, count);
455 #include "icuglue/glver.h"
456
457 #if COLL_FE_DEBUG
458 printf("VCF: appended count=%d\n", count);
459 #endif
460
461 gLocCount = count;
462 gLocales = strs;
463 }
464 count = gLocCount;
465 return gLocales;
466 }
467
468
469 /* Plugin Code */
470
471 #include <stdio.h>
472 #include <unicode/uversion.h>
473
474 static URegistryKey rk = NULL;
475
coll_provider_register(UErrorCode & status)476 void coll_provider_register(UErrorCode &status) {
477 rk = Collator::registerFactory(new VersionCollatorFactory(), status);
478 }
479
coll_provider_unregister(UErrorCode & status)480 void coll_provider_unregister(UErrorCode &status) {
481 Collator::unregister(rk, status);
482 }
483
484 /* Plugin- only ICU 4.4+ */
485 #if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM==4)&&(U_ICU_VERSION_MINOR_NUM>3))
486 #include "unicode/icuplug.h"
487
488 U_CAPI UPlugTokenReturn U_EXPORT2 coll_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status);
489
coll_provider_plugin(UPlugData * data,UPlugReason reason,UErrorCode * status)490 U_CAPI UPlugTokenReturn U_EXPORT2 coll_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status)
491 {
492 switch(reason) {
493 case UPLUG_REASON_QUERY:
494 uplug_setPlugName(data, "Collation Provider Plugin");
495 uplug_setPlugLevel(data, UPLUG_LEVEL_HIGH);
496 break;
497 case UPLUG_REASON_LOAD:
498 coll_provider_register(*status);
499 break;
500 case UPLUG_REASON_UNLOAD:
501 coll_provider_unregister(*status);
502 break;
503 default:
504 break; /* not handled */
505 }
506 return UPLUG_TOKEN;
507 }
508 #else
509
510 /*
511 Note: this ICU version must explicitly call 'coll_provider_plugin'
512 */
513
514 #endif /* plugin */
515
516 #endif /* provider side (vs target) */
517