blob: 1b2442932a4f811b35ce9e46c48033c22b32b3cf [file] [log] [blame]
/*
*******************************************************************************
*
* Copyright (C) 2009-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
*/
#ifndef COLL_FE_DEBUG
#define COLL_FE_DEBUG 0
#endif
#include <icuglue/icuglue.h>
#include <unicode/coll.h>
//#include <unicode/tblcoll.h>
#include <unicode/ucol.h>
#include <string.h>
#include <stdio.h>
#include "unicode/ustring.h"
#if COLL_FE_DEBUG
#define debugfprintf(x) fprintf x
#else
#define debugfprintf(x)
#endif
/*
* Before ICU 50.0.2 (50m2) - there was a different collator signature.
* see: ticket:9460 ticket:9346
*/
#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))
#define PRE_50_0_2_COLLATOR
#define CONST_BEFORE_50_0_2 const
#define CONST_AFTER_50_0_2
#define REF_AFTER_50_0_2
#else
/* "current" API */
#define CONST_BEFORE_50_0_2
#define CONST_AFTER_50_0_2 const
#define REF_AFTER_50_0_2 &
#endif
/**
* Macro to define the Collator_glue_4_2 class
*/
#define GLUE_VER(x) class GLUE_SYM_V( Collator, x ) : public Collator { \
\
public: static Collator *create(const Locale &loc, const char *ver); \
private: UCollator *_this; GLUE_SYM_V( Collator, x ) ( UCollator* tn ) : _this(tn){} \
virtual ~ GLUE_SYM_V ( Collator, x) (); \
public: \
virtual void* getDynamicClassID() const; \
static void* getStaticClassID() ; \
virtual Collator* clone() const; \
virtual UCollationResult compare(const UnicodeString&, const UnicodeString&, UErrorCode&) const; \
virtual UCollationResult compare(const UnicodeString&, const UnicodeString&, int32_t, UErrorCode&) const; \
virtual UCollationResult compare(const UChar*, int32_t, const UChar*, int32_t, UErrorCode&) const; \
virtual CollationKey& getCollationKey(const UnicodeString&, CollationKey&, UErrorCode&) const; \
virtual CollationKey& getCollationKey(const UChar*, int32_t, CollationKey&, UErrorCode&) const; \
virtual int32_t hashCode() const; \
virtual CONST_BEFORE_50_0_2 Locale getLocale(ULocDataLocaleType, UErrorCode&) const; \
virtual ECollationStrength getStrength() const; \
virtual void setStrength(ECollationStrength); \
virtual void getVersion(uint8_t*) const; \
virtual void setAttribute(UColAttribute, UColAttributeValue, UErrorCode&) ; \
virtual UColAttributeValue getAttribute(UColAttribute, UErrorCode&) CONST_AFTER_50_0_2; \
virtual uint32_t setVariableTop(const UChar*, int32_t, UErrorCode&); \
virtual uint32_t setVariableTop(const UnicodeString REF_AFTER_50_0_2, UErrorCode&); \
virtual void setVariableTop(uint32_t, UErrorCode&); \
virtual uint32_t getVariableTop(UErrorCode&) const; \
virtual Collator* safeClone() CONST_AFTER_50_0_2 ; \
virtual int32_t getSortKey(const UnicodeString&, uint8_t*, int32_t) const; \
virtual int32_t getSortKey(const UChar*, int32_t, uint8_t*, int32_t) const; \
public: static int32_t countAvailable(); \
public: static int32_t appendAvailable(UnicodeString* strs, int32_t i, int32_t count); \
public: virtual int32_t internalGetShortDefinitionString(const char *locale, char *buffer, int32_t capacity, UErrorCode &status) const; \
};
/** ==================================== The following code runs inside the 'target' version (i.e. old ICU) ========== **/
#if defined ( ICUGLUE_VER )
// these from tblcoll.h
static Collator::ECollationStrength _getECollationStrength(
const UCollationStrength &strength)
{
switch (strength)
{
case UCOL_PRIMARY :
return Collator::PRIMARY;
case UCOL_SECONDARY :
return Collator::SECONDARY;
case UCOL_TERTIARY :
return Collator::TERTIARY;
case UCOL_QUATERNARY :
return Collator::QUATERNARY;
default :
return Collator::IDENTICAL;
}
}
static UCollationStrength _getUCollationStrength(
const Collator::ECollationStrength &strength)
{
switch (strength)
{
case Collator::PRIMARY :
return UCOL_PRIMARY;
case Collator::SECONDARY :
return UCOL_SECONDARY;
case Collator::TERTIARY :
return UCOL_TERTIARY;
case Collator::QUATERNARY :
return UCOL_QUATERNARY;
default :
return UCOL_IDENTICAL;
}
}
/* code for some version */
#include <icuglue/gluren.h>
#include "oicu.h"
/* Expand GLUE_VER to define the class */
#ifdef GLUE_VER
GLUE_VER( ICUGLUE_VER )
#endif
GLUE_SYM ( Collator ) :: ~ GLUE_SYM(Collator) () {
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " ucol_close");
#endif
OICU_ucol_close(_this);
}
#if 0
U_CFUNC int32_t U_CALLCONV
GLUE_SYM ( glue_calcSortKey) (const UCollator *coll,
const UChar *source,
int32_t sourceLength,
uint8_t **result,
uint32_t resultLength,
UBool allocateSKBuffer,
UErrorCode *status);
#endif
Collator *
GLUE_SYM ( Collator ) :: create (const Locale &loc, const char */*ver*/) {
// TODO: save 'ver' off.
UErrorCode status = U_ZERO_ERROR;
char locBuf[200];
char kwvBuf[200];
int32_t len = loc.getKeywordValue("collation", kwvBuf, 200, status);
strcpy(locBuf,loc.getBaseName());
if(len>0) {
strcat(locBuf,"@collator=");
strcat(locBuf,kwvBuf);
}
UCollator * uc = OICU_ucol_open( locBuf, status);
if(U_FAILURE(status)) return NULL; // TODO: ERR?
Collator *c = new GLUE_SYM( Collator ) ( uc );
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " ucol_open=%s ->> %p\n", locBuf, c);
#endif
return c;
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION( GLUE_SYM( Collator ) )
Collator* GLUE_SYM ( Collator ) :: clone() const {
UErrorCode status = U_ZERO_ERROR;
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " clone %p -> " , this);
#endif
UCollator *clc = OICU_ucol_safeClone( _this, NULL, 0, &status);
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " .. safeclone %s _this %p-> %p " , u_errorName(status), _this, clc);
#endif
if(U_FAILURE(status)||clc==NULL) return NULL;
Collator *c = new GLUE_SYM( Collator ) ( clc );
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " .. wrap(%p) -> %p\n", clc, c);
#endif
return c;
}
UCollationResult GLUE_SYM ( Collator ) :: compare(const UnicodeString&, const UnicodeString&, UErrorCode&) const {
return (UCollationResult)0;
}
UCollationResult GLUE_SYM ( Collator ) :: compare(const UnicodeString&, const UnicodeString&, int32_t, UErrorCode&) const {
return (UCollationResult)0;
}
UCollationResult GLUE_SYM ( Collator ) :: compare(const UChar* s, int32_t sl, const UChar* d , int32_t dl, UErrorCode&/*e*/ ) const {
return OICU_ucol_strcoll(_this, s, sl, d, dl);
}
#include "unicode/sortkey.h"
static CollationKey kk;
CollationKey& GLUE_SYM ( Collator ) :: getCollationKey(const UnicodeString&, CollationKey&, UErrorCode&) const {
//#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " GCK - notimp");
//#endif
return kk;
}
CollationKey& GLUE_SYM ( Collator ) :: getCollationKey(const UChar*, int32_t, CollationKey&, UErrorCode&) const {
fprintf(stderr, "VCF " ICUGLUE_VER_STR " GKK2 - notimp");
return kk;
}
int32_t GLUE_SYM ( Collator ) :: hashCode() const {
return 0;
}
CONST_BEFORE_50_0_2 Locale GLUE_SYM ( Collator ) :: getLocale(ULocDataLocaleType, UErrorCode&) const {
return Locale();
}
Collator::ECollationStrength
GLUE_SYM ( Collator ) :: getStrength() const {
return _getECollationStrength(OICU_ucol_getStrength(_this));
}
void GLUE_SYM ( Collator ) :: setStrength(ECollationStrength s) {
OICU_ucol_setStrength(_this, _getUCollationStrength(s));
}
void GLUE_SYM ( Collator ) :: getVersion(uint8_t*) const {
}
void GLUE_SYM ( Collator ) :: setAttribute(UColAttribute, UColAttributeValue, UErrorCode&) {
}
UColAttributeValue GLUE_SYM ( Collator ) :: getAttribute(UColAttribute, UErrorCode&) CONST_AFTER_50_0_2 {
return (UColAttributeValue)0;
}
uint32_t GLUE_SYM ( Collator ) :: setVariableTop(const UChar*, int32_t, UErrorCode&) {
return 0;
}
uint32_t GLUE_SYM ( Collator ) :: setVariableTop(const UnicodeString REF_AFTER_50_0_2, UErrorCode&) {
return 0;
}
void GLUE_SYM ( Collator ) :: setVariableTop(uint32_t, UErrorCode&) {
}
uint32_t GLUE_SYM ( Collator ) :: getVariableTop(UErrorCode&) const {
return 0;
}
Collator* GLUE_SYM ( Collator ) :: safeClone() CONST_AFTER_50_0_2 {
return clone();
}
int32_t GLUE_SYM ( Collator ) :: getSortKey(const UnicodeString& s, uint8_t*buf, int32_t len) const {
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " GSK");
#endif
return getSortKey(s.getBuffer(),s.length(), buf, len);
}
int32_t GLUE_SYM ( Collator ) :: getSortKey(const UChar*s, int32_t l, uint8_t*d, int32_t b) const {
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " GKS");
#endif
return OICU_ucol_getSortKey(_this, s,l,d,b);
}
int32_t GLUE_SYM (Collator ) :: internalGetShortDefinitionString(const char *locale, char *buffer, int32_t capacity, UErrorCode &status) const {
if(U_FAILURE(status)) return 0;
int32_t intRes = OICU_ucol_getShortDefinitionString(_this, locale, buffer, capacity, &status);
int32_t newRes = (intRes += 7); /* _PICU38 */
int32_t remainCap = capacity - newRes;
if(remainCap < 0 && U_SUCCESS(status)) {
status = U_BUFFER_OVERFLOW_ERROR; /* ran out of space on our watch */
}
if(U_SUCCESS(status)) {
char *p = buffer+strlen(buffer);
strncat(p,"_PICU",5);
p +=5 ;
CPY_VERSTR(p, ICUGLUE_VER_STR);
p +=2;
if(remainCap>0) {
*(p++)=0;
}
}
return newRes;
}
int32_t GLUE_SYM ( Collator ) :: countAvailable() {
int32_t count = OICU_ucol_countAvailable();
return count;
}
int32_t GLUE_SYM ( Collator ) :: appendAvailable(UnicodeString* strs, int32_t i, int32_t /*count*/) {
int avail = OICU_ucol_countAvailable();
UErrorCode status = U_ZERO_ERROR;
OICU_u_init(&status);
#if COLL_FE_DEBUG
fprintf(stderr, "VCF " ICUGLUE_VER_STR " avail %d - init %s\n", avail, u_errorName(status));
#endif
for(int j=0;j<avail;j++) {
strs[i+j].append(OICU_ucol_getAvailable(j));
strs[i+j].append("@sp=icu");
if(IS_OLD_VERSTR(ICUGLUE_VER_STR)) {
strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MAJ] ); // X_y
strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MIN] ); // x_Y
} else {
strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MAJ] ); // Xy_
strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MIN] ); // xY_
}
#if COLL_FE_DEBUG
{
char foo[999];
const UChar *ss = strs[i+j].getTerminatedBuffer();
u_austrcpy(foo, ss);
debugfprintf((stderr, "VCF " ICUGLUE_VER_STR " appending [%d+%d=%d] <<%s>>\n", i, j, i+j, foo));
}
#endif
}
return OICU_ucol_countAvailable();
}
#else
/** ==================================== The following code runs inside the 'provider' version (i.e. current ICU) ========== **/
// define Collator_XX
#include "icuglue/glver.h"
// generate list of versions
static
#include <icuglue/fe_verlist.h>
class VersionCollatorFactory : public CollatorFactory {
public:
virtual Collator *createCollator(const Locale &loc);
virtual const UnicodeString *getSupportedIDs(int32_t &count, UErrorCode &status);
virtual void* getDynamicClassID() const;
static void* getStaticClassID() ;
};
UOBJECT_DEFINE_RTTI_IMPLEMENTATION( VersionCollatorFactory )
Collator *VersionCollatorFactory::createCollator(const Locale &loc) {
// pull off provider #
char provider[200];
UErrorCode status = U_ZERO_ERROR;
#if COLL_FE_DEBUG
fprintf(stderr, "VCF:CC %s\n", loc.getName());
#endif
int32_t len = loc.getKeywordValue("sp", provider, 200, status);
if(U_FAILURE(status)||len==0) return NULL;
#if COLL_FE_DEBUG
fprintf(stderr, "VCF:KWV> %s/%d\n", u_errorName(status), len);
#endif
provider[len]=0;
#if COLL_FE_DEBUG
fprintf(stderr, "VCF:KWV %s\n", provider);
#endif
if(strncmp(provider,"icu",3)) return NULL;
const char *icuver=provider+3;
#if COLL_FE_DEBUG
fprintf(stderr, "VCF:ICUV %s\n", icuver);
#endif
#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) \
debugfprintf((stderr,"%c/%c|%c/%c\n", icuver[0],(#x)[0],icuver[1],(#x)[2])); \
if(CMP_VERSTR(icuver, (#x))) { \
Collator *c = glue ## Collator ## x :: create(loc, icuver); \
debugfprintf((stderr, "VCF::CC %s -> %p\n", loc.getName(), c)); \
return c; \
}
#include "icuglue/glver.h"
#if COLL_FE_DEBUG
fprintf(stderr, "VCF:CC %s failed\n", loc.getName());
#endif
return NULL;
}
static const UnicodeString *gLocales = NULL;
static int32_t gLocCount = 0;
const UnicodeString
*VersionCollatorFactory::getSupportedIDs(int32_t &count, UErrorCode &/*status*/) {
if(gLocales==NULL) {
count = 0;
/* gather counts */
#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) count += glue ## Collator ## x :: countAvailable();
#include "icuglue/glver.h"
#if COLL_FE_DEBUG
printf("VCF: count=%d\n", count);
#endif
UnicodeString *strs = new UnicodeString[count];
int32_t i = 0;
#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) i += glue ## Collator ## x :: appendAvailable(strs, i, count);
#include "icuglue/glver.h"
#if COLL_FE_DEBUG
printf("VCF: appended count=%d\n", count);
#endif
gLocCount = count;
gLocales = strs;
}
count = gLocCount;
return gLocales;
}
/* Plugin Code */
#include <stdio.h>
#include <unicode/uversion.h>
static URegistryKey rk = NULL;
void coll_provider_register(UErrorCode &status) {
rk = Collator::registerFactory(new VersionCollatorFactory(), status);
}
void coll_provider_unregister(UErrorCode &status) {
Collator::unregister(rk, status);
}
/* Plugin- only ICU 4.4+ */
#if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM==4)&&(U_ICU_VERSION_MINOR_NUM>3))
#include "unicode/icuplug.h"
U_CAPI UPlugTokenReturn U_EXPORT2 coll_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status);
U_CAPI UPlugTokenReturn U_EXPORT2 coll_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status)
{
switch(reason) {
case UPLUG_REASON_QUERY:
uplug_setPlugName(data, "Collation Provider Plugin");
uplug_setPlugLevel(data, UPLUG_LEVEL_HIGH);
break;
case UPLUG_REASON_LOAD:
coll_provider_register(*status);
break;
case UPLUG_REASON_UNLOAD:
coll_provider_unregister(*status);
break;
default:
break; /* not handled */
}
return UPLUG_TOKEN;
}
#else
/*
Note: this ICU version must explicitly call 'coll_provider_plugin'
*/
#endif /* plugin */
#endif /* provider side (vs target) */