]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/usprep.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / common / usprep.cpp
index 975a598d2fdcf1df6ccfb95eb91ab92e30859a2c..415253c332e31277d29873f41f0da0a3e47a4558 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *******************************************************************************
  *
- *   Copyright (C) 2003-2004, International Business Machines
+ *   Copyright (C) 2003-2010, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  *
  *******************************************************************************
@@ -32,7 +32,9 @@
 #include "cstring.h"
 #include "udataswp.h"
 #include "ucln_cmn.h"
-#include "unormimp.h"
+#include "ubidi_props.h"
+
+U_NAMESPACE_USE
 
 U_CDECL_BEGIN
 
@@ -49,6 +51,24 @@ static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
 /* the Unicode version of the sprep data */
 static UVersionInfo dataVersion={ 0, 0, 0, 0 };
 
+/* Profile names must be aligned to UStringPrepProfileType */
+static const char *PROFILE_NAMES[] = {
+    "rfc3491",      /* USPREP_RFC3491_NAMEPREP */
+    "rfc3530cs",    /* USPREP_RFC3530_NFS4_CS_PREP */
+    "rfc3530csci",  /* USPREP_RFC3530_NFS4_CS_PREP_CI */
+    "rfc3491",      /* USPREP_RFC3530_NSF4_CIS_PREP */
+    "rfc3530mixp",  /* USPREP_RFC3530_NSF4_MIXED_PREP_PREFIX */
+    "rfc3491",      /* USPREP_RFC3530_NSF4_MIXED_PREP_SUFFIX */
+    "rfc3722",      /* USPREP_RFC3722_ISCSI */
+    "rfc3920node",  /* USPREP_RFC3920_NODEPREP */
+    "rfc3920res",   /* USPREP_RFC3920_RESOURCEPREP */
+    "rfc4011",      /* USPREP_RFC4011_MIB */
+    "rfc4013",      /* USPREP_RFC4013_SASLPREP */
+    "rfc4505",      /* USPREP_RFC4505_TRACE */
+    "rfc4518",      /* USPREP_RFC4518_LDAP */
+    "rfc4518ci",    /* USPREP_RFC4518_LDAP_CI */
+};
+
 static UBool U_CALLCONV
 isSPrepAcceptable(void * /* context */,
              const char * /* type */, 
@@ -82,7 +102,7 @@ getSPrepFoldingOffset(uint32_t data) {
 }
 
 /* hashes an entry  */
-static int32_t U_EXPORT2 U_CALLCONV 
+static int32_t U_CALLCONV 
 hashEntry(const UHashTok parm) {
     UStringPrepKey *b = (UStringPrepKey *)parm.pointer;
     UHashTok namekey, pathkey;
@@ -92,7 +112,7 @@ hashEntry(const UHashTok parm) {
 }
 
 /* compares two entries */
-static UBool U_EXPORT2 U_CALLCONV 
+static UBool U_CALLCONV 
 compareEntries(const UHashTok p1, const UHashTok p2) {
     UStringPrepKey *b1 = (UStringPrepKey *)p1.pointer;
     UStringPrepKey *b2 = (UStringPrepKey *)p2.pointer;
@@ -183,30 +203,23 @@ static UBool U_CALLCONV usprep_cleanup(void){
 }
 U_CDECL_END
 
-static void 
-usprep_init() {
-    umtx_init(&usprepMutex);
-}
 
 /** Initializes the cache for resources */
 static void 
 initCache(UErrorCode *status) {
-    UBool makeCache = FALSE;
-    umtx_lock(&usprepMutex);
-    makeCache = (SHARED_DATA_HASHTABLE ==  NULL);
-    umtx_unlock(&usprepMutex);
+    UBool makeCache;
+    UMTX_CHECK(&usprepMutex, (SHARED_DATA_HASHTABLE ==  NULL), makeCache);
     if(makeCache) {
-        UHashtable *newCache = uhash_open(hashEntry, compareEntries, status);
-        if (U_FAILURE(*status)) {
-            return;
-        }
-        umtx_lock(&usprepMutex);
-        if(SHARED_DATA_HASHTABLE == NULL) {
-            SHARED_DATA_HASHTABLE = newCache;
-            ucln_common_registerCleanup(UCLN_COMMON_USPREP, usprep_cleanup);
-            newCache = NULL;
+        UHashtable *newCache = uhash_open(hashEntry, compareEntries, NULL, status);
+        if (U_SUCCESS(*status)) {
+            umtx_lock(&usprepMutex);
+            if(SHARED_DATA_HASHTABLE == NULL) {
+                SHARED_DATA_HASHTABLE = newCache;
+                ucln_common_registerCleanup(UCLN_COMMON_USPREP, usprep_cleanup);
+                newCache = NULL;
+            }
+            umtx_unlock(&usprepMutex);
         }
-        umtx_unlock(&usprepMutex);
         if(newCache != NULL) {
             uhash_close(newCache);
         }
@@ -263,7 +276,7 @@ loadData(UStringPrepProfile* profile,
     /* initialize some variables */
     profile->mappingData=(uint16_t *)((uint8_t *)(p+_SPREP_INDEX_TOP)+profile->indexes[_SPREP_INDEX_TRIE_SIZE]);
     
-    unorm_getUnicodeVersion(&normUnicodeVersion, errorCode);
+    u_getUnicodeVersion(normUnicodeVersion);
     normUniVer = (normUnicodeVersion[0] << 24) + (normUnicodeVersion[1] << 16) + 
                  (normUnicodeVersion[2] << 8 ) + (normUnicodeVersion[3]);
     sprepUniVer = (dataVersion[0] << 24) + (dataVersion[1] << 16) + 
@@ -316,71 +329,70 @@ usprep_getProfile(const char* path,
     stackKey.path = (char*) path;
 
     /* fetch the data from the cache */
+    umtx_lock(&usprepMutex);
     profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
+    if(profile != NULL) {
+        profile->refCount++;
+    }
+    umtx_unlock(&usprepMutex);
     
-    if(profile == NULL){
-        UStringPrepKey* key   = (UStringPrepKey*) uprv_malloc(sizeof(UStringPrepKey));
-        if(key == NULL){
-            *status = U_MEMORY_ALLOCATION_ERROR;
-            return NULL;
-        }
+    if(profile == NULL) {
         /* else load the data and put the data in the cache */
-        profile = (UStringPrepProfile*) uprv_malloc(sizeof(UStringPrepProfile));
-        if(profile == NULL){
+        LocalMemory<UStringPrepProfile> newProfile;
+        if(newProfile.allocateInsteadAndReset() == NULL) {
             *status = U_MEMORY_ALLOCATION_ERROR;
-            uprv_free(key);
             return NULL;
         }
 
-        /* initialize the data struct members */
-        uprv_memset(profile->indexes,0,sizeof(profile->indexes));
-        profile->mappingData = NULL;
-        profile->sprepData   = NULL;
-        profile->refCount    = 0;
-    
-        /* initialize the  key memebers */
-        key->name  = (char*) uprv_malloc(uprv_strlen(name)+1);
-        if(key->name == NULL){
-            *status = U_MEMORY_ALLOCATION_ERROR;
-            uprv_free(key);
-            uprv_free(profile);
+        /* load the data */
+        if(!loadData(newProfile.getAlias(), path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){
             return NULL;
         }
 
-        uprv_strcpy(key->name, name);
-        
-        key->path=NULL;
+        /* get the options */
+        newProfile->doNFKC = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0);
+        newProfile->checkBiDi = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0);
 
-        if(path != NULL){
-            key->path      = (char*) uprv_malloc(uprv_strlen(path)+1);
-            if(key->path == NULL){
-                *status = U_MEMORY_ALLOCATION_ERROR;
-                uprv_free(key->path);
-                uprv_free(key);
-                uprv_free(profile);
-                return NULL;
-            }
-            uprv_strcpy(key->path, path);
-        }        
+        if(newProfile->checkBiDi) {
+            newProfile->bdp = ubidi_getSingleton();
+        }
 
-        /* load the data */
-        if(!loadData(profile, path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){
+        LocalMemory<UStringPrepKey> key;
+        LocalMemory<char> keyName;
+        LocalMemory<char> keyPath;
+        if( key.allocateInsteadAndReset() == NULL ||
+            keyName.allocateInsteadAndCopy(uprv_strlen(name)+1) == NULL ||
+            (path != NULL &&
+             keyPath.allocateInsteadAndCopy(uprv_strlen(path)+1) == NULL)
+         ) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            usprep_unload(newProfile.getAlias());
             return NULL;
         }
-        
-        /* get the options */
-        profile->doNFKC            = (UBool)((profile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0);
-        profile->checkBiDi         = (UBool)((profile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0);
-        
+
         umtx_lock(&usprepMutex);
-        /* add the data object to the cache */
-        uhash_put(SHARED_DATA_HASHTABLE, key, profile, status);
+        // If another thread already inserted the same key/value, refcount and cleanup our thread data
+        profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
+        if(profile != NULL) {
+            profile->refCount++;
+            usprep_unload(newProfile.getAlias());
+        }
+        else {
+            /* initialize the key members */
+            key->name = keyName.orphan();
+            uprv_strcpy(key->name, name);
+            if(path != NULL){
+                key->path = keyPath.orphan();
+                uprv_strcpy(key->path, path);
+            }        
+            profile = newProfile.orphan();
+    
+            /* add the data object to the cache */
+            profile->refCount = 1;
+            uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status);
+        }
         umtx_unlock(&usprepMutex);
     }
-    umtx_lock(&usprepMutex);
-    /* increment the refcount */
-    profile->refCount++;
-    umtx_unlock(&usprepMutex);
 
     return profile;
 }
@@ -393,11 +405,23 @@ usprep_open(const char* path,
     if(status == NULL || U_FAILURE(*status)){
         return NULL;
     }
-    /* initialize the mutex */
-    usprep_init();
        
     /* initialize the profile struct members */
-    return usprep_getProfile(path,name,status);;
+    return usprep_getProfile(path,name,status);
+}
+
+U_CAPI UStringPrepProfile* U_EXPORT2
+usprep_openByType(UStringPrepProfileType type,
+                                 UErrorCode* status) {
+    if(status == NULL || U_FAILURE(*status)){
+        return NULL;
+    }
+    int32_t index = (int32_t)type;
+    if (index < 0 || index >= (int32_t)(sizeof(PROFILE_NAMES)/sizeof(PROFILE_NAMES[0]))) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    return usprep_open(NULL, PROFILE_NAMES[index], status);
 }
 
 U_CAPI void U_EXPORT2
@@ -427,7 +451,7 @@ uprv_syntaxError(const UChar* rules,
     parseError->line = 0 ; // we are not using line numbers 
     
     // for pre-context
-    int32_t start = (pos <=U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1));
+    int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1));
     int32_t limit = pos;
     
     u_memcpy(parseError->preContext,rules+start,limit-start);
@@ -459,8 +483,12 @@ getValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
          * the source codepoint is copied to the destination
          */
         type = USPREP_TYPE_LIMIT;
+        isIndex =FALSE;
+        value = 0;
     }else if(trieWord >= _SPREP_TYPE_THRESHOLD){
         type = (UStringPrepType) (trieWord - _SPREP_TYPE_THRESHOLD);
+        isIndex =FALSE;
+        value = 0;
     }else{
         /* get the type */
         type = USPREP_MAP;
@@ -468,12 +496,10 @@ getValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
         if(trieWord & 0x02){
             isIndex = TRUE;
             value = trieWord  >> 2; //mask off the lower 2 bits and shift
-
         }else{
             isIndex = FALSE;
             value = (int16_t)trieWord;
             value =  (value >> 2);
-
         }
  
         if((trieWord>>2) == _SPREP_MAX_INDEX_VALUE){
@@ -586,20 +612,9 @@ static int32_t
 usprep_normalize(   const UChar* src, int32_t srcLength, 
                     UChar* dest, int32_t destCapacity,
                     UErrorCode* status ){
-    /*
-     * Option UNORM_BEFORE_PRI_29:
-     *
-     * IDNA as interpreted by IETF members (see unicode mailing list 2004H1)
-     * requires strict adherence to Unicode 3.2 normalization,
-     * including buggy composition from before fixing Public Review Issue #29.
-     * Note that this results in some valid but nonsensical text to be
-     * either corrupted or rejected, depending on the text.
-     * See http://www.unicode.org/review/resolved-pri.html#pri29
-     * See unorm.cpp and cnormtst.c
-     */
     return unorm_normalize(
         src, srcLength,
-        UNORM_NFKC, UNORM_UNICODE_3_2|UNORM_BEFORE_PRI_29,
+        UNORM_NFKC, UNORM_UNICODE_3_2,
         dest, destCapacity,
         status);
 }
@@ -752,17 +767,19 @@ usprep_prepare(   const UStringPrepProfile* profile,
             goto CLEANUP;
         }
 
-        direction = u_charDirection(ch);
-        if(firstCharDir == U_CHAR_DIRECTION_COUNT){
-            firstCharDir = direction;
-        }
-        if(direction == U_LEFT_TO_RIGHT){
-            leftToRight = TRUE;
-            ltrPos = b2Index-1;
-        }
-        if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
-            rightToLeft = TRUE;
-            rtlPos = b2Index-1;
+        if(profile->checkBiDi) {
+            direction = ubidi_getClass(profile->bdp, ch);
+            if(firstCharDir == U_CHAR_DIRECTION_COUNT){
+                firstCharDir = direction;
+            }
+            if(direction == U_LEFT_TO_RIGHT){
+                leftToRight = TRUE;
+                ltrPos = b2Index-1;
+            }
+            if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
+                rightToLeft = TRUE;
+                rtlPos = b2Index-1;
+            }
         }
     }           
     if(profile->checkBiDi == TRUE){
@@ -783,7 +800,7 @@ usprep_prepare(   const UStringPrepProfile* profile,
             return FALSE;
         }
     }
-    if(b2Len <= destCapacity){
+    if(b2Len>0 && b2Len <= destCapacity){
         uprv_memmove(dest,b2, b2Len*U_SIZEOF_UCHAR);
     }