]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/ucol_elm.cpp
ICU-491.11.3.tar.gz
[apple/icu.git] / icuSources / i18n / ucol_elm.cpp
index dd07039157f631adee4d8024f02b6f5787745270..3a92e1d02a1f0458587d0ed8b20f3135c392b081 100644 (file)
@@ -1,7 +1,7 @@
 /*
 *******************************************************************************
 *
-*   Copyright (C) 2001-2004, International Business Machines
+*   Copyright (C) 2001-2012, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
 #include "unicode/unistr.h"
 #include "unicode/ucoleitr.h"
 #include "unicode/normlzr.h"
+#include "unicode/utf16.h"
+#include "normalizer2impl.h"
 #include "ucol_elm.h"
-#include "unormimp.h"
+#include "ucol_tok.h"
+#include "ucol_cnt.h"
 #include "unicode/caniter.h"
 #include "cmemory.h"
+#include "uassert.h"
 
-U_NAMESPACE_BEGIN
+U_NAMESPACE_USE
 
 static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status);
 
 U_CDECL_BEGIN
-static int32_t U_EXPORT2 U_CALLCONV
+static int32_t U_CALLCONV
 prefixLookupHash(const UHashTok e) {
-  UCAElements *element = (UCAElements *)e.pointer;
-  UChar buf[256];
-  UHashTok key;
-  key.pointer = buf;
-  uprv_memcpy(buf, element->cPoints, element->cSize*sizeof(UChar));
-  buf[element->cSize] = 0;
-  //key.pointer = element->cPoints;
-  //element->cPoints[element->cSize] = 0;
-  return uhash_hashUChars(key);
+    UCAElements *element = (UCAElements *)e.pointer;
+    UChar buf[256];
+    UHashTok key;
+    key.pointer = buf;
+    uprv_memcpy(buf, element->cPoints, element->cSize*sizeof(UChar));
+    buf[element->cSize] = 0;
+    //key.pointer = element->cPoints;
+    //element->cPoints[element->cSize] = 0;
+    return uhash_hashUChars(key);
 }
 
-static int8_t U_EXPORT2 U_CALLCONV
+static int8_t U_CALLCONV
 prefixLookupComp(const UHashTok e1, const UHashTok e2) {
-  UCAElements *element1 = (UCAElements *)e1.pointer;
-  UCAElements *element2 = (UCAElements *)e2.pointer;
-
-  UChar buf1[256];
-  UHashTok key1;
-  key1.pointer = buf1;
-  uprv_memcpy(buf1, element1->cPoints, element1->cSize*sizeof(UChar));
-  buf1[element1->cSize] = 0;
-
-  UChar buf2[256];
-  UHashTok key2;
-  key2.pointer = buf2;
-  uprv_memcpy(buf2, element2->cPoints, element2->cSize*sizeof(UChar));
-  buf2[element2->cSize] = 0;
-
-  return uhash_compareUChars(key1, key2);
+    UCAElements *element1 = (UCAElements *)e1.pointer;
+    UCAElements *element2 = (UCAElements *)e2.pointer;
+
+    UChar buf1[256];
+    UHashTok key1;
+    key1.pointer = buf1;
+    uprv_memcpy(buf1, element1->cPoints, element1->cSize*sizeof(UChar));
+    buf1[element1->cSize] = 0;
+
+    UChar buf2[256];
+    UHashTok key2;
+    key2.pointer = buf2;
+    uprv_memcpy(buf2, element2->cPoints, element2->cSize*sizeof(UChar));
+    buf2[element2->cSize] = 0;
+
+    return uhash_compareUChars(key1, key2);
 }
 U_CDECL_END
 
@@ -109,291 +113,313 @@ static int32_t uprv_uca_addExpansion(ExpansionTable *expansions, uint32_t value,
 
 U_CAPI tempUCATable*  U_EXPORT2
 uprv_uca_initTempTable(UCATableHeader *image, UColOptionSet *opts, const UCollator *UCA, UColCETags initTag, UColCETags supplementaryInitTag, UErrorCode *status) {
-  tempUCATable *t = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
-  /* test for NULL */
-  if (t == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      return NULL;
-  }
-  MaxExpansionTable *maxet  = (MaxExpansionTable *)uprv_malloc(
-                                                   sizeof(MaxExpansionTable));
-  /* test for NULL */
-  if (maxet == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      uprv_free(t);
-      return NULL;
-  }
-  MaxJamoExpansionTable *maxjet = (MaxJamoExpansionTable *)uprv_malloc(
-                                               sizeof(MaxJamoExpansionTable));
-  /* test for NULL */
-  if (maxjet == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      uprv_free(t);
-      uprv_free(maxet);
-      return NULL;
-  }
-  t->image = image;
-  t->options = opts;
-
-  t->UCA = UCA;
-  t->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
-  /* test for NULL */
-  if (t->expansions == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      uprv_free(t);
-      uprv_free(maxet);
-      uprv_free(maxjet);
-      return NULL;
-  }
-  uprv_memset(t->expansions, 0, sizeof(ExpansionTable));
-  /*t->mapping = ucmpe32_open(UCOL_SPECIAL_FLAG | (initTag<<24), UCOL_SPECIAL_FLAG | (SURROGATE_TAG<<24), UCOL_SPECIAL_FLAG | (LEAD_SURROGATE_TAG<<24), status);*/
-  /*t->mapping = utrie_open(NULL, NULL, 0x100000, UCOL_SPECIAL_FLAG | (initTag<<24), TRUE); // Do your own mallocs for the structure, array and have linear Latin 1*/
-
-  t->mapping = utrie_open(NULL, NULL, 0x100000,
-                          UCOL_SPECIAL_FLAG | (initTag<<24),
-                          UCOL_SPECIAL_FLAG | (supplementaryInitTag << 24),
-                          TRUE); // Do your own mallocs for the structure, array and have linear Latin 1
-  t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, status);
-  uhash_setValueDeleter(t->prefixLookup, uhash_freeBlock);
-
-  t->contractions = uprv_cnttab_open(t->mapping, status);
-
-  /* copy UCA's maxexpansion and merge as we go along */
-  t->maxExpansions       = maxet;
-  if (UCA != NULL) {
-    /* adding an extra initial value for easier manipulation */
-    maxet->size            = (UCA->lastEndExpansionCE - UCA->endExpansionCE) 
-                             + 2;
-    maxet->position        = maxet->size - 1;
-    maxet->endExpansionCE  = 
-                      (uint32_t *)uprv_malloc(sizeof(uint32_t) * maxet->size);
+    MaxJamoExpansionTable *maxjet;
+    MaxExpansionTable *maxet;
+    tempUCATable *t = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
     /* test for NULL */
-    if (maxet->endExpansionCE == NULL) {
+    if (t == NULL) {
         *status = U_MEMORY_ALLOCATION_ERROR;
         return NULL;
     }
-    maxet->expansionCESize =
-                        (uint8_t *)uprv_malloc(sizeof(uint8_t) * maxet->size);
-    /* test for NULL */
-    if (maxet->expansionCESize == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        uprv_free(maxet->endExpansionCE);
-        return NULL;
+    uprv_memset(t, 0, sizeof(tempUCATable));
+
+    maxet  = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable));
+    if (maxet == NULL) {
+        goto allocation_failure;
     }
-    /* initialized value */
-    *(maxet->endExpansionCE)  = 0;
-    *(maxet->expansionCESize) = 0;
-    uprv_memcpy(maxet->endExpansionCE + 1, UCA->endExpansionCE, 
-                sizeof(uint32_t) * (maxet->size - 1));
-    uprv_memcpy(maxet->expansionCESize + 1, UCA->expansionCESize, 
-                sizeof(uint8_t) * (maxet->size - 1));
-  }
-  else {
-    maxet->size     = 0;
-  }
-  t->maxJamoExpansions = maxjet;
-  maxjet->endExpansionCE = NULL;
-  maxjet->isV = NULL;
-  maxjet->size = 0;
-  maxjet->position = 0;
-  maxjet->maxLSize = 1;
-  maxjet->maxVSize = 1;
-  maxjet->maxTSize = 1;
-
-  t->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
-  /* test for NULL */
-  if (t->unsafeCP == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      return NULL;
-  }
-  t->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
-  /* test for NULL */
-  if (t->contrEndCP == NULL) {
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      uprv_free(t->unsafeCP);
-      return NULL;
-  }
-  uprv_memset(t->unsafeCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
-  uprv_memset(t->contrEndCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
-return t;
-}
+    uprv_memset(maxet, 0, sizeof(MaxExpansionTable));
+    t->maxExpansions       = maxet;
 
-U_CAPI tempUCATable* U_EXPORT2
-uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status) {
-  if(U_FAILURE(*status)) {
-    return NULL;
-  }
+    maxjet = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable));
+    if (maxjet == NULL) {
+        goto allocation_failure;
+    }
+    uprv_memset(maxjet, 0, sizeof(MaxJamoExpansionTable));
+    t->maxJamoExpansions = maxjet;
 
-  tempUCATable *r = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
-  /* test for NULL */
-  if (r == NULL) {
-    *status = U_MEMORY_ALLOCATION_ERROR;
-    return NULL;
-  }
-  uprv_memset(r, 0, sizeof(tempUCATable));
-
-  /* mapping */
-  if(t->mapping != NULL) {
-    /*r->mapping = ucmpe32_clone(t->mapping, status);*/
-    r->mapping = utrie_clone(NULL, t->mapping, NULL, 0);
-  }
-
-  // a hashing clone function would be very nice. We have none currently...
-  // However, we should be good, as closing should not produce any prefixed elements.
-  r->prefixLookup = NULL; // prefixes are not used in closing
-
-  /* expansions */
-  if(t->expansions != NULL) {
-    r->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
+    t->image = image;
+    t->options = opts;
+
+    t->UCA = UCA;
+    t->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
     /* test for NULL */
-    if (r->expansions == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
+    if (t->expansions == NULL) {
+        goto allocation_failure;
     }
-    r->expansions->position = t->expansions->position;
-    r->expansions->size = t->expansions->size;
-    if(t->expansions->CEs != NULL) {
-      r->expansions->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->expansions->size);
-      /* test for NULL */
-      if (r->expansions->CEs == NULL) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          return NULL;
-      }
-      uprv_memcpy(r->expansions->CEs, t->expansions->CEs, sizeof(uint32_t)*t->expansions->position);
-    } else {
-      r->expansions->CEs = NULL;
+    uprv_memset(t->expansions, 0, sizeof(ExpansionTable));
+
+    t->mapping = utrie_open(NULL, NULL, UCOL_ELM_TRIE_CAPACITY,
+        UCOL_SPECIAL_FLAG | (initTag<<24),
+        UCOL_SPECIAL_FLAG | (supplementaryInitTag << 24),
+        TRUE); // Do your own mallocs for the structure, array and have linear Latin 1
+    if (U_FAILURE(*status)) {
+        goto allocation_failure;
+    }
+    t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, NULL, status);
+    if (U_FAILURE(*status)) {
+        goto allocation_failure;
     }
-  }
+    uhash_setValueDeleter(t->prefixLookup, uprv_free);
 
-  if(t->contractions != NULL) {
-    r->contractions = uprv_cnttab_clone(t->contractions, status);
-    r->contractions->mapping = r->mapping;
-  }
+    t->contractions = uprv_cnttab_open(t->mapping, status);
+    if (U_FAILURE(*status)) {
+        goto cleanup;
+    }
 
-  if(t->maxExpansions != NULL) {
-    r->maxExpansions = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable));
-    /* test for NULL */
-    if (r->maxExpansions == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
+    /* copy UCA's maxexpansion and merge as we go along */
+    if (UCA != NULL) {
+        /* adding an extra initial value for easier manipulation */
+        maxet->size            = (int32_t)(UCA->lastEndExpansionCE - UCA->endExpansionCE) + 2;
+        maxet->position        = maxet->size - 1;
+        maxet->endExpansionCE  = 
+            (uint32_t *)uprv_malloc(sizeof(uint32_t) * maxet->size);
+        /* test for NULL */
+        if (maxet->endExpansionCE == NULL) {
+            goto allocation_failure;
+        }
+        maxet->expansionCESize =
+            (uint8_t *)uprv_malloc(sizeof(uint8_t) * maxet->size);
+        /* test for NULL */
+        if (maxet->expansionCESize == NULL) {
+            goto allocation_failure;
+        }
+        /* initialized value */
+        *(maxet->endExpansionCE)  = 0;
+        *(maxet->expansionCESize) = 0;
+        uprv_memcpy(maxet->endExpansionCE + 1, UCA->endExpansionCE, 
+            sizeof(uint32_t) * (maxet->size - 1));
+        uprv_memcpy(maxet->expansionCESize + 1, UCA->expansionCESize, 
+            sizeof(uint8_t) * (maxet->size - 1));
     }
-    r->maxExpansions->size = t->maxExpansions->size;
-    r->maxExpansions->position = t->maxExpansions->position;
-    if(t->maxExpansions->endExpansionCE != NULL) {
-      r->maxExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxExpansions->size);
-      /* test for NULL */
-      if (r->maxExpansions->endExpansionCE == NULL) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          return NULL;
-      }
-      uprv_memcpy(r->maxExpansions->endExpansionCE, t->maxExpansions->endExpansionCE, t->maxExpansions->position*sizeof(uint32_t));
-    } else {
-      r->maxExpansions->endExpansionCE = NULL;
-    }
-    if(t->maxExpansions->expansionCESize != NULL) {
-      r->maxExpansions->expansionCESize = (uint8_t *)uprv_malloc(sizeof(uint8_t)*t->maxExpansions->size);
-      /* test for NULL */
-      if (r->maxExpansions->expansionCESize == NULL) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          return NULL;
-      }
-      uprv_memcpy(r->maxExpansions->expansionCESize, t->maxExpansions->expansionCESize, t->maxExpansions->position*sizeof(uint8_t));
-    } else {
-      r->maxExpansions->expansionCESize = NULL;
+    else {
+        maxet->size     = 0;
     }
-  }
-
-  if(t->maxJamoExpansions != NULL) {
-    r->maxJamoExpansions = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable));
+    maxjet->endExpansionCE = NULL;
+    maxjet->isV = NULL;
+    maxjet->size = 0;
+    maxjet->position = 0;
+    maxjet->maxLSize = 1;
+    maxjet->maxVSize = 1;
+    maxjet->maxTSize = 1;
+
+    t->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
     /* test for NULL */
-    if (r->maxJamoExpansions == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
+    if (t->unsafeCP == NULL) {
+        goto allocation_failure;
     }
-    r->maxJamoExpansions->size = t->maxJamoExpansions->size;
-    r->maxJamoExpansions->position = t->maxJamoExpansions->position;
-    r->maxJamoExpansions->maxLSize = t->maxJamoExpansions->maxLSize;
-    r->maxJamoExpansions->maxVSize = t->maxJamoExpansions->maxVSize;
-    r->maxJamoExpansions->maxTSize = t->maxJamoExpansions->maxTSize;
-    if(t->maxJamoExpansions->size != 0) {
-      r->maxJamoExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxJamoExpansions->size);
-      /* test for NULL */
-      if (r->maxJamoExpansions->endExpansionCE == NULL) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          return NULL;
-      }
-      uprv_memcpy(r->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->position*sizeof(uint32_t));
-      r->maxJamoExpansions->isV = (UBool *)uprv_malloc(sizeof(UBool)*t->maxJamoExpansions->size);
-      /* test for NULL */
-      if (r->maxJamoExpansions->isV == NULL) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          return NULL;
-      }
-      uprv_memcpy(r->maxJamoExpansions->isV, t->maxJamoExpansions->isV, t->maxJamoExpansions->position*sizeof(UBool));
-    } else {
-      r->maxJamoExpansions->endExpansionCE = NULL;
-      r->maxJamoExpansions->isV = NULL;
+    t->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+    /* test for NULL */
+    if (t->contrEndCP == NULL) {
+        goto allocation_failure;
     }
-  }
+    uprv_memset(t->unsafeCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
+    uprv_memset(t->contrEndCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
+    t->cmLookup = NULL;
+    return t;
 
-  if(t->unsafeCP != NULL) {
-    r->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
-    /* test for NULL */
-    if (r->unsafeCP == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
+allocation_failure:
+    *status = U_MEMORY_ALLOCATION_ERROR;
+cleanup:
+    uprv_uca_closeTempTable(t);
+    return NULL;
+}
+
+static tempUCATable* U_EXPORT2
+uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status) {
+    if(U_FAILURE(*status)) {
         return NULL;
     }
-    uprv_memcpy(r->unsafeCP, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE);
-  }
 
-  if(t->contrEndCP != NULL) {
-    r->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+    tempUCATable *r = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
     /* test for NULL */
-    if (r->contrEndCP == NULL) {
+    if (r == NULL) {
         *status = U_MEMORY_ALLOCATION_ERROR;
         return NULL;
     }
-    uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE);
-  }
+    uprv_memset(r, 0, sizeof(tempUCATable));
 
-  r->UCA = t->UCA;
-  r->image = t->image;
-  r->options = t->options;
+    /* mapping */
+    if(t->mapping != NULL) {
+        /*r->mapping = ucmpe32_clone(t->mapping, status);*/
+        r->mapping = utrie_clone(NULL, t->mapping, NULL, 0);
+    }
 
-  return r;
-}
+    // a hashing clone function would be very nice. We have none currently...
+    // However, we should be good, as closing should not produce any prefixed elements.
+    r->prefixLookup = NULL; // prefixes are not used in closing
 
+    /* expansions */
+    if(t->expansions != NULL) {
+        r->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
+        /* test for NULL */
+        if (r->expansions == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        r->expansions->position = t->expansions->position;
+        r->expansions->size = t->expansions->size;
+        if(t->expansions->CEs != NULL) {
+            r->expansions->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->expansions->size);
+            /* test for NULL */
+            if (r->expansions->CEs == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto cleanup;
+            }
+            uprv_memcpy(r->expansions->CEs, t->expansions->CEs, sizeof(uint32_t)*t->expansions->position);
+        } else {
+            r->expansions->CEs = NULL;
+        }
+    }
 
-U_CAPI void  U_EXPORT2
-uprv_uca_closeTempTable(tempUCATable *t) {
-  if(t != NULL) {
-    uprv_free(t->expansions->CEs);
-    uprv_free(t->expansions);
     if(t->contractions != NULL) {
-      uprv_cnttab_close(t->contractions);
+        r->contractions = uprv_cnttab_clone(t->contractions, status);
+        // Check for cloning failure.
+        if (r->contractions == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        r->contractions->mapping = r->mapping;
     }
-    /*ucmpe32_close(t->mapping);*/
-    utrie_close(t->mapping);
 
-    if(t->prefixLookup != NULL) {
-      uhash_close(t->prefixLookup);
+    if(t->maxExpansions != NULL) {
+        r->maxExpansions = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable));
+        /* test for NULL */
+        if (r->maxExpansions == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        r->maxExpansions->size = t->maxExpansions->size;
+        r->maxExpansions->position = t->maxExpansions->position;
+        if(t->maxExpansions->endExpansionCE != NULL) {
+            r->maxExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxExpansions->size);
+            /* test for NULL */
+            if (r->maxExpansions->endExpansionCE == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto cleanup;
+            }
+            uprv_memset(r->maxExpansions->endExpansionCE, 0xDB, sizeof(uint32_t)*t->maxExpansions->size);
+            uprv_memcpy(r->maxExpansions->endExpansionCE, t->maxExpansions->endExpansionCE, t->maxExpansions->position*sizeof(uint32_t));
+        } else {
+            r->maxExpansions->endExpansionCE = NULL;
+        }
+        if(t->maxExpansions->expansionCESize != NULL) {
+            r->maxExpansions->expansionCESize = (uint8_t *)uprv_malloc(sizeof(uint8_t)*t->maxExpansions->size);
+            /* test for NULL */
+            if (r->maxExpansions->expansionCESize == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto cleanup;
+            }
+            uprv_memset(r->maxExpansions->expansionCESize, 0xDB, sizeof(uint8_t)*t->maxExpansions->size);
+            uprv_memcpy(r->maxExpansions->expansionCESize, t->maxExpansions->expansionCESize, t->maxExpansions->position*sizeof(uint8_t));
+        } else {
+            r->maxExpansions->expansionCESize = NULL;
+        }
     }
 
-    uprv_free(t->maxExpansions->endExpansionCE);
-    uprv_free(t->maxExpansions->expansionCESize);
-    uprv_free(t->maxExpansions);
+    if(t->maxJamoExpansions != NULL) {
+        r->maxJamoExpansions = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable));
+        /* test for NULL */
+        if (r->maxJamoExpansions == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        r->maxJamoExpansions->size = t->maxJamoExpansions->size;
+        r->maxJamoExpansions->position = t->maxJamoExpansions->position;
+        r->maxJamoExpansions->maxLSize = t->maxJamoExpansions->maxLSize;
+        r->maxJamoExpansions->maxVSize = t->maxJamoExpansions->maxVSize;
+        r->maxJamoExpansions->maxTSize = t->maxJamoExpansions->maxTSize;
+        if(t->maxJamoExpansions->size != 0) {
+            r->maxJamoExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxJamoExpansions->size);
+            /* test for NULL */
+            if (r->maxJamoExpansions->endExpansionCE == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto cleanup;
+            }
+            uprv_memcpy(r->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->position*sizeof(uint32_t));
+            r->maxJamoExpansions->isV = (UBool *)uprv_malloc(sizeof(UBool)*t->maxJamoExpansions->size);
+            /* test for NULL */
+            if (r->maxJamoExpansions->isV == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto cleanup;
+            }
+            uprv_memcpy(r->maxJamoExpansions->isV, t->maxJamoExpansions->isV, t->maxJamoExpansions->position*sizeof(UBool));
+        } else {
+            r->maxJamoExpansions->endExpansionCE = NULL;
+            r->maxJamoExpansions->isV = NULL;
+        }
+    }
 
-    if (t->maxJamoExpansions->size > 0) {
-      uprv_free(t->maxJamoExpansions->endExpansionCE);
-      uprv_free(t->maxJamoExpansions->isV);
+    if(t->unsafeCP != NULL) {
+        r->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+        /* test for NULL */
+        if (r->unsafeCP == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        uprv_memcpy(r->unsafeCP, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE);
+    }
+
+    if(t->contrEndCP != NULL) {
+        r->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+        /* test for NULL */
+        if (r->contrEndCP == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE);
     }
-    uprv_free(t->maxJamoExpansions);
 
-    uprv_free(t->unsafeCP);
-    uprv_free(t->contrEndCP);
+    r->UCA = t->UCA;
+    r->image = t->image;
+    r->options = t->options;
 
-    uprv_free(t);
-  }
+    return r;
+cleanup:
+    uprv_uca_closeTempTable(t);
+    return NULL;
+}
+
+
+U_CAPI void  U_EXPORT2
+uprv_uca_closeTempTable(tempUCATable *t) {
+    if(t != NULL) {
+        if (t->expansions != NULL) {
+            uprv_free(t->expansions->CEs);
+            uprv_free(t->expansions);
+        }
+        if(t->contractions != NULL) {
+            uprv_cnttab_close(t->contractions);
+        }
+        if (t->mapping != NULL) {
+            utrie_close(t->mapping);
+        }
+
+        if(t->prefixLookup != NULL) {
+            uhash_close(t->prefixLookup);
+        }
+
+        if (t->maxExpansions != NULL) {
+            uprv_free(t->maxExpansions->endExpansionCE);
+            uprv_free(t->maxExpansions->expansionCESize);
+            uprv_free(t->maxExpansions);
+        }
+
+        if (t->maxJamoExpansions->size > 0) {
+            uprv_free(t->maxJamoExpansions->endExpansionCE);
+            uprv_free(t->maxJamoExpansions->isV);
+        }
+        uprv_free(t->maxJamoExpansions);
+
+        uprv_free(t->unsafeCP);
+        uprv_free(t->contrEndCP);
+        
+        if (t->cmLookup != NULL) {
+            uprv_free(t->cmLookup->cPoints);
+            uprv_free(t->cmLookup);
+        }
+
+        uprv_free(t);
+    }
 }
 
 /**
@@ -407,134 +433,135 @@ uprv_uca_closeTempTable(tempUCATable *t) {
 * @returns size of the maxexpansion and maxsize used.
 */
 static int uprv_uca_setMaxExpansion(uint32_t           endexpansion,
-                             uint8_t            expansionsize,
-                             MaxExpansionTable *maxexpansion,
-                             UErrorCode        *status)
+                                    uint8_t            expansionsize,
+                                    MaxExpansionTable *maxexpansion,
+                                    UErrorCode        *status)
 {
-  if (maxexpansion->size == 0) {
-    /* we'll always make the first element 0, for easier manipulation */
-    maxexpansion->endExpansionCE = 
-               (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(int32_t));
-    /* test for NULL */
-    if (maxexpansion->endExpansionCE == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+    if (maxexpansion->size == 0) {
+        /* we'll always make the first element 0, for easier manipulation */
+        maxexpansion->endExpansionCE = 
+            (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(int32_t));
+        /* test for NULL */
+        if (maxexpansion->endExpansionCE == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *(maxexpansion->endExpansionCE) = 0;
+        maxexpansion->expansionCESize =
+            (uint8_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint8_t));
+        /* test for NULL */;
+        if (maxexpansion->expansionCESize == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *(maxexpansion->expansionCESize) = 0;
+        maxexpansion->size     = INIT_EXP_TABLE_SIZE;
+        maxexpansion->position = 0;
     }
-    *(maxexpansion->endExpansionCE) = 0;
-    maxexpansion->expansionCESize =
-               (uint8_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint8_t));
-    /* test for NULL */;
-    if (maxexpansion->expansionCESize == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+
+    if (maxexpansion->position + 1 == maxexpansion->size) {
+        uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, 
+            2 * maxexpansion->size * sizeof(uint32_t));
+        if (neweece == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        maxexpansion->endExpansionCE  = neweece;
+
+        uint8_t  *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize, 
+            2 * maxexpansion->size * sizeof(uint8_t));
+        if (neweces == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        maxexpansion->expansionCESize = neweces;
+        maxexpansion->size *= 2;
     }
-    *(maxexpansion->expansionCESize) = 0;
-    maxexpansion->size     = INIT_EXP_TABLE_SIZE;
-    maxexpansion->position = 0;
-  }
-
-  if (maxexpansion->position + 1 == maxexpansion->size) {
-    uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, 
-                                   2 * maxexpansion->size * sizeof(uint32_t));
-    uint8_t  *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize, 
-                                    2 * maxexpansion->size * sizeof(uint8_t));
-    if (neweece == NULL || neweces == NULL) {
-#ifdef UCOL_DEBUG
-      fprintf(stderr, "out of memory for maxExpansions\n");
-#endif
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      return -1;
-    }
-    maxexpansion->endExpansionCE  = neweece;
-    maxexpansion->expansionCESize = neweces;
-    maxexpansion->size *= 2;
-  }
-
-  uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
-  uint8_t  *pexpansionsize  = maxexpansion->expansionCESize;
-  int      pos              = maxexpansion->position;
-
-  uint32_t *start = pendexpansionce;
-  uint32_t *limit = pendexpansionce + pos;
-
-  /* using binary search to determine if last expansion element is 
-     already in the array */
-  uint32_t *mid;                                                        
-  int       result = -1;
-  while (start < limit - 1) {                                                
-    mid = start + ((limit - start) >> 1);                                    
-    if (endexpansion <= *mid) {                                                   
-      limit = mid;                                                           
-    }                                                                        
-    else {                                                                   
-      start = mid;                                                           
-    }                                                                        
-  } 
-
-  if (*start == endexpansion) {                                                     
-    result = start - pendexpansionce;  
-  }                                                                          
-  else                                                                       
-    if (*limit == endexpansion) {                                                     
-      result = limit - pendexpansionce;      
-    }                                            
-
-  if (result > -1) {
-    /* found the ce in expansion, we'll just modify the size if it is 
-       smaller */
-    uint8_t *currentsize = pexpansionsize + result;
-    if (*currentsize < expansionsize) {
-      *currentsize = expansionsize;
-    }
-  }
-  else {
-    /* we'll need to squeeze the value into the array. 
-       initial implementation. */
-    /* shifting the subarray down by 1 */
-    int      shiftsize     = (pendexpansionce + pos) - start;
-    uint32_t *shiftpos     = start + 1;
-    uint8_t  *sizeshiftpos = pexpansionsize + (shiftpos - pendexpansionce);
-
-    /* okay need to rearrange the array into sorted order */
-    if (shiftsize == 0 /*|| *(pendexpansionce + pos) < endexpansion*/) { /* the commented part is actually both redundant and dangerous */
-      *(pendexpansionce + pos + 1) = endexpansion;
-      *(pexpansionsize + pos + 1)  = expansionsize;
+
+    uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
+    uint8_t  *pexpansionsize  = maxexpansion->expansionCESize;
+    int      pos              = maxexpansion->position;
+
+    uint32_t *start = pendexpansionce;
+    uint32_t *limit = pendexpansionce + pos;
+
+    /* using binary search to determine if last expansion element is
+    already in the array */
+    uint32_t *mid;
+    int       result = -1;
+    while (start < limit - 1) {
+        mid = start + ((limit - start) >> 1);
+        if (endexpansion <= *mid) {
+            limit = mid;
+        }
+        else {
+            start = mid;
+        }
     }
-    else {
-      uprv_memmove(shiftpos + 1, shiftpos, shiftsize * sizeof(int32_t));
-      uprv_memmove(sizeshiftpos + 1, sizeshiftpos, 
-                                                shiftsize * sizeof(uint8_t));
-      *shiftpos     = endexpansion;
-      *sizeshiftpos = expansionsize;
+
+    if (*start == endexpansion) {
+        result = (int)(start - pendexpansionce);
+    }
+    else if (*limit == endexpansion) {
+        result = (int)(limit - pendexpansionce);
     }
-    maxexpansion->position ++;
+
+    if (result > -1) {
+        /* found the ce in expansion, we'll just modify the size if it is
+        smaller */
+        uint8_t *currentsize = pexpansionsize + result;
+        if (*currentsize < expansionsize) {
+            *currentsize = expansionsize;
+        }
+    }
+    else {
+        /* we'll need to squeeze the value into the array.
+        initial implementation. */
+        /* shifting the subarray down by 1 */
+        int      shiftsize     = (int)((pendexpansionce + pos) - start);
+        uint32_t *shiftpos     = start + 1;
+        uint8_t  *sizeshiftpos = pexpansionsize + (shiftpos - pendexpansionce);
+
+        /* okay need to rearrange the array into sorted order */
+        if (shiftsize == 0 /*|| *(pendexpansionce + pos) < endexpansion*/) { /* the commented part is actually both redundant and dangerous */
+            *(pendexpansionce + pos + 1) = endexpansion;
+            *(pexpansionsize + pos + 1)  = expansionsize;
+        }
+        else {
+            uprv_memmove(shiftpos + 1, shiftpos, shiftsize * sizeof(int32_t));
+            uprv_memmove(sizeshiftpos + 1, sizeshiftpos, 
+                shiftsize * sizeof(uint8_t));
+            *shiftpos     = endexpansion;
+            *sizeshiftpos = expansionsize;
+        }
+        maxexpansion->position ++;
 
 #ifdef UCOL_DEBUG
-    int   temp;
-    UBool found = FALSE;
-    for (temp = 0; temp < maxexpansion->position; temp ++) {
-      if (pendexpansionce[temp] >= pendexpansionce[temp + 1]) {
-        fprintf(stderr, "expansions %d\n", temp);
-      }
-      if (pendexpansionce[temp] == endexpansion) {
-        found =TRUE;
-        if (pexpansionsize[temp] < expansionsize) {
-          fprintf(stderr, "expansions size %d\n", temp);
-        }
-      }
-    }
-    if (pendexpansionce[temp] == endexpansion) {
-        found =TRUE;
-        if (pexpansionsize[temp] < expansionsize) {
-          fprintf(stderr, "expansions size %d\n", temp);
-        }
-      }
-    if (!found)
-      fprintf(stderr, "expansion not found %d\n", temp);
+        int   temp;
+        UBool found = FALSE;
+        for (temp = 0; temp < maxexpansion->position; temp ++) {
+            if (pendexpansionce[temp] >= pendexpansionce[temp + 1]) {
+                fprintf(stderr, "expansions %d\n", temp);
+            }
+            if (pendexpansionce[temp] == endexpansion) {
+                found =TRUE;
+                if (pexpansionsize[temp] < expansionsize) {
+                    fprintf(stderr, "expansions size %d\n", temp);
+                }
+            }
+        }
+        if (pendexpansionce[temp] == endexpansion) {
+            found =TRUE;
+            if (pexpansionsize[temp] < expansionsize) {
+                fprintf(stderr, "expansions size %d\n", temp);
+            }
+        }
+        if (!found)
+            fprintf(stderr, "expansion not found %d\n", temp);
 #endif
-  }
+    }
 
-  return maxexpansion->position;
+    return maxexpansion->position;
 }
 
 /**
@@ -549,90 +576,99 @@ static int uprv_uca_setMaxExpansion(uint32_t           endexpansion,
 * @returns size of the maxexpansion and maxsize used.
 */
 static int uprv_uca_setMaxJamoExpansion(UChar                  ch,
-                                 uint32_t               endexpansion,
-                                 uint8_t                expansionsize,
-                                 MaxJamoExpansionTable *maxexpansion,
-                                 UErrorCode            *status)
+                                        uint32_t               endexpansion,
+                                        uint8_t                expansionsize,
+                                        MaxJamoExpansionTable *maxexpansion,
+                                        UErrorCode            *status)
 {
-  UBool isV = TRUE;
-  if (((uint32_t)ch - 0x1100) <= (0x1112 - 0x1100)) {
-      /* determines L for Jamo, doesn't need to store this since it is never
-      at the end of a expansion */
-      if (maxexpansion->maxLSize < expansionsize) {
-          maxexpansion->maxLSize = expansionsize;
-      }
-      return maxexpansion->position;
-  }
-
-  if (((uint32_t)ch - 0x1161) <= (0x1175 - 0x1161)) {
-      /* determines V for Jamo */
-      if (maxexpansion->maxVSize < expansionsize) {
-          maxexpansion->maxVSize = expansionsize;
-      }
-  }
-
-  if (((uint32_t)ch - 0x11A8) <= (0x11C2 - 0x11A8)) {
-      isV = FALSE;
-      /* determines T for Jamo */
-      if (maxexpansion->maxTSize < expansionsize) {
-          maxexpansion->maxTSize = expansionsize;
-      }
-  }
-
-  if (maxexpansion->size == 0) {
-    /* we'll always make the first element 0, for easier manipulation */
-    maxexpansion->endExpansionCE = 
-               (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint32_t));
-    /* test for NULL */;
-    if (maxexpansion->endExpansionCE == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+    UBool isV = TRUE;
+    if (((uint32_t)ch - 0x1100) <= (0x1112 - 0x1100)) {
+        /* determines L for Jamo, doesn't need to store this since it is never
+        at the end of a expansion */
+        if (maxexpansion->maxLSize < expansionsize) {
+            maxexpansion->maxLSize = expansionsize;
+        }
+        return maxexpansion->position;
     }
-    *(maxexpansion->endExpansionCE) = 0;
-    maxexpansion->isV = 
-                 (UBool *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(UBool));
-    /* test for NULL */;
-    if (maxexpansion->isV == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+
+    if (((uint32_t)ch - 0x1161) <= (0x1175 - 0x1161)) {
+        /* determines V for Jamo */
+        if (maxexpansion->maxVSize < expansionsize) {
+            maxexpansion->maxVSize = expansionsize;
+        }
+    }
+
+    if (((uint32_t)ch - 0x11A8) <= (0x11C2 - 0x11A8)) {
+        isV = FALSE;
+        /* determines T for Jamo */
+        if (maxexpansion->maxTSize < expansionsize) {
+            maxexpansion->maxTSize = expansionsize;
+        }
+    }
+
+    if (maxexpansion->size == 0) {
+        /* we'll always make the first element 0, for easier manipulation */
+        maxexpansion->endExpansionCE = 
+            (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint32_t));
+        /* test for NULL */;
+        if (maxexpansion->endExpansionCE == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *(maxexpansion->endExpansionCE) = 0;
+        maxexpansion->isV = 
+            (UBool *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(UBool));
+        /* test for NULL */;
+        if (maxexpansion->isV == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            uprv_free(maxexpansion->endExpansionCE);
+            maxexpansion->endExpansionCE = NULL;
+            return 0;
+        }
+        *(maxexpansion->isV) = 0;
+        maxexpansion->size     = INIT_EXP_TABLE_SIZE;
+        maxexpansion->position = 0;
     }
-    *(maxexpansion->isV) = 0;
-    maxexpansion->size     = INIT_EXP_TABLE_SIZE;
-    maxexpansion->position = 0;
-  }
-
-  if (maxexpansion->position + 1 == maxexpansion->size) {
-    uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, 
-                                   2 * maxexpansion->size * sizeof(uint32_t));
-    UBool    *newisV  = (UBool *)uprv_realloc(maxexpansion->isV, 
-                                   2 * maxexpansion->size * sizeof(UBool));
-    if (neweece == NULL || newisV == NULL) {
+
+    if (maxexpansion->position + 1 == maxexpansion->size) {
+        maxexpansion->size *= 2;
+        maxexpansion->endExpansionCE = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, 
+            maxexpansion->size * sizeof(uint32_t));
+        if (maxexpansion->endExpansionCE == NULL) {
+#ifdef UCOL_DEBUG
+            fprintf(stderr, "out of memory for maxExpansions\n");
+#endif
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        maxexpansion->isV  = (UBool *)uprv_realloc(maxexpansion->isV, 
+            maxexpansion->size * sizeof(UBool));
+        if (maxexpansion->isV == NULL) {
 #ifdef UCOL_DEBUG
-      fprintf(stderr, "out of memory for maxExpansions\n");
+            fprintf(stderr, "out of memory for maxExpansions\n");
 #endif
-      *status = U_MEMORY_ALLOCATION_ERROR;
-      return -1;
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            uprv_free(maxexpansion->endExpansionCE);
+            maxexpansion->endExpansionCE = NULL;
+            return 0;
+        }
     }
-    maxexpansion->endExpansionCE  = neweece;
-    maxexpansion->isV             = newisV;
-    maxexpansion->size *= 2;
-  }
 
-  uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
-  int       pos             = maxexpansion->position;
+    uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
+    int       pos             = maxexpansion->position;
 
-  while (pos > 0) {
-      pos --;
-      if (*(pendexpansionce + pos) == endexpansion) {
-          return maxexpansion->position;
-      }
-  }
+    while (pos > 0) {
+        pos --;
+        if (*(pendexpansionce + pos) == endexpansion) {
+            return maxexpansion->position;
+        }
+    }
 
-  *(pendexpansionce + maxexpansion->position) = endexpansion;
-  *(maxexpansion->isV + maxexpansion->position) = isV;
-  maxexpansion->position ++;
+    *(pendexpansionce + maxexpansion->position) = endexpansion;
+    *(maxexpansion->isV + maxexpansion->position) = isV;
+    maxexpansion->position ++;
 
-  return maxexpansion->position;
+    return maxexpansion->position;
 }
 
 
@@ -666,51 +702,133 @@ static void unsafeCPSet(uint8_t *table, UChar c) {
     *htByte |= (1 << (hash & 7));
 }
 
+static void
+uprv_uca_createCMTable(tempUCATable *t, int32_t noOfCM, UErrorCode *status) {
+    t->cmLookup = (CombinClassTable *)uprv_malloc(sizeof(CombinClassTable));
+    if (t->cmLookup==NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    t->cmLookup->cPoints=(UChar *)uprv_malloc(noOfCM*sizeof(UChar));
+    if (t->cmLookup->cPoints ==NULL) {
+        uprv_free(t->cmLookup);
+        t->cmLookup = NULL;
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    t->cmLookup->size=noOfCM;
+    uprv_memset(t->cmLookup->index, 0, sizeof(t->cmLookup->index));
+
+    return;
+}
 
-/*  to the UnsafeCP hash table, add all chars with combining class != 0     */
+static void
+uprv_uca_copyCMTable(tempUCATable *t, UChar *cm, uint16_t *index) {
+    int32_t count=0;
+
+    for (int32_t i=0; i<256; ++i) {
+        if (index[i]>0) {
+            // cPoints is ordered by combining class value.
+            uprv_memcpy(t->cmLookup->cPoints+count, cm+(i<<8), index[i]*sizeof(UChar));
+            count += index[i];
+        }
+        t->cmLookup->index[i]=count;
+    }
+    return;
+}
+
+/* 1. to the UnsafeCP hash table, add all chars with combining class != 0     */
+/* 2. build combining marks table for all chars with combining class != 0     */
 static void uprv_uca_unsafeCPAddCCNZ(tempUCATable *t, UErrorCode *status) {
 
     UChar              c;
-    uint16_t           fcd;     // Hi byte is lead combining class.
-                                // lo byte is trailing combing class.
-    const uint16_t    *fcdTrieData;
-
-    fcdTrieData = unorm_getFCDTrie(status);
+    uint16_t           fcd;     // Hi byte is lead combining class. lo byte is trailing combing class.
+    UBool buildCMTable = (t->cmLookup==NULL); // flag for building combining class table
+    UChar *cm=NULL;
+    uint16_t index[256];
+    int32_t count=0;
+    const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status);
     if (U_FAILURE(*status)) {
         return;
     }
 
+    if (buildCMTable) {
+        if (cm==NULL) {
+            cm = (UChar *)uprv_malloc(sizeof(UChar)*UCOL_MAX_CM_TAB);
+            if (cm==NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+        }
+        uprv_memset(index, 0, sizeof(index));
+    }
     for (c=0; c<0xffff; c++) {
-        fcd = unorm_getFCD16(fcdTrieData, c);
+        if (U16_IS_LEAD(c)) {
+            fcd = 0;
+            if (nfcImpl->singleLeadMightHaveNonZeroFCD16(c)) {
+                UChar32 supp = U16_GET_SUPPLEMENTARY(c, 0xdc00);
+                UChar32 suppLimit = supp + 0x400;
+                while (supp < suppLimit) {
+                    fcd |= nfcImpl->getFCD16FromNormData(supp++);
+                }
+            }
+        } else {
+            fcd = nfcImpl->getFCD16(c);
+        }
         if (fcd >= 0x100 ||               // if the leading combining class(c) > 0 ||
-            (UTF_IS_LEAD(c) && fcd != 0)) //    c is a leading surrogate with some FCD data
-                unsafeCPSet(t->unsafeCP, c);
+            (U16_IS_LEAD(c) && fcd != 0)) {//    c is a leading surrogate with some FCD data
+            if (buildCMTable) {
+                uint32_t cClass = fcd & 0xff;
+                //uint32_t temp=(cClass<<8)+index[cClass];
+                cm[(cClass<<8)+index[cClass]] = c; //
+                index[cClass]++;
+                count++;
+            }
+            unsafeCPSet(t->unsafeCP, c);
+        }
+    }
+
+    // copy to cm table
+    if (buildCMTable) {
+        uprv_uca_createCMTable(t, count, status);
+        if(U_FAILURE(*status)) {
+            if (cm!=NULL) {
+                uprv_free(cm);
+            }
+            return;
+        }
+        uprv_uca_copyCMTable(t, cm, index);
     }
 
     if(t->prefixLookup != NULL) {
-      int32_t i = -1;
-      const UHashElement *e = NULL;
-      UCAElements *element = NULL;
-      UChar NFCbuf[256];
-      uint32_t NFCbufLen = 0;
-      while((e = uhash_nextElement(t->prefixLookup, &i)) != NULL) {
-        element = (UCAElements *)e->value.pointer;
-        // codepoints here are in the NFD form. We need to add the
-        // first code point of the NFC form to unsafe, because 
-        // strcoll needs to backup over them.
-        NFCbufLen = unorm_normalize(element->cPoints, element->cSize, UNORM_NFC, 0,
-          NFCbuf, 256, status);
-        unsafeCPSet(t->unsafeCP, NFCbuf[0]);
-      } 
+        int32_t i = -1;
+        const UHashElement *e = NULL;
+        UCAElements *element = NULL;
+        UChar NFCbuf[256];
+        while((e = uhash_nextElement(t->prefixLookup, &i)) != NULL) {
+            element = (UCAElements *)e->value.pointer;
+            // codepoints here are in the NFD form. We need to add the
+            // first code point of the NFC form to unsafe, because
+            // strcoll needs to backup over them.
+            unorm_normalize(element->cPoints, element->cSize, UNORM_NFC, 0,
+                NFCbuf, 256, status);
+            unsafeCPSet(t->unsafeCP, NFCbuf[0]);
+        }
+    }
+
+    if (cm!=NULL) {
+        uprv_free(cm);
     }
 }
 
-static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE, 
-                                 UCAElements *element, UErrorCode *status) {
-  // currently the longest prefix we're supporting in Japanese is two characters
-  // long. Although this table could quite easily mimic complete contraction stuff
-  // there is no good reason to make a general solution, as it would require some 
-  // error prone messing.
+static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE,
+                                   UCAElements *element, UErrorCode *status)
+{
+    // currently the longest prefix we're supporting in Japanese is two characters
+    // long. Although this table could quite easily mimic complete contraction stuff
+    // there is no good reason to make a general solution, as it would require some
+    // error prone messing.
     CntTable *contractions = t->contractions;
     UChar32 cp;
     uint32_t cpsize = 0;
@@ -724,48 +842,48 @@ static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE,
     uint32_t j = 0;
 #ifdef UCOL_DEBUG
     for(j=0; j<element->cSize; j++) {
-      fprintf(stdout, "CP: %04X ", element->cPoints[j]);
+        fprintf(stdout, "CP: %04X ", element->cPoints[j]);
     }
     fprintf(stdout, "El: %08X Pref: ", CE);
     for(j=0; j<element->prefixSize; j++) {
-      fprintf(stdout, "%04X ", element->prefix[j]);
+        fprintf(stdout, "%04X ", element->prefix[j]);
     }
     fprintf(stdout, "%08X ", element->mapCE);
 #endif
 
     for (j = 1; j<element->prefixSize; j++) {   /* First add NFD prefix chars to unsafe CP hash table */
-      // Unless it is a trail surrogate, which is handled algoritmically and 
-      // shouldn't take up space in the table.
-      if(!(UTF_IS_TRAIL(element->prefix[j]))) {
-        unsafeCPSet(t->unsafeCP, element->prefix[j]);
-      }
+        // Unless it is a trail surrogate, which is handled algoritmically and
+        // shouldn't take up space in the table.
+        if(!(U16_IS_TRAIL(element->prefix[j]))) {
+            unsafeCPSet(t->unsafeCP, element->prefix[j]);
+        }
     }
 
     UChar tempPrefix = 0;
 
     for(j = 0; j < /*nfcSize*/element->prefixSize/2; j++) { // prefixes are going to be looked up backwards
-      // therefore, we will promptly reverse the prefix buffer...
-      tempPrefix = *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1);
-      *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1) = element->prefix[j];
-      element->prefix[j] = tempPrefix;
+        // therefore, we will promptly reverse the prefix buffer...
+        tempPrefix = *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1);
+        *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1) = element->prefix[j];
+        element->prefix[j] = tempPrefix;
     }
 
 #ifdef UCOL_DEBUG
     fprintf(stdout, "Reversed: ");
     for(j=0; j<element->prefixSize; j++) {
-      fprintf(stdout, "%04X ", element->prefix[j]);
+        fprintf(stdout, "%04X ", element->prefix[j]);
     }
     fprintf(stdout, "%08X\n", element->mapCE);
 #endif
 
     // the first codepoint is also unsafe, as it forms a 'contraction' with the prefix
-    if(!(UTF_IS_TRAIL(element->cPoints[0]))) {
-      unsafeCPSet(t->unsafeCP, element->cPoints[0]);
+    if(!(U16_IS_TRAIL(element->cPoints[0]))) {
+        unsafeCPSet(t->unsafeCP, element->cPoints[0]);
     }
 
     // Maybe we need this... To handle prefixes completely in the forward direction...
     //if(element->cSize == 1) {
-    //  if(!(UTF_IS_TRAIL(element->cPoints[0]))) {
+    //  if(!(U16_IS_TRAIL(element->cPoints[0]))) {
     //    ContrEndCPSet(t->contrEndCP, element->cPoints[0]);
     //  }
     //}
@@ -774,44 +892,43 @@ static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE,
     element->cSize = element->prefixSize;
 
     // Add the last char of the contraction to the contraction-end hash table.
-    // unless it is a trail surrogate, which is handled algorithmically and 
+    // unless it is a trail surrogate, which is handled algorithmically and
     // shouldn't be in the table
-    if(!(UTF_IS_TRAIL(element->cPoints[element->cSize -1]))) {
-      ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
+    if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) {
+        ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
     }
 
     // First we need to check if contractions starts with a surrogate
-    UTF_NEXT_CHAR(element->cPoints, cpsize, element->cSize, cp);
+    U16_NEXT(element->cPoints, cpsize, element->cSize, cp);
 
-    // If there are any Jamos in the contraction, we should turn on special 
+    // If there are any Jamos in the contraction, we should turn on special
     // processing for Jamos
     if(UCOL_ISJAMO(element->prefix[0])) {
-      t->image->jamoSpecial = TRUE;
+        t->image->jamoSpecial = TRUE;
     }
     /* then we need to deal with it */
     /* we could aready have something in table - or we might not */
 
-    if(!isPrefix(CE)) { 
-      /* if it wasn't contraction, we wouldn't end up here*/
-      int32_t firstContractionOffset = 0;
-      int32_t contractionOffset = 0;
-      firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
-      uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-      contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->prefix, newCE, status);
-      contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
-      CE =  constructContractCE(SPEC_PROC_TAG, firstContractionOffset);
+    if(!isPrefix(CE)) {
+        /* if it wasn't contraction, we wouldn't end up here*/
+        int32_t firstContractionOffset = 0;
+        firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
+        uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+        uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->prefix, newCE, status);
+        uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
+        CE =  constructContractCE(SPEC_PROC_TAG, firstContractionOffset);
     } else { /* we are adding to existing contraction */
-      /* there were already some elements in the table, so we need to add a new contraction */
-      /* Two things can happen here: either the codepoint is already in the table, or it is not */
-      int32_t position = uprv_cnttab_findCP(contractions, CE, *element->prefix, status);
-      if(position > 0) {       /* if it is we just continue down the chain */
-        uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
-        uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
-        uprv_cnttab_setContraction(contractions, CE, position, *(element->prefix), newCE, status);
-      } else {                  /* if it isn't, we will have to create a new sequence */
-        uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-        uprv_cnttab_insertContraction(contractions, CE, *(element->prefix), element->mapCE, status);
-      }
+        /* there were already some elements in the table, so we need to add a new contraction */
+        /* Two things can happen here: either the codepoint is already in the table, or it is not */
+        int32_t position = uprv_cnttab_findCP(contractions, CE, *element->prefix, status);
+        if(position > 0) {       /* if it is we just continue down the chain */
+            uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
+            uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+            uprv_cnttab_setContraction(contractions, CE, position, *(element->prefix), newCE, status);
+        } else {                  /* if it isn't, we will have to create a new sequence */
+            uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+            uprv_cnttab_insertContraction(contractions, CE, *(element->prefix), element->mapCE, status);
+        }
     }
 
     element->cPoints = oldCP;
@@ -826,7 +943,8 @@ static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE,
 // as it doesn't affect the performance AND handling surrogates specially
 // would complicate code way too much.
 static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE, 
-                                 UCAElements *element, UErrorCode *status) {
+                                        UCAElements *element, UErrorCode *status)
+{
     CntTable *contractions = t->contractions;
     UChar32 cp;
     uint32_t cpsize = 0;
@@ -834,65 +952,64 @@ static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE,
     contractions->currentTag = CONTRACTION_TAG;
 
     // First we need to check if contractions starts with a surrogate
-    UTF_NEXT_CHAR(element->cPoints, cpsize, element->cSize, cp);
+    U16_NEXT(element->cPoints, cpsize, element->cSize, cp);
 
     if(cpsize<element->cSize) { // This is a real contraction, if there are other characters after the first
-      uint32_t j = 0;
-      for (j=1; j<element->cSize; j++) {   /* First add contraction chars to unsafe CP hash table */
-        // Unless it is a trail surrogate, which is handled algoritmically and 
-        // shouldn't take up space in the table.
-        if(!(UTF_IS_TRAIL(element->cPoints[j]))) {
-          unsafeCPSet(t->unsafeCP, element->cPoints[j]);
-        }
-      }
-      // Add the last char of the contraction to the contraction-end hash table.
-      // unless it is a trail surrogate, which is handled algorithmically and 
-      // shouldn't be in the table
-      if(!(UTF_IS_TRAIL(element->cPoints[element->cSize -1]))) {
-        ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
-      }
+        uint32_t j = 0;
+        for (j=1; j<element->cSize; j++) {   /* First add contraction chars to unsafe CP hash table */
+            // Unless it is a trail surrogate, which is handled algoritmically and 
+            // shouldn't take up space in the table.
+            if(!(U16_IS_TRAIL(element->cPoints[j]))) {
+                unsafeCPSet(t->unsafeCP, element->cPoints[j]);
+            }
+        }
+        // Add the last char of the contraction to the contraction-end hash table.
+        // unless it is a trail surrogate, which is handled algorithmically and 
+        // shouldn't be in the table
+        if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) {
+            ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
+        }
 
-      // If there are any Jamos in the contraction, we should turn on special 
-      // processing for Jamos
-      if(UCOL_ISJAMO(element->cPoints[0])) {
-        t->image->jamoSpecial = TRUE;
-      }
-      /* then we need to deal with it */
-      /* we could aready have something in table - or we might not */
-      element->cPoints+=cpsize;
-      element->cSize-=cpsize;
-      if(!isContraction(CE)) { 
-        /* if it wasn't contraction, we wouldn't end up here*/
-        int32_t firstContractionOffset = 0;
-        int32_t contractionOffset = 0;
-        firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
-        uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-        contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
-        contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
-        CE =  constructContractCE(CONTRACTION_TAG, firstContractionOffset);
-      } else { /* we are adding to existing contraction */
-        /* there were already some elements in the table, so we need to add a new contraction */
-        /* Two things can happen here: either the codepoint is already in the table, or it is not */
-        int32_t position = uprv_cnttab_findCP(contractions, CE, *element->cPoints, status);
-        if(position > 0) {       /* if it is we just continue down the chain */
-          uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
-          uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
-          uprv_cnttab_setContraction(contractions, CE, position, *(element->cPoints), newCE, status);
-        } else {                  /* if it isn't, we will have to create a new sequence */
-          uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-          uprv_cnttab_insertContraction(contractions, CE, *(element->cPoints), newCE, status);
-        }
-      }
-      element->cPoints-=cpsize;
-      element->cSize+=cpsize;
-      /*ucmpe32_set(t->mapping, cp, CE);*/
-      utrie_set32(t->mapping, cp, CE);
+        // If there are any Jamos in the contraction, we should turn on special 
+        // processing for Jamos
+        if(UCOL_ISJAMO(element->cPoints[0])) {
+            t->image->jamoSpecial = TRUE;
+        }
+        /* then we need to deal with it */
+        /* we could aready have something in table - or we might not */
+        element->cPoints+=cpsize;
+        element->cSize-=cpsize;
+        if(!isContraction(CE)) { 
+            /* if it wasn't contraction, we wouldn't end up here*/
+            int32_t firstContractionOffset = 0;
+            firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
+            uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+            uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
+            uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
+            CE =  constructContractCE(CONTRACTION_TAG, firstContractionOffset);
+        } else { /* we are adding to existing contraction */
+            /* there were already some elements in the table, so we need to add a new contraction */
+            /* Two things can happen here: either the codepoint is already in the table, or it is not */
+            int32_t position = uprv_cnttab_findCP(contractions, CE, *element->cPoints, status);
+            if(position > 0) {       /* if it is we just continue down the chain */
+                uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
+                uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+                uprv_cnttab_setContraction(contractions, CE, position, *(element->cPoints), newCE, status);
+            } else {                  /* if it isn't, we will have to create a new sequence */
+                uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+                uprv_cnttab_insertContraction(contractions, CE, *(element->cPoints), newCE, status);
+            }
+        }
+        element->cPoints-=cpsize;
+        element->cSize+=cpsize;
+        /*ucmpe32_set(t->mapping, cp, CE);*/
+        utrie_set32(t->mapping, cp, CE);
     } else if(!isContraction(CE)) { /* this is just a surrogate, and there is no contraction */
-      /*ucmpe32_set(t->mapping, cp, element->mapCE);*/
-      utrie_set32(t->mapping, cp, element->mapCE);
+        /*ucmpe32_set(t->mapping, cp, element->mapCE);*/
+        utrie_set32(t->mapping, cp, element->mapCE);
     } else { /* fill out the first stage of the contraction with the surrogate CE */
-      uprv_cnttab_changeContraction(contractions, CE, 0, element->mapCE, status);
-      uprv_cnttab_changeContraction(contractions, CE, 0xFFFF, element->mapCE, status);
+        uprv_cnttab_changeContraction(contractions, CE, 0, element->mapCE, status);
+        uprv_cnttab_changeContraction(contractions, CE, 0xFFFF, element->mapCE, status);
     }
     return CE;
 }
@@ -900,8 +1017,7 @@ static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE,
 
 static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status) {
     int32_t firstContractionOffset = 0;
-    int32_t contractionOffset = 0;
-//    uint32_t contractionElement = UCOL_NOT_FOUND;
+    //    uint32_t contractionElement = UCOL_NOT_FOUND;
 
     if(U_FAILURE(*status)) {
         return UCOL_NOT_FOUND;
@@ -909,13 +1025,13 @@ static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements
 
     /* end of recursion */
     if(element->cSize == 1) {
-      if(isCntTableElement(existingCE) && ((UColCETags)getCETag(existingCE) == contractions->currentTag)) {
-        uprv_cnttab_changeContraction(contractions, existingCE, 0, element->mapCE, status);
-        uprv_cnttab_changeContraction(contractions, existingCE, 0xFFFF, element->mapCE, status);
-        return existingCE;
-      } else {
-        return element->mapCE; /*can't do just that. existingCe might be a contraction, meaning that we need to do another step */
-      }
+        if(isCntTableElement(existingCE) && ((UColCETags)getCETag(existingCE) == contractions->currentTag)) {
+            uprv_cnttab_changeContraction(contractions, existingCE, 0, element->mapCE, status);
+            uprv_cnttab_changeContraction(contractions, existingCE, 0xFFFF, element->mapCE, status);
+            return existingCE;
+        } else {
+            return element->mapCE; /*can't do just that. existingCe might be a contraction, meaning that we need to do another step */
+        }
     }
 
     /* this recursion currently feeds on the only element we have... We will have to copy it in order to accomodate */
@@ -926,24 +1042,24 @@ static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements
     element->cPoints++;
     element->cSize--;
     if(!isCntTableElement(existingCE)) { 
-      /* if it wasn't contraction, we wouldn't end up here*/
-      firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, existingCE, status);
-      uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-      contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
-      contractionOffset = uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, existingCE, status);
-      existingCE =  constructContractCE(contractions->currentTag, firstContractionOffset);
-    } else { /* we are adding to existing contraction */
-      /* there were already some elements in the table, so we need to add a new contraction */
-      /* Two things can happen here: either the codepoint is already in the table, or it is not */
-      int32_t position = uprv_cnttab_findCP(contractions, existingCE, *element->cPoints, status);
-      if(position > 0) {       /* if it is we just continue down the chain */
-        uint32_t eCE = uprv_cnttab_getCE(contractions, existingCE, position, status);
-        uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
-        uprv_cnttab_setContraction(contractions, existingCE, position, *(element->cPoints), newCE, status);
-      } else {                  /* if it isn't, we will have to create a new sequence */
+        /* if it wasn't contraction, we wouldn't end up here*/
+        firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, existingCE, status);
         uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
-        uprv_cnttab_insertContraction(contractions, existingCE, *(element->cPoints), newCE, status);
-      }
+        uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
+        uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, existingCE, status);
+        existingCE =  constructContractCE(contractions->currentTag, firstContractionOffset);
+    } else { /* we are adding to existing contraction */
+        /* there were already some elements in the table, so we need to add a new contraction */
+        /* Two things can happen here: either the codepoint is already in the table, or it is not */
+        int32_t position = uprv_cnttab_findCP(contractions, existingCE, *element->cPoints, status);
+        if(position > 0) {       /* if it is we just continue down the chain */
+            uint32_t eCE = uprv_cnttab_getCE(contractions, existingCE, position, status);
+            uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+            uprv_cnttab_setContraction(contractions, existingCE, position, *(element->cPoints), newCE, status);
+        } else {                  /* if it isn't, we will have to create a new sequence */
+            uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+            uprv_cnttab_insertContraction(contractions, existingCE, *(element->cPoints), newCE, status);
+        }
     }
     element->cPoints--;
     element->cSize++;
@@ -951,346 +1067,366 @@ static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements
 }
 
 static uint32_t uprv_uca_finalizeAddition(tempUCATable *t, UCAElements *element, UErrorCode *status) {
-  uint32_t CE = UCOL_NOT_FOUND;
-  // This should add a completely ignorable element to the 
-  // unsafe table, so that backward iteration will skip
-  // over it when treating contractions.
-  uint32_t i = 0;
-  if(element->mapCE == 0) {
-    for(i = 0; i < element->cSize; i++) {
-      if(!UTF_IS_TRAIL(element->cPoints[i])) {
-        unsafeCPSet(t->unsafeCP, element->cPoints[i]);
-      }
-    }
-  }
-  if(element->cSize > 1) { /* we're adding a contraction */
+    uint32_t CE = UCOL_NOT_FOUND;
+    // This should add a completely ignorable element to the 
+    // unsafe table, so that backward iteration will skip
+    // over it when treating contractions.
     uint32_t i = 0;
-    UChar32 cp;
-
-    UTF_NEXT_CHAR(element->cPoints, i, element->cSize, cp);
-    /*CE = ucmpe32_get(t->mapping, cp);*/
-    CE = utrie_get32(t->mapping, cp, NULL);
-
-    CE = uprv_uca_addContraction(t, CE, element, status);
-  } else { /* easy case, */
-    /*CE = ucmpe32_get(t->mapping, element->cPoints[0]);*/
-    CE = utrie_get32(t->mapping, element->cPoints[0], NULL);
-
-    if( CE != UCOL_NOT_FOUND) {
-      if(isCntTableElement(CE) /*isContraction(CE)*/) { /* adding a non contraction element (thai, expansion, single) to already existing contraction */
-        if(!isPrefix(element->mapCE)) { // we cannot reenter prefix elements - as we are going to create a dead loop
-          // Only expansions and regular CEs can go here... Contractions will never happen in this place
-            uprv_cnttab_setContraction(t->contractions, CE, 0, 0, element->mapCE, status);
-            /* This loop has to change the CE at the end of contraction REDO!*/
-            uprv_cnttab_changeLastCE(t->contractions, CE, element->mapCE, status);
-        }
-      } else {
-        /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
-        utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+    if(element->mapCE == 0) {
+        for(i = 0; i < element->cSize; i++) {
+            if(!U16_IS_TRAIL(element->cPoints[i])) {
+                unsafeCPSet(t->unsafeCP, element->cPoints[i]);
+            }
+        }
+    }
+    if(element->cSize > 1) { /* we're adding a contraction */
+        uint32_t i = 0;
+        UChar32 cp;
+
+        U16_NEXT(element->cPoints, i, element->cSize, cp);
+        /*CE = ucmpe32_get(t->mapping, cp);*/
+        CE = utrie_get32(t->mapping, cp, NULL);
+
+        CE = uprv_uca_addContraction(t, CE, element, status);
+    } else { /* easy case, */
+        /*CE = ucmpe32_get(t->mapping, element->cPoints[0]);*/
+        CE = utrie_get32(t->mapping, element->cPoints[0], NULL);
+
+        if( CE != UCOL_NOT_FOUND) {
+            if(isCntTableElement(CE) /*isContraction(CE)*/) { /* adding a non contraction element (thai, expansion, single) to already existing contraction */
+                if(!isPrefix(element->mapCE)) { // we cannot reenter prefix elements - as we are going to create a dead loop
+                    // Only expansions and regular CEs can go here... Contractions will never happen in this place
+                    uprv_cnttab_setContraction(t->contractions, CE, 0, 0, element->mapCE, status);
+                    /* This loop has to change the CE at the end of contraction REDO!*/
+                    uprv_cnttab_changeLastCE(t->contractions, CE, element->mapCE, status);
+                }
+            } else {
+                /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
+                utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+                if ((element->prefixSize!=0) && (!isSpecial(CE) || (getCETag(CE)!=IMPLICIT_TAG))) {
+                    UCAElements *origElem = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+                    /* test for NULL */
+                    if (origElem== NULL) {
+                        *status = U_MEMORY_ALLOCATION_ERROR;
+                        return 0;
+                    }
+                    /* copy the original UCA value */
+                    origElem->prefixSize = 0;
+                    origElem->prefix = NULL;
+                    origElem->cPoints = origElem->uchars;
+                    origElem->cPoints[0] = element->cPoints[0];
+                    origElem->cSize = 1;
+                    origElem->CEs[0]=CE;
+                    origElem->mapCE=CE;
+                    origElem->noOfCEs=1;
+                    uprv_uca_finalizeAddition(t, origElem, status);
+                    uprv_free(origElem);
+                }
 #ifdef UCOL_DEBUG
-        fprintf(stderr, "Warning - trying to overwrite existing data %08X for cp %04X with %08X\n", CE, element->cPoints[0], element->CEs[0]);
-        //*status = U_ILLEGAL_ARGUMENT_ERROR;
+                fprintf(stderr, "Warning - trying to overwrite existing data %08X for cp %04X with %08X\n", CE, element->cPoints[0], element->CEs[0]);
+                //*status = U_ILLEGAL_ARGUMENT_ERROR;
 #endif
-      }
-    } else {
-      /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
-      utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+            }
+        } else {
+            /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
+            utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+        }
     }
-  }
-  return CE;
+    return CE;
 }
 
 /* This adds a read element, while testing for existence */
 U_CAPI uint32_t  U_EXPORT2
 uprv_uca_addAnElement(tempUCATable *t, UCAElements *element, UErrorCode *status) {
-  ExpansionTable *expansions = t->expansions;
-
-  uint32_t i = 1;
-  uint32_t expansion = 0;
-  uint32_t CE;
-
-  if(U_FAILURE(*status)) {
-      return 0xFFFF;
-  }
-
-  element->mapCE = 0; // clear mapCE so that we can catch expansions
-
-  if(element->noOfCEs == 1) {
-    if(element->isThai == FALSE) {
-          element->mapCE = element->CEs[0];      
-    } else { /* add thai - totally bad here */
-      expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (THAI_TAG<<UCOL_TAG_SHIFT) 
-        | ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4) 
-        | 0x1);
-      element->mapCE = expansion;
-    }
-  } else {     
-    /* ICU 2.1 long primaries */
-    /* unfortunately, it looks like we have to look for a long primary here */
-    /* since in canonical closure we are going to hit some long primaries from */
-    /* the first phase, and they will come back as continuations/expansions */
-    /* destroying the effect of the previous opitimization */
-    /* A long primary is a three byte primary with starting secondaries and tertiaries */
-    /* It can appear in long runs of only primary differences (like east Asian tailorings) */
-    /* also, it should not be an expansion, as expansions would break with this */
-    // This part came in from ucol_bld.cpp
-    //if(tok->expansion == 0
-      //&& noOfBytes[0] == 3 && noOfBytes[1] == 1 && noOfBytes[2] == 1
-      //&& CEparts[1] == (UCOL_BYTE_COMMON << 24) && CEparts[2] == (UCOL_BYTE_COMMON << 24)) {
-      /* we will construct a special CE that will go unchanged to the table */
-    if(element->noOfCEs == 2 // a two CE expansion 
-      && isContinuation(element->CEs[1]) // which  is a continuation
-      && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation,
-      && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary
-      && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary
-      ) {
+    U_NAMESPACE_USE
+
+    ExpansionTable *expansions = t->expansions;
+
+    uint32_t i = 1;
+    uint32_t expansion = 0;
+    uint32_t CE;
+
+    if(U_FAILURE(*status)) {
+        return 0xFFFF;
+    }
+
+    element->mapCE = 0; // clear mapCE so that we can catch expansions
+
+    if(element->noOfCEs == 1) {
+        element->mapCE = element->CEs[0];      
+    } else {     
+        /* ICU 2.1 long primaries */
+        /* unfortunately, it looks like we have to look for a long primary here */
+        /* since in canonical closure we are going to hit some long primaries from */
+        /* the first phase, and they will come back as continuations/expansions */
+        /* destroying the effect of the previous opitimization */
+        /* A long primary is a three byte primary with starting secondaries and tertiaries */
+        /* It can appear in long runs of only primary differences (like east Asian tailorings) */
+        /* also, it should not be an expansion, as expansions would break with this */
+        // This part came in from ucol_bld.cpp
+        //if(tok->expansion == 0
+        //&& noOfBytes[0] == 3 && noOfBytes[1] == 1 && noOfBytes[2] == 1
+        //&& CEparts[1] == (UCOL_BYTE_COMMON << 24) && CEparts[2] == (UCOL_BYTE_COMMON << 24)) {
+        /* we will construct a special CE that will go unchanged to the table */
+        if(element->noOfCEs == 2 // a two CE expansion 
+            && isContinuation(element->CEs[1]) // which  is a continuation
+            && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation,
+            && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary
+            && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary
+            )
+        {
 #ifdef UCOL_DEBUG
-      fprintf(stdout, "Long primary %04X\n", element->cPoints[0]);
+            fprintf(stdout, "Long primary %04X\n", element->cPoints[0]);
 #endif
-      element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special
-        | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary
-        | ((element->CEs[1]>>24) & 0xFF);   // third byte of primary
-    } else {
-      expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT) 
-        | ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4)
-        & 0xFFFFF0);
-        
-      for(i = 1; i<element->noOfCEs; i++) {
-        uprv_uca_addExpansion(expansions, element->CEs[i], status);
-      }
-      if(element->noOfCEs <= 0xF) {
-        expansion |= element->noOfCEs;
-      } else {
-        uprv_uca_addExpansion(expansions, 0, status);
-      }
-      element->mapCE = expansion;
-      uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1],
-                               (uint8_t)element->noOfCEs,
-                               t->maxExpansions,
-                               status);
-      if(UCOL_ISJAMO(element->cPoints[0])) {
-        t->image->jamoSpecial = TRUE;
-        uprv_uca_setMaxJamoExpansion(element->cPoints[0],
-                                 element->CEs[element->noOfCEs - 1],
-                                 (uint8_t)element->noOfCEs,
-                                 t->maxJamoExpansions,
-                                 status);
-      }
-    }
-  }
-
-  // We treat digits differently - they are "uber special" and should be
-  // processed differently if numeric collation is on. 
-  UChar32 uniChar = 0;
-  //printElement(element);
-  if ((element->cSize == 2) && U16_IS_LEAD(element->uchars[0])){
-      uniChar = U16_GET_SUPPLEMENTARY(element->uchars[0], element->uchars[1]);
-  } else if (element->cSize == 1){
-      uniChar = element->uchars[0];
-  }
-
-  // Here, we either have one normal CE OR mapCE is set. Therefore, we stuff only
-  // one element to the expansion buffer. When we encounter a digit and we don't 
-  // do numeric collation, we will just pick the CE we have and break out of case
-  // (see ucol.cpp ucol_prv_getSpecialCE && ucol_prv_getSpecialPrevCE). If we picked
-  // a special, further processing will occur. If it's a simple CE, we'll return due
-  // to how the loop is constructed.
-  if (uniChar != 0 && u_isdigit(uniChar)){
-      expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (DIGIT_TAG<<UCOL_TAG_SHIFT) | 1); // prepare the element
-      if(element->mapCE) { // if there is an expansion, we'll pick it here
-        expansion |= ((uprv_uca_addExpansion(expansions, element->mapCE, status)+(headersize>>2))<<4);
-      } else {
-        expansion |= ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4);
-      }
-      element->mapCE = expansion;
-      
-      // Need to go back to the beginning of the digit string if in the middle!
-      if(uniChar <= 0xFFFF) { // supplementaries are always unsafe. API takes UChars
-        unsafeCPSet(t->unsafeCP, (UChar)uniChar);
-      }
-  }
-
-  // here we want to add the prefix structure.
-  // I will try to process it as a reverse contraction, if possible.
-  // prefix buffer is already reversed.
-
-  if(element->prefixSize!=0) {
-    // We keep the seen prefix starter elements in a hashtable
-    // we need it to be able to distinguish between the simple
-    // codepoints and prefix starters. Also, we need to use it
-    // for canonical closure.
-
-    UCAElements *composed = (UCAElements *)uprv_malloc(sizeof(UCAElements));
-    /* test for NULL */
-    if (composed == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+            element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special
+                | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary
+                | ((element->CEs[1]>>24) & 0xFF);   // third byte of primary
+        }
+        else {
+            expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT) 
+                | (((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4)
+                   & 0xFFFFF0));
+
+            for(i = 1; i<element->noOfCEs; i++) {
+                uprv_uca_addExpansion(expansions, element->CEs[i], status);
+            }
+            if(element->noOfCEs <= 0xF) {
+                expansion |= element->noOfCEs;
+            } else {
+                uprv_uca_addExpansion(expansions, 0, status);
+            }
+            element->mapCE = expansion;
+            uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1],
+                (uint8_t)element->noOfCEs,
+                t->maxExpansions,
+                status);
+            if(UCOL_ISJAMO(element->cPoints[0])) {
+                t->image->jamoSpecial = TRUE;
+                uprv_uca_setMaxJamoExpansion(element->cPoints[0],
+                    element->CEs[element->noOfCEs - 1],
+                    (uint8_t)element->noOfCEs,
+                    t->maxJamoExpansions,
+                    status);
+            }
+            if (U_FAILURE(*status)) {
+                return 0;
+            }
+        }
     }
-    uprv_memcpy(composed, element, sizeof(UCAElements));
-    composed->cPoints = composed->uchars;
-    composed->prefix = composed->prefixChars;
 
-    composed->prefixSize = unorm_normalize(element->prefix, element->prefixSize, UNORM_NFC, 0, composed->prefix, 128, status);
+    // We treat digits differently - they are "uber special" and should be
+    // processed differently if numeric collation is on. 
+    UChar32 uniChar = 0;
+    //printElement(element);
+    if ((element->cSize == 2) && U16_IS_LEAD(element->cPoints[0])){
+        uniChar = U16_GET_SUPPLEMENTARY(element->cPoints[0], element->cPoints[1]);
+    } else if (element->cSize == 1){
+        uniChar = element->cPoints[0];
+    }
 
+    // Here, we either have one normal CE OR mapCE is set. Therefore, we stuff only
+    // one element to the expansion buffer. When we encounter a digit and we don't 
+    // do numeric collation, we will just pick the CE we have and break out of case
+    // (see ucol.cpp ucol_prv_getSpecialCE && ucol_prv_getSpecialPrevCE). If we picked
+    // a special, further processing will occur. If it's a simple CE, we'll return due
+    // to how the loop is constructed.
+    if (uniChar != 0 && u_isdigit(uniChar)){
+        expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (DIGIT_TAG<<UCOL_TAG_SHIFT) | 1); // prepare the element
+        if(element->mapCE) { // if there is an expansion, we'll pick it here
+            expansion |= ((uprv_uca_addExpansion(expansions, element->mapCE, status)+(headersize>>2))<<4);
+        } else {
+            expansion |= ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4);
+        }
+        element->mapCE = expansion;
 
-    if(t->prefixLookup != NULL) {
-      UCAElements *uCE = (UCAElements *)uhash_get(t->prefixLookup, element);
-      if(uCE != NULL) { // there is already a set of code points here
-        element->mapCE = uprv_uca_addPrefix(t, uCE->mapCE, element, status);
-      } else { // no code points, so this spot is clean
-        element->mapCE = uprv_uca_addPrefix(t, UCOL_NOT_FOUND, element, status);
-        uCE = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+        // Need to go back to the beginning of the digit string if in the middle!
+        if(uniChar <= 0xFFFF) { // supplementaries are always unsafe. API takes UChars
+            unsafeCPSet(t->unsafeCP, (UChar)uniChar);
+        }
+    }
+
+    // here we want to add the prefix structure.
+    // I will try to process it as a reverse contraction, if possible.
+    // prefix buffer is already reversed.
+
+    if(element->prefixSize!=0) {
+        // We keep the seen prefix starter elements in a hashtable
+        // we need it to be able to distinguish between the simple
+        // codepoints and prefix starters. Also, we need to use it
+        // for canonical closure.
+
+        UCAElements *composed = (UCAElements *)uprv_malloc(sizeof(UCAElements));
         /* test for NULL */
-        if (uCE == NULL) {
+        if (composed == NULL) {
             *status = U_MEMORY_ALLOCATION_ERROR;
             return 0;
         }
-        uprv_memcpy(uCE, element, sizeof(UCAElements));
-        uCE->cPoints = uCE->uchars;
-        uhash_put(t->prefixLookup, uCE, uCE, status);
-      }
-      if(composed->prefixSize != element->prefixSize || uprv_memcmp(composed->prefix, element->prefix, element->prefixSize)) {
-        // do it!
-        composed->mapCE = uprv_uca_addPrefix(t, element->mapCE, composed, status);
-      }
-    }
-    uprv_free(composed);
-  }
-
-  // We need to use the canonical iterator here
-  // the way we do it is to generate the canonically equivalent strings 
-  // for the contraction and then add the sequences that pass FCD check
-  if(element->cSize > 1 && !(element->cSize==2 && UTF16_IS_LEAD(element->cPoints[0]) && UTF16_IS_TRAIL(element->cPoints[1]))) { // this is a contraction, we should check whether a composed form should also be included
-    UnicodeString source(element->cPoints, element->cSize);
-    CanonicalIterator it(source, *status);
-    source = it.next();
-    while(!source.isBogus()) {
-      if(Normalizer::quickCheck(source, UNORM_FCD, *status) != UNORM_NO) {
-        element->cSize = source.extract(element->cPoints, 128, *status);
-        uprv_uca_finalizeAddition(t, element, status);
-      }
-      source = it.next();
-    }
-    CE = element->mapCE;
-  } else {
-      CE = uprv_uca_finalizeAddition(t, element, status);  
-  }
-
-  return CE;
+        uprv_memcpy(composed, element, sizeof(UCAElements));
+        composed->cPoints = composed->uchars;
+        composed->prefix = composed->prefixChars;
+
+        composed->prefixSize = unorm_normalize(element->prefix, element->prefixSize, UNORM_NFC, 0, composed->prefix, 128, status);
+
+
+        if(t->prefixLookup != NULL) {
+            UCAElements *uCE = (UCAElements *)uhash_get(t->prefixLookup, element);
+            if(uCE != NULL) { // there is already a set of code points here
+                element->mapCE = uprv_uca_addPrefix(t, uCE->mapCE, element, status);
+            } else { // no code points, so this spot is clean
+                element->mapCE = uprv_uca_addPrefix(t, UCOL_NOT_FOUND, element, status);
+                uCE = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+                /* test for NULL */
+                if (uCE == NULL) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    return 0;
+                }
+                uprv_memcpy(uCE, element, sizeof(UCAElements));
+                uCE->cPoints = uCE->uchars;
+                uhash_put(t->prefixLookup, uCE, uCE, status);
+            }
+            if(composed->prefixSize != element->prefixSize || uprv_memcmp(composed->prefix, element->prefix, element->prefixSize)) {
+                // do it!
+                composed->mapCE = uprv_uca_addPrefix(t, element->mapCE, composed, status);
+            }
+        }
+        uprv_free(composed);
+    }
+
+    // We need to use the canonical iterator here
+    // the way we do it is to generate the canonically equivalent strings 
+    // for the contraction and then add the sequences that pass FCD check
+    if(element->cSize > 1 && !(element->cSize==2 && U16_IS_LEAD(element->cPoints[0]) && U16_IS_TRAIL(element->cPoints[1]))) { // this is a contraction, we should check whether a composed form should also be included
+        UnicodeString source(element->cPoints, element->cSize);
+        CanonicalIterator it(source, *status);
+        source = it.next();
+        while(!source.isBogus()) {
+            if(Normalizer::quickCheck(source, UNORM_FCD, *status) != UNORM_NO) {
+                element->cSize = source.extract(element->cPoints, 128, *status);
+                uprv_uca_finalizeAddition(t, element, status);
+            }
+            source = it.next();
+        }
+        CE = element->mapCE;
+    } else {
+        CE = uprv_uca_finalizeAddition(t, element, status);  
+    }
+
+    return CE;
 }
 
 
 /*void uprv_uca_getMaxExpansionJamo(CompactEIntArray       *mapping, */
 static void uprv_uca_getMaxExpansionJamo(UNewTrie       *mapping, 
-                                  MaxExpansionTable     *maxexpansion,
-                                  MaxJamoExpansionTable *maxjamoexpansion,
-                                  UBool                  jamospecial,
-                                  UErrorCode            *status)
+                                         MaxExpansionTable     *maxexpansion,
+                                         MaxJamoExpansionTable *maxjamoexpansion,
+                                         UBool                  jamospecial,
+                                         UErrorCode            *status)
 {
-  const uint32_t VBASE  = 0x1161;
-  const uint32_t TBASE  = 0x11A8;
-  const uint32_t VCOUNT = 21;
-  const uint32_t TCOUNT = 28;
-
-  uint32_t v = VBASE + VCOUNT - 1;
-  uint32_t t = TBASE + TCOUNT - 1;
-  uint32_t ce;
-
-  while (v >= VBASE) {
-      /*ce = ucmpe32_get(mapping, v);*/
-      ce = utrie_get32(mapping, v, NULL);
-      if (ce < UCOL_SPECIAL_FLAG) {
-          uprv_uca_setMaxExpansion(ce, 2, maxexpansion, status);
-      }
-      v --;
-  }
-
-  while (t >= TBASE)
-  {
-      /*ce = ucmpe32_get(mapping, t);*/
-      ce = utrie_get32(mapping, t, NULL);
-      if (ce < UCOL_SPECIAL_FLAG) {
-          uprv_uca_setMaxExpansion(ce, 3, maxexpansion, status);
-      }
-      t --;
-  }
-  /*  According to the docs, 99% of the time, the Jamo will not be special */
-  if (jamospecial) {
-      /* gets the max expansion in all unicode characters */
-      int     count    = maxjamoexpansion->position;
-      uint8_t maxTSize = (uint8_t)(maxjamoexpansion->maxLSize + 
-                                   maxjamoexpansion->maxVSize +
-                                   maxjamoexpansion->maxTSize);
-      uint8_t maxVSize = (uint8_t)(maxjamoexpansion->maxLSize + 
-                                   maxjamoexpansion->maxVSize);
-
-      while (count > 0) {
-          count --;
-          if (*(maxjamoexpansion->isV + count) == TRUE) {
+    const uint32_t VBASE  = 0x1161;
+    const uint32_t TBASE  = 0x11A8;
+    const uint32_t VCOUNT = 21;
+    const uint32_t TCOUNT = 28;
+
+    uint32_t v = VBASE + VCOUNT - 1;
+    uint32_t t = TBASE + TCOUNT - 1;
+    uint32_t ce;
+
+    while (v >= VBASE) {
+        /*ce = ucmpe32_get(mapping, v);*/
+        ce = utrie_get32(mapping, v, NULL);
+        if (ce < UCOL_SPECIAL_FLAG) {
+            uprv_uca_setMaxExpansion(ce, 2, maxexpansion, status);
+        }
+        v --;
+    }
+
+    while (t >= TBASE)
+    {
+        /*ce = ucmpe32_get(mapping, t);*/
+        ce = utrie_get32(mapping, t, NULL);
+        if (ce < UCOL_SPECIAL_FLAG) {
+            uprv_uca_setMaxExpansion(ce, 3, maxexpansion, status);
+        }
+        t --;
+    }
+    /*  According to the docs, 99% of the time, the Jamo will not be special */
+    if (jamospecial) {
+        /* gets the max expansion in all unicode characters */
+        int     count    = maxjamoexpansion->position;
+        uint8_t maxTSize = (uint8_t)(maxjamoexpansion->maxLSize + 
+            maxjamoexpansion->maxVSize +
+            maxjamoexpansion->maxTSize);
+        uint8_t maxVSize = (uint8_t)(maxjamoexpansion->maxLSize + 
+            maxjamoexpansion->maxVSize);
+
+        while (count > 0) {
+            count --;
+            if (*(maxjamoexpansion->isV + count) == TRUE) {
                 uprv_uca_setMaxExpansion(
-                                   *(maxjamoexpansion->endExpansionCE + count), 
-                                   maxVSize, maxexpansion, status);
-          }
-          else {
+                    *(maxjamoexpansion->endExpansionCE + count), 
+                    maxVSize, maxexpansion, status);
+            }
+            else {
                 uprv_uca_setMaxExpansion(
-                                   *(maxjamoexpansion->endExpansionCE + count), 
-                                   maxTSize, maxexpansion, status);
-          }
-      }
-  }
+                    *(maxjamoexpansion->endExpansionCE + count), 
+                    maxTSize, maxexpansion, status);
+            }
+        }
+    }
 }
 
 U_CDECL_BEGIN
 static inline uint32_t U_CALLCONV
 getFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset)
 {
-  uint32_t value;
-  uint32_t tag;
-  UChar32 limit;
-  UBool inBlockZero;
-
-  limit=start+0x400;
-  while(start<limit) {
-      value=utrie_get32(trie, start, &inBlockZero);
-      tag = getCETag(value);
-      if(inBlockZero == TRUE) {
-          start+=UTRIE_DATA_BLOCK_LENGTH;
-      } else if(!(isSpecial(value) && (tag == IMPLICIT_TAG || tag == NOT_FOUND_TAG))) {
-        /* These are values that are starting in either UCA (IMPLICIT_TAG) or in the 
-         * tailorings (NOT_FOUND_TAG). Presence of these tags means that there is 
-         * nothing in this position and that it should be skipped.
-         */
+    uint32_t value;
+    uint32_t tag;
+    UChar32 limit;
+    UBool inBlockZero;
+
+    limit=start+0x400;
+    while(start<limit) {
+        value=utrie_get32(trie, start, &inBlockZero);
+        tag = getCETag(value);
+        if(inBlockZero == TRUE) {
+            start+=UTRIE_DATA_BLOCK_LENGTH;
+        } else if(!(isSpecial(value) && (tag == IMPLICIT_TAG || tag == NOT_FOUND_TAG))) {
+            /* These are values that are starting in either UCA (IMPLICIT_TAG) or in the 
+            * tailorings (NOT_FOUND_TAG). Presence of these tags means that there is 
+            * nothing in this position and that it should be skipped.
+            */
 #ifdef UCOL_DEBUG
-        static int32_t count = 1;
-        fprintf(stdout, "%i, Folded %08X, value %08X\n", count++, start, value);
+            static int32_t count = 1;
+            fprintf(stdout, "%i, Folded %08X, value %08X\n", count++, start, value);
 #endif
-          return (uint32_t)(UCOL_SPECIAL_FLAG | (SURROGATE_TAG<<24) | offset);
-      } else {
-          ++start;
-      }
-  }
-  return 0;
+            return (uint32_t)(UCOL_SPECIAL_FLAG | (SURROGATE_TAG<<24) | offset);
+        } else {
+            ++start;
+        }
+    }
+    return 0;
 }
 U_CDECL_END
 
 #ifdef UCOL_DEBUG
 // This is a debug function to print the contents of a trie.
 // It is used in conjuction with the code around utrie_unserialize call
-void enumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
-  if(start<0x10000) {
-    fprintf(stdout, "%08X, %08X, %08X\n", start, limit, value);
-  } else {
-    fprintf(stdout, "%08X=%04X %04X, %08X=%04X %04X, %08X\n", start, UTF16_LEAD(start), UTF16_TRAIL(start), limit, UTF16_LEAD(limit), UTF16_TRAIL(limit), value);
-  }
+UBool enumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
+    if(start<0x10000) {
+        fprintf(stdout, "%08X, %08X, %08X\n", start, limit, value);
+    } else {
+        fprintf(stdout, "%08X=%04X %04X, %08X=%04X %04X, %08X\n", start, U16_LEAD(start), U16_TRAIL(start), limit, U16_LEAD(limit), U16_TRAIL(limit), value);
+    }
+    return TRUE;
 }
 
 int32_t 
 myGetFoldingOffset(uint32_t data) {
-  if(data > UCOL_NOT_FOUND && getCETag(data) == SURROGATE_TAG) {
-    return (data&0xFFFFFF);
-  } else {
-    return 0;
-  }
+    if(data > UCOL_NOT_FOUND && getCETag(data) == SURROGATE_TAG) {
+        return (data&0xFFFFFF);
+    } else {
+        return 0;
+    }
 }
 #endif
 
@@ -1315,7 +1451,7 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
     /* the trie is compacted */
     /* sets jamo expansions */
     uprv_uca_getMaxExpansionJamo(mapping, maxexpansion, t->maxJamoExpansions,
-                                 t->image->jamoSpecial, status);
+        t->image->jamoSpecial, status);
 
     /*ucmpe32_compact(mapping);*/
     /*UMemoryStream *ms = uprv_mstrm_openNew(8192);*/
@@ -1331,16 +1467,16 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
     /* TODO: LATIN1 array is now in the utrie - it should be removed from the calculation */
 
     uint32_t toAllocate =(uint32_t)(headersize+                                    
-                                    paddedsize(expansions->position*sizeof(uint32_t))+
-                                    paddedsize(mappingSize)+
-                                    paddedsize(contractionsSize*(sizeof(UChar)+sizeof(uint32_t)))+
-                                    //paddedsize(0x100*sizeof(uint32_t))  /* Latin1 is now included in the trie */
-                                     /* maxexpansion array */
-                                     + paddedsize(maxexpansion->position * sizeof(uint32_t)) +
-                                     /* maxexpansion size array */
-                                     paddedsize(maxexpansion->position * sizeof(uint8_t)) +
-                                     paddedsize(UCOL_UNSAFECP_TABLE_SIZE) +   /*  Unsafe chars             */
-                                     paddedsize(UCOL_UNSAFECP_TABLE_SIZE));    /*  Contraction Ending chars */
+        paddedsize(expansions->position*sizeof(uint32_t))+
+        paddedsize(mappingSize)+
+        paddedsize(contractionsSize*(sizeof(UChar)+sizeof(uint32_t)))+
+        //paddedsize(0x100*sizeof(uint32_t))  /* Latin1 is now included in the trie */
+        /* maxexpansion array */
+        + paddedsize(maxexpansion->position * sizeof(uint32_t)) +
+        /* maxexpansion size array */
+        paddedsize(maxexpansion->position * sizeof(uint8_t)) +
+        paddedsize(UCOL_UNSAFECP_TABLE_SIZE) +   /*  Unsafe chars             */
+        paddedsize(UCOL_UNSAFECP_TABLE_SIZE));    /*  Contraction Ending chars */
 
 
     dataStart = (uint8_t *)uprv_malloc(toAllocate);
@@ -1382,20 +1518,20 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
 
     /* contractions block */
     if(contractionsSize != 0) {
-      /* copy contraction index */
-      /*myData->contractionIndex = (UChar *)(dataStart+tableOffset);*/
-      myData->contractionIndex = tableOffset;
-      uprv_memcpy(dataStart+tableOffset, contractions->codePoints, contractionsSize*sizeof(UChar));
-      tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(UChar)));
-
-      /* copy contraction collation elements */
-      /*myData->contractionCEs = (uint32_t *)(dataStart+tableOffset);*/
-      myData->contractionCEs = tableOffset;
-      uprv_memcpy(dataStart+tableOffset, contractions->CEs, contractionsSize*sizeof(uint32_t));
-      tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(uint32_t)));
+        /* copy contraction index */
+        /*myData->contractionIndex = (UChar *)(dataStart+tableOffset);*/
+        myData->contractionIndex = tableOffset;
+        uprv_memcpy(dataStart+tableOffset, contractions->codePoints, contractionsSize*sizeof(UChar));
+        tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(UChar)));
+
+        /* copy contraction collation elements */
+        /*myData->contractionCEs = (uint32_t *)(dataStart+tableOffset);*/
+        myData->contractionCEs = tableOffset;
+        uprv_memcpy(dataStart+tableOffset, contractions->CEs, contractionsSize*sizeof(uint32_t));
+        tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(uint32_t)));
     } else {
-      myData->contractionIndex = 0;
-      myData->contractionCEs = 0;
+        myData->contractionIndex = 0;
+        myData->contractionCEs = 0;
     }
 
     /* copy mapping table */
@@ -1408,14 +1544,14 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
 #ifdef UCOL_DEBUG
     // This is debug code to dump the contents of the trie. It needs two functions defined above
     {
-      UTrie UCAt = { 0 };
-      uint32_t trieWord;
-      utrie_unserialize(&UCAt, dataStart+tableOffset, 9999999, status);
-      UCAt.getFoldingOffset = myGetFoldingOffset;
-      if(U_SUCCESS(*status)) {
-        utrie_enum(&UCAt, NULL, enumRange, NULL);
-      }
-      trieWord = UTRIE_GET32_FROM_LEAD(UCAt, 0xDC01) 
+        UTrie UCAt = { 0 };
+        uint32_t trieWord;
+        utrie_unserialize(&UCAt, dataStart+tableOffset, 9999999, status);
+        UCAt.getFoldingOffset = myGetFoldingOffset;
+        if(U_SUCCESS(*status)) {
+            utrie_enum(&UCAt, NULL, enumRange, NULL);
+        }
+        trieWord = UTRIE_GET32_FROM_LEAD(&UCAt, 0xDC01);
     }
 #endif
     tableOffset += paddedsize(mappingSize);
@@ -1425,22 +1561,22 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
 
     /* copy max expansion table */
     myData->endExpansionCE      = tableOffset;
-    myData->endExpansionCECount = maxexpansion->position;
+    myData->endExpansionCECount = maxexpansion->position - 1;
     /* not copying the first element which is a dummy */
     uprv_memcpy(dataStart + tableOffset, maxexpansion->endExpansionCE + 1, 
-                maxexpansion->position * sizeof(uint32_t));
-    tableOffset += (uint32_t)(paddedsize(maxexpansion->position * sizeof(uint32_t)));
+        (maxexpansion->position - 1) * sizeof(uint32_t));
+    tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint32_t)));
     myData->expansionCESize = tableOffset;
     uprv_memcpy(dataStart + tableOffset, maxexpansion->expansionCESize + 1, 
-                maxexpansion->position * sizeof(uint8_t));
-    tableOffset += (uint32_t)(paddedsize(maxexpansion->position * sizeof(uint8_t)));
+        (maxexpansion->position - 1) * sizeof(uint8_t));
+    tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint8_t)));
 
     /* Unsafe chars table.  Finish it off, then copy it. */
     uprv_uca_unsafeCPAddCCNZ(t, status);
     if (t->UCA != 0) {              /* Or in unsafebits from UCA, making a combined table.    */
-       for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) {    
-           t->unsafeCP[i] |= t->UCA->unsafeCP[i];
-       }
+        for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) {    
+            t->unsafeCP[i] |= t->UCA->unsafeCP[i];
+        }
     }
     myData->unsafeCP = tableOffset;
     uprv_memcpy(dataStart + tableOffset, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE);
@@ -1475,133 +1611,460 @@ uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
 
 
 struct enumStruct {
-  tempUCATable *t;
-  UCollator *tempColl;
-  UCollationElements* colEl;
-  int32_t noOfClosures;
-  UErrorCode *status;
+    tempUCATable *t;
+    UCollator *tempColl;
+    UCollationElements* colEl;
+    const Normalizer2Impl *nfcImpl;
+    UnicodeSet *closed;
+    int32_t noOfClosures;
+    UErrorCode *status;
 };
 U_CDECL_BEGIN
 static UBool U_CALLCONV
 _enumCategoryRangeClosureCategory(const void *context, UChar32 start, UChar32 limit, UCharCategory type) {
 
-  UErrorCode *status = ((enumStruct *)context)->status;
-  tempUCATable *t = ((enumStruct *)context)->t;
-  UCollator *tempColl = ((enumStruct *)context)->tempColl;
-  UCollationElements* colEl = ((enumStruct *)context)->colEl;
-  UCAElements el;
-  UChar decomp[256] = { 0 };
-  int32_t noOfDec = 0;
-
-  UChar32 u32 = 0;
-  UChar comp[2];
-  uint32_t len = 0;
-
-  if (type != U_UNASSIGNED && type != U_PRIVATE_USE_CHAR) { // if the range is assigned - we might ommit more categories later
-    for(u32 = start; u32 < limit; u32++) {
-      noOfDec = unorm_getDecomposition(u32, FALSE, decomp, 256);
-      //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1
-        //|| (noOfDec == 1 && *decomp != (UChar)u32))
-      if(noOfDec > 0) // if we're positive, that means there is no decomposition
-      {
-        len = 0;
-        UTF_APPEND_CHAR_UNSAFE(comp, len, u32);
-        if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) {
+    if (type != U_UNASSIGNED && type != U_PRIVATE_USE_CHAR) { // if the range is assigned - we might ommit more categories later
+        UErrorCode *status = ((enumStruct *)context)->status;
+        tempUCATable *t = ((enumStruct *)context)->t;
+        UCollator *tempColl = ((enumStruct *)context)->tempColl;
+        UCollationElements* colEl = ((enumStruct *)context)->colEl;
+        UCAElements el;
+        UChar decompBuffer[4];
+        const UChar *decomp;
+        int32_t noOfDec = 0;
+
+        UChar32 u32 = 0;
+        UChar comp[2];
+        uint32_t len = 0;
+
+        for(u32 = start; u32 < limit; u32++) {
+            decomp = ((enumStruct *)context)->nfcImpl->
+                getDecomposition(u32, decompBuffer, noOfDec);
+            //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1
+            //|| (noOfDec == 1 && *decomp != (UChar)u32))
+            if(decomp != NULL)
+            {
+                len = 0;
+                U16_APPEND_UNSAFE(comp, len, u32);
+                if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) {
 #ifdef UCOL_DEBUG
-          fprintf(stderr, "Closure: %08X -> ", u32);
-          uint32_t i = 0;
-          for(i = 0; i<noOfDec; i++) {
-            fprintf(stderr, "%04X ", decomp[i]);
-          }
-          fprintf(stderr, "\n");
+                    fprintf(stderr, "Closure: U+%04X -> ", u32);
+                    UChar32 c;
+                    int32_t i = 0;
+                    while(i < noOfDec) {
+                        U16_NEXT(decomp, i, noOfDec, c);
+                        fprintf(stderr, "%04X ", c);
+                    }
+                    fprintf(stderr, "\n");
+                    // print CEs for code point vs. decomposition
+                    fprintf(stderr, "U+%04X CEs: ", u32);
+                    UCollationElements *iter = ucol_openElements(tempColl, comp, len, status);
+                    int32_t ce;
+                    while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) {
+                        fprintf(stderr, "%08X ", ce);
+                    }
+                    fprintf(stderr, "\nDecomp CEs: ");
+                    ucol_setText(iter, decomp, noOfDec, status);
+                    while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) {
+                        fprintf(stderr, "%08X ", ce);
+                    }
+                    fprintf(stderr, "\n");
+                    ucol_closeElements(iter);
 #endif
-          ((enumStruct *)context)->noOfClosures++;
-          el.cPoints = decomp;
-          el.cSize = noOfDec;
-          el.noOfCEs = 0;
-          el.prefix = el.prefixChars;
-          el.prefixSize = 0;
-
-          UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &el);
-          if(prefix == NULL) {
-            el.cPoints = comp;
-            el.cSize = len;
-            el.prefix = el.prefixChars;
-            el.prefixSize = 0;
-            el.noOfCEs = 0;
-            ucol_setText(colEl, decomp, noOfDec, status);
-            while((el.CEs[el.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
-              el.noOfCEs++;
+                    if(((enumStruct *)context)->closed != NULL) {
+                        ((enumStruct *)context)->closed->add(u32);
+                    }
+                    ((enumStruct *)context)->noOfClosures++;
+                    el.cPoints = (UChar *)decomp;
+                    el.cSize = noOfDec;
+                    el.noOfCEs = 0;
+                    el.prefix = el.prefixChars;
+                    el.prefixSize = 0;
+
+                    UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &el);
+                    el.cPoints = comp;
+                    el.cSize = len;
+                    el.prefix = el.prefixChars;
+                    el.prefixSize = 0;
+                    if(prefix == NULL) {
+                        el.noOfCEs = 0;
+                        ucol_setText(colEl, decomp, noOfDec, status);
+                        while((el.CEs[el.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+                            el.noOfCEs++;
+                        }
+                    } else {
+                        el.noOfCEs = 1;
+                        el.CEs[0] = prefix->mapCE;
+                        // This character uses a prefix. We have to add it 
+                        // to the unsafe table, as it decomposed form is already
+                        // in. In Japanese, this happens for \u309e & \u30fe
+                        // Since unsafeCPSet is static in ucol_elm, we are going
+                        // to wrap it up in the uprv_uca_unsafeCPAddCCNZ function
+                    }
+                    uprv_uca_addAnElement(t, &el, status);
+                }
             }
-          } else {
-            el.cPoints = comp;
-            el.cSize = len;
-            el.prefix = el.prefixChars;
-            el.prefixSize = 0;
-            el.noOfCEs = 1;
-            el.CEs[0] = prefix->mapCE;
-            // This character uses a prefix. We have to add it 
-            // to the unsafe table, as it decomposed form is already
-            // in. In Japanese, this happens for \u309e & \u30fe
-            // Since unsafeCPSet is static in ucol_elm, we are going
-            // to wrap it up in the uprv_uca_unsafeCPAddCCNZ function
-          }
-          if(UCOL_ISTHAIPREVOWEL(el.cPoints[0])) {
-            el.isThai = TRUE;
-          } else {
-            el.isThai = FALSE;
-          }
-
-          uprv_uca_addAnElement(t, &el, status);
-        }
-      }
-    }
-  }
-  return TRUE;
+        }
+    }
+    return TRUE;
 }
 U_CDECL_END
 
-U_CAPI int32_t U_EXPORT2
-uprv_uca_canonicalClosure(tempUCATable *t, UErrorCode *status) 
+static void
+uprv_uca_setMapCE(tempUCATable *t, UCAElements *element, UErrorCode *status) {
+    uint32_t expansion = 0;
+    int32_t j;
+
+    ExpansionTable *expansions = t->expansions;
+    if(element->noOfCEs == 2 // a two CE expansion
+        && isContinuation(element->CEs[1]) // which  is a continuation
+        && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation,
+        && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary
+        && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary
+        ) {
+            element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special
+                | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary
+                | ((element->CEs[1]>>24) & 0xFF);   // third byte of primary
+        } else {
+            expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT)
+                | (((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4)
+                   & 0xFFFFF0));
+
+            for(j = 1; j<(int32_t)element->noOfCEs; j++) {
+                uprv_uca_addExpansion(expansions, element->CEs[j], status);
+            }
+            if(element->noOfCEs <= 0xF) {
+                expansion |= element->noOfCEs;
+            } else {
+                uprv_uca_addExpansion(expansions, 0, status);
+            }
+            element->mapCE = expansion;
+            uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1],
+                (uint8_t)element->noOfCEs,
+                t->maxExpansions,
+                status);
+        }
+}
+
+static void
+uprv_uca_addFCD4AccentedContractions(tempUCATable *t,
+                                      UCollationElements* colEl,
+                                      UChar *data,
+                                      int32_t len,
+                                      UCAElements *el,
+                                      UErrorCode *status) {
+    UChar decomp[256], comp[256];
+    int32_t decLen, compLen;
+
+    decLen = unorm_normalize(data, len, UNORM_NFD, 0, decomp, 256, status);
+    compLen = unorm_normalize(data, len, UNORM_NFC, 0, comp, 256, status);
+    decomp[decLen] = comp[compLen] = 0;
+
+    el->cPoints = decomp;
+    el->cSize = decLen;
+    el->noOfCEs = 0;
+    el->prefixSize = 0;
+    el->prefix = el->prefixChars;
+
+    UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el);
+    el->cPoints = comp;
+    el->cSize = compLen;
+    el->prefix = el->prefixChars;
+    el->prefixSize = 0;
+    if(prefix == NULL) {
+        el->noOfCEs = 0;
+        ucol_setText(colEl, decomp, decLen, status);
+        while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+            el->noOfCEs++;
+        }
+        uprv_uca_setMapCE(t, el, status);
+        uprv_uca_addAnElement(t, el, status);
+    }
+    el->cPoints=NULL; /* don't leak reference to stack */
+}
+
+static void
+uprv_uca_addMultiCMContractions(tempUCATable *t,
+                                UCollationElements* colEl,
+                                tempTailorContext *c,
+                                UCAElements *el,
+                                UErrorCode *status) {
+    CombinClassTable *cmLookup = t->cmLookup;
+    UChar  newDecomp[256];
+    int32_t maxComp, newDecLen;
+    const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status);
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    int16_t curClass = nfcImpl->getFCD16(c->tailoringCM) & 0xff;
+    CompData *precomp = c->precomp;
+    int32_t  compLen = c->compLen;
+    UChar *comp = c->comp;
+    maxComp = c->precompLen;
+
+    for (int32_t j=0; j < maxComp; j++) {
+        int32_t count=0;
+        do {
+            if ( count == 0 ) {  // Decompose the saved precomposed char.
+                UChar temp[2];
+                temp[0]=precomp[j].cp;
+                temp[1]=0;
+                newDecLen = unorm_normalize(temp, 1, UNORM_NFD, 0,
+                            newDecomp, sizeof(newDecomp)/sizeof(UChar), status);
+                newDecomp[newDecLen++] = cmLookup->cPoints[c->cmPos];
+            }
+            else {  // swap 2 combining marks when they are equal.
+                uprv_memcpy(newDecomp, c->decomp, sizeof(UChar)*(c->decompLen));
+                newDecLen = c->decompLen;
+                newDecomp[newDecLen++] = precomp[j].cClass;
+            }
+            newDecomp[newDecLen] = 0;
+            compLen = unorm_normalize(newDecomp, newDecLen, UNORM_NFC, 0,
+                              comp, 256, status);
+            if (compLen==1) {
+                comp[compLen++] = newDecomp[newDecLen++] = c->tailoringCM;
+                comp[compLen] = newDecomp[newDecLen] = 0;
+                el->cPoints = newDecomp;
+                el->cSize = newDecLen;
+
+                UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el);
+                el->cPoints = c->comp;
+                el->cSize = compLen;
+                el->prefix = el->prefixChars;
+                el->prefixSize = 0;
+                if(prefix == NULL) {
+                    el->noOfCEs = 0;
+                    ucol_setText(colEl, newDecomp, newDecLen, status);
+                    while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+                        el->noOfCEs++;
+                    }
+                    uprv_uca_setMapCE(t, el, status);
+                    uprv_uca_finalizeAddition(t, el, status);
+
+                    // Save the current precomposed char and its class to find any
+                    // other combining mark combinations.
+                    precomp[c->precompLen].cp=comp[0];
+                    precomp[c->precompLen].cClass = curClass;
+                    c->precompLen++;
+                }
+            }
+        } while (++count<2 && (precomp[j].cClass == curClass));
+    }
+
+}
+
+static void
+uprv_uca_addTailCanonicalClosures(tempUCATable *t,
+                                  UCollationElements* colEl,
+                                  UChar baseCh,
+                                  UChar cMark,
+                                  UCAElements *el,
+                                  UErrorCode *status) {
+    CombinClassTable *cmLookup = t->cmLookup;
+    const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status);
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    int16_t maxIndex = nfcImpl->getFCD16(cMark) & 0xff;
+    UCAElements element;
+    uint16_t *index;
+    UChar  decomp[256];
+    UChar  comp[256];
+    CompData precomp[256];   // precomposed array
+    int32_t  precompLen = 0; // count for precomp
+    int32_t i, len, decompLen, replacedPos;
+    tempTailorContext c;
+
+    if ( cmLookup == NULL ) {
+        return;
+    }
+    index = cmLookup->index;
+    int32_t cClass=nfcImpl->getFCD16(cMark) & 0xff;
+    maxIndex = (int32_t)index[(nfcImpl->getFCD16(cMark) & 0xff)-1];
+    c.comp = comp;
+    c.decomp = decomp;
+    c.precomp = precomp;
+    c.tailoringCM =  cMark;
+
+    if (cClass>0) {
+        maxIndex = (int32_t)index[cClass-1];
+    }
+    else {
+        maxIndex=0;
+    }
+    decomp[0]=baseCh;
+    for ( i=0; i<maxIndex ; i++ ) {
+        decomp[1] = cmLookup->cPoints[i];
+        decomp[2]=0;
+        decompLen=2;
+        len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status);
+        if (len==1) {
+            // Save the current precomposed char and its class to find any
+            // other combining mark combinations.
+            precomp[precompLen].cp=comp[0];
+            precomp[precompLen].cClass =
+                       index[nfcImpl->getFCD16(decomp[1]) & 0xff];
+            precompLen++;
+            replacedPos=0;
+            for (decompLen=0; decompLen< (int32_t)el->cSize; decompLen++) {
+                decomp[decompLen] = el->cPoints[decompLen];
+                if (decomp[decompLen]==cMark) {
+                    replacedPos = decompLen;  // record the position for later use
+                }
+            }
+            if ( replacedPos != 0 ) {
+                decomp[replacedPos]=cmLookup->cPoints[i];
+            }
+            decomp[decompLen] = 0;
+            len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status);
+            comp[len++] = decomp[decompLen++] = cMark;
+            comp[len] = decomp[decompLen] = 0;
+            element.cPoints = decomp;
+            element.cSize = decompLen;
+            element.noOfCEs = 0;
+            element.prefix = el->prefixChars;
+            element.prefixSize = 0;
+
+            UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &element);
+            element.cPoints = comp;
+            element.cSize = len;
+            element.prefix = el->prefixChars;
+            element.prefixSize = 0;
+            if(prefix == NULL) {
+                element.noOfCEs = 0;
+                ucol_setText(colEl, decomp, decompLen, status);
+                while((element.CEs[element.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+                    element.noOfCEs++;
+                }
+                uprv_uca_setMapCE(t, &element, status);
+                uprv_uca_finalizeAddition(t, &element, status);
+            }
+
+            // This is a fix for tailoring contractions with accented
+            // character at the end of contraction string.
+            if ((len>2) && 
+                (nfcImpl->getFCD16(comp[len-2]) & 0xff00)==0) {
+                uprv_uca_addFCD4AccentedContractions(t, colEl, comp, len, &element, status);
+            }
+
+            if (precompLen >1) {
+                c.compLen = len;
+                c.decompLen = decompLen;
+                c.precompLen = precompLen;
+                c.cmPos = i;
+                uprv_uca_addMultiCMContractions(t, colEl, &c, &element, status);
+                precompLen = c.precompLen;
+            }
+        }
+    }
+}
+
+U_CFUNC int32_t U_EXPORT2
+uprv_uca_canonicalClosure(tempUCATable *t,
+                          UColTokenParser *src,
+                          UnicodeSet *closed,
+                          UErrorCode *status)
 {
-  enumStruct context;
-  context.noOfClosures = 0;
-  if(U_SUCCESS(*status)) {
+    enumStruct context;
+    context.closed = closed;
+    context.noOfClosures = 0;
+    UCAElements el;
+    UColToken *tok;
+    uint32_t i = 0, j = 0;
+    UChar  baseChar, firstCM;
+    context.nfcImpl=Normalizer2Factory::getNFCImpl(*status);
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
     UCollator *tempColl = NULL;
     tempUCATable *tempTable = uprv_uca_cloneTempTable(t, status);
+    // Check for null pointer
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
 
     UCATableHeader *tempData = uprv_uca_assembleTable(tempTable, status);
     tempColl = ucol_initCollator(tempData, 0, t->UCA, status);
-    uprv_uca_closeTempTable(tempTable);    
+    if ( tempTable->cmLookup != NULL ) {
+        t->cmLookup = tempTable->cmLookup;  // copy over to t
+        tempTable->cmLookup = NULL;
+    }
+    uprv_uca_closeTempTable(tempTable);
 
     if(U_SUCCESS(*status)) {
-      tempColl->rb = NULL;
-      tempColl->elements = NULL;
-      tempColl->validLocale = NULL;
-      tempColl->requestedLocale = NULL;
-      tempColl->hasRealData = TRUE;
-      tempColl->freeImageOnClose = TRUE;
+        tempColl->ucaRules = NULL;
+        tempColl->actualLocale = NULL;
+        tempColl->validLocale = NULL;
+        tempColl->requestedLocale = NULL;
+        tempColl->hasRealData = TRUE;
+        tempColl->freeImageOnClose = TRUE;
     } else if(tempData != 0) {
-      uprv_free(tempData);
+        uprv_free(tempData);
     }
 
     /* produce canonical closure */
     UCollationElements* colEl = ucol_openElements(tempColl, NULL, 0, status);
-
+    // Check for null pointer
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
     context.t = t;
     context.tempColl = tempColl;
     context.colEl = colEl;
     context.status = status;
     u_enumCharTypes(_enumCategoryRangeClosureCategory, &context);
 
+    if ( (src==NULL) || !src->buildCCTabFlag ) {
+        ucol_closeElements(colEl);
+        ucol_close(tempColl);
+        return context.noOfClosures;  // no extra contraction needed to add
+    }
+
+    for (i=0; i < src->resultLen; i++) {
+        baseChar = firstCM= (UChar)0;
+        tok = src->lh[i].first;
+        while (tok != NULL && U_SUCCESS(*status)) {
+            el.prefix = el.prefixChars;
+            el.cPoints = el.uchars;
+            if(tok->prefix != 0) {
+                el.prefixSize = tok->prefix>>24;
+                uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar));
+
+                el.cSize = (tok->source >> 24)-(tok->prefix>>24);
+                uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar));
+            } else {
+                el.prefixSize = 0;
+                *el.prefix = 0;
+
+                el.cSize = (tok->source >> 24);
+                uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar));
+            }
+            if(src->UCA != NULL) {
+                for(j = 0; j<el.cSize; j++) {
+                    int16_t fcd = context.nfcImpl->getFCD16(el.cPoints[j]);
+                    if ( (fcd & 0xff) == 0 ) {
+                        baseChar = el.cPoints[j];  // last base character
+                        firstCM=0;  // reset combining mark value
+                    }
+                    else {
+                        if ( (baseChar!=0) && (firstCM==0) ) {
+                            firstCM = el.cPoints[j];  // first combining mark
+                        }
+                    }
+                }
+            }
+            if ( (baseChar!= (UChar)0) && (firstCM != (UChar)0) ) {
+                // find all the canonical rules
+                uprv_uca_addTailCanonicalClosures(t, colEl, baseChar, firstCM, &el, status);
+            }
+            tok = tok->next;
+        }
+    }
     ucol_closeElements(colEl);
     ucol_close(tempColl);
-  }
-  return context.noOfClosures;
-}
 
-U_NAMESPACE_END
+    return context.noOfClosures;
+}
 
 #endif /* #if !UCONFIG_NO_COLLATION */
-
-