usprep.cpp revision c73f511526464f8e56c242df80552e9b0d94ae3d
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *******************************************************************************
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Copyright (C) 2003-2013, International Business Machines
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Corporation and others.  All Rights Reserved.
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *******************************************************************************
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   file name:  usprep.cpp
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   encoding:   US-ASCII
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   tab size:   8 (not used)
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   indentation:4
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   created on: 2003jul2
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   created by: Ram Viswanadha
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/utypes.h"
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if !UCONFIG_NO_IDNA
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/usprep.h"
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/unorm.h"
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/ustring.h"
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/uchar.h"
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "unicode/uversion.h"
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "umutex.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "cmemory.h"
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "sprpimpl.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ustr_imp.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "uhash.h"
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "cstring.h"
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "udataswp.h"
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ucln_cmn.h"
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ubidi_props.h"
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_NAMESPACE_USE
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_CDECL_BEGIN
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
41fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch/*
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Static cache for already opened StringPrep profiles
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)*/
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UHashtable *SHARED_DATA_HASHTABLE = NULL;
4507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochstatic icu::UInitOnce gSharedDataInitOnce;
4607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UMutex usprepMutex = U_MUTEX_INITIALIZER;
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* format version of spp file */
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
5193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
5293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/* the Unicode version of the sprep data */
5393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static UVersionInfo dataVersion={ 0, 0, 0, 0 };
5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* Profile names must be aligned to UStringPrepProfileType */
567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic const char * const PROFILE_NAMES[] = {
577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "rfc3491",      /* USPREP_RFC3491_NAMEPREP */
587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "rfc3530cs",    /* USPREP_RFC3530_NFS4_CS_PREP */
597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "rfc3530csci",  /* USPREP_RFC3530_NFS4_CS_PREP_CI */
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3491",      /* USPREP_RFC3530_NSF4_CIS_PREP */
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3530mixp",  /* USPREP_RFC3530_NSF4_MIXED_PREP_PREFIX */
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3491",      /* USPREP_RFC3530_NSF4_MIXED_PREP_SUFFIX */
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3722",      /* USPREP_RFC3722_ISCSI */
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3920node",  /* USPREP_RFC3920_NODEPREP */
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc3920res",   /* USPREP_RFC3920_RESOURCEPREP */
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc4011",      /* USPREP_RFC4011_MIB */
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc4013",      /* USPREP_RFC4013_SASLPREP */
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc4505",      /* USPREP_RFC4505_TRACE */
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc4518",      /* USPREP_RFC4518_LDAP */
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "rfc4518ci",    /* USPREP_RFC4518_LDAP_CI */
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UBool U_CALLCONV
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)isSPrepAcceptable(void * /* context */,
75fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch             const char * /* type */,
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             const char * /* name */,
77591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch             const UDataInfo *pInfo) {
78e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    if(
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->size>=20 &&
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->charsetFamily==U_CHARSET_FAMILY &&
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[0]==0x53 &&   /* dataFormat="SPRP" */
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[1]==0x50 &&
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[2]==0x52 &&
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[3]==0x50 &&
86fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        pInfo->formatVersion[0]==3 &&
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->formatVersion[2]==UTRIE_SHIFT &&
881fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ) {
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        //uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
921fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        return TRUE;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FALSE;
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int32_t U_CALLCONV
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)getSPrepFoldingOffset(uint32_t data) {
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return (int32_t)data;
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
10493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
10593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/* hashes an entry  */
10693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static int32_t U_CALLCONV
10793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)hashEntry(const UHashTok parm) {
10893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    UStringPrepKey *b = (UStringPrepKey *)parm.pointer;
10993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    UHashTok namekey, pathkey;
11093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    namekey.pointer = b->name;
11193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    pathkey.pointer = b->path;
11293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey);
11393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
11493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
11593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/* compares two entries */
11693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)static UBool U_CALLCONV
11793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)compareEntries(const UHashTok p1, const UHashTok p2) {
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepKey *b1 = (UStringPrepKey *)p1.pointer;
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepKey *b2 = (UStringPrepKey *)p2.pointer;
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UHashTok name1, name2, path1, path2;
12193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    name1.pointer = b1->name;
122fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    name2.pointer = b2->name;
12393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    path1.pointer = b1->path;
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    path2.pointer = b2->path;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return ((UBool)(uhash_compareChars(name1, name2) &
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uhash_compareChars(path1, path2)));
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_unload(UStringPrepProfile* data){
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    udata_close(data->sprepData);
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int32_t
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_internal_flushCache(UBool noRefCount){
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepProfile *profile = NULL;
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepKey  *key  = NULL;
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t pos = -1;
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t deletedNum = 0;
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const UHashElement *e;
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
142fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    /*
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * if shared data hasn't even been lazy evaluated yet
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * return 0
145fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch     */
1461fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    umtx_lock(&usprepMutex);
1471fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    if (SHARED_DATA_HASHTABLE == NULL) {
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        umtx_unlock(&usprepMutex);
1491fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        return 0;
1501fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    }
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1521fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    /*creates an enumeration to iterate through every element in the table */
1531fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    while ((e = uhash_nextElement(SHARED_DATA_HASHTABLE, &pos)) != NULL)
1541fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    {
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        profile = (UStringPrepProfile *) e->value.pointer;
1561fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        key  = (UStringPrepKey *) e->key.pointer;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if ((noRefCount== FALSE && profile->refCount == 0) ||
15909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)             noRefCount== TRUE) {
16009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            deletedNum++;
16109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            uhash_removeElement(SHARED_DATA_HASHTABLE, e);
16209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
16309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            /* unload the data */
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            usprep_unload(profile);
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(key->name != NULL) {
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                uprv_free(key->name);
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                key->name=NULL;
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(key->path != NULL) {
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                uprv_free(key->path);
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                key->path=NULL;
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_free(profile);
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_free(key);
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    umtx_unlock(&usprepMutex);
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return deletedNum;
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* Works just like ucnv_flushCache()
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int32_t
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_flushCache(){
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return usprep_internal_flushCache(FALSE);
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)*/
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UBool U_CALLCONV usprep_cleanup(void){
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (SHARED_DATA_HASHTABLE != NULL) {
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        usprep_internal_flushCache(TRUE);
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uhash_close(SHARED_DATA_HASHTABLE);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            SHARED_DATA_HASHTABLE = NULL;
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    gSharedDataInitOnce.reset();
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return (SHARED_DATA_HASHTABLE == NULL);
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_CDECL_END
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/** Initializes the cache for resources */
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void U_CALLCONV
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)createCache(UErrorCode &status) {
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SHARED_DATA_HASHTABLE = uhash_open(hashEntry, compareEntries, NULL, &status);
209fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    if (U_FAILURE(status)) {
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        SHARED_DATA_HASHTABLE = NULL;
21109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
212521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    ucln_common_registerCleanup(UCLN_COMMON_USPREP, usprep_cleanup);
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)initCache(UErrorCode *status) {
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    umtx_initOnce(gSharedDataInitOnce, &createCache, *status);
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UBool U_CALLCONV
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)loadData(UStringPrepProfile* profile,
222fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch         const char* path,
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         const char* name,
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         const char* type,
22507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch         UErrorCode* errorCode) {
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* load Unicode SPREP data from file */
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UTrie _sprepTrie={ 0,0,0,0,0,0,0 };
2287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    UDataMemory *dataMemory;
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const int32_t *p=NULL;
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const uint8_t *pb;
231fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    UVersionInfo normUnicodeVersion;
232fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    int32_t normUniVer, sprepUniVer, normCorrVer;
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(errorCode==NULL || U_FAILURE(*errorCode)) {
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* open the data outside the mutex block */
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //TODO: change the path
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    dataMemory=udata_openChoice(path, type, name, isSPrepAcceptable, NULL, errorCode);
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(U_FAILURE(*errorCode)) {
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FALSE;
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    p=(const int32_t *)udata_getMemory(dataMemory);
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    pb=(const uint8_t *)(p+_SPREP_INDEX_TOP);
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    utrie_unserialize(&_sprepTrie, pb, p[_SPREP_INDEX_TRIE_SIZE], errorCode);
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _sprepTrie.getFoldingOffset=getSPrepFoldingOffset;
249fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(U_FAILURE(*errorCode)) {
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        udata_close(dataMemory);
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FALSE;
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* in the mutex block, set the data for this process */
2577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    umtx_lock(&usprepMutex);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile->sprepData==NULL) {
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        profile->sprepData=dataMemory;
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        dataMemory=NULL;
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_memcpy(&profile->indexes, p, sizeof(profile->indexes));
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_memcpy(&profile->sprepTrie, &_sprepTrie, sizeof(UTrie));
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        p=(const int32_t *)udata_getMemory(profile->sprepData);
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    umtx_unlock(&usprepMutex);
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* initialize some variables */
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    profile->mappingData=(uint16_t *)((uint8_t *)(p+_SPREP_INDEX_TOP)+profile->indexes[_SPREP_INDEX_TRIE_SIZE]);
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    u_getUnicodeVersion(normUnicodeVersion);
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    normUniVer = (normUnicodeVersion[0] << 24) + (normUnicodeVersion[1] << 16) +
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 (normUnicodeVersion[2] << 8 ) + (normUnicodeVersion[3]);
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sprepUniVer = (dataVersion[0] << 24) + (dataVersion[1] << 16) +
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  (dataVersion[2] << 8 ) + (dataVersion[3]);
275fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    normCorrVer = profile->indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION];
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(U_FAILURE(*errorCode)){
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        udata_close(dataMemory);
279fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        return FALSE;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if( normUniVer < sprepUniVer && /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        normUniVer < normCorrVer && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ((profile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0) /* normalization turned on*/
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      ){
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *errorCode = U_INVALID_FORMAT_ERROR;
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        udata_close(dataMemory);
28793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        return FALSE;
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    profile->isDataLoaded = TRUE;
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* if a different thread set it first, then close the extra data */
29293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if(dataMemory!=NULL) {
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        udata_close(dataMemory); /* NULL if it was set correctly */
29493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
29693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return profile->isDataLoaded;
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static UStringPrepProfile*
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_getProfile(const char* path,
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  const char* name,
30393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  UErrorCode *status){
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepProfile* profile = NULL;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    initCache(status);
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(U_FAILURE(*status)){
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return NULL;
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepKey stackKey;
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /*
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * const is cast way to save malloc, strcpy and free calls
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * we use the passed in pointers for fetching the data from the
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * hash table which is safe
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stackKey.name = (char*) name;
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stackKey.path = (char*) path;
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* fetch the data from the cache */
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    umtx_lock(&usprepMutex);
324fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile != NULL) {
326fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        profile->refCount++;
327fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    }
328926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    umtx_unlock(&usprepMutex);
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile == NULL) {
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* else load the data and put the data in the cache */
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LocalMemory<UStringPrepProfile> newProfile;
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(newProfile.allocateInsteadAndReset() == NULL) {
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return NULL;
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* load the data */
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(!loadData(newProfile.getAlias(), path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return NULL;
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* get the options */
344fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        newProfile->doNFKC = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0);
345fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        newProfile->checkBiDi = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0);
346fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
347fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        if(newProfile->checkBiDi) {
348fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            newProfile->bdp = ubidi_getSingleton();
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
350fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
351fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        LocalMemory<UStringPrepKey> key;
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LocalMemory<char> keyName;
353fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        LocalMemory<char> keyPath;
354fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        if( key.allocateInsteadAndReset() == NULL ||
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            keyName.allocateInsteadAndCopy(uprv_strlen(name)+1) == NULL ||
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            (path != NULL &&
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             keyPath.allocateInsteadAndCopy(uprv_strlen(path)+1) == NULL)
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         ) {
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            usprep_unload(newProfile.getAlias());
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return NULL;
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        umtx_lock(&usprepMutex);
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // If another thread already inserted the same key/value, refcount and cleanup our thread data
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(profile != NULL) {
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            profile->refCount++;
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            usprep_unload(newProfile.getAlias());
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            /* initialize the key members */
373f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            key->name = keyName.orphan();
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_strcpy(key->name, name);
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(path != NULL){
376fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch                key->path = keyPath.orphan();
377fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch                uprv_strcpy(key->path, path);
378fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            }
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            profile = newProfile.orphan();
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            /* add the data object to the cache */
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            profile->refCount = 1;
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status);
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
38593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        umtx_unlock(&usprepMutex);
38693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
38793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
38893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return profile;
38993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
3907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
39193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)U_CAPI UStringPrepProfile* U_EXPORT2
39293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)usprep_open(const char* path,
393fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            const char* name,
394fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            UErrorCode* status){
395fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
39693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)){
39793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        return NULL;
39893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
39993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
40093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    /* initialize the profile struct members */
40193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return usprep_getProfile(path,name,status);
40293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_CAPI UStringPrepProfile* U_EXPORT2
405f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)usprep_openByType(UStringPrepProfileType type,
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				  UErrorCode* status) {
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)){
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return NULL;
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
410e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    int32_t index = (int32_t)type;
411e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    if (index < 0 || index >= (int32_t)(sizeof(PROFILE_NAMES)/sizeof(PROFILE_NAMES[0]))) {
412e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        *status = U_ILLEGAL_ARGUMENT_ERROR;
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return NULL;
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return usprep_open(NULL, PROFILE_NAMES[index], status);
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_CAPI void U_EXPORT2
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_close(UStringPrepProfile* profile){
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile==NULL){
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
423e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
4247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    umtx_lock(&usprepMutex);
425e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    /* decrement the ref count*/
426e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    if(profile->refCount > 0){
427e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        profile->refCount--;
428e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    }
429e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    umtx_unlock(&usprepMutex);
4307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
432e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
4337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochU_CFUNC void
434e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdochuprv_syntaxError(const UChar* rules,
4357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                 int32_t pos,
4367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                 int32_t rulesLen,
4377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                 UParseError* parseError){
4387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if(parseError == NULL){
4397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return;
440e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    }
441e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    parseError->offset = pos;
442e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    parseError->line = 0 ; // we are not using line numbers
443e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
444fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    // for pre-context
445fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1));
446fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    int32_t limit = pos;
447e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
448e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    u_memcpy(parseError->preContext,rules+start,limit-start);
449e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    //null terminate the buffer
450e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    parseError->preContext[limit-start] = 0;
451e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
452e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    // for post-context; include error rules[pos]
453fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    start = pos;
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    limit = start + (U_PARSE_CONTEXT_LEN-1);
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (limit > rulesLen) {
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        limit = rulesLen;
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (start < rulesLen) {
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        u_memcpy(parseError->postContext,rules+start,limit-start);
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //null terminate the buffer
462fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    parseError->postContext[limit-start]= 0;
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
466fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdochstatic inline UStringPrepType
467fff8884795cb540f87cf6e6d67b629519b00eb8bBen MurdochgetValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
469fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    UStringPrepType type;
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(trieWord == 0){
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /*
472fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch         * Initial value stored in the mapping table
473fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch         * just return USPREP_TYPE_LIMIT .. so that
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         * the source codepoint is copied to the destination
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         */
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        type = USPREP_TYPE_LIMIT;
477fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        isIndex =FALSE;
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        value = 0;
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }else if(trieWord >= _SPREP_TYPE_THRESHOLD){
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        type = (UStringPrepType) (trieWord - _SPREP_TYPE_THRESHOLD);
481fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        isIndex =FALSE;
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        value = 0;
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }else{
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* get the type */
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        type = USPREP_MAP;
486fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        /* ascertain if the value is index or delta */
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(trieWord & 0x02){
488fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            isIndex = TRUE;
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            value = trieWord  >> 2; //mask off the lower 2 bits and shift
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }else{
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            isIndex = FALSE;
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            value = (int16_t)trieWord;
49393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            value =  (value >> 2);
49493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        }
49593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
49693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if((trieWord>>2) == _SPREP_MAX_INDEX_VALUE){
49793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            type = USPREP_DELETE;
49893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            isIndex =FALSE;
49993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            value = 0;
50093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        }
501fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    }
502fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    return type;
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
504fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
505fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
506fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
507fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdochstatic int32_t
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_map(  const UStringPrepProfile* profile,
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             const UChar* src, int32_t srcLength,
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             UChar* dest, int32_t destCapacity,
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             int32_t options,
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             UParseError* parseError,
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             UErrorCode* status ){
514fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    uint16_t result;
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t destIndex=0;
517fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    int32_t srcIndex;
518fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    UBool allowUnassigned = (UBool) ((options & USPREP_ALLOW_UNASSIGNED)>0);
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepType type;
52093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    int16_t value;
52193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    UBool isIndex;
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const int32_t* indexes = profile->indexes;
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // no error checking the caller check for error and arguments
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // no string length check the caller finds out the string length
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for(srcIndex=0;srcIndex<srcLength;){
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        UChar32 ch;
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        U16_NEXT(src,srcIndex,srcLength,ch);
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result=0;
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        UTRIE_GET16(&profile->sprepTrie,ch,result);
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
536fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        type = getValues(result, value, isIndex);
537fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // check if the source codepoint is unassigned
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(type == USPREP_UNASSIGNED && allowUnassigned == FALSE){
5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_syntaxError(src,srcIndex-U16_LENGTH(ch), srcLength,parseError);
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_STRINGPREP_UNASSIGNED_ERROR;
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return 0;
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }else if(type == USPREP_MAP){
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int32_t index, length;
548f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
549f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            if(isIndex){
550f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                index = value;
551f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                if(index >= indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START] &&
552f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                         index < indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]){
553f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    length = 1;
554f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                }else if(index >= indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START] &&
555f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                         index < indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START]){
556f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    length = 2;
557f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                }else if(index >= indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] &&
558f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                         index < indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]){
559f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    length = 3;
560f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                }else{
561f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    length = profile->mappingData[index++];
562f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
563f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                }
564f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
565f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                /* copy mapping to destination */
566f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                for(int32_t i=0; i< length; i++){
567f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    if(destIndex < destCapacity  ){
568f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                        dest[destIndex] = profile->mappingData[index+i];
569f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    }
570f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)                    destIndex++; /* for pre-flighting */
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }else{
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                // subtract the delta to arrive at the code point
5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ch -= value;
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }else if(type==USPREP_DELETE){
579fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch             // just consume the codepoint and contine
580fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            continue;
5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
582fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        //copy the code point into destination
5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(ch <= 0xFFFF){
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(destIndex < destCapacity ){
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                dest[destIndex] = (UChar)ch;
5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            destIndex++;
5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }else{
5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(destIndex+1 < destCapacity ){
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                dest[destIndex]   = U16_LEAD(ch);
591fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch                dest[destIndex+1] = U16_TRAIL(ch);
592fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            }
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            destIndex +=2;
5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return u_terminateUChars(dest, destCapacity, destIndex, status);
5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int32_t
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_normalize(   const UChar* src, int32_t srcLength,
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    UChar* dest, int32_t destCapacity,
6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    UErrorCode* status ){
6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return unorm_normalize(
6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        src, srcLength,
6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        UNORM_NFKC, UNORM_UNICODE_3_2,
6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        dest, destCapacity,
6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        status);
6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
61493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) /*
61593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)   1) Map -- For each character in the input, check if it has a mapping
61693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      and, if so, replace it with its mapping.
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   2) Normalize -- Possibly normalize the result of step 1 using Unicode
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      normalization.
620fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
621fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch   3) Prohibit -- Check for any characters that are not allowed in the
622fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch      output.  If any are found, return an error.
623fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   4) Check bidi -- Possibly check for right-to-left characters, and if
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      any are found, make sure that the whole string satisfies the
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      requirements for bidirectional strings.  If the string does not
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      satisfy the requirements for bidirectional strings, return an
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      error.
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      [Unicode3.2] defines several bidirectional categories; each character
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       has one bidirectional category assigned to it.  For the purposes of
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       the requirements below, an "RandALCat character" is a character that
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       has Unicode bidirectional categories "R" or "AL"; an "LCat character"
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       is a character that has Unicode bidirectional category "L".  Note
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
63653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)       that there are many characters which fall in neither of the above
63753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)       definitions; Latin digits (<U+0030> through <U+0039>) are examples of
63853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)       this because they have bidirectional category "EN".
63953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
64053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)       In any profile that specifies bidirectional character handling, all
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       three of the following requirements MUST be met:
642e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
6437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch       1) The characters in section 5.8 MUST be prohibited.
644fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       2) If a string contains any RandALCat character, the string MUST NOT
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          contain any LCat character.
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       3) If a string contains any RandALCat character, a RandALCat
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          character MUST be the first character of the string, and a
650f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)          RandALCat character MUST be the last character of the string.
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)*/
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
653f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#define MAX_STACK_BUFFER_SIZE 300
6547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
655e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)usprep_prepare(   const UStringPrepProfile* profile,
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  const UChar* src, int32_t srcLength,
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  UChar* dest, int32_t destCapacity,
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  int32_t options,
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  UParseError* parseError,
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                  UErrorCode* status ){
6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // check error status
6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)){
6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //check arguments
670fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    if(profile==NULL || src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *status=U_ILLEGAL_ARGUMENT_ERROR;
672fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        return 0;
6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UChar b1Stack[MAX_STACK_BUFFER_SIZE], b2Stack[MAX_STACK_BUFFER_SIZE];
6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UChar *b1 = b1Stack, *b2 = b2Stack;
677fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    int32_t b1Len, b2Len=0,
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            b1Capacity = MAX_STACK_BUFFER_SIZE ,
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            b2Capacity = MAX_STACK_BUFFER_SIZE;
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    uint16_t result;
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t b2Index = 0;
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UCharDirection direction=U_CHAR_DIRECTION_COUNT, firstCharDir=U_CHAR_DIRECTION_COUNT;
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UBool leftToRight=FALSE, rightToLeft=FALSE;
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t rtlPos =-1, ltrPos =-1;
6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //get the string length
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(srcLength == -1){
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        srcLength = u_strlen(src);
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // map
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    b1Len = usprep_map(profile, src, srcLength, b1, b1Capacity, options, parseError, status);
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(*status == U_BUFFER_OVERFLOW_ERROR){
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // redo processing of string
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* we do not have enough room so grow the buffer*/
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(b1==NULL){
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            goto CLEANUP;
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *status = U_ZERO_ERROR; // reset error
7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b1Len = usprep_map(profile, src, srcLength, b1, b1Len, options, parseError, status);
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // normalize
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile->doNFKC == TRUE){
7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b2Len = usprep_normalize(b1,b1Len, b2,b2Capacity,status);
7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(*status == U_BUFFER_OVERFLOW_ERROR){
7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // redo processing of string
7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            /* we do not have enough room so grow the buffer*/
7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(b2==NULL){
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                *status = U_MEMORY_ALLOCATION_ERROR;
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                goto CLEANUP;
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_ZERO_ERROR; // reset error
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            b2Len = usprep_normalize(b1,b1Len, b2,b2Len,status);
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }else{
7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b2 = b1;
7295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b2Len = b1Len;
7305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(U_FAILURE(*status)){
734fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        goto CLEANUP;
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
737fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    UChar32 ch;
7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UStringPrepType type;
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int16_t value;
740fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    UBool isIndex;
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Prohibit and checkBiDi in one pass
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for(b2Index=0; b2Index<b2Len;){
7447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        ch = 0;
7467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        U16_NEXT(b2, b2Index, b2Len, ch);
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        UTRIE_GET16(&profile->sprepTrie,ch,result);
7507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        type = getValues(result, value, isIndex);
7527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if( type == USPREP_PROHIBITED ||
7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ((result < _SPREP_TYPE_THRESHOLD) && (result & 0x01) /* first bit says it the code point is prohibited*/)
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           ){
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_STRINGPREP_PROHIBITED_ERROR;
7577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            uprv_syntaxError(b1, b2Index-U16_LENGTH(ch), b2Len, parseError);
7587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            goto CLEANUP;
7597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(profile->checkBiDi) {
7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            direction = ubidi_getClass(profile->bdp, ch);
7637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if(firstCharDir == U_CHAR_DIRECTION_COUNT){
7647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                firstCharDir = direction;
7657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(direction == U_LEFT_TO_RIGHT){
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                leftToRight = TRUE;
7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ltrPos = b2Index-1;
7695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                rightToLeft = TRUE;
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                rtlPos = b2Index-1;
7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(profile->checkBiDi == TRUE){
7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // satisfy 2
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if( leftToRight == TRUE && rightToLeft == TRUE){
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_STRINGPREP_CHECK_BIDI_ERROR;
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_syntaxError(b2,(rtlPos>ltrPos) ? rtlPos : ltrPos, b2Len, parseError);
7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            goto CLEANUP;
7825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
783fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
7845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        //satisfy 3
7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if( rightToLeft == TRUE &&
7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !((firstCharDir == U_RIGHT_TO_LEFT || firstCharDir == U_RIGHT_TO_LEFT_ARABIC) &&
7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC))
7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           ){
7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *status = U_STRINGPREP_CHECK_BIDI_ERROR;
7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            uprv_syntaxError(b2, rtlPos, b2Len, parseError);
7915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FALSE;
7925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(b2Len>0 && b2Len <= destCapacity){
7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_memmove(dest,b2, b2Len*U_SIZEOF_UCHAR);
7965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)CLEANUP:
7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(b1!=b1Stack){
8005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_free(b1);
8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b1=NULL;
8025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(b2!=b1Stack && b2!=b2Stack && b2!=b1 /* b1 should not be freed twice */){
8055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        uprv_free(b2);
8065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b2=NULL;
8075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return u_terminateUChars(dest, destCapacity, b2Len, status);
8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
81007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
811926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
812fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch/* data swapping ------------------------------------------------------------ */
813fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
814fff8884795cb540f87cf6e6d67b629519b00eb8bBen MurdochU_CAPI int32_t U_EXPORT2
815fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdochusprep_swap(const UDataSwapper *ds,
816fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            const void *inData, int32_t length, void *outData,
817fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            UErrorCode *pErrorCode) {
818fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    const UDataInfo *pInfo;
819591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    int32_t headerSize;
820591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
8215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const uint8_t *inBytes;
8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    uint8_t *outBytes;
8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const int32_t *inIndexes;
8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t indexes[16];
8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int32_t i, offset, count, size;
8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* udata_swapDataHeader checks the arguments */
8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
83107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
835fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch    /* check data format and format version */
8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    pInfo=(const UDataInfo *)((const char *)inData+4);
8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(!(
8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[0]==0x53 &&   /* dataFormat="SPRP" */
8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[1]==0x50 &&
8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[2]==0x52 &&
8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->dataFormat[3]==0x50 &&
8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pInfo->formatVersion[0]==3
8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    )) {
8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        udata_printError(ds, "usprep_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as StringPrep .spp data\n",
8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         pInfo->dataFormat[0], pInfo->dataFormat[1],
8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         pInfo->dataFormat[2], pInfo->dataFormat[3],
8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         pInfo->formatVersion[0]);
8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *pErrorCode=U_UNSUPPORTED_ERROR;
8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    inBytes=(const uint8_t *)inData+headerSize;
85381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    outBytes=(uint8_t *)outData+headerSize;
8545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    inIndexes=(const int32_t *)inBytes;
8565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(length>=0) {
85881a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)        length-=headerSize;
859fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch        if(length<16*4) {
860fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch            udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for StringPrep .spp data\n",
861fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch                             length);
8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return 0;
86402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        }
865591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    }
8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* read the first 16 indexes (ICU 2.8/format version 3: _SPREP_INDEX_TOP==16, might grow) */
8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for(i=0; i<16; ++i) {
8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        indexes[i]=udata_readInt32(ds, inIndexes[i]);
87081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    }
8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /* calculate the total length of the data */
8735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size=
8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        16*4+ /* size of indexes[] */
8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        indexes[_SPREP_INDEX_TRIE_SIZE]+
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if(length>=0) {
8795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if(length<size) {
8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for all of StringPrep .spp data\n",
8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                             length);
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return 0;
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* copy the data for inaccessible bytes */
887f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if(inBytes!=outBytes) {
888f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            uprv_memcpy(outBytes, inBytes, size);
889f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        }
890f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
891f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        offset=0;
892f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
893f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        /* swap the int32_t indexes[] */
894f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        count=16*4;
895f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
896f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        offset+=count;
897f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* swap the UTrie */
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        count=indexes[_SPREP_INDEX_TRIE_SIZE];
9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        offset+=count;
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        /* swap the uint16_t mappingTable[] */
9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        count=indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        offset+=count;
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return headerSize+size;
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
912fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch#endif /* #if !UCONFIG_NO_IDNA */
913fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch